Friday, October 19, 2012

Hack You CTF - Reverse 300 [Team xbios]

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")           = 0
The 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 0x00402273
Once 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 = 99
This way, we followed the three function calls and extracted the final key kecc-hack-yo0u

No comments :

Post a Comment