title: Quals NdH 2015 Clark Kent - re150 author: depierre published: 2015-04-06 categories: CTF, Security, Reverse Engineering keywords: quals, nuit du hack, ctf, write-up, re, 100, challenge, security, hackgyver Last week-end I participated to the qualifications of [NdH](http://quals.nuitduhack.com/) with [HackGyver](http://hackgyver.org) ([scoreboard](/static/images/qualsndh2k15/scoreboard.png)). We gathered at the hackerspace's local with [futex](http://remchp.com/), kiwhacks and pastrep (a new member met at the SecuRT 2015). We finished 32 over more than 200 teams that validated at least one challenge. It is not that bad, knowing that some of our key comrades where not available this Saturday. ![Clark Kent Reboot](/static/images/qualsndh2k15/clarkkent_strace.png) I had to do some stuff that I never did before and it was really fun. That is why I wanted to do the write-up of the [Clark Kent](http://quals.nuitduhack.com/challenges/view/2) reverse engineering challenge. # Clark Kent - The challenge On its web page: > "There's a shadow inside all of us. But that doesn't mean you need to embrace it. You decide who you really are. And > I know you'll make the right choice and become the hero you're destined to be." (Clark Kent) > > Become that hero you're destined to be. Discover and evolve your reversing powers. :::bash ultra-depierre :: ctf/ndh2k15/clarkkent » file clark clark: ELF 32-bit LSB executable, Intel 80386, invalid version (SYSV), for GNU/Linux 2.6.24, dynamically linked, interpreter \004, corrupted section header size Looks like they had fun with the ELF header. :::bash ultra-depierre :: ctf/ndh2k15/clarkkent » strings clark # . . . mprotect ptrace # . . . Booh! Don't debug me! Welcome to NDH2k15 No no no! Don't patch me! # . . . And also that they added a couple of anti-reverse stuffs. # Basic protections First ``clark`` run ``ptrace`` in order to check if it was currently being debugged. Indeed, ``ptrace`` will fail if the process is already ptraced. :::nasm hl_lines="7" LOAD:080484DD main proc near ; DATA XREF: start+17o ; [. . .] LOAD:080484E6 mov dword ptr [esp+0Ch], 0 LOAD:080484EE mov dword ptr [esp+8], 1 LOAD:080484F6 mov dword ptr [esp+4], 0 LOAD:080484FE mov dword ptr [esp], 0 ; request LOAD:08048505 call ptrace ; Anti-debug ptrace trick LOAD:0804850A cmp eax, 0FFFFFFFFh ; ptrace returns -1 when process is already ptraced LOAD:0804850D jnz short loc_8048527 LOAD:0804850F mov dword ptr [esp], offset s ; "Booh! Don't debug me!" LOAD:08048516 call puts LOAD:0804851B mov dword ptr [esp], 1 ; status LOAD:08048522 call exit Then the binary computed a checksum and decrypted a chunk of code with that checksum: :::nasm LOAD:08048527 loc_8048527: ; CODE XREF: main+30j LOAD:08048527 mov dword ptr [esp], offset aWelcomeToNdh2k ; "Welcome to NDH2k15" LOAD:0804852E call puts LOAD:08048533 mov edx, offset loc_80485E1 LOAD:08048538 mov eax, offset loc_80484E6 LOAD:0804853D sub edx, eax ; size to checksum LOAD:0804853F mov eax, edx LOAD:08048541 mov [esp+4], eax LOAD:08048545 mov dword ptr [esp], offset loc_80484E6 ; start offset of what to checksum LOAD:0804854C call compute_checksum LOAD:08048551 mov [esp+14h], eax LOAD:08048555 mov eax, [esp+14h] LOAD:08048559 mov [esp+8], eax ; result of the checksum LOAD:0804855D mov dword ptr [esp+4], 186h LOAD:08048565 mov dword ptr [esp], offset enc_chunk LOAD:0804856C call decrypt_chunk After it computed another checksum and checked if the binary had been patched: :::nasm LOAD:08048571 mov [esp+18h], eax LOAD:08048575 mov dword ptr [esp+4], 186h LOAD:0804857D mov eax, [esp+18h] LOAD:08048581 mov [esp], eax LOAD:08048584 call compute_checksum LOAD:08048589 cmp eax, 5780C882h LOAD:0804858E jz short loc_80485A8 LOAD:08048590 mov dword ptr [esp], offset aNoNoNoDonTPatc ; "No no no! Don't patch me!" LOAD:08048597 call puts LOAD:0804859C mov dword ptr [esp], 1 ; status LOAD:080485A3 call exit Finally, it changed the protection of the allocated buffer that contained the decrypted code and jumped in it: :::nasm LOAD:080485A8 loc_80485A8: ; CODE XREF: main+B1j LOAD:080485A8 mov eax, [esp+18h] LOAD:080485AC and eax, 0FFFFF000h LOAD:080485B1 mov dword ptr [esp+8], 5 ; prot LOAD:080485B9 mov dword ptr [esp+4], 186h ; len LOAD:080485C1 mov [esp], eax ; addr LOAD:080485C4 call mprotect LOAD:080485C9 mov [esp+1Ch], eax LOAD:080485CD cmp dword ptr [esp+1Ch], 0 LOAD:080485D2 jns short loc_80485DB LOAD:080485D4 mov eax, 1 LOAD:080485D9 jmp short locret_80485E6 ; Jump to exit. LOAD:080485DB loc_80485DB: ; CODE XREF: main+F5j LOAD:080485DB mov eax, [esp+18h] LOAD:080485DF call eax ; Jump into the decrypted buffer. # Patch like a noob First thing I wanted to extract was the checksum algorithm to decrypt the chunk of code locally. :::c int __cdecl compute_checksum(int start_offset, int size) { int i; // [sp+8h] [bp-8h]@1 int checksum; // [sp+Ch] [bp-4h]@1 checksum = 0; for ( i = 0; i < size; ++i ) checksum = 0x1000193 * (*(_BYTE *)(i + start_offset) ^ checksum); return checksum; } It gave me ``0xB4DF7F49`` but sadly, I could not make the decrypt function work properly. I changed my mind and decided to patch the program instead. So I patched the ``ptrace`` call with ``mov eax, 1; cmp eax, -1; jnz``. Then I hardcoded the checksum with the one I extracted ``mov eax, 0xB4DF7F49`` and hardcoded the last checksum as well ``mov eax, 0x5780C882, cmp eax, 0x5780C882``. # Film the strace Now I was ready to run the program. Using ``strace`` I was able to see what the binary was trying to do: :::bash ; . . . mprotect(0x9f11000, 390, PROT_READ|PROT_EXEC) = 0 getuid() = 1000 write(1, "Need supercow power!!!\nBye!\n\0", 29Need supercow power!!! Bye! ) = 29 _exit(1) Are you asking to run you as root? No way!. After hearing jvoisin's idea to booby-trap CTF binaries, there is no way I would run a binary as root. Instead I fired-up a 32bit Kali machine. The problem I had was that I could not read the program output when run as root. It was too fast and the VM kept rebooting. I had the idea to film the VM thanks to VirtualBox's *Video Capture* feature. It gave me the following output: ![Clark Kent Reboot](/static/images/qualsndh2k15/clarkkent_strace.png) I tried to ``LD_PRELOAD`` the binary and intercept the ``reboot`` function with no success until I realized that the binary was rebooting the VM via a system call. *Now that the CTF is over, I could have ``LD_PRELOAD`` the binary to hook the ``mprotect`` function and dump the code chunk instead of remote-debugged the binary with IDA... But I did not think about that :P* # Remote debugging via IDA Instead, I chose a less obvious way. Since gdb would fail everytime (*change one byte in the headers and gdb is completely lost...*) I did not know what tool to use. Then futex told me about one article he wrote a couple of month ago: [Remote debugging with IDA](http://remchp.com/blog/?p=187). I copied ``IDA/dbgsrv/linux_server`` onto my Kali VM: :::bash root@kali32:~# ./linux_server IDA Linux 32-bit remote debug server(ST) v1.17. Hex-Rays (c) 2004-2014 Listening on port #23946... And configured IDA via ``Debugger -> Process options`` like below: ![IDA Remote Options](/static/images/qualsndh2k15/ida_remote.png) I put a breakpoint on the ``mprotect`` call and checked the heap: ![Clark Kent Flag](/static/images/qualsndh2k15/clark_flag.png) Luckily, the flag was in clear right here: **WhyN0P4tch?** *Note:* Using ``rasm2`` (or IDA who cares?) on the heap chunk :::nasm 0x0000004d 5 ba67452301 mov edx, 0x1234567 0x00000052 5 b969191228 mov ecx, 0x28121969 0x00000057 5 bbaddee1fe mov ebx, 0xfee1dead 0x0000005c 5 b858000000 mov eax, 0x58 ; reboot syscall 0x00000061 2 cd80 int 0x80 Bastards!