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.
Files changed (152) hide show
  1. package/AGENTS.md +131 -0
  2. package/Dockerfile +192 -0
  3. package/README.md +522 -0
  4. package/agents/ctf-analyzer.md +58 -0
  5. package/agents/ctf-controller.md +151 -0
  6. package/agents/ctf-speedrun.md +74 -0
  7. package/bin/ctf-agent.js +119 -0
  8. package/docker-compose.yml +13 -0
  9. package/mcp_config.json +19 -0
  10. package/package.json +44 -0
  11. package/references/ctf-triage-ladder.md +68 -0
  12. package/references/exploit-databases.md +575 -0
  13. package/references/llm-safety-and-policy-compliance.md +173 -0
  14. package/references/multi-agent-orchestration-and-policy-routing.md +278 -0
  15. package/references/security-events-and-intelligence.md +566 -0
  16. package/references/version-matrix.md +59 -0
  17. package/rules/ctf-execution-rules.md +44 -0
  18. package/rules/ctf-safety-framing-rules.md +140 -0
  19. package/rules/flag-validation-rules.md +25 -0
  20. package/scripts/__init__.py +1 -0
  21. package/scripts/ctf-tools.lock +205 -0
  22. package/scripts/ctf_init.py +1026 -0
  23. package/scripts/ctf_update.py +583 -0
  24. package/scripts/ctfd_client.py +81 -0
  25. package/scripts/cve_lookup.py +453 -0
  26. package/scripts/extract_flags.py +155 -0
  27. package/scripts/install_as_agent.py +278 -0
  28. package/scripts/install_ctf_tools.sh +603 -0
  29. package/scripts/parallel_triage.py +395 -0
  30. package/scripts/prompt_policy_sanitizer.py +283 -0
  31. package/scripts/scope_guard.py +444 -0
  32. package/scripts/skill_validator.py +504 -0
  33. package/scripts/workspace_cleaner.py +141 -0
  34. package/skills/ctf-ai-ml/SKILL.md +120 -0
  35. package/skills/ctf-ai-ml/adversarial-ml.md +623 -0
  36. package/skills/ctf-ai-ml/llm-attacks.md +487 -0
  37. package/skills/ctf-ai-ml/model-attacks.md +422 -0
  38. package/skills/ctf-crypto/SKILL.md +320 -0
  39. package/skills/ctf-crypto/advanced-math.md +798 -0
  40. package/skills/ctf-crypto/classic-ciphers.md +651 -0
  41. package/skills/ctf-crypto/ecc-attacks.md +347 -0
  42. package/skills/ctf-crypto/exotic-crypto-2.md +380 -0
  43. package/skills/ctf-crypto/exotic-crypto.md +528 -0
  44. package/skills/ctf-crypto/historical.md +113 -0
  45. package/skills/ctf-crypto/lattice-and-lwe.md +524 -0
  46. package/skills/ctf-crypto/modern-ciphers-2.md +563 -0
  47. package/skills/ctf-crypto/modern-ciphers-3.md +453 -0
  48. package/skills/ctf-crypto/modern-ciphers.md +649 -0
  49. package/skills/ctf-crypto/prng-attacks.md +257 -0
  50. package/skills/ctf-crypto/prng.md +664 -0
  51. package/skills/ctf-crypto/rsa-attacks-2.md +792 -0
  52. package/skills/ctf-crypto/rsa-attacks.md +487 -0
  53. package/skills/ctf-crypto/stream-ciphers.md +390 -0
  54. package/skills/ctf-crypto/zkp-and-advanced.md +456 -0
  55. package/skills/ctf-forensics/3d-printing.md +121 -0
  56. package/skills/ctf-forensics/SKILL.md +379 -0
  57. package/skills/ctf-forensics/disk-advanced.md +497 -0
  58. package/skills/ctf-forensics/disk-and-memory.md +491 -0
  59. package/skills/ctf-forensics/disk-recovery.md +699 -0
  60. package/skills/ctf-forensics/linux-forensics.md +511 -0
  61. package/skills/ctf-forensics/network-advanced.md +583 -0
  62. package/skills/ctf-forensics/network.md +645 -0
  63. package/skills/ctf-forensics/peripheral-capture.md +287 -0
  64. package/skills/ctf-forensics/signals-and-hardware.md +713 -0
  65. package/skills/ctf-forensics/steganography.md +694 -0
  66. package/skills/ctf-forensics/stego-advanced-2.md +475 -0
  67. package/skills/ctf-forensics/stego-advanced.md +481 -0
  68. package/skills/ctf-forensics/stego-image.md +691 -0
  69. package/skills/ctf-forensics/windows.md +625 -0
  70. package/skills/ctf-malware/SKILL.md +181 -0
  71. package/skills/ctf-malware/c2-and-protocols.md +274 -0
  72. package/skills/ctf-malware/pe-and-dotnet.md +108 -0
  73. package/skills/ctf-malware/scripts-and-obfuscation.md +449 -0
  74. package/skills/ctf-misc/SKILL.md +498 -0
  75. package/skills/ctf-misc/bashjails.md +323 -0
  76. package/skills/ctf-misc/ctfd-navigation.md +465 -0
  77. package/skills/ctf-misc/dns.md +255 -0
  78. package/skills/ctf-misc/encodings-advanced.md +504 -0
  79. package/skills/ctf-misc/encodings.md +431 -0
  80. package/skills/ctf-misc/games-and-vms-2.md +254 -0
  81. package/skills/ctf-misc/games-and-vms-3.md +690 -0
  82. package/skills/ctf-misc/games-and-vms-4.md +229 -0
  83. package/skills/ctf-misc/games-and-vms.md +529 -0
  84. package/skills/ctf-misc/linux-privesc.md +333 -0
  85. package/skills/ctf-misc/pyjails.md +671 -0
  86. package/skills/ctf-misc/rf-sdr.md +91 -0
  87. package/skills/ctf-osint/SKILL.md +198 -0
  88. package/skills/ctf-osint/geolocation-and-media.md +464 -0
  89. package/skills/ctf-osint/social-media.md +312 -0
  90. package/skills/ctf-osint/web-and-dns.md +341 -0
  91. package/skills/ctf-pwn/SKILL.md +214 -0
  92. package/skills/ctf-pwn/advanced-exploits-2.md +579 -0
  93. package/skills/ctf-pwn/advanced-exploits-3.md +598 -0
  94. package/skills/ctf-pwn/advanced-exploits-4.md +590 -0
  95. package/skills/ctf-pwn/advanced-exploits-5.md +119 -0
  96. package/skills/ctf-pwn/advanced-exploits.md +773 -0
  97. package/skills/ctf-pwn/advanced.md +326 -0
  98. package/skills/ctf-pwn/field-notes.md +245 -0
  99. package/skills/ctf-pwn/format-string.md +694 -0
  100. package/skills/ctf-pwn/heap-fsop.md +285 -0
  101. package/skills/ctf-pwn/heap-techniques-2.md +333 -0
  102. package/skills/ctf-pwn/heap-techniques.md +513 -0
  103. package/skills/ctf-pwn/kernel-bypass.md +421 -0
  104. package/skills/ctf-pwn/kernel-techniques.md +366 -0
  105. package/skills/ctf-pwn/kernel.md +636 -0
  106. package/skills/ctf-pwn/overflow-basics.md +611 -0
  107. package/skills/ctf-pwn/rop-advanced.md +725 -0
  108. package/skills/ctf-pwn/rop-and-shellcode.md +659 -0
  109. package/skills/ctf-pwn/sandbox-escape.md +313 -0
  110. package/skills/ctf-reverse/SKILL.md +163 -0
  111. package/skills/ctf-reverse/anti-analysis-ctf.md +204 -0
  112. package/skills/ctf-reverse/anti-analysis.md +693 -0
  113. package/skills/ctf-reverse/field-notes.md +376 -0
  114. package/skills/ctf-reverse/languages-compiled.md +666 -0
  115. package/skills/ctf-reverse/languages-platforms.md +592 -0
  116. package/skills/ctf-reverse/languages.md +553 -0
  117. package/skills/ctf-reverse/patterns-ctf-2.md +397 -0
  118. package/skills/ctf-reverse/patterns-ctf-3.md +797 -0
  119. package/skills/ctf-reverse/patterns-ctf.md +670 -0
  120. package/skills/ctf-reverse/patterns-runtime.md +274 -0
  121. package/skills/ctf-reverse/patterns.md +572 -0
  122. package/skills/ctf-reverse/platforms-hardware.md +387 -0
  123. package/skills/ctf-reverse/platforms.md +664 -0
  124. package/skills/ctf-reverse/tools-advanced-2.md +421 -0
  125. package/skills/ctf-reverse/tools-advanced.md +407 -0
  126. package/skills/ctf-reverse/tools-dynamic.md +679 -0
  127. package/skills/ctf-reverse/tools-emulation.md +319 -0
  128. package/skills/ctf-reverse/tools.md +573 -0
  129. package/skills/ctf-web/SKILL.md +153 -0
  130. package/skills/ctf-web/auth-and-access-2.md +82 -0
  131. package/skills/ctf-web/auth-and-access.md +783 -0
  132. package/skills/ctf-web/auth-infra.md +321 -0
  133. package/skills/ctf-web/auth-jwt.md +186 -0
  134. package/skills/ctf-web/client-side-advanced.md +739 -0
  135. package/skills/ctf-web/client-side.md +529 -0
  136. package/skills/ctf-web/cves.md +373 -0
  137. package/skills/ctf-web/field-notes.md +482 -0
  138. package/skills/ctf-web/node-and-prototype.md +200 -0
  139. package/skills/ctf-web/server-side-2.md +337 -0
  140. package/skills/ctf-web/server-side-advanced-2.md +559 -0
  141. package/skills/ctf-web/server-side-advanced-3.md +125 -0
  142. package/skills/ctf-web/server-side-advanced-4.md +480 -0
  143. package/skills/ctf-web/server-side-advanced.md +378 -0
  144. package/skills/ctf-web/server-side-deser.md +443 -0
  145. package/skills/ctf-web/server-side-exec-2.md +799 -0
  146. package/skills/ctf-web/server-side-exec.md +457 -0
  147. package/skills/ctf-web/server-side.md +629 -0
  148. package/skills/ctf-web/sql-injection.md +790 -0
  149. package/skills/ctf-web/web3.md +374 -0
  150. package/skills/ctf-writeup/SKILL.md +90 -0
  151. package/skills/solve-challenge/SKILL.md +269 -0
  152. package/skills.json +16 -0
@@ -0,0 +1,287 @@
1
+ # CTF Forensics - Peripheral Capture Analysis
2
+
3
+ USB, HID, and Bluetooth peripheral traffic reconstruction from packet captures. For general network PCAP forensics (DNS/TCP/ICMP/SMB/RADIUS/RC4), see [network-advanced.md](network-advanced.md). For basic network forensics, see [network.md](network.md).
4
+
5
+ ## Table of Contents
6
+ - [USB HID Mouse/Pen Drawing Recovery (EHAX 2026)](#usb-hid-mousepen-drawing-recovery-ehax-2026)
7
+ - [USB HID Keyboard Capture Decoding (EKOPARTY CTF 2016)](#usb-hid-keyboard-capture-decoding-ekoparty-ctf-2016)
8
+ - [USB Keyboard LED Morse Code Exfiltration (BITSCTF 2017)](#usb-keyboard-led-morse-code-exfiltration-bitsctf-2017)
9
+ - [USB HID Keyboard Arrow Key Navigation Tracking (HackIT 2017)](#usb-hid-keyboard-arrow-key-navigation-tracking-hackit-2017)
10
+ - [Bluetooth RFCOMM Packet Reassembly (HITCON 2018)](#bluetooth-rfcomm-packet-reassembly-hitcon-2018)
11
+ - [GBA USB URB_INTERRUPT Framebuffer Extraction (hxp 2018)](#gba-usb-urb_interrupt-framebuffer-extraction-hxp-2018)
12
+
13
+ ---
14
+
15
+ ## USB HID Mouse/Pen Drawing Recovery (EHAX 2026)
16
+
17
+ **Pattern (Painter):** PCAP contains USB HID interrupt transfers from a mouse/pen device. Drawing data encoded as relative movements with multiple draw modes.
18
+
19
+ **Packet format (7-byte HID reports):**
20
+ | Byte | Field | Notes |
21
+ |------|-------|-------|
22
+ | 0 | Button state | 0x01 = pressed (may be constant) |
23
+ | 1 | Mode/pad | 0=hover, 1=draw mode 1, 2=draw mode 2 |
24
+ | 2-3 | dx (int16 LE) | Relative X movement |
25
+ | 4-5 | dy (int16 LE) | Relative Y movement |
26
+ | 6 | Wheel | Usually 0 |
27
+
28
+ **Extraction and rendering:**
29
+ ```python
30
+ import struct
31
+ from PIL import Image, ImageDraw
32
+
33
+ # Extract HID data
34
+ # tshark -r capture.pcap -Y "usb.transfer_type==1" -T fields -e usb.capdata
35
+
36
+ packets = []
37
+ with open('hid_data.txt') as f:
38
+ for line in f:
39
+ raw = bytes.fromhex(line.strip().replace(':', ''))
40
+ if len(raw) >= 7:
41
+ btn = raw[0]
42
+ mode = raw[1]
43
+ dx = struct.unpack('<h', raw[2:4])[0]
44
+ dy = struct.unpack('<h', raw[4:6])[0]
45
+ packets.append((btn, mode, dx, dy))
46
+
47
+ # Accumulate positions per mode
48
+ SCALE = 5
49
+ positions = {0: [], 1: [], 2: []}
50
+ x, y = 0, 0
51
+ for btn, mode, dx, dy in packets:
52
+ x += dx
53
+ y += dy
54
+ positions[mode].append((x, y))
55
+
56
+ # Render each mode separately (different colors = different text layers)
57
+ for mode in [1, 2]:
58
+ pts = positions[mode]
59
+ if not pts:
60
+ continue
61
+ min_x = min(p[0] for p in pts) - 100
62
+ min_y = min(p[1] for p in pts) - 100
63
+ max_x = max(p[0] for p in pts) + 100
64
+ max_y = max(p[1] for p in pts) + 100
65
+ w = (max_x - min_x) * SCALE
66
+ h = (max_y - min_y) * SCALE
67
+ img = Image.new('RGB', (w, h), 'white')
68
+ draw = ImageDraw.Draw(img)
69
+ for i in range(1, len(pts)):
70
+ x0 = (pts[i-1][0] - min_x) * SCALE
71
+ y0 = (pts[i-1][1] - min_y) * SCALE
72
+ x1 = (pts[i][0] - min_x) * SCALE
73
+ y1 = (pts[i][1] - min_y) * SCALE
74
+ # Skip long jumps (pen lifts)
75
+ if abs(pts[i][0]-pts[i-1][0]) < 50 and abs(pts[i][1]-pts[i-1][1]) < 50:
76
+ draw.line([(x0,y0),(x1,y1)], fill='black', width=3)
77
+ img.save(f'mode_{mode}.png')
78
+ ```
79
+
80
+ **Key techniques:**
81
+ - **Separate modes:** Different button/mode values draw different text layers — render each independently
82
+ - **Skip pen lifts:** Large dx/dy jumps indicate pen was lifted, not drawn — filter by distance threshold
83
+ - **High resolution:** Scale 5-8x with margins for readable handwriting
84
+ - **Time gradient:** Color points by temporal order (rainbow gradient) to trace stroke direction
85
+ - **Character segmentation:** Group consecutive same-mode points by large X gaps to isolate characters
86
+
87
+ **Alternative: AWK extraction + SVG rendering (faster pipeline):**
88
+ ```bash
89
+ # Extract capdata and convert to signed deltas in one pass
90
+ tshark -r pref.pcap -Y "usb.transfer_type==0x01 && usb.endpoint_address==0x81 && usb.capdata" \
91
+ -T fields -e usb.capdata > capdata.txt
92
+
93
+ awk '
94
+ function hexval(c){ return index("0123456789abcdef",tolower(c))-1 }
95
+ function hex2dec(h, n,i){ n=0; for(i=1;i<=length(h);i++) n=n*16+hexval(substr(h,i,1)); return n }
96
+ function s16(u){ return (u>=32768)?u-65536:u }
97
+ { d=$1; if(length(d)!=14) next
98
+ btn=hex2dec(substr(d,3,2))
99
+ x=s16(hex2dec(substr(d,7,2) substr(d,5,2)))
100
+ y=s16(hex2dec(substr(d,11,2) substr(d,9,2)))
101
+ print btn, x, y }' capdata.txt > deltas.txt
102
+ ```
103
+ Then render with SVG (Python) — filter on pen-down state (button=2), accumulate deltas, flip Y axis, draw strokes between consecutive pen-down points.
104
+
105
+ **Difference from keyboard HID:** Mouse HID uses relative movements (accumulated), keyboard uses keycodes (direct). Mouse drawing requires rendering; keyboard requires keymap lookup.
106
+
107
+ ---
108
+
109
+ ## USB HID Keyboard Capture Decoding (EKOPARTY CTF 2016)
110
+
111
+ USB keyboard captures contain HID scan codes that map to keystrokes. Decode the capture to reconstruct typed text.
112
+
113
+ ```python
114
+ # USB HID keyboard report format:
115
+ # Byte 0: Modifier keys (Shift, Ctrl, Alt)
116
+ # Byte 1: Reserved (0x00)
117
+ # Bytes 2-7: Up to 6 simultaneous key codes
118
+
119
+ # HID scan code to character mapping (partial)
120
+ HID_MAP = {
121
+ 0x04: 'a', 0x05: 'b', 0x06: 'c', 0x07: 'd', 0x08: 'e',
122
+ 0x09: 'f', 0x0a: 'g', 0x0b: 'h', 0x0c: 'i', 0x0d: 'j',
123
+ 0x0e: 'k', 0x0f: 'l', 0x10: 'm', 0x11: 'n', 0x12: 'o',
124
+ 0x13: 'p', 0x14: 'q', 0x15: 'r', 0x16: 's', 0x17: 't',
125
+ 0x18: 'u', 0x19: 'v', 0x1a: 'w', 0x1b: 'x', 0x1c: 'y',
126
+ 0x1d: 'z', 0x1e: '1', 0x1f: '2', 0x20: '3', 0x21: '4',
127
+ 0x22: '5', 0x23: '6', 0x24: '7', 0x25: '8', 0x26: '9',
128
+ 0x27: '0', 0x28: '\n', 0x2c: ' ', 0x2d: '-', 0x2e: '=',
129
+ 0x2f: '[', 0x30: ']', 0x33: ';', 0x34: "'", 0x36: ',',
130
+ 0x37: '.', 0x38: '/',
131
+ }
132
+
133
+ SHIFT_MAP = {
134
+ 'a': 'A', 'b': 'B', '1': '!', '2': '@', '3': '#', '4': '$',
135
+ '5': '%', '6': '^', '7': '&', '8': '*', '9': '(', '0': ')',
136
+ '-': '_', '=': '+', '[': '{', ']': '}', ';': ':', "'": '"',
137
+ ',': '<', '.': '>', '/': '?',
138
+ }
139
+
140
+ def decode_hid_keyboard(capture_data):
141
+ """Decode USB HID keyboard capture to text"""
142
+ text = ""
143
+ for report in capture_data:
144
+ modifier = report[0]
145
+ keycode = report[2] # first key in report
146
+
147
+ if keycode == 0:
148
+ continue
149
+
150
+ char = HID_MAP.get(keycode, '')
151
+ if modifier & 0x22: # Left or Right Shift
152
+ char = SHIFT_MAP.get(char, char.upper())
153
+
154
+ text += char
155
+ return text
156
+
157
+ # Extract from Wireshark: tshark -r capture.pcapng -T fields -e usb.capdata
158
+ # Or from text dump: parse +XX/-XX format (+ = keydown, - = keyup)
159
+ ```
160
+
161
+ **Key insight:** USB HID keyboards send 8-byte reports where byte 0 is modifiers (Shift/Ctrl/Alt) and bytes 2-7 are active key scan codes. In Wireshark, filter with `usb.transfer_type == 1` and extract `usb.capdata`. Ignore reports where byte 2 is 0x00 (key release).
162
+
163
+ ---
164
+
165
+ ## USB Keyboard LED Morse Code Exfiltration (BITSCTF 2017)
166
+
167
+ **Pattern (Ghost in the Machine):** A pcap of USB keyboard traffic contains host-to-device packets with alternating `0x01`/`0x03` values controlling the Caps Lock LED state. Timing differences between LED state changes encode Morse code: durations >300ms represent dashes, shorter durations represent dots. Decode the Morse sequence to recover the flag.
168
+
169
+ ```python
170
+ from scapy.all import rdpcap
171
+ import struct
172
+
173
+ packets = rdpcap('usb_capture.pcap')
174
+ signals = []
175
+
176
+ for p in packets:
177
+ raw = bytes(p)
178
+ # USB HID SET_REPORT to keyboard (host -> device)
179
+ if len(raw) >= 35 and raw[30] in (0x01, 0x03):
180
+ timestamp = p.time
181
+ led_state = raw[30] # 0x01 = LED off, 0x03 = LED on
182
+ signals.append((timestamp, led_state))
183
+
184
+ # Convert timing to Morse
185
+ morse = ''
186
+ for i in range(0, len(signals) - 1, 2):
187
+ duration = signals[i+1][0] - signals[i][0]
188
+ if duration > 0.3:
189
+ morse += '-'
190
+ else:
191
+ morse += '.'
192
+ # Gap between signals indicates letter/word boundary
193
+ ```
194
+
195
+ **Key insight:** Data exfiltration via keyboard LED state changes captured in USB pcap. The LED control packets use HID SET_REPORT class requests. Timing analysis of on/off transitions reveals Morse code patterns. Tools: Wireshark USB dissector, filter on `usb.transfer_type == 0x02` (interrupt) and direction host→device.
196
+
197
+ ---
198
+
199
+ ## USB HID Keyboard Arrow Key Navigation Tracking (HackIT 2017)
200
+
201
+ USB HID keyboard traffic from an Apple Keyboard requires tracking arrow key navigation. Decode HID keycodes using the USB HID usage table. Modifier byte `0x02` = Shift (uppercase). Track cursor position via up/down arrow presses to determine which line contains the flag.
202
+
203
+ ```bash
204
+ tshark -r capture.pcap -T fields -e usb.capdata | \
205
+ python3 decode_hid.py # Must track arrow keys for line position
206
+ ```
207
+
208
+ Arrow key HID codes to track:
209
+ - `0x4F` = Right Arrow
210
+ - `0x50` = Left Arrow
211
+ - `0x51` = Down Arrow (next line)
212
+ - `0x52` = Up Arrow (previous line)
213
+
214
+ ```python
215
+ # Skeleton: track line position during HID decode
216
+ line = 0
217
+ lines = {0: ""}
218
+ for report in hid_reports:
219
+ modifier = report[0]
220
+ keycode = report[2]
221
+ if keycode == 0x51: # Down arrow
222
+ line += 1; lines.setdefault(line, "")
223
+ elif keycode == 0x52: # Up arrow
224
+ line -= 1; lines.setdefault(line, "")
225
+ elif keycode in HID_MAP:
226
+ char = HID_MAP[keycode]
227
+ if modifier & 0x22:
228
+ char = char.upper()
229
+ lines[line] += char
230
+ # Flag is on a specific line determined by arrow navigation
231
+ ```
232
+
233
+ **Key insight:** USB keyboard captures must account for cursor movement keys (arrows, backspace). Track cursor line position to reconstruct text typed on each line separately — the flag may be on a non-zero line that arrow keys navigated to.
234
+
235
+ ---
236
+
237
+ ## Bluetooth RFCOMM Packet Reassembly (HITCON 2018)
238
+
239
+ **Pattern:** A Lego EV3-over-Bluetooth capture contains RFCOMM frames whose payloads are EV3 direct commands. Packets are 32–34 bytes long, have an 8-byte RFCOMM header, and carry an `order` byte plus a `group_number` byte that together reorder into a coherent binary. Reassemble by (1) filtering `btrfcomm` in Wireshark, (2) sorting packets first by `group_number` then by `order`, and (3) concatenating the data fields after the header.
240
+
241
+ ```python
242
+ # Python with pyshark
243
+ import pyshark
244
+ cap = pyshark.FileCapture("capture.pcap", display_filter="btrfcomm")
245
+ frames = []
246
+ for pkt in cap:
247
+ raw = bytes.fromhex(pkt.btrfcomm.payload.replace(":", ""))
248
+ # RFCOMM header size varies: 4 (UIH) or 5 (with length extension)
249
+ hdr_len = 4 if raw[2] & 0x01 == 0 else 5
250
+ body = raw[hdr_len:]
251
+ order, group = body[0], body[1]
252
+ frames.append((group, order, body[2:]))
253
+ frames.sort()
254
+ binary = b"".join(chunk for _, _, chunk in frames)
255
+ open("payload.bin", "wb").write(binary)
256
+ ```
257
+
258
+ **Key insight:** RFCOMM is a TCP-like serial port emulation layered on L2CAP; it fragments application payloads when they exceed the MTU. CTF challenges love to split flags across many frames because most pcap walkthroughs stop at TCP/UDP and skip the Bluetooth link layer. Use Wireshark filters `btrfcomm.channel`, `btl2cap`, or `btsnoop_hci` to isolate the relevant flows, then sort by any available order/group bytes before concatenating. Similar logic applies to USB bulk transfers (`usb.transfer_type == 0x03`) and MIDI-over-BLE traffic.
259
+
260
+ **References:** HITCON CTF 2018 — EV3 Basic, writeup 11902
261
+
262
+ ---
263
+
264
+ ## GBA USB URB_INTERRUPT Framebuffer Extraction (hxp 2018)
265
+
266
+ **Pattern:** pcap contains USB `URB_INTERRUPT` packets from a Game Boy Advance debug adapter. The GBA framebuffer is `240 × 160` at RGB565 (2 bytes/pixel = 76 800 bytes). Block type 6 carries memory dumps; split each packet's payload into the framebuffer grid and convert RGB565 to 8-bit RGB tuples.
267
+
268
+ ```python
269
+ from PIL import Image
270
+ from scapy.all import rdpcap
271
+ pkts = [p for p in rdpcap('cap.pcap') if p.haslayer('Raw')]
272
+ img = Image.new('RGB', (240, 160))
273
+ for p in pkts:
274
+ if p.Raw.load[3] == 0x06: # type 6 = memory dump
275
+ data = p.Raw.load[4:]
276
+ for i in range(76800 // 2):
277
+ rgb = int.from_bytes(data[2*i:2*i+2], 'little')
278
+ r = (rgb & 0xF800) >> 8
279
+ g = (rgb & 0x07E0) >> 3
280
+ b = (rgb & 0x001F) << 3
281
+ img.putpixel((i % 240, i // 240), (r, g, b))
282
+ img.save('screen.png')
283
+ ```
284
+
285
+ **Key insight:** Handheld console debug protocols usually wrap memory dumps in typed blocks. When you see GBA/NDS/PSP USB traffic, grep for block type 6 (framebuffer) or type 7 (audio) before parsing the rest.
286
+
287
+ **References:** hxp CTF 2018 — cheatquest of hxpschr 2, writeup 12591