# [zer0pts CTF 2020] Hobbit ###### tags: `zer0pts CTF` `reversing` ## Overview We're given a qemu environment. ``` ~ # ls chall.hbt hobbit.ko ~ # ./chall.hbt FLAG: hoge Wrong! ~ # hexdump -C chall.hbt 00000000 48 4f 42 42 49 54 01 02 b6 98 81 8f 38 72 1d 8c |HOBBIT......8r..| 00000010 30 f0 fc b1 8c f8 70 8c ba 68 03 a0 d0 72 45 e2 |0.....p..h...rE.| 00000020 30 9e 1d 2f de 3a 74 e8 40 00 00 00 00 00 ad de |0../.:t.@.......| 00000030 00 00 00 00 7e 00 00 00 00 00 ef be 00 00 00 00 |....~...........| 00000040 cf 83 06 e3 ab e6 36 51 b3 55 9b a9 5b 80 e5 bf |......6Q.U..[...| 00000050 a0 ab 44 e6 36 e3 e0 46 c3 4e 91 6d 5e f5 d2 ee |..D.6..F.N.m^...| 00000060 93 e4 60 c9 04 1a 40 b6 8d 08 31 0c de 2d 69 4e |..`...@...1..-iN| 00000070 37 ce 6e 7e ac 86 61 02 27 41 9a 96 c7 94 bc c9 |7.n~..a.'A......| 00000080 14 d3 b6 52 60 21 f2 b0 be 7e 1c f1 9e d9 dc a3 |...R`!...~......| 00000090 b1 d7 30 5d 22 cc d0 a7 85 49 62 25 b4 77 d1 5d |..0]"....Ib%.w.]| 000000a0 6a a3 4c 4b cb 8c ae 36 e8 8e f2 29 63 e9 58 af |j.LK...6...)c.X.| 000000b0 e6 5c 9e de 21 89 6a 40 d0 a2 0a 6e fb 03 3a 24 |.\..!.j@...n..:$| 000000c0 3d e2 46 f9 16 7a 8e 0e 43 a5 0d d8 56 9c a3 9d |=.F..z..C...V...| 000000d0 e8 50 a5 64 55 f8 50 96 c5 83 03 96 6c 47 17 21 |.P.dU.P.....lG.!| 000000e0 d7 08 0c 99 3e 93 a3 39 9e 97 a6 b6 ab fb 00 23 |....>..9.......#| 000000f0 61 8e 76 ad 69 b9 2c 5f 7e 2d 54 14 70 d1 |a.v.i.,_~-T.p.| 000000fe ~ # ``` It seems a new binary format is registered in this kernel. Let's check `hobbit.ko`. ## Analysis By analysing `hobbit.ko` you can find the HOBBIT format. | Member | Offset | Size | Description | |:-:|:-:|:-:|:-:| | magic | 0x00 | 0x08 | `HOBBIT\x01\x02` | | key_data | 0x08 | 0x10 | 16-byte key to decrypt data section | | key_text | 0x18 | 0x10 | 16-byte key to decrypt text section | | size_data | 0x28 | 0x04 | The size of data section | | addr_data | 0x2c | 0x08 | The address of data section | | size_text | 0x34 | 0x04 | The size of text section | | addr_text | 0x38 | 0x08 | The address of text section | | enc_data | 0x40 | size_data | The encrypted data section | | enc_text | 0x40 + size_data | size_text | The encrypted text section | If you can read the kernel driver, you'll find the encryption method is plain RC4. ## Solution If you decrypt the text section, you'll see a code like this: ```nasm _start: ;; write(1, "FLAG: ", 7); mov rdx, 7 mov rsi, 0xdead0000 xor eax, eax inc eax mov rdi, rax syscall ;; read(0, buf, 0x100) mov rdx, 0x100 mov rsi, 0xdead00ef xor eax, eax xor edi, edi syscall ;; xor(buf, code, 39); cld mov rcx, 39 mov rsi, 0xdead00ef mov rdi, rsi ENCIPHER: lodsb xor al, cl stosb loop ENCIPHER ;; memcmp(buf, E"zer0pts{...}", 39); mov rcx, 39 mov rsi, 0xdead0019 mov rdi, 0xdead00ef repe cmpsb je CORRECT WRONG: ;; write(1, "Wrong!\n", 8); mov rdx, 8 mov rsi, 0xdead0011 xor eax, eax inc eax mov rdi, rax syscall ;; exit(0); EXIT: mov rdi, 0 mov rax, 60 syscall CORRECT: ;; write(1, "Correct!\n", 10); mov rdx, 10 mov rsi, 0xdead0007 xor eax, eax inc eax mov rdi, rax syscall jmp EXIT ``` You can decode the flag with python or whatever. ```python from ptrlib import u32, u64 import os def KSA(key): S = [i for i in range(0x100)] j = 0 for i in range(0x100): j = (j + S[i] + key[i % len(key)]) % 256 S[i], S[j] = S[j], S[i] return S def PRGA(S): i, j = 0, 0 while True: i = (i + 1) % 256 j = (j + S[i]) % 256 S[i], S[j] = S[j], S[i] K = S[(S[i] + S[j]) % 256] yield K def RC4(data, key): S = KSA(key) gen = PRGA(S) data = bytearray(data) result = bytearray(c ^ n for c, n in zip(data, gen)) return result with open("../challenge/chall.hbt", "rb") as f: f.seek(0x8) key_data = f.read(16) key_text = f.read(16) f.seek(0x28) len_data = u32(f.read(4)) f.seek(0x34) len_text = u32(f.read(4)) f.seek(0x40) data = f.read(len_data) text = f.read(len_text) output = '' for i, c in enumerate(RC4(data, key_data)[0x19:]): output += chr(c ^ (39 - i)) print(output) ```