# Wired SPI Exfil | Field | Value | |-------|-------| | Category | Hardware | | Difficulty | Medium-Hard | | Points | 500 | | Author | Eun0us | | CTF | Espilon 2026 | --- ## Description A WIRED-MED module's SPI flash chip is accessible via a probe station. Issue standard SPI commands to read the flash contents. - SPI Probe: `tcp/:3500` Not all partitions are listed. Dig deeper. Format: **ESPILON{...}** --- ## TL;DR Use standard SPI flash opcodes (RDID, SFDP, READ) to identify the chip, discover a hidden partition at 0x030000 via vendor-specific SFDP parameters, read the hidden partition contents, and XOR-decrypt the data with key `WIRED_SPI` to recover the flag. --- ## Tools | Tool | Purpose | |------|---------| | `nc` | Connect to the SPI probe interface | | Python 3 | XOR decryption | | SPI flash opcode reference | RDID=0x9F, READ=0x03, SFDP=0x5A | --- ## Solution ![flashrom SPI dump and strings extraction](https://git.espilon.net/Eun0us/ESPILON-CTF-2026-Writeups/raw/branch/main/screens/spi_flash.png) ### Step 1 — Connect and assert chip select ```bash nc 3500 ``` ```text cs 0 ``` > 📸 `[screenshot: SPI probe interface ready with CS asserted]` ### Step 2 — Read the chip ID Send RDID opcode 0x9F: ```text tx 9F ``` Response: `EF 40 18` — Winbond W25Q128 (128 Mbit SPI flash). ### Step 3 — Read the SFDP header SFDP (Serial Flash Discoverable Parameters) reveals flash capabilities. Send SFDP opcode 0x5A with 3-byte address and 1 dummy byte: ```text tx 5A 00 00 00 00 ``` The SFDP header shows 2 parameter tables. The first is the standard JEDEC table; the second is a vendor-specific table at offset 0x80. > 📸 `[screenshot: SFDP header output showing two parameter table entries]` ### Step 4 — Read the vendor SFDP table ```text tx 5A 00 00 80 00 ``` The vendor table data includes a hidden partition entry: ``` Offset: 0x030000 Label: HIDDEN Size: 4096 bytes ``` This partition does not appear in the normal partition table. > 📸 `[screenshot: vendor SFDP data revealing hidden partition at 0x030000]` ### Step 5 — Read the hidden partition Use the READ opcode 0x03 with 3-byte address: ```text tx 03 03 00 00 ``` The response starts with the ASCII header `WIRED_HIDDEN_PARTITION` followed by XOR-encrypted bytes. ### Step 6 — Decrypt the flag The data is XOR'd with the repeating key `WIRED_SPI`: ```python # data_hex = hex bytes from the tx read response after the header key = b"WIRED_SPI" encrypted = bytes.fromhex("...") # from response flag = bytes(b ^ key[i % len(key)] for i, b in enumerate(encrypted)) print(flag.rstrip(b'\x00').decode()) ``` > 📸 `[screenshot: Python decryption script printing the recovered flag]` ### Key concepts - **SPI flash commands**: Standard opcodes work across most vendors: `0x9F` = RDID, `0x03` = READ, `0x5A` = SFDP - **SFDP**: Serial Flash Discoverable Parameters standardises capability discovery; vendor-specific extensions can hide extra metadata, including non-standard partition info - **Hidden partitions**: Not all sectors appear in standard partition tables — manual probing or SFDP analysis is required to find them - **Data at rest XOR**: Simple XOR protection on stored secrets is common in embedded firmware; knowing the plaintext structure (header magic bytes) allows key recovery --- ## Flag `ESPILON{sp1_fl4sh_3xf1ltr4t3d}`