HTB Reversing Writeup: Golfer

I think I broke my PB for this challenge — sub 10 minutes!

A friend gave you an odd executable file, in fact it is very tiny for a simple ELF, what secret can this file hide?

The hint is accurate; the file is extremely small, coming in at 312 bytes. Run it:

» ./golfer      
»

Nothing visible, and no obvious opportunity for input. We investigate by prodding the binary with a few tools:

» checksec golfer             
Traceback (most recent call last):
  File "/home/░░░/.local/bin/checksec", line 8, in <module>
    sys.exit(main())
  File "/home/░░░/.local/lib/python3.10/site-packages/pwnlib/commandline/common.py", line 32, in main
    pwnlib.commandline.main.main()
  File "/home/░░░/.local/lib/python3.10/site-packages/pwnlib/commandline/main.py", line 56, in main
    commands[args.command](args)
  File "/home/░░░/.local/lib/python3.10/site-packages/pwnlib/commandline/checksec.py", line 39, in main
    e = ELF(f.name)
  File "/home/░░░/.local/lib/python3.10/site-packages/pwnlib/elf/elf.py", line 226, in __init__
    super(ELF,self).__init__(self.mmap)
  File "/home/░░░/.local/lib/python3.10/site-packages/elftools/elf/elffile.py", line 73, in __init__
    self._identify_file()
  File "/home/░░░/.local/lib/python3.10/site-packages/elftools/elf/elffile.py", line 522, in _identify_file
    raise ELFError('Invalid EI_DATA %s' % repr(ei_data))
elftools.common.exceptions.ELFError: Invalid EI_DATA b'a'
» rabin2 -I golfer       
arch     x86
baddr    0x8000000
binsz    312
bintype  elf
bits     32
canary   false
class    ELF32
flags    0xbeef7242
crypto   false
endian   little
havecode true
laddr    0x0
lang     c
linenum  false
lsyms    false
machine  Intel 80386
nx       false
os       linux
pic      false
relocs   false
rpath    NONE
sanitize false
static   true
stripped true
subsys   linux
va       true

checksec is really not happy, and the ELF flags look suspicious. Take a closer look with xxd; it’s small enough we can look at the whole thing:

» xxd golfer             
00000000: 7f45 4c46 0161 3466 5455 487d 7952 7b6c  .ELF.a4fTUH}yR{l
00000010: 0200 0300 0100 0000 4c00 0008 2c00 0000  ........L...,...
00000020: 675f 3330 4272 efbe 3400 2000 0100 0000  g_30Br..4. .....
00000030: 0000 0000 0000 0008 0000 0008 3801 0000  ............8...
00000040: 3801 0000 0500 0000 0010 0000 e9d6 0000  8...............
00000050: 00fe c3fe c2b9 0a00 0008 e8d0 0000 00b9  ................
00000060: 0800 0008 e8c6 0000 00b9 2400 0008 e8bc  ..........$.....
00000070: 0000 00b9 0e00 0008 e8b2 0000 00b9 0c00  ................
00000080: 0008 e8a8 0000 00b9 2300 0008 e89e 0000  ........#.......
00000090: 00b9 0900 0008 e894 0000 00b9 2100 0008  ............!...
000000a0: e88a 0000 00b9 0600 0008 e880 0000 00b9  ................
000000b0: 0d00 0008 e876 0000 00b9 2200 0008 e86c  .....v...."....l
000000c0: 0000 00b9 2100 0008 e862 0000 00b9 0500  ....!....b......
000000d0: 0008 e858 0000 00b9 2100 0008 e84e 0000  ...X....!....N..
000000e0: 00b9 2000 0008 e844 0000 00b9 2300 0008  .. ....D....#...
000000f0: e83a 0000 00b9 0f00 0008 e830 0000 00b9  .:.........0....
00000100: 0700 0008 e826 0000 00b9 2200 0008 e81c  .....&....".....
00000110: 0000 00b9 2500 0008 e812 0000 00b9 0b00  ....%...........
00000120: 0008 e808 0000 0030 c0fe c0b3 2acd 8055  .......0....*..U
00000130: 89e5 b004 cd80 c9c3                      ........

It looks like the headers have been overwritten; magic looks like it holds something interesting. Over to r2 to see what the instructions look like.

» r2 -AAA golfer
INFO: Analyze all flags starting with sym. and entry0 (aa)
INFO: Analyze all functions arguments/locals (afva@@@F)
INFO: Analyze function calls (aac)
INFO: Analyze len bytes of instructions for references (aar)
INFO: Finding and parsing C++ vtables (avrr)
INFO: Type matching analysis for all functions (aaft)
INFO: Propagate noreturn information (aanr)
INFO: Scanning for strings constructed in code (/azs)
INFO: Finding function preludes (aap)
INFO: Enable anal.types.constraint for experimental type propagation
[0x0800004c]> pdf
            ;-- eip:
┌ 13: entry0 ();
│       ┌─< 0x0800004c      e9d6000000     jmp 0x8000127
..
│       │   ; CODE XREF from entry0 @ 0x800004c(x)
│       └─> 0x08000127      30c0           xor al, al
│           0x08000129      fec0           inc al
│           0x0800012b      b32a           mov bl, 0x2a                ; '*' ; 42
└           0x0800012d      cd80           int 0x80

There’s a jump right at the very beginning. With the use of pdf, r2 isn’t showing us what we’re jumping over. Let’s look:

[0x0800004c]> pd 50
            ;-- eip:
┌ 13: entry0 ();
│       ┌─< 0x0800004c      e9d6000000     jmp 0x8000127
        │   0x08000051      fec3           inc bl
        │   0x08000053      fec2           inc dl
        │   0x08000055      b90a000008     mov ecx, 0x800000a          ; '\n'
        │   0x0800005a      e8d0000000     call fcn.0800012f
        │   0x0800005f      b908000008     mov ecx, 0x8000008
        │   0x08000064      e8c6000000     call fcn.0800012f
        │   0x08000069      b924000008     mov ecx, 0x8000024          ; '$'
        │   0x0800006e      e8bc000000     call fcn.0800012f
        │   0x08000073      b90e000008     mov ecx, 0x800000e          ; '\x0e'
        │   0x08000078      e8b2000000     call fcn.0800012f
        │   0x0800007d      b90c000008     mov ecx, 0x800000c          ; '\f'
        │   0x08000082      e8a8000000     call fcn.0800012f
        │   0x08000087      b923000008     mov ecx, 0x8000023          ; '#'
        │   0x0800008c      e89e000000     call fcn.0800012f
        │   0x08000091      b909000008     mov ecx, 0x8000009
        │   0x08000096      e894000000     call fcn.0800012f
        │   0x0800009b      b921000008     mov ecx, 0x8000021          ; '!'
        │   0x080000a0      e88a000000     call fcn.0800012f
        │   0x080000a5      b906000008     mov ecx, 0x8000006
        │   0x080000aa      e880000000     call fcn.0800012f
        │   0x080000af      b90d000008     mov ecx, 0x800000d          ; '\r'
        │   0x080000b4      e876000000     call fcn.0800012f
        │   0x080000b9      b922000008     mov ecx, 0x8000022          ; '\"'
        │   0x080000be      e86c000000     call fcn.0800012f
        │   0x080000c3      b921000008     mov ecx, 0x8000021          ; '!'
        │   0x080000c8      e862000000     call fcn.0800012f
        │   0x080000cd      b905000008     mov ecx, 0x8000005
        │   0x080000d2      e858000000     call fcn.0800012f
        │   0x080000d7      b921000008     mov ecx, 0x8000021          ; '!'
        │   0x080000dc      e84e000000     call fcn.0800012f
        │   0x080000e1      b920000008     mov ecx, 0x8000020          ; ' '
        │   0x080000e6      e844000000     call fcn.0800012f
        │   0x080000eb      b923000008     mov ecx, 0x8000023          ; '#'
        │   0x080000f0      e83a000000     call fcn.0800012f
        │   0x080000f5      b90f000008     mov ecx, 0x800000f          ; '\x0f'
        │   0x080000fa      e830000000     call fcn.0800012f
        │   0x080000ff      b907000008     mov ecx, 0x8000007
        │   0x08000104      e826000000     call fcn.0800012f
        │   0x08000109      b922000008     mov ecx, 0x8000022          ; '\"'
        │   0x0800010e      e81c000000     call fcn.0800012f
        │   0x08000113      b925000008     mov ecx, 0x8000025          ; '%'
        │   0x08000118      e812000000     call fcn.0800012f
        │   0x0800011d      b90b000008     mov ecx, 0x800000b          ; '\v'
        │   0x08000122      e808000000     call fcn.0800012f
│       │   ; CODE XREF from entry0 @ 0x800004c(x)
│       └─> 0x08000127      30c0           xor al, al
│           0x08000129      fec0           inc al
│           0x0800012b      b32a           mov bl, 0x2a                ; '*' ; 42
└           0x0800012d      cd80           int 0x80
            ; XREFS(21)
┌ 9: fcn.0800012f ();
│           0x0800012f      55             push ebp

This looks like some obfuscated string manipulation. Let’s try patching out this jump instruction. I still like doing this with xxd and vim; one day I’ll learn r2’s patching and debugging utilities, but today isn’t that day.

» xxd gofler > golfer.xxd
» nvim golfer.xxd
» xxd -r goflfer.xxd > golfer.patch

The only change I made was to change the jump instruction from e9d6000000 to e900000000; i.e., jump 0x00 relative rather than jumping 0xd6 relative. Run the patched binary:

» ./golfer.patch
HTB{░░░}%

That was quick!