# [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)
```