Artificial truth

The more you see, the less you believe.

[archives] [latest] | [homepage] | [atom/rss]

PwniumCTF 2014 - kernel (150) with radare2
Mon 11 August 2014 — download

I though that I published this writeup right after the end of the CTF, but apparently I forgot. The task wasn't hard at all, and the only point of this blogpost is to show how to use radare2 to get things done™.

$ r2 -A kernel
DWARF: version 4 is yet not supported
DWARF: version 4 is yet not supported
DWARF: version 4 is yet not supported
DWARF: version 4 is yet not supported
DWARF: version 4 is yet not supported
[0x001005f0]> iI~class
class   ELF32
[0x001005f0]>

So, it seems that the file is a x86 ELF binary, likely some kernel-related thing. The challenge said:

The third Tick gives you the answer ;) http://41.231.53.40/kernel

[0x001005f0]> is~tick
addr=0x001060c0 off=0x000060c0 ord=082 fwd=NONE sz=4 bind=GLOBAL type=OBJECT name=tick
addr=0x00100958 off=0x00000958 ord=107 fwd=NONE sz=72 bind=GLOBAL type=FUNC name=timer_tick

The is command stands for Information about Symbols, while the tild is used in radare2 as a grep operator.

[0x001005f0]> pdf@timer_tick
Invalid address (timer_tick)
[0x001005f0]> pdf@sym.timer_tick
          ; UNKNOWN XREF from 0x00100951 (unk)
          ; DATA XREF from 0x000019a3 (fcn.000019a0)
          ; DATA XREF from 0x001009a3 (unk)
         0x00100958    83ec14       sub esp, 0x14
         0x0010095b    a1c0601000   mov eax, [sym.tick]
         0x00100960    8d5001       lea edx, [eax+0x1]
         0x00100963    8915c0601000 mov [sym.tick], edx
         0x00100969    50           push eax
         0x0010096a    6803221000   push str._d_Tick.._n ; str._d_Tick.._n
         0x0010096f    e8d5050000   call sym.printf
         0x00100974    0fb60dc0601. movzx ecx, byte [sym.tick]
         0x0010097b    83c410       add esp, 0x10
         0x0010097e    b800000000   mov eax, 0x0
          ; JMP XREF from 0x0010099a (unk)
         0x00100983    89ca         mov edx, ecx
         0x00100985    329060301000 xor dl, [eax+sym.flag]
         0x0010098b    83c201       add edx, 0x1
         0x0010098e    889060301000 mov [eax+sym.flag], dl
         0x00100994    83c001       add eax, 0x1
         0x00100997    83f828       cmp eax, 0x28
         0x0010099a    75e7         jne loc.00100983
         0x0010099c    83c40c       add esp, 0xc
         0x0010099f    c3           ret
[0x001005f0]>

This seems to be a decryption function, something like:

for i in range(0x28):
    A[i] = (A[i] ^ tick) + 1

Let's take a look at the sym.flag global variable with the pxa command (Print heXdump Annotated).

[0x001005f0]> pxa @sym.flag
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
              /sym.flag                                                             
0x00103060  4974 6f66 726a 7862 3260 2e2e 632e 322e  Itofrjxb2`..c.2.
0x00103070  3630 3331 5d67 3662 3167 6730 5e29 6231  6031]g6b1gg0^)b1
                                            /sym.color                              
0x00103080  3163 625e 5e2d 5d7a 0000 0000 0f00 0000  1cb^^-]z........
              /sym.video/section_end..data                                          
0x00103090  0080 0b00 ff08 0000 0400 0000 0000 0401  ................
0x001030a0  d900 0000 01d4 0100 0064 0000 000c 0010  .........d......
0x001030b0  0029 0500 0000 0000 0002 6e02 0000 0206  .)........n.....
0x001030c0  3000 0000 0304 0780 0300 0004 0405 696e  0.............in
0x001030d0  7400 0281 0200 0002 0849 0000 0003 0207  t........I......
0x001030e0  4900 0000 0302 0592 0100 0002 9900 0000  I...............
0x001030f0  020a 6200 0000 0301 0836 0000 0003 0106  ..b......6......
0x00103100  3f00 0000 02b7 0000 0003 217b 0000 0005  ?.........!{....
0x00103110  0481 0000 0006 8c00 0000 078c 0000 0000  ................
0x00103120  0504 9200 0000 0800 0000 0009 1700 0000  ................
0x00103130  0803 32e0 0000 000a c901 0000 0334 3e00  ..2..........4>.
0x00103140  0000 000a 2100 0000 0335 3e00 0000 020a  ....!....5>.....
0x00103150  9000 0000 0336 5700 0000 040a cd00 0000  .....6W.........

Unfortunately, I can't show you the rights colours, but the hexdump is highlighting variables.

Protip: You can directly dump sym.flag to Python with three commands:

  • s sym.flag to Seek to sym.flag
  • pcp 0x28 to Print Code Python
  • s- to undo Seek
[0x001005f0]> s sym.flag;pcp 0x28;s-
import struct
buf = struct.pack ("40B", 
0x49,0x74,0x6f,0x66,0x72,0x6a,0x78,0x62,0x32,0x60,0x2e,
0x2e,0x63,0x2e,0x32,0x2e,0x36,0x30,0x33,0x31,0x5d,0x67,
0x36,0x62,0x31,0x67,0x67,0x30,0x5e,0x29,0x62,0x31,0x31,
0x63,0x62,0x5e,0x5e,0x2d,0x5d,0x7a)
[0x001005f0]> 

The hint was that the third Tick gives the answer. Since sym.flag is a global variable, the decryption routine has to be repeated 4 times (since there is 3 ticks) to give us the flag.

Here is the final keygen:

flag = [
0x49,0x74,0x6f,0x66,0x72,0x6a,0x78,0x62,0x32,0x60,0x2e,
0x2e,0x63,0x2e,0x32,0x2e,0x36,0x30,0x33,0x31,0x5d,0x67,
0x36,0x62,0x31,0x67,0x67,0x30,0x5e,0x29,0x62,0x31,0x31,
0x63,0x62,0x5e,0x5e,0x2d,0x5d,0x7a]

for i in range(1, 4):
    for x in range(0x28):
        flag[x] = (flag[x]^i)+1

print ''.join((chr(i) for i in flag))

And here you go:

$ python keygen.py
Pwnium{e5c11b1519328df9e8ff3a0e88beaa4d}