Description
New Adventure! It’s AMO time~
Analysis
run 함수에서 w/a/s/d 중 하나를 입력해서 분기문을 따라가보면,
위와 같이 opcode를 XOR 연산하여 8바이트 복원시키는 것을 알 수 있다. (여기서는 암호화된 opcode 주소가 0x162b이다.)
위 그림은 복호화시킨 opcode이다.
보다시피 r8 주소에 임의의 값인 0x2C를 더하고 다시한번 더 w/a/s/d를 입력받는다.
win
void __fastcall __noreturn win(__int64 a1, __int64 a2, __int64 a3, __int64 a4, unsigned __int64 a5) { int fd; // [rsp+4h] [rbp-11Ch] __int64 buf[34]; // [rsp+10h] [rbp-110h] BYREF buf[33] = __readfsqword(0x28u); if ( a5 > 0xC6 ) { puts("Failed!"); printf("%d\n", a5); exit(1); } memset(buf, 0, 256); fd = open("flag.txt", 0); read(fd, buf, 0xFFuLL); puts((const char *)buf); close(fd); exit(0); }
r8 레지스터는 곧 a5 변수로,
값이 0xC6 보다 작아야 플래그를 획득할 수 있다.
결국 w/a/s/d 입력을 통해 미로를 풀어서 r8 레지스터값이 0xc6보다 작도록 만들고,
탈출구인 win 함수를 찾아야되는 듯 하다.
Solution
ida의 idc 스크립트를 작성해보는 것은 익숙하지 않아서 chatgpt를 참고하면서 코드를 만들어보았다.
스크립트의 작동방식은 아래와 같이 생각하면서 chatgpt에게 물어보았다.
1. opcode를 복호화하는 과정에는 항상 mov, lea, xor, mov 순의 opcode 패턴이 존재하기 때문에
그것에 해당되는 opcode를 검색한다.
2. mov [rax], rdx opcode는 nop으로 패치해서 복호화가 작동되지 않도록 하고,
스크립트내에서 복호화된 opcode 8바이트로 패치하도록 만든다.
아무튼 그런 아이디어로 스크립트를 한번 만들어보았다.
static main(void) { auto ea, end_ea, ea_next; auto instr; ea = 0x1160;//BeginEA(); // Start from the current cursor position end_ea = 0x721b;//SegEnd(ea); // End address of the current segment // Iterate over the instructions in the segment Message("instruction search start.\n"); for (ea = NextHead(ea, end_ea); ea != BADADDR; ea = NextHead(ea, end_ea)) { instr = GetMnem(ea); // Get the mnemonic of the instruction if (instr == "mov") { ea_next = NextHead(ea, end_ea); if(GetMnem(ea_next) == "lea") { ea_next = NextHead(ea_next, end_ea); if(GetMnem(ea_next) == "xor") { ea_next = NextHead(ea_next, end_ea); if(GetMnem(ea_next) == "mov") { PatchByte(ea_next, 0x90); PatchByte(ea_next+1, 0x90); PatchByte(ea_next+2, 0x90); ea_next = NextHead(ea_next, end_ea); Message("Address: 0x%x, src: 0x%x, src_read: 0x%x, enc_instr: 0x%x, Instruction: %s %s\n", ea, GetOperandValue(ea, 1), Qword(GetOperandValue(ea, 1)), Qword(ea_next), GetDisasm(ea)); PatchQword(ea_next, Qword(ea_next) ^ Qword(GetOperandValue(ea, 1))); } } } } } Message("instruction search completed.\n"); }
완전히 스크립트가 작동되지 않아 손수 하나씩 수정해줄 필요도 있긴 하지만,
아무튼 그렇게 패치하고 opcode를 복호화시키면, patched byte 수는 2462 바이트 정도 된다.
win 함수를 호출하는 분기점은 loc_411C이며,
위와 같이 run 함수에서 Graph View로 변환하고 (말그대로 모양이 maze다…),
되도록 최대한 위로 올라갈 수 있는 분기문을 따라올라가 call win을 호출하는 끝점에서 시작점까지 하나씩 찾았다.
key / branched loc / r8 add value -> s, loc_15C8, +0x14 -> s, loc_1B9E, +0x2f -> s, loc_2170, +0x1c -> s, loc_2741, +0x31 -> s, loc_2D12, +0x19 -> s, loc_32E3, +0x39 -> s, loc_38B4, +0x21 -> d, loc_3E85, +0x21 -> d, loc_3EE8, +0x36 -> d, loc_3F4B, +0x11 -> d, loc_3FAE, +0x38 -> d, loc_4011, +0x1e -> d, loc_4074, +0x11 -> d, loc_40B9, +0x14
from pwn import * #context.log_level = 'debug' context(arch='amd64',os='linux') warnings.filterwarnings('ignore') p = remote('host3.dreamhack.games', 17910) #p = process('./maze-amo') for i in range(7): p.sendline("s") for i in range(7): p.sendline("d") p.interactive()
Result
ubuntu@wh1te4ever-main:~/Desktop/dreamhack-CTF/Adventure-Maze_Odyssey$ python3 solve.py [+] Opening connection to host3.dreamhack.games on port 17910: Done [*] Switching to interactive mode @&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&& ..... ,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&# .... &&&&&&&&&&& &&&&&&@&&&& . ...... ,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ...... . &&&&&&&&&& &&&&&&&&&&& &@@@ ....... *&&&&&&&&&&&&&&&&&&&&&&&&&&&& ....... @@@@ .,&&&&&&&&& &&&&&&&&&&& @@@@@& ........ &&&&&&&&&&&&&&&&&&&&&&& ......... @@@@@ .,&&&&&&&&& &&&&&&&&&&& ./@@@@@@ ......... ,&&&&&#*. ,/&&&&&& ........../@@@@@@ .*&&&&&&&&& &&&&&&&&&&& . @@@@@@@ ....................................../@@@@@@#. &&&&&&&&&& @&&&&&&&&&&.. @@@@@@@% .................................... @@@@@@@ . &&&&&&&&&& &&&&&&&&&&&& .*@@@@@@ ..................................... &@@@@@@ .,&&&&&&&&&& &&&&&&&&&&&& . @@@@ ......................................... @@@@ . &&&&&&&&&&& &&&&&&&&&&&&& .*@@ ........................................... /@@ ..&&&&&&&&&&& &&&&&&&&&&&&& . @ .............................................. . &&&&&&&&&&&& &&&&&&&&&&&&&& ....... %%%%%%%%# ............. *%%%%%%%%. ........*&&&&&&&&&&&& &&&&&&&&&&&&&& ..... #%%%% %%.......... %% %%%%% ..... &&&&&&&&&&&&& &&&&&&&&&&&&&& .... %%%% @ %*....... %. @ %%%% .....*&&&&&&&&&&&& @&&&&&&&&&&&&& .... %%%% (@@@#. %% ......*% (@@@%* #%%% ......&&&&&&&&&&&& &&&&&&&&&&&&&& ......%%%% @ (% ....... %% % *%%%% .....#&&&&&&&&&&&& &&&&&&&&&&&&&&/...... %%%%%%%%%%%%( .... ... %%%%%%%%%%%% ...... &&&&&&&&&&&&& &&&&&&&&&&&&&&. ....... ....... ...... ........ (&&&&&&&&&&&& &&&&&&&&&&&&&&&&& ............................................. &&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&# ....................................... .&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&* ............................... &&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&# .*##. ............. ### &&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&.... ##*......@@@@@@@@@@@...... ## ... &&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&& .... ## .......@@@@@@@@@........ #(.... &&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&& . .@@@@@ ........@@@@@........ @@@@@& ../&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&& @@@@@@@@/................... @@@@@@@@ &&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&#*@@@@@@@ ................... @@@@@@@@ &&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&# , ....................... . &&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&/........................... &&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&& ......... .........*&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&& ............ ............./&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&& ............. ............. &&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&& @@@@@@@@@@@& &(.@@@@@@@@@@@ &&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&, #&&&&&&&&&&/ ,&&&&&&&&&&&&&&&&&&&&&&&&&&&&& @&&&&&&&&&&&&&&&&&&&@&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Welcome to maze! Input (w/a/s/d) > Going down... Input (w/a/s/d) > Going down... Input (w/a/s/d) > Going down... Input (w/a/s/d) > Going down... Input (w/a/s/d) > Going down... Input (w/a/s/d) > Going down... Input (w/a/s/d) > Going down... Input (w/a/s/d) > Going right... Input (w/a/s/d) > Going right... Input (w/a/s/d) > Going right... Input (w/a/s/d) > Going right... Input (w/a/s/d) > Going right... Input (w/a/s/d) > Going right... Input (w/a/s/d) > Going right... DH{bdfa950d55175a8465e4d80f382b785189df3b260275d8bae2faf89ff5b86b6c} [*] Got EOF while reading in interactive $ [*] Interrupted [*] Closed connection to host3.dreamhack.games port 17910