rootfoo.org

2013 Legitbs Defcon CTF Qualifiers - gnireenigne 1

2013-06-17
By meta

The first reverse engineering challenge was a 32-bit Linux ELF binary and corresponding core dump. Using gdb to load the core file shows us that the core was dumped at the start of the program. Hence examining the stack doesn't reveal much. You can see the environment (ASCII chars) at the bottom, that's about it. The main function is short and sweet, it sets some terminal attributes, printfs a string, getchars some input, puts a string, then exits. We spent some time reversing tty_raw() but didn't find anything out of the ordinary.

Core was generated by `policebox'.
#0  0x08048621 in main ()
(gdb) disas main
Dump of assembler code for function main:
   0x0804861e <+0>:	push   ebp
   0x0804861f <+1>:	mov    ebp,esp
=> 0x08048621 <+3>:	and    esp,0xfffffff0
   0x08048624 <+6>:	sub    esp,0x20
   0x08048627 <+9>:	mov    eax,ds:0x804a044
   0x0804862c <+14>:	mov    DWORD PTR [esp],eax
   0x0804862f <+17>:	call   0x80484d0 
   0x08048634 <+22>:	test   eax,eax
   0x08048636 <+24>:	jne    0x8048644 
   0x08048638 <+26>:	mov    DWORD PTR [esp],0x804888c
   0x0804863f <+33>:	call   0x8048470 
   0x08048644 <+38>:	mov    eax,ds:0x804a044
   0x08048649 <+43>:	mov    DWORD PTR [esp+0x4],0x804a060
   0x08048651 <+51>:	mov    DWORD PTR [esp],eax
   0x08048654 <+54>:	call   0x80484e0 
   0x08048659 <+59>:	test   eax,eax
   0x0804865b <+61>:	jns    0x8048669 
   0x0804865d <+63>:	mov    DWORD PTR [esp],0x8048899
   0x08048664 <+70>:	call   0x8048470 
   0x08048669 <+75>:	mov    DWORD PTR [esp],0x8048611
   0x08048670 <+82>:	call   0x8048830 
   0x08048675 <+87>:	call   0x80486c1 
   0x0804867a <+92>:	mov    DWORD PTR [esp+0x1c],0x0
   0x08048682 <+100>:	mov    DWORD PTR [esp],0x80488b0
   0x08048689 <+107>:	call   0x8048440 
   0x0804868e <+112>:	jmp    0x80486b3 
   0x08048690 <+114>:	call   0x8048450 
   0x08048695 <+119>:	mov    BYTE PTR [esp+0x1b],al
   0x08048699 <+123>:	cmp    BYTE PTR [esp+0x1b],0xd
   0x0804869e <+128>:	jne    0x80486ae 
   0x080486a0 <+130>:	mov    DWORD PTR [esp],0x80488bd
   0x080486a7 <+137>:	call   0x80484a0 
   0x080486ac <+142>:	jmp    0x80486ba 
   0x080486ae <+144>:	add    DWORD PTR [esp+0x1c],0x1
   0x080486b3 <+149>:	cmp    DWORD PTR [esp+0x1c],0x3f
   0x080486b8 <+154>:	jle    0x8048690 
   0x080486ba <+156>:	mov    eax,0x0
   0x080486bf <+161>:	leave  
   0x080486c0 <+162>:	ret    
End of assembler dump.


(gdb) x/150x $esp
0xbffff298:	0x00000000	0xb7e364d3	0x00000001	0xbffff334
0xbffff2a8:	0xbffff33c	0xb7fdd858	0x00000000	0xbffff31c
0xbffff2b8:	0xbffff33c	0x00000000	0x0804829c	0xb7fc3000
0xbffff2c8:	0x00000000	0x00000000	0x00000000	0x15191352
0xbffff2d8:	0x2c357742	0x00000000	0x00000000	0x00000000
0xbffff2e8:	0x00000001	0x080484f0	0x00000000	0xb7ff26a0
0xbffff2f8:	0xb7e363e9	0xb7fff000	0x00000001	0x080484f0
0xbffff308:	0x00000000	0x08048511	0x0804861e	0x00000001
0xbffff318:	0xbffff334	0x080487b0	0x08048820	0xb7fed270
0xbffff328:	0xbffff32c	0xb7fff938	0x00000001	0xbffff493
0xbffff338:	0x00000000	0xbffff4b8	0xbffff4cc	0xbffff507
0xbffff348:	0xbffff517	0xbffff522	0xbffff572	0xbffff584
0xbffff358:	0xbffff5be	0xbffff5dc	0xbffff5ec	0xbffffb0d
0xbffff368:	0xbffffb47	0xbffffb7b	0xbffffbb1	0xbffffbe4
0xbffff378:	0xbffffc38	0xbffffc43	0xbffffc70	0xbffffc87
0xbffff388:	0xbffffcfe	0xbffffd0d	0xbffffd2c	0xbffffd3d
0xbffff398:	0xbffffd55	0xbffffd8b	0xbffffda8	0xbffffdc7
0xbffff3a8:	0xbffffdd0	0xbffffde2	0xbffffdf8	0xbffffe00
0xbffff3b8:	0xbffffe2c	0xbffffe3f	0xbffffe59	0xbffffebb
0xbffff3c8:	0xbfffff0a	0xbfffff2a	0xbfffff35	0xbfffff5a
0xbffff3d8:	0xbfffff74	0xbfffff96	0xbfffffbe	0x00000000
0xbffff3e8:	0x00000010	0x1f8bfbff	0x00000006	0x00001000
0xbffff3f8:	0x00000011	0x00000064	0x00000003	0x08048034
0xbffff408:	0x00000004	0x00000020	0x00000005	0x00000009
0xbffff418:	0x00000007	0xb7fde000	0x00000008	0x00000000
0xbffff428:	0x00000009	0x080484f0	0x0000000b	0x000003e9
0xbffff438:	0x0000000c	0x000003e9	0x0000000d	0x000003e9
0xbffff448:	0x0000000e	0x000003e9	0x00000017	0x00000000
0xbffff458:	0x00000019	0xbffff47b	0x0000001f	0xbfffffd7
0xbffff468:	0x0000000f	0xbffff48b	0x00000000	0x00000000
0xbffff478:	0x6d000000	0x29801a3b	0x5e16f57e	0x6c62f32d
0xbffff488:	0x69e6925f	0x00363836	0x2f000000	0x656d6f68
0xbffff498:	0x6761722f	0x79646567	0x2f6e616d	0x696c6f70
0xbffff4a8:	0x6f626563	0x6f702f78	0x6563696c	0x00786f62
0xbffff4b8:	0x5f485353	0x4e454741	0x49505f54	0x36313d44
0xbffff4c8:	0x00383034	0x5f475047	0x4e454741	0x4e495f54
0xbffff4d8:	0x2f3d4f46	0x2f6e7572	0x72657375	0x6761722f
0xbffff4e8:	0x79646567	0x2f6e616d

Running the program by itself prompts the user to type the key, does not echo the input (like a password prompt), and then exits. This leads us to believe that the goal is to extract the typed key from the core file. We use ltrace to get a quick overview of what the program is doing. The man-page for tcsetattr confirms that they are setting terminal attributes (termios) to prevent the input from being echoed.

$ ./policebox 
The key is: 


$ ltrace -if ./policebox 
[pid 15237] [0x8048511] __libc_start_main(0x804861e, 1, 0xffc931d4, 0x80487b0, 0x8048820
[pid 15237] [0x8048634] isatty(0)                                 = 1
[pid 15237] [0x8048659] tcgetattr(0, 0x0804a060)                  = 0
[pid 15237] [0x8048863] __cxa_atexit(0x8048611, 0, 0, 0xf76c4ff4, 0) = 0
[pid 15237] [0x804878d] tcsetattr(0, 2, 0xffc930c0)               = 0
[pid 15237] [0x804868e] printf("The key is: ")                    = 12
The key is: 
[pid 15237] [0x8048695] getchar(0x80488b0, 0x804a060, 0xffc931dc, 0xf7553225, 0xf76f4280) = 65
[pid 15237] [0x8048695] getchar(0x80488b0, 0x804a060, 0xffc931dc, 0xf7553225, 0xf76f4280) = 65
[pid 15237] [0x8048695] getchar(0x80488b0, 0x804a060, 0xffc931dc, 0xf7553225, 0xf76f4280) = 65
[pid 15237] [0x8048695] getchar(0x80488b0, 0x804a060, 0xffc931dc, 0xf7553225, 0xf76f4280) = 65
[pid 15237] [0x8048695] getchar(0x80488b0, 0x804a060, 0xffc931dc, 0xf7553225, 0xf76f4280) = 13
[pid 15237] [0x80486ac] puts("\r") = 2
[pid 15237] [0x80485ff] tcsetattr(0, 2, 0x0804a060)               = 0
[pid 15237] [0xffffffff] +++ exited (status 0) +++

Next we look at the sections in the core file using readelf. Everything looks normal except the "precord" section. By dumping that section as hex we see values which are almost certainly pointers to addresses on the stack. However, this particular section isn't loaded into memory nor is it marked as writable. In contrast, section 16 is most likely the stack because it's loaded where we expect (0xbffdf000) and is writeable but not executable.

$ readelf -S core.orig 
There are 18 section headers, starting at offset 0x272b98:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] precord           PROGBITS        00000000 1f5760 07d41a 00      0   0  1
  [ 2] note0             NOTE            00000000 000234 00052c 00   A  0   0  1
  [ 3] load              PROGBITS        08048000 000760 001000 00  AX  0   0  1
  [ 4] load              PROGBITS        08049000 001760 001000 00   A  0   0  1
  [ 5] load              PROGBITS        0804a000 002760 001000 00  WA  0   0  1
  [ 6] load              PROGBITS        b7e1c000 003760 001000 00  WA  0   0  1
  [ 7] load              PROGBITS        b7e1d000 004760 1a3000 00  AX  0   0  1
  [ 8] load              PROGBITS        b7fc0000 1a7760 001000 00   A  0   0  1
  [ 9] load              PROGBITS        b7fc1000 1a8760 002000 00   A  0   0  1
  [10] load              PROGBITS        b7fc3000 1aa760 001000 00  WA  0   0  1
  [11] load              PROGBITS        b7fc4000 1ab760 003000 00  WA  0   0  1
  [12] load              PROGBITS        b7fda000 1ae760 004000 00  WA  0   0  1
  [13] load              PROGBITS        b7fde000 1b2760 020000 00  AX  0   0  1
  [14] load              PROGBITS        b7ffe000 1d2760 001000 00   A  0   0  1
  [15] load              PROGBITS        b7fff000 1d3760 001000 00  WA  0   0  1
  [16] load              PROGBITS        bffdf000 1d4760 021000 00  WA  0   0  1
  [17] .shstrtab         STRTAB          00000000 272b7a 00001e 00      0   0  1


$ readelf -x 1 core.orig | head -n 30

Hex dump of section 'precord':
  0x00000000 20091016 01000000 0490f2ff bf010000  ...............
  0x00000010 00098602 20000100 00000824 86040800 .... ......$....
  0x00000020 00000000 00000001 01000000 0470f2ff .............p..
  0x00000030 bf010000 00098202 20000100 00000827 ........ ......'
  0x00000040 86040800 00000000 00000002 01000000 ................
  0x00000050 00000000 00010000 00082c86 04080000 ..........,.....
  0x00000060 00000000 00000302 00000004 00000000 ................
  0x00000070 bffff270 00000000 01000000 082f8604 ...p........./..
  0x00000080 08000000 00000000 00040100 0000046c ...............l
  0x00000090 f2ffbf02 00000004 00000000 bffff26c ...............l
  0x000000a0 34860408 01000000 08d08404 08000000 4...............
  0x000000b0 00000000 00050100 00000982 02200001 ............. ..
  0x000000c0 00000008 d6840408 00000000 00000000 ................
  0x000000d0 06010000 000468f2 ffbf0200 00000400 ......h.........
  0x000000e0 000000bf fff26848 00000001 00000008 ......hH........
  0x000000f0 db840408 00000000 00000000 07010000 ................
  0x00000100 00083084 04080000 00000000 00000801 ..0.............
  0x00000110 00000004 64f2ffbf 02000000 04000000 ....d...........
  0x00000120 00bffff2 6438f9ff b7010000 00083684 ....d8........6.
  0x00000130 04080000 00000000 00000901 00000009 ................
  0x00000140 82022000 01000000 089026ff b7000000 .. .......&.....
  0x00000150 00000000 000a0100 00000460 f2ffbf02 ...........`....
  0x00000160 00000004 00000000 bffff260 00000000 ...........`....
  0x00000170 01000000 089126ff b7000000 00000000 ......&.........
  0x00000180 000b0100 0000045c f2ffbf02 00000004 .......\........
  0x00000190 00000000 bffff25c 34f3ffbf 01000000 .......\4.......
  0x000001a0 089226ff b7000000 00000000 000c0100 ..&.............
  0x000001b0 00000458 f2ffbf02 00000004 00000000 ...X............

For comparison, let's use gdb to create our own core file. This will give us a baseline to verify that the "precord" section is indeed worth investigating.

$ gdb ./policebox 

(gdb) disas main
Dump of assembler code for function main:
   0x0804861e <+0>:	push   ebp
   0x0804861f <+1>:	mov    ebp,esp
   0x08048621 <+3>:	and    esp,0xfffffff0
   0x08048624 <+6>:	sub    esp,0x20
   0x08048627 <+9>:	mov    eax,ds:0x804a044

(gdb) break *0x08048621
Breakpoint 1 at 0x8048621

(gdb) run
Starting program: /media/sf_ctf/2013/LegitBS-QUALS/.gnireenigne-1-solved/working/meta/policebox 

Breakpoint 1, 0x08048621 in main ()

(gdb) generate-core-file 
Saved corefile core.8528

(gdb) quit

$ readelf -S core.8528 
There are 17 section headers, starting at offset 0x1f3628:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] note0             NOTE            00000000 000214 0003fc 00   A  0   0  1
  [ 2] load              PROGBITS        08048000 000610 001000 00  AX  0   0  1
  [ 3] load              PROGBITS        08049000 001610 001000 00   A  0   0  1
  [ 4] load              PROGBITS        0804a000 002610 001000 00  WA  0   0  1
  [ 5] load              PROGBITS        b7e1c000 003610 001000 00  WA  0   0  1
  [ 6] load              PROGBITS        b7e1d000 004610 1a3000 00  AX  0   0  1
  [ 7] load              PROGBITS        b7fc0000 1a7610 002000 00   A  0   0  1
  [ 8] load              PROGBITS        b7fc2000 1a9610 001000 00  WA  0   0  1
  [ 9] load              PROGBITS        b7fc3000 1aa610 003000 00  WA  0   0  1
  [10] load              PROGBITS        b7fdb000 1ad610 002000 00  WA  0   0  1
  [11] load              PROGBITS        b7fdd000 1af610 001000 00  AX  0   0  1
  [12] load              PROGBITS        b7fde000 1b0610 020000 00  AX  0   0  1
  [13] load              PROGBITS        b7ffe000 1d0610 001000 00   A  0   0  1
  [14] load              PROGBITS        b7fff000 1d1610 001000 00  WA  0   0  1
  [15] load              PROGBITS        bffdf000 1d2610 021000 00  WA  0   0  1
  [16] .shstrtab         STRTAB          00000000 1f3610 000016 00      0   0  1

Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

Google tells us that GDB has a lesser known feature for recording and replaying process execution - how cool is that! Actually, I've known about this feature for awhile but somehow have never taken the time to learn how it works. Thank you CTF for forcing me to learn about all of the cool things. After a little light reading we figure out how to replay the session. Don't forget to debug the process sufficiently so you know where to set a breakpoint to see the interesting bits. GDB Process Record and Replay

$ gdb --core core.orig policebox 

GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
...
Reading symbols from /media/sf_ctf/dolly/gnireenigne-1/working/meta/policebox...(no debugging symbols found)...done.
[New LWP 17170]

warning: .dynamic section for "/lib/ld-linux.so.2" is not at the expected address (wrong library or version mismatch?)
Core was generated by `policebox'.
#0  0x08048621 in main ()

(gdb) target record
Restored records from core file /media/sf_ctf/dolly/gnireenigne-1/working/meta/core.orig.
#0  0x08048621 in main ()

(gdb) rc
Continuing.
No more reverse-execution history.

(gdb) break *0x08048695
Breakpoint 1 at 0x8048695

(gdb) disp/c $eax
2: /c $eax = 1 '\001'
(gdb) c
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 119 'w'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 48 '0'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 114 'r'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 108 'l'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 100 'd'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 115 's'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 46 '.'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 119 'w'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 48 '0'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 114 'r'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 115 's'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 116 't'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 46 '.'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 107 'k'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 51 '3'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 121 'y'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 108 'l'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 48 '0'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 103 'g'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 103 'g'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 101 'e'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 114 'r'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 33 '!'
(gdb) 
Continuing.

Breakpoint 1, 0x08048695 in main ()
2: /c $eax = 13 '\r'
(gdb) 
Continuing.

No more reverse-execution history.
0xb7fdf1b0 in ?? () from /lib/ld-linux.so.2
2: /c $eax = -4 '\374'

The key is: w0rlds.w0rst.k3yl0gger!