ctf-agent 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +131 -0
- package/Dockerfile +192 -0
- package/README.md +522 -0
- package/agents/ctf-analyzer.md +58 -0
- package/agents/ctf-controller.md +151 -0
- package/agents/ctf-speedrun.md +74 -0
- package/bin/ctf-agent.js +119 -0
- package/docker-compose.yml +13 -0
- package/mcp_config.json +19 -0
- package/package.json +44 -0
- package/references/ctf-triage-ladder.md +68 -0
- package/references/exploit-databases.md +575 -0
- package/references/llm-safety-and-policy-compliance.md +173 -0
- package/references/multi-agent-orchestration-and-policy-routing.md +278 -0
- package/references/security-events-and-intelligence.md +566 -0
- package/references/version-matrix.md +59 -0
- package/rules/ctf-execution-rules.md +44 -0
- package/rules/ctf-safety-framing-rules.md +140 -0
- package/rules/flag-validation-rules.md +25 -0
- package/scripts/__init__.py +1 -0
- package/scripts/ctf-tools.lock +205 -0
- package/scripts/ctf_init.py +1026 -0
- package/scripts/ctf_update.py +583 -0
- package/scripts/ctfd_client.py +81 -0
- package/scripts/cve_lookup.py +453 -0
- package/scripts/extract_flags.py +155 -0
- package/scripts/install_as_agent.py +278 -0
- package/scripts/install_ctf_tools.sh +603 -0
- package/scripts/parallel_triage.py +395 -0
- package/scripts/prompt_policy_sanitizer.py +283 -0
- package/scripts/scope_guard.py +444 -0
- package/scripts/skill_validator.py +504 -0
- package/scripts/workspace_cleaner.py +141 -0
- package/skills/ctf-ai-ml/SKILL.md +120 -0
- package/skills/ctf-ai-ml/adversarial-ml.md +623 -0
- package/skills/ctf-ai-ml/llm-attacks.md +487 -0
- package/skills/ctf-ai-ml/model-attacks.md +422 -0
- package/skills/ctf-crypto/SKILL.md +320 -0
- package/skills/ctf-crypto/advanced-math.md +798 -0
- package/skills/ctf-crypto/classic-ciphers.md +651 -0
- package/skills/ctf-crypto/ecc-attacks.md +347 -0
- package/skills/ctf-crypto/exotic-crypto-2.md +380 -0
- package/skills/ctf-crypto/exotic-crypto.md +528 -0
- package/skills/ctf-crypto/historical.md +113 -0
- package/skills/ctf-crypto/lattice-and-lwe.md +524 -0
- package/skills/ctf-crypto/modern-ciphers-2.md +563 -0
- package/skills/ctf-crypto/modern-ciphers-3.md +453 -0
- package/skills/ctf-crypto/modern-ciphers.md +649 -0
- package/skills/ctf-crypto/prng-attacks.md +257 -0
- package/skills/ctf-crypto/prng.md +664 -0
- package/skills/ctf-crypto/rsa-attacks-2.md +792 -0
- package/skills/ctf-crypto/rsa-attacks.md +487 -0
- package/skills/ctf-crypto/stream-ciphers.md +390 -0
- package/skills/ctf-crypto/zkp-and-advanced.md +456 -0
- package/skills/ctf-forensics/3d-printing.md +121 -0
- package/skills/ctf-forensics/SKILL.md +379 -0
- package/skills/ctf-forensics/disk-advanced.md +497 -0
- package/skills/ctf-forensics/disk-and-memory.md +491 -0
- package/skills/ctf-forensics/disk-recovery.md +699 -0
- package/skills/ctf-forensics/linux-forensics.md +511 -0
- package/skills/ctf-forensics/network-advanced.md +583 -0
- package/skills/ctf-forensics/network.md +645 -0
- package/skills/ctf-forensics/peripheral-capture.md +287 -0
- package/skills/ctf-forensics/signals-and-hardware.md +713 -0
- package/skills/ctf-forensics/steganography.md +694 -0
- package/skills/ctf-forensics/stego-advanced-2.md +475 -0
- package/skills/ctf-forensics/stego-advanced.md +481 -0
- package/skills/ctf-forensics/stego-image.md +691 -0
- package/skills/ctf-forensics/windows.md +625 -0
- package/skills/ctf-malware/SKILL.md +181 -0
- package/skills/ctf-malware/c2-and-protocols.md +274 -0
- package/skills/ctf-malware/pe-and-dotnet.md +108 -0
- package/skills/ctf-malware/scripts-and-obfuscation.md +449 -0
- package/skills/ctf-misc/SKILL.md +498 -0
- package/skills/ctf-misc/bashjails.md +323 -0
- package/skills/ctf-misc/ctfd-navigation.md +465 -0
- package/skills/ctf-misc/dns.md +255 -0
- package/skills/ctf-misc/encodings-advanced.md +504 -0
- package/skills/ctf-misc/encodings.md +431 -0
- package/skills/ctf-misc/games-and-vms-2.md +254 -0
- package/skills/ctf-misc/games-and-vms-3.md +690 -0
- package/skills/ctf-misc/games-and-vms-4.md +229 -0
- package/skills/ctf-misc/games-and-vms.md +529 -0
- package/skills/ctf-misc/linux-privesc.md +333 -0
- package/skills/ctf-misc/pyjails.md +671 -0
- package/skills/ctf-misc/rf-sdr.md +91 -0
- package/skills/ctf-osint/SKILL.md +198 -0
- package/skills/ctf-osint/geolocation-and-media.md +464 -0
- package/skills/ctf-osint/social-media.md +312 -0
- package/skills/ctf-osint/web-and-dns.md +341 -0
- package/skills/ctf-pwn/SKILL.md +214 -0
- package/skills/ctf-pwn/advanced-exploits-2.md +579 -0
- package/skills/ctf-pwn/advanced-exploits-3.md +598 -0
- package/skills/ctf-pwn/advanced-exploits-4.md +590 -0
- package/skills/ctf-pwn/advanced-exploits-5.md +119 -0
- package/skills/ctf-pwn/advanced-exploits.md +773 -0
- package/skills/ctf-pwn/advanced.md +326 -0
- package/skills/ctf-pwn/field-notes.md +245 -0
- package/skills/ctf-pwn/format-string.md +694 -0
- package/skills/ctf-pwn/heap-fsop.md +285 -0
- package/skills/ctf-pwn/heap-techniques-2.md +333 -0
- package/skills/ctf-pwn/heap-techniques.md +513 -0
- package/skills/ctf-pwn/kernel-bypass.md +421 -0
- package/skills/ctf-pwn/kernel-techniques.md +366 -0
- package/skills/ctf-pwn/kernel.md +636 -0
- package/skills/ctf-pwn/overflow-basics.md +611 -0
- package/skills/ctf-pwn/rop-advanced.md +725 -0
- package/skills/ctf-pwn/rop-and-shellcode.md +659 -0
- package/skills/ctf-pwn/sandbox-escape.md +313 -0
- package/skills/ctf-reverse/SKILL.md +163 -0
- package/skills/ctf-reverse/anti-analysis-ctf.md +204 -0
- package/skills/ctf-reverse/anti-analysis.md +693 -0
- package/skills/ctf-reverse/field-notes.md +376 -0
- package/skills/ctf-reverse/languages-compiled.md +666 -0
- package/skills/ctf-reverse/languages-platforms.md +592 -0
- package/skills/ctf-reverse/languages.md +553 -0
- package/skills/ctf-reverse/patterns-ctf-2.md +397 -0
- package/skills/ctf-reverse/patterns-ctf-3.md +797 -0
- package/skills/ctf-reverse/patterns-ctf.md +670 -0
- package/skills/ctf-reverse/patterns-runtime.md +274 -0
- package/skills/ctf-reverse/patterns.md +572 -0
- package/skills/ctf-reverse/platforms-hardware.md +387 -0
- package/skills/ctf-reverse/platforms.md +664 -0
- package/skills/ctf-reverse/tools-advanced-2.md +421 -0
- package/skills/ctf-reverse/tools-advanced.md +407 -0
- package/skills/ctf-reverse/tools-dynamic.md +679 -0
- package/skills/ctf-reverse/tools-emulation.md +319 -0
- package/skills/ctf-reverse/tools.md +573 -0
- package/skills/ctf-web/SKILL.md +153 -0
- package/skills/ctf-web/auth-and-access-2.md +82 -0
- package/skills/ctf-web/auth-and-access.md +783 -0
- package/skills/ctf-web/auth-infra.md +321 -0
- package/skills/ctf-web/auth-jwt.md +186 -0
- package/skills/ctf-web/client-side-advanced.md +739 -0
- package/skills/ctf-web/client-side.md +529 -0
- package/skills/ctf-web/cves.md +373 -0
- package/skills/ctf-web/field-notes.md +482 -0
- package/skills/ctf-web/node-and-prototype.md +200 -0
- package/skills/ctf-web/server-side-2.md +337 -0
- package/skills/ctf-web/server-side-advanced-2.md +559 -0
- package/skills/ctf-web/server-side-advanced-3.md +125 -0
- package/skills/ctf-web/server-side-advanced-4.md +480 -0
- package/skills/ctf-web/server-side-advanced.md +378 -0
- package/skills/ctf-web/server-side-deser.md +443 -0
- package/skills/ctf-web/server-side-exec-2.md +799 -0
- package/skills/ctf-web/server-side-exec.md +457 -0
- package/skills/ctf-web/server-side.md +629 -0
- package/skills/ctf-web/sql-injection.md +790 -0
- package/skills/ctf-web/web3.md +374 -0
- package/skills/ctf-writeup/SKILL.md +90 -0
- package/skills/solve-challenge/SKILL.md +269 -0
- package/skills.json +16 -0
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
# CTF Reverse - Hardware and Advanced Architecture Reversing
|
|
2
|
+
|
|
3
|
+
HD44780 LCD GPIO reconstruction, RISC-V advanced extensions and debugging, ARM64/AArch64 reversing and exploitation.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
- [HD44780 LCD Controller GPIO Reconstruction (32C3 2015)](#hd44780-lcd-controller-gpio-reconstruction-32c3-2015)
|
|
7
|
+
- [RISC-V (Advanced)](#risc-v-advanced)
|
|
8
|
+
- [Custom Extensions](#custom-extensions)
|
|
9
|
+
- [Privileged Modes](#privileged-modes)
|
|
10
|
+
- [RISC-V Debugging](#risc-v-debugging)
|
|
11
|
+
- [ARM64/AArch64 Reversing and Exploitation](#arm64aarch64-reversing-and-exploitation)
|
|
12
|
+
- [MIPS64 Cavium OCTEON Coprocessor 2 Crypto (SEC-T CTF 2017)](#mips64-cavium-octeon-coprocessor-2-crypto-sec-t-ctf-2017)
|
|
13
|
+
- [EFM32 ARM Microcontroller MMIO AES (SEC-T CTF 2017)](#efm32-arm-microcontroller-mmio-aes-sec-t-ctf-2017)
|
|
14
|
+
- [MBR/Bootloader Reversing with QEMU + GDB (Square CTF 2017)](#mbrbootloader-reversing-with-qemu--gdb-square-ctf-2017)
|
|
15
|
+
- [Game Boy ROM Z80 Analysis in bgb Debugger (Square CTF 2017)](#game-boy-rom-z80-analysis-in-bgb-debugger-square-ctf-2017)
|
|
16
|
+
- [KVM Guest Analysis via ioctl + KVM_EXIT_HLT Block Chaining (CSAW 2018)](#kvm-guest-analysis-via-ioctl--kvm_exit_hlt-block-chaining-csaw-2018)
|
|
17
|
+
- [Coreboot ROM XOR-Pair Bit-Flip Address Discovery (Hack.lu 2018)](#coreboot-rom-xor-pair-bit-flip-address-discovery-hacklu-2018)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## HD44780 LCD Controller GPIO Reconstruction (32C3 2015)
|
|
22
|
+
|
|
23
|
+
Recover text displayed on an HD44780 LCD from raw Raspberry Pi GPIO recordings:
|
|
24
|
+
|
|
25
|
+
1. **Identify signal lines:** Map GPIO pins to HD44780 signals (RS, CLK, D4-D7 for 4-bit mode)
|
|
26
|
+
2. **Clock edge detection:** Sample data lines on falling clock edges (1->0 transition)
|
|
27
|
+
3. **Nibble assembly:** Combine two 4-bit samples into one 8-bit command/data byte
|
|
28
|
+
4. **DRAM address mapping:** HD44780 uses non-contiguous addressing for multi-line displays:
|
|
29
|
+
- Line 0: 0x00-0x27
|
|
30
|
+
- Line 1: 0x40-0x67
|
|
31
|
+
- Line 2: 0x14-0x3B
|
|
32
|
+
- Line 3: 0x54-0x7B
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
display = [' '] * 80 # 4 lines x 20 chars
|
|
36
|
+
cursor = 0
|
|
37
|
+
|
|
38
|
+
for timestamp, gpio_state in sorted(gpio_log):
|
|
39
|
+
if falling_edge(gpio_state, CLK_PIN):
|
|
40
|
+
nibble = extract_data_bits(gpio_state)
|
|
41
|
+
byte = assemble_nibble(nibble) # Two nibbles per byte
|
|
42
|
+
if rs_high(gpio_state): # RS=1: data write
|
|
43
|
+
display[dram_to_position(cursor)] = chr(byte)
|
|
44
|
+
cursor += 1
|
|
45
|
+
else: # RS=0: command (set cursor, clear, etc.)
|
|
46
|
+
cursor = parse_command(byte)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Key insight:** GPIO pin-to-signal mapping is rarely documented; identify CLK by finding the pin with most transitions, RS by correlation with data patterns (alternating command/data phases).
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## RISC-V (Advanced)
|
|
54
|
+
|
|
55
|
+
Beyond basic disassembly (see [tools.md](tools.md#risc-v-binary-analysis-ehax-2026)):
|
|
56
|
+
|
|
57
|
+
### Custom Extensions
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
Bitmanip extensions (Zbb, Zbc, Zbs):
|
|
61
|
+
clz, ctz, cpop -> count leading/trailing zeros, popcount
|
|
62
|
+
orc.b, rev8 -> byte-level bit manipulation
|
|
63
|
+
andn, orn, xnor -> negated logic operations
|
|
64
|
+
clmul, clmulh, clmulr -> carry-less multiplication (crypto)
|
|
65
|
+
bset, bclr, binv, bext -> single-bit operations
|
|
66
|
+
|
|
67
|
+
Crypto extensions (Zk*):
|
|
68
|
+
aes32esi, aes32dsmi -> AES round operations
|
|
69
|
+
sha256sig0, sha512sum0 -> SHA hash acceleration
|
|
70
|
+
sm3p0, sm4ed -> Chinese crypto standards
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Privileged Modes
|
|
74
|
+
|
|
75
|
+
```text
|
|
76
|
+
Machine mode (M): Highest privilege, firmware/bootloader
|
|
77
|
+
Supervisor mode (S): OS kernel
|
|
78
|
+
User mode (U): Applications
|
|
79
|
+
|
|
80
|
+
CSR registers to watch:
|
|
81
|
+
mstatus/sstatus -> privilege level, interrupt enable
|
|
82
|
+
mtvec/stvec -> trap handler address
|
|
83
|
+
mepc/sepc -> exception return address
|
|
84
|
+
mcause/scause -> trap cause
|
|
85
|
+
satp -> page table root (virtual memory)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### RISC-V Debugging
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# OpenOCD + GDB for hardware debugging
|
|
92
|
+
openocd -f interface/jlink.cfg -f target/riscv.cfg
|
|
93
|
+
|
|
94
|
+
# GDB for RISC-V
|
|
95
|
+
riscv64-unknown-elf-gdb binary
|
|
96
|
+
(gdb) target remote :3333
|
|
97
|
+
|
|
98
|
+
# QEMU with GDB server
|
|
99
|
+
qemu-riscv64 -g 1234 -L /usr/riscv64-linux-gnu/ ./binary
|
|
100
|
+
riscv64-linux-gnu-gdb -ex 'target remote :1234' ./binary
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## ARM64/AArch64 Reversing and Exploitation
|
|
106
|
+
|
|
107
|
+
AArch64 (ARM 64-bit) appears in mobile apps, cloud servers (AWS Graviton), Apple Silicon, and CTF challenges. Key differences from x86-64 affect both reversing and exploitation.
|
|
108
|
+
|
|
109
|
+
**Setup and emulation:**
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Install cross-toolchain and emulator
|
|
113
|
+
apt install gcc-aarch64-linux-gnu gdb-multiarch qemu-user-static
|
|
114
|
+
|
|
115
|
+
# Run AArch64 binary on x86 host
|
|
116
|
+
qemu-aarch64-static -L /usr/aarch64-linux-gnu/ ./arm64_binary
|
|
117
|
+
|
|
118
|
+
# Debug with GDB
|
|
119
|
+
qemu-aarch64-static -g 12345 -L /usr/aarch64-linux-gnu/ ./arm64_binary &
|
|
120
|
+
gdb-multiarch -ex 'set arch aarch64' -ex 'target remote :1234' ./arm64_binary
|
|
121
|
+
|
|
122
|
+
# With library preloading (for challenges that ship libc)
|
|
123
|
+
qemu-aarch64-static -g 12345 -E LD_PRELOAD=./libc.so.6 -L ./lib ./arm64_binary
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**AArch64 calling convention (key differences from x86-64):**
|
|
127
|
+
|
|
128
|
+
```text
|
|
129
|
+
Registers:
|
|
130
|
+
x0-x7 -- function arguments AND return values (x0 = first arg / return)
|
|
131
|
+
x8 -- indirect result location (struct returns)
|
|
132
|
+
x9-x15 -- caller-saved temporaries
|
|
133
|
+
x19-x28 -- callee-saved (preserved across calls)
|
|
134
|
+
x29 (fp) -- frame pointer
|
|
135
|
+
x30 (lr) -- link register (return address, NOT on stack by default)
|
|
136
|
+
sp -- stack pointer (must be 16-byte aligned)
|
|
137
|
+
xzr -- zero register (reads as 0, writes discarded)
|
|
138
|
+
|
|
139
|
+
Key exploitation differences:
|
|
140
|
+
- Return address in LR (x30), not on stack -- pushed only if function calls others
|
|
141
|
+
- No RIP-relative addressing like x86 -- uses ADRP+ADD pairs for PC-relative loads
|
|
142
|
+
- Fixed 4-byte instruction width -- no variable-length gadget tricks
|
|
143
|
+
- NOP = 0xD503201F (not 0x90)
|
|
144
|
+
- BLR x8 / BR x30 -- indirect calls/jumps use register operands
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Common AArch64 patterns in Ghidra/IDA:**
|
|
148
|
+
|
|
149
|
+
```text
|
|
150
|
+
# PC-relative address loading (equivalent to x86 LEA):
|
|
151
|
+
ADRP x0, #0x411000 ; Load page address (4KB aligned)
|
|
152
|
+
ADD x0, x0, #0x8 ; Add page offset -> x0 = 0x411008
|
|
153
|
+
|
|
154
|
+
# Function prologue:
|
|
155
|
+
STP x29, x30, [sp, #-0x30]! ; Push fp + lr, decrement sp
|
|
156
|
+
MOV x29, sp ; Set frame pointer
|
|
157
|
+
|
|
158
|
+
# Function epilogue:
|
|
159
|
+
LDP x29, x30, [sp], #0x30 ; Pop fp + lr, increment sp
|
|
160
|
+
RET ; Branch to x30 (lr)
|
|
161
|
+
|
|
162
|
+
# Switch/jump table:
|
|
163
|
+
ADR x1, jump_table
|
|
164
|
+
LDRB w2, [x1, x0] ; Load offset byte
|
|
165
|
+
ADD x1, x1, w2, SXTB ; Sign-extend and add
|
|
166
|
+
BR x1 ; Indirect branch
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**ROP on AArch64:**
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
from pwn import *
|
|
173
|
+
|
|
174
|
+
# AArch64 gadgets differ from x86:
|
|
175
|
+
# - "pop {x0}; ret" equivalent: LDP x0, x1, [sp], #0x10; RET
|
|
176
|
+
# - Prologue gadgets: LDP x29, x30, [sp, #0x20]; ... RET
|
|
177
|
+
# - system() call: x0 = pointer to "/bin/sh", BLR to system
|
|
178
|
+
|
|
179
|
+
context.arch = 'aarch64'
|
|
180
|
+
elf = ELF('./arm64_binary')
|
|
181
|
+
|
|
182
|
+
# Common gadget pattern in AArch64 libc:
|
|
183
|
+
# LDP X19, X20, [SP,#var_s10]
|
|
184
|
+
# LDP X29, X30, [SP+var_s0],#0x20
|
|
185
|
+
# RET
|
|
186
|
+
# Controls x19, x20, x29, x30 and advances sp by 0x20
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Key insight:** AArch64's fixed instruction width and register-based return address (`lr`/`x30`) make ROP gadgets more constrained than x86. Look for `LDP` (load pair) gadgets that pop multiple registers from the stack. The `STP`/`LDP` instruction pairs that save/restore callee-saved registers in function prologues/epilogues are the primary gadget source.
|
|
190
|
+
|
|
191
|
+
**When to recognize:** `file` shows "ELF 64-bit LSB ... ARM aarch64". Ghidra auto-detects but may need manual processor selection for raw binaries. Use `qemu-aarch64-static` for emulation on x86 hosts.
|
|
192
|
+
|
|
193
|
+
**Tools:** radare2 (`r2 -AA -a arm -b 64`), Ghidra (auto-detect), `aarch64-linux-gnu-objdump -d`, Unicorn Engine (`UC_ARCH_ARM64`)
|
|
194
|
+
|
|
195
|
+
**References:** Google CTF 2016 "Forced Puns", Insomni'hack 2018 "onecall"
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## MIPS64 Cavium OCTEON Coprocessor 2 Crypto (SEC-T CTF 2017)
|
|
200
|
+
|
|
201
|
+
Cavium OCTEON network processors implement hardware AES and SHA256 via MIPS Coprocessor 2 (CP2) using `dmtc2` (move to CP2) and `dmfc2` (move from CP2) instructions. These look like ordinary register moves to a disassembler but drive the hardware crypto engine.
|
|
202
|
+
|
|
203
|
+
**Key CP2 register layout (OCTEON):**
|
|
204
|
+
```text
|
|
205
|
+
AES key registers:
|
|
206
|
+
0x0104 – AES key quadword 0
|
|
207
|
+
0x0105 – AES key quadword 1
|
|
208
|
+
0x0106 – AES key quadword 2
|
|
209
|
+
0x0107 – AES key quadword 3
|
|
210
|
+
|
|
211
|
+
SHA256 hash registers:
|
|
212
|
+
0x400E–0x4012 – SHA256 intermediate hash words
|
|
213
|
+
0x404F – SHA256 control/result
|
|
214
|
+
|
|
215
|
+
dmtc2 rN, 0x0104 ; load 64 bits of AES key into CP2 register 0x104
|
|
216
|
+
dmtc2 rN, 0x0105 ; ...next quadword
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Approach:**
|
|
220
|
+
1. Disassemble in IDA/Ghidra — `dmtc2`/`dmfc2` with selector in 0x100-0x40FF range indicates OCTEON CP2
|
|
221
|
+
2. Cross-reference the Cavium OCTEON Hardware Reference Manual for register semantics
|
|
222
|
+
3. Trace the key loading sequence to recover the AES or HMAC key material
|
|
223
|
+
|
|
224
|
+
**Key insight:** Hardware crypto accelerators on MIPS appear as CP2 register writes (`dmtc2`/`dmfc2`). Identify the base register address and cross-reference vendor documentation.
|
|
225
|
+
|
|
226
|
+
**References:** SEC-T CTF 2017
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## EFM32 ARM Microcontroller MMIO AES (SEC-T CTF 2017)
|
|
231
|
+
|
|
232
|
+
Silicon Labs EFM32 Cortex-M binary — a flat binary loaded at 0x1000 in Thumb mode.
|
|
233
|
+
|
|
234
|
+
**IDA setup:**
|
|
235
|
+
```text
|
|
236
|
+
Processor: ARM Little-endian (ARMv7-M)
|
|
237
|
+
Load address: 0x1000
|
|
238
|
+
Set T register = 1 (force Thumb mode decoding)
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**AES accelerator MMIO layout (EFM32 AES peripheral at 0x400E0000):**
|
|
242
|
+
```text
|
|
243
|
+
0x400E0000 + 0x000 CTRL – enable, decrypt mode
|
|
244
|
+
0x400E0000 + 0x004 CMD – start/stop
|
|
245
|
+
0x400E0000 + 0x010 KEYLA – key low word 0
|
|
246
|
+
0x400E0000 + 0x014 KEYLB – key low word 1
|
|
247
|
+
0x400E0000 + 0x018 KEYLC – key low word 2
|
|
248
|
+
0x400E0000 + 0x01C KEYLD – key low word 3
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
The binary loads two separate values, XORs them together, then writes the result as the AES key. Decrypt the embedded ciphertext block with the composed key in ECB mode.
|
|
252
|
+
|
|
253
|
+
```python
|
|
254
|
+
from Crypto.Cipher import AES
|
|
255
|
+
|
|
256
|
+
key_part_a = bytes.fromhex("...") # extracted from IDA .data section
|
|
257
|
+
key_part_b = bytes.fromhex("...") # second value
|
|
258
|
+
key = bytes(a ^ b for a, b in zip(key_part_a, key_part_b))
|
|
259
|
+
|
|
260
|
+
cipher = AES.new(key, AES.MODE_ECB)
|
|
261
|
+
plaintext = cipher.decrypt(ciphertext)
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
**Key insight:** Hardware AES accelerators on microcontrollers appear as MMIO register writes at a specific base address — cross-reference the vendor reference manual (EFM32 Reference Manual for Silicon Labs peripherals).
|
|
265
|
+
|
|
266
|
+
**References:** SEC-T CTF 2017
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## MBR/Bootloader Reversing with QEMU + GDB (Square CTF 2017)
|
|
271
|
+
|
|
272
|
+
Boot a floppy/disk image in QEMU with the GDB stub enabled, then attach GDB for full source-level debugging of 16-bit real mode or 32-bit protected mode bootloader code.
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
# Boot with GDB stub on port 1234; -S pauses execution at start
|
|
276
|
+
qemu-system-x86_64 -fda disk.img -s -S
|
|
277
|
+
|
|
278
|
+
# In another terminal, attach GDB
|
|
279
|
+
gdb -ex "set architecture i8086" \
|
|
280
|
+
-ex "target remote :1234" \
|
|
281
|
+
-ex "break *0x7c00" \
|
|
282
|
+
-ex "continue"
|
|
283
|
+
|
|
284
|
+
# Common MBR entry point is 0x7c00 (BIOS loads MBR here)
|
|
285
|
+
# Step through bootloader, inspect registers and memory:
|
|
286
|
+
(gdb) x/20i $pc
|
|
287
|
+
(gdb) info registers
|
|
288
|
+
(gdb) x/16xb 0x7c00
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
To bypass a password check: identify the conditional jump after the comparison and NOP it out in the image file, or patch the comparison to always succeed.
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
# Find the comparison offset in the image and patch it
|
|
295
|
+
python3 -c "
|
|
296
|
+
data = open('disk.img', 'rb').read()
|
|
297
|
+
# Replace JNZ (0x75) with JMP-short-always or NOP
|
|
298
|
+
data = data[:offset] + b'\x90\x90' + data[offset+2:]
|
|
299
|
+
open('disk_patched.img', 'wb').write(data)
|
|
300
|
+
"
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**Key insight:** QEMU's `-s` flag exposes a GDB stub on port 1234 for full debugging of MBR/bootloader code — workflow identical to userland debugging.
|
|
304
|
+
|
|
305
|
+
**References:** Square CTF 2017
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## Game Boy ROM Z80 Analysis in bgb Debugger (Square CTF 2017)
|
|
310
|
+
|
|
311
|
+
Game Boy ROMs use the Sharp SM83 (LR35902) CPU, a Z80/8080 hybrid. Load the ROM in the **bgb** emulator which provides GDB-like debugging: breakpoints, memory inspection, and register display.
|
|
312
|
+
|
|
313
|
+
**Key instructions for flag comparisons:**
|
|
314
|
+
```asm
|
|
315
|
+
LD A, [HL] ; load byte from memory pointed to by HL into A
|
|
316
|
+
AND [HL] ; A = A & *HL — compares player byte against memory value
|
|
317
|
+
CP N ; compare A with immediate N (sets Z flag if equal)
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
When `and (hl)` or `cp (hl)` fires during input validation, the expected byte is visible at the `(hl)` address in the memory view.
|
|
321
|
+
|
|
322
|
+
**bgb workflow:**
|
|
323
|
+
1. Load ROM: File → Open ROM
|
|
324
|
+
2. Right-click disassembly → "Run to cursor" or set breakpoint (F2)
|
|
325
|
+
3. When comparison fires, inspect Registers panel (HL value) and Memory panel (`*HL`)
|
|
326
|
+
4. Note expected value, advance to next comparison position
|
|
327
|
+
|
|
328
|
+
**Key insight:** Game Boy ROMs are Z80/SM83 architecture. The bgb debugger provides GDB-like functionality; key comparisons use `(hl)`-indirect addressing so the expected value is directly visible in the memory view during the comparison.
|
|
329
|
+
|
|
330
|
+
**References:** Square CTF 2017
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## KVM Guest Analysis via ioctl + KVM_EXIT_HLT Block Chaining (CSAW 2018)
|
|
335
|
+
|
|
336
|
+
**Pattern:** A userspace process hosts a KVM-based VM whose guest "program" is nothing but a sequence of code blocks that end in `HLT`. The host handler reads `KVM_EXIT_HLT`, inspects guest registers, and dispatches to the next block by looking up `rax` in a jump table at `0x2020A0`. Reverse the whole program by (1) running the binary under `strace -v` to capture `KVM_GET_REGS`/`KVM_SET_REGS` pairs, (2) dumping each code block from the KVM memory region, and (3) reconstructing the dispatch graph from the host's rax-indexed table.
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
# 1. Observe KVM ioctls + register snapshots
|
|
340
|
+
strace -v -e ioctl ./challenge 2>&1 | grep -E "KVM_RUN|KVM_(GET|SET)_REGS"
|
|
341
|
+
|
|
342
|
+
# 2. Dump guest code memory (offset + size from KVM_SET_USER_MEMORY_REGION ioctl)
|
|
343
|
+
gdb -batch -ex "attach $(pgrep challenge)" \
|
|
344
|
+
-ex "dump binary memory guest.bin 0x400000 0x410000" \
|
|
345
|
+
-ex "detach"
|
|
346
|
+
|
|
347
|
+
# 3. Disassemble each HLT-terminated block
|
|
348
|
+
objdump -D -b binary -m i386:x86-64 guest.bin | less
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
```python
|
|
352
|
+
# Rebuild the dispatch graph
|
|
353
|
+
import struct
|
|
354
|
+
with open("challenge", "rb") as f:
|
|
355
|
+
data = f.read()
|
|
356
|
+
# Host table at 0x2020A0 maps rax → next block offset
|
|
357
|
+
table = struct.unpack_from("<128Q", data, 0x2020A0)
|
|
358
|
+
for rax, ptr in enumerate(table):
|
|
359
|
+
if ptr:
|
|
360
|
+
print(f"rax={rax:02x} → block {ptr:#x}")
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
**Key insight:** KVM-backed challenges hide control flow by moving it into the host process, not the guest. The guest code itself is just a pile of opaque blocks. `strace` on the KVM ioctls replaces a debugger: every `KVM_EXIT_HLT` is a "basic block boundary" and the host's response is the real transition function. Any time you see a CTF binary linked against `-lkvm` or opening `/dev/kvm`, drop your normal reverse-engineering pipeline and start from the ioctl trace.
|
|
364
|
+
|
|
365
|
+
**References:** CSAW CTF Qualification Round 2018 — kvm, writeup 11206
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Coreboot ROM XOR-Pair Bit-Flip Address Discovery (Hack.lu 2018)
|
|
370
|
+
|
|
371
|
+
**Pattern:** A firmware image loads its flag location by XOR-ing two constants from ROM at boot. The challenge service lets the attacker flip a single bit anywhere in the ROM and observe the new flag address. Compute the intended address `X = C1 ^ C2`, compare against the advertised address, and the bit that differs — always exactly one bit away in a well-designed challenge — tells you which ROM byte + bit pair controls the redirect.
|
|
372
|
+
|
|
373
|
+
```python
|
|
374
|
+
# Two constants in ROM
|
|
375
|
+
C1 = 0xEF56BF92
|
|
376
|
+
C2 = 0xEF5A3F92
|
|
377
|
+
intended = C1 ^ C2 # 0xC8000 per the source
|
|
378
|
+
actual = 0xC0000 # where the flag really lives in memory
|
|
379
|
+
|
|
380
|
+
diff = intended ^ actual # 0x08000 → bit 15
|
|
381
|
+
# Find the ROM offset that, when a single bit is flipped, produces `actual`.
|
|
382
|
+
# The flip must land in either C1 or C2 so the XOR result has bit 15 cleared.
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
**Key insight:** XOR of two ROM constants is trivially a linear operation: any single-bit flip in either operand XORs the corresponding bit into the result. Walk the Hamming distance between computed and observed addresses and you get a bounded list of candidate patch sites — usually one or two. Pairs of addresses in firmware are suspicious: they frequently compose via XOR, ADD, or SUB and every arithmetic relation is a candidate for a targeted single-bit flip attack. Also applies to rowhammer: the sensitive bit is the *differential* between two constants, not the constants themselves.
|
|
386
|
+
|
|
387
|
+
**References:** Hack.lu CTF 2018 — 1-bit-missile, writeups 11862, 11865
|