We were given a binary which was packed. "strings" revealed something like "This file is packed with the LOL executable packer http://upx.sf.net". Unpacking with UPX didn't help. But strace gave the following info
[ctf@renorobert rev300]# strace ./task3.bin execve("./task3.bin", ["./task3.bin"], [/* 52 vars */]) = 0 [ Process PID=5086 runs in 32 bit mode. ] getpid() = 5086 gettimeofday({1350641971, 320063}, NULL) = 0 unlink("/tmp/upxDHV4WSUAIXC") = -1 ENOENT (No such file or directory) open("/tmp/upxDHV4WSUAIXC", O_RDWR|O_CREAT|O_EXCL, 0700) = 3 ftruncate(3, 9036) = 0 old_mmap(NULL, 9036, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0) = 0xfffffffff770a000 old_mmap(0xf770d000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xfffffffff770d000 munmap(0xf770a000, 9036) = 0 close(3) = 0 open("/tmp/upxDHV4WSUAIXC", O_RDONLY) = 3 getpid() = 5086 access("/proc/5086/fd/3", R_OK|X_OK) = 0 unlink("/tmp/upxDHV4WSUAIXC") = 0The binary unpacks itself into /tmp before gettting executed. So the idea was to grab a copy of it. Using objdump we found an entry point into the packed binary. By running the binary in gdb and setting necessary breakpoints, we got the copy of unpacked binary from /tmp before the file is unlinked.
[ctf@renorobert rev300]# objdump -f task3.bin task3.bin: file format elf32-i386 architecture: i386, flags 0x00000102: EXEC_P, D_PAGED start address 0x00402273Once the binary was unpacked, it nicely decompiled into a readable source. Here is the part of the source that we got
void __cdecl sub_8048617(int a1, int a2) { int v2; int v3; if ( a1 != 3 ) { printf("Usage: %s <user> <key>\n", *(_DWORD *)a2); exit(1); } if ( sub_8049A30(*(_DWORD *)(a2 + 4), "hackyou") ) { v3 = *(_DWORD *)(a2 + 4); v2 = *(_DWORD *)(a2 + 8); if ( sub_8049A00(v2) != 14 ) // length of key checked here sub_80485C9(); if ( *(_BYTE *)(v2 + 4) == 45 ) // key looks like ABCD-ABCD-ABCD { if ( *(_BYTE *)(v2 + 9) == 45 ) { if ( !sub_804838C(v3, v2) ) //function call to check 1st part of key sub_80485C9(); if ( !sub_804844B(v3, v2 + 5) ) //function call to check 2nd part of key sub_80485C9(); if ( !sub_804850A(v3, v2 + 10) ) //function call to check 3rd part of key sub_80485C9(); sub_80485F0(); } } sub_80485C9(); } printf("Err, something went wrong...\n"); exit(2); } signed int __cdecl sub_804838C(int a1, int a2) //first part of key is checked with this function { int v2; signed int i; char v5[64]; int v6; int v7; int v8; int v9; v6 = 23; v7 = 13; v8 = 34; v9 = 40; v2 = sub_8049A00(a1); sub_8048DC4(a1, v2, (int)v5, 64); for ( i = 0; i < 4; ++i ) { if ( sub_804831C(v5[*(&v6 + i)]) != *(_BYTE *)(i + a2) ) //key is checked here return 0; } return 1337; }After this, the process is straight forward. With gdb and junk input as key, we started tracing through the function calls setting up breakpoints and changing $eip's.
//Check for first part of key 0x8048418: call 0x804831c 0x804841d: add $0x4,%esp 0x8048420: mov 0xc(%ebp),%ecx 0x8048423: mov -0x54(%ebp),%edx 0x8048426: add %edx,%ecx 0x8048428: movsbl (%ecx),%edx 0x804842b: cmp %edx,%eax //key is checked here 0x804842d: je 0x804843d 0x8048433: mov $0x0,%eax 0x8048438: jmp 0x8048449 0x804843d: jmp 0x80483f1 0x804843f: mov $0x539,%eax 0x8048444: jmp 0x8048449 0x8048449: leave 0x804844a: ret (gdb) p $eax $4 = 107 (gdb) p $eax $5 = 101 (gdb) p $eax $6 = 99 (gdb) p $eax $9 = 99This way, we followed the three function calls and extracted the final key kecc-hack-yo0u
No comments :
Post a Comment