Harald Blåtann — BLE Device Information Service
Platform: NNS CTF 2026
Category: Reverse Engineering / Bluetooth
1. Artifact and first hypothesis
The challenge provides an Intel HEX image for ARM Thumb firmware running on an nRF/Zephyr Bluetooth device advertised as NNS flag checker. The image contains a long custom characteristic value that looks attractive, but it is an explicit decoy: NNS{th15_is_n0t_th3_fl4g}.
The correct approach is to reconstruct the GATT data instead of trusting the most visible string. Zephyr stores attribute records, UUID references, callbacks, permissions, and user-data pointers in the firmware image. Standard Bluetooth services are also more likely to have meaningful labels than arbitrary vendor characteristics.
2. Parsing the Intel HEX image
extract_dis_flag.py reads every HEX record, validates its checksum, handles extended segment and linear addresses, and reconstructs a contiguous image beginning at 0x01000000. This validation matters: one ignored address record or bad checksum could make every later pointer incorrect.
Each reconstructed attribute is interpreted as six little-endian words/halfwords. UUID references are read from the image, and NUL-terminated strings are resolved through the attribute’s user-data pointer.
3. Locating the useful service
The service declaration at 0x01026F78 points to UUID 0x180A, the standard Device Information Service. Its value attributes have the expected UUIDs:
0x01026FA0→0x2A24, Model Number;0x01026FC8→0x2A29, Manufacturer Name;0x01027018→0x2A25, Serial Number.
The script checks each UUID before reading its pointer. This prevents accidentally interpreting an adjacent attribute or a decoy string as the answer.
4. Extracting and assembling the values
The exact NUL-terminated values are:
Model Number (UUID 0x2A24): Flag checker
Manufacturer Name (UUID 0x2A29): NNS
Serial Number (UUID 0x2A25): 1337
The model confirms that this is the intended checker. The manufacturer supplies the flag namespace and the serial number supplies the body. Combining them according to the challenge convention gives Manufacturer{Serial Number}.
5. Reproduction
cd /home/z13db/CTF/reverse/harald-blatann
python3 extract_dis_flag.py
The script asserts the HEX checksums, minimum flash address, service UUID, all three characteristic UUIDs, and all expected string values. It then prints the assembled result.
6. Verified flag
NNS{1337}
7. Lessons
- Do not assume a custom characteristic is the intended data source.
- Standard GATT services have stable UUID semantics and are excellent anchors during firmware analysis.
- Validate binary checksums and pointers before trusting extracted strings.
- When a challenge includes a decoy, prove the final value through several independent structure checks.