Skip to content

Commit 43d5b9a

Browse files
committed
HITCON 2020: dual writeup
1 parent 2fc528d commit 43d5b9a

File tree

7 files changed

+3234
-0
lines changed

7 files changed

+3234
-0
lines changed

2020/HITCON/runrunrun/README.md

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
1. Use [https://github.com/pzl/ciqdb](https://github.com/pzl/ciqdb) to dump symbol and code sections from hitcon.prg
2+
2. Download Garmin's ConnectIQ SDK
3+
3. Decompile their compiler (written in Java)
4+
4. Learn MonkeyC's opcodes and their encoding from com.garmin.monkeybrains.asm.Opcode
5+
5. Disassemble the code
6+
6. Dump the encrypted flag and decryption algorithm
7+
6. Write an assymptotically faster flag decryption algorithm
8+
7. ???
9+
8. Profit
10+
11+
Flag Decryption Algorithm
12+
-------------------------
13+
14+
def solve(cnt):
15+
a = 1
16+
b = 1
17+
c = 1
18+
19+
for _ in range(cnt):
20+
d = (a*2 + b + c*7)%31337
21+
c = b
22+
b = a
23+
a = d
24+
25+
return a
26+
27+
enc = [98, 32, 84, 253, 217, 18, 92, 22, 112, 138, 147, 46, 168, 229, 31, 149, 72, 94, 191, 124, 21, 176, 10, 104, 154, 213, 235, 25, 237, 61, 18, 15]
28+
keys = [1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683, 59049, 177147, 531441, 1594323, 4782969, 14348907, 43046721, 129140163, 387420489, 1162261467, 3486784401, 10460353203, 31381059609, 94143178827, 282429536481, 847288609443, 2541865828329, 7625597484987, 22876792454961, 68630377364883, 205891132094649, 617673396283947]
29+
30+
flag = bytearray()
31+
for e, k in zip(enc, keys):
32+
flag.append(e ^^ (solve(k)&0xff))
33+
print(flag)
34+
35+
Faster Version (in SageMath)
36+
----------------------------
37+
38+
K = GF(31337)
39+
40+
update = Matrix([
41+
[2, 1, 7],
42+
[1, 0, 0],
43+
[0, 1, 0],
44+
], ring=K)
45+
46+
col = Matrix([[1], [1], [1]], ring=K)
47+
48+
def solve(n):
49+
return int(((update^n) * col)[0,0])

2020/HITCON/runrunrun/code.bin

2.19 KB
Binary file not shown.

2020/HITCON/runrunrun/decrypt.sage

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
enc = [98, 32, 84, 253, 217, 18, 92, 22, 112, 138, 147, 46, 168, 229, 31, 149, 72, 94, 191, 124, 21, 176, 10, 104, 154, 213, 235, 25, 237, 61, 18, 15]
2+
keys = [1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683, 59049, 177147, 531441, 1594323, 4782969, 14348907, 43046721, 129140163, 387420489, 1162261467, 3486784401, 10460353203, 31381059609, 94143178827, 282429536481, 847288609443, 2541865828329, 7625597484987, 22876792454961, 68630377364883, 205891132094649, 617673396283947]
3+
4+
K = GF(31337)
5+
6+
update = Matrix([
7+
[2, 1, 7],
8+
[1, 0, 0],
9+
[0, 1, 0],
10+
], ring=K)
11+
12+
col = Matrix([[1], [1], [1]], ring=K)
13+
14+
def solve(cnt):
15+
a = 1
16+
b = 1
17+
c = 1
18+
19+
for _ in range(cnt):
20+
d = (a*2 + b + c*7)%31337
21+
c = b
22+
b = a
23+
a = d
24+
25+
return a
26+
27+
def fast_solve(n):
28+
return int(((update^n) * col)[0,0])
29+
30+
flag = bytearray()
31+
32+
for e, k in zip(enc, keys):
33+
flag.append(e ^^ (fast_solve(k)&0xff))
34+
print(flag)

2020/HITCON/runrunrun/disasm.py

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from braindead import *
2+
from opcodes import OP_BY_ID, OPSIZE
3+
4+
args = Args()
5+
args.add('LOAD', help='Dumped code section')
6+
args.add('META', help='Dumped metadata')
7+
args.parse()
8+
9+
pc2ln = {}
10+
syms = {}
11+
12+
with open(args.META) as f:
13+
for line in f:
14+
if line.startswith('c0de7ab1'):
15+
for line in f:
16+
line = line.strip()
17+
if len(line) == 0:
18+
break
19+
filename, symbol, _, pc = line.split()
20+
pc = int(pc[:-1])
21+
pc2ln[pc] = (filename, symbol)
22+
elif line.startswith('5717b015'):
23+
for line in f:
24+
line = line.strip()
25+
if len(line) == 0:
26+
break
27+
symid, symname = line.split(': ')
28+
syms[int(symid)] = symname
29+
30+
prg = util.slurp(args.LOAD)
31+
base = 0x10000000
32+
33+
pc = base
34+
35+
while pc-base < len(prg):
36+
op = prg[pc-base]
37+
if op not in OPSIZE:
38+
print(f'{pc:08} {op:02x} .. .. .. .. invalid')
39+
ops = OPSIZE[op]
40+
hx = []
41+
for i in range(min(9, ops)):
42+
hx.append(f'{prg[pc+i-base]:02x}')
43+
while len(hx) < 9:
44+
hx.append('..')
45+
46+
if op not in OP_BY_ID:
47+
print('wtf')
48+
break
49+
opn = OP_BY_ID[op]
50+
51+
52+
arg_len = ops-1
53+
arg_val = int.from_bytes(prg[pc+1-base:pc+1-base+arg_len], 'big')
54+
if opn == 'SPUSH':
55+
arg_fmt = syms[arg_val]
56+
else:
57+
arg_fmt = f'0x{arg_val:x}'
58+
59+
if pc in pc2ln:
60+
print(';', *pc2ln[pc])
61+
print(f'{pc:08x} {" ".join(hx)} {opn} {arg_fmt}')
62+
pc += ops

0 commit comments

Comments
 (0)