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!