💾 Archived View for 0x80.org › gemlog › 2015-10-05-dctf-r400.gmi captured on 2022-04-28 at 17:40:46. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2021-12-03)
-=-=-=-=-=-=-
This challenge asks for a password. We see that it calls getenv to check for LD_PRELOAD, ptrace which are used to detect if a processes is debugged.
[0x00400875]> afl ~env 0x00400660 6 1 sym.imp.getenv [0x00400875]> afl ~ptr 0x004006f0 6 1 sym.imp.ptrace
Since this is dynamic binary we can bypass these without patching via LD_PRELOAD, we let getenv return 0, and ptrace return 0 to bypass the protection.
#include <stdio.h> int ptrace(int request, int pid, int addr, int data){ return 0; } char *getenv(const char *name){ return 0; }
After asking for the password we reach this.
[0x006010a7]> pd 4 0x006010a7 5e pop rsi 0x006010a8 6a00 push 0 0x006010aa 59 pop rcx 0x006010ab eb03 jmp 0x6010b0
rsi point to a block of code bytes, rcx is a counter in that block.
[0x006010a7]> s 0x6010b0 [0x006010b0]> pd 2 0x006010b0 xor dword [rsi + rcx], edx 0x006010b3 jmp 0x6010b8
our input is xored with dword in the rsi[rcx]
[0x006010b0]> s 0x6010b8 [0x006010b8]> pd 6 || 0x006010b8 add ecx, 4 || 0x006010bb cmp byte [rsi + rcx], 0xf0 ; [0xf0:1]=0 |`=< 0x006010bf jne 0x6010ab | 0x006010c1 cmp byte [rsi + rcx + 1], 0xd ; [0xd:1]=0 `==< 0x006010c6 jne 0x6010ab 0x006010c8 jmp rsi
increment counter, then compare to see if we reached the end which is 0xf00d, and jump to rsi if we reached the end. rsi is pointing to this block : 0x6010D8-0x601129 which is supposed to be valid instructions after xoring. We dump the block for analysis to find the key.
[0x006010d8]> s 0x6010D8 [0x006010d8]> wt xored_block.bin 82 dumped 0x52 bytes Dumped 82 bytes from 0x006010d8 into xored_block.bin
We assume the function contains at least int 0x80, and the key is printable. We write a script that searches for such thing
#!/usr/bin/env python2 from pwn import * from string import printable def main(): xcode = open("xored_block.bin", "rb").read() for i in xrange(0, 0xff): for j in xrange(0,0xff): k = chr(i)+chr(j) if "\xcd\x80" in xor(xcode, k) and \ all(c in printable for c in k): print "Found : ", k if __name__ == "__main__": main() ➜ r400 python2 find.py Found : 4b Found : ;& Found : fb Found : pk Found : v/
These are the possible beginning of the key, we use them and it seems '4b' is the one that makes sense here. Applying the key and looking at the disassembly, trying to make sense of the rest of it reveals that it's 'f6', we can also use the above script to find the last two characters by looking at 0x9090.
➜ r400 r2 -w xored_block.bin -- Excellent; we can attack in any direction! [0x00000000]> wox 0x34626636 [0x00000000]> aaa [0x00000000]> afl 0x00000000 80 1 fcn.00000000 [0x00000000]> pdf fcn.00000000 / (fcn) fcn.00000000 80 | 0x00000000 6a0a push 0xa | 0x00000002 686f726421 push 0x2164726f | 0x00000007 6861737377 push 0x77737361 | 0x0000000c 6868652070 push 0x70206568 | 0x00000011 686e642074 push 0x7420646e | 0x00000016 6820666f75 push 0x756f6620 | 0x0000001b 6820596f75 push 0x756f5920 | 0x00000020 686f6e7321 push 0x21736e6f | 0x00000025 686c617469 push 0x6974616c | ; DATA XREF from 0x00000034 (fcn.00000000) | 0x0000002a 6872617475 push 0x75746172 | 0x0000002f 68436f6e67 push 0x676e6f43 | 0x00000034 ba2a000000 mov edx, 0x2a ; '*' | 0x00000039 89e1 mov ecx, esp | 0x0000003b bb01000000 mov ebx, 1 | 0x00000040 b804000000 mov eax, 4 | 0x00000045 cd80 int 0x80 ;read (0x0,0x0,0x0) ; fcn.00000000+-1 | 0x00000047 b801000000 mov eax, 1 | 0x0000004c cd80 int 0x80 ;read (0x0,0x0,0x0) ; fcn.00000000+-1 | 0x0000004e 90 nop \ 0x0000004f 90 nop
password : 4bf6.
➜ r400 echo -ne '436f6e67726174756c6174696f6e732120596f7520666f756e64207468652070617373776f726421' | rax2 -s Congratulations! You found the password