From db4eec3cd637fe26b113a92d123f39ee28a68589 Mon Sep 17 00:00:00 2001 From: Eun0us Date: Thu, 26 Mar 2026 17:33:26 +0000 Subject: [PATCH] write-up: Hardware/Signal_Tap_Lain/README.md --- Hardware/Signal_Tap_Lain/README.md | 153 +++++++++++++++++++++++------ 1 file changed, 123 insertions(+), 30 deletions(-) diff --git a/Hardware/Signal_Tap_Lain/README.md b/Hardware/Signal_Tap_Lain/README.md index 1ec85f0..e2215e2 100644 --- a/Hardware/Signal_Tap_Lain/README.md +++ b/Hardware/Signal_Tap_Lain/README.md @@ -1,57 +1,150 @@ -# Signal Tap Lain — Solution +# Signal Tap Lain -## Overview +| Field | Value | +|-------|-------| +| Category | Hardware | +| Difficulty | Medium-Hard | +| Points | 500 | +| Author | Eun0us | +| CTF | Espilon 2026 | -A logic analyzer capture is streamed with 3 channels. Channel 1 (ch1) contains -UART data at 9600 baud, 8N1 format. The player must identify the protocol from -signal timing and decode the ASCII message. +--- -## Steps +## Description -1. Connect and capture the data: +A debug probe is capturing signals from Lain's NAVI. +Three channels are being recorded, but what protocol is in use? + +- Signal Tap: `tcp/:3800` + +Capture the data, identify the protocol, and decode the message. + +Format: **ESPILON{...}** + +--- + +## TL;DR + +Download a multi-channel logic analyzer CSV capture. Identify that channel 1 carries UART +at 9600 baud by measuring the bit period. Implement UART 8N1 decoding (LSB-first) and +extract the ASCII flag, which is repeated 3 times in the stream. + +--- + +## Tools + +| Tool | Purpose | +|------|---------| +| `nc` | Capture the signal tap data | +| Python 3 / numpy | Logic analysis and UART decoding | +| `info` command | Get channel metadata from the service | + +--- + +## Solution + +### Step 1 — Connect and capture ```bash nc 3800 > capture.csv ``` -Wait for `--- END OF CAPTURE ---`. +Wait for `--- END OF CAPTURE ---` then press Ctrl+C. -1. Analyze the capture. Use `info` command for metadata: +### Step 2 — Get metadata + +Connect again and issue: ```text info ``` -Shows 3 channels: ch0 (reference), ch1 (data), ch2 (noise). +Output: -1. Focus on ch1. Look for patterns: +``` +Channels: 3 + ch0: reference clock (always HIGH) + ch1: data line + ch2: noise channel +Sample rate: 1 MHz +``` - - Idle state is HIGH (1) - - Periodic falling edges = start bits - - Measure time between start bits to find character period +> 📸 `[screenshot: info command output listing the three channels]` -1. Calculate baud rate: +### Step 3 — Analyze channel 1 - - Bit period ≈ 104.17 μs → 9600 baud - - Character frame = 10 bits (1 start + 8 data + 1 stop) = ~1041.67 μs +Focus on ch1. The key observations: -1. Decode UART 8N1: +- Idle state is **HIGH** (logic 1) — consistent with UART +- Periodic **falling edges** = start bits +- Measure the time between the start bit falling edge and the next bit transition - - Start bit: falling edge (HIGH → LOW) - - Sample data bits at center of each bit period (1.5 × bit_period after start) - - 8 data bits, LSB first - - Stop bit: HIGH +### Step 4 — Calculate baud rate -1. Script or manually decode the ch1 data to ASCII. The message contains the flag - repeated 3 times. +Measure the minimum pulse width in the ch1 column: -## Key Concepts +``` +Bit period ≈ 104.17 μs +Baud rate = 1 / 0.00010417 ≈ 9600 baud +``` -- **Logic analysis**: Reading digital signals and identifying protocols from timing patterns -- **UART 8N1**: Universal Asynchronous Receiver/Transmitter — start bit, 8 data bits LSB-first, no parity, 1 stop bit -- **Baud rate detection**: Measuring the shortest pulse width gives the bit period → baud rate -- **Signal separation**: In a multi-channel capture, identifying which channel carries useful data +A 10-bit UART frame (1 start + 8 data + 1 stop) = ~1041.67 μs. + +> 📸 `[screenshot: Python script measuring bit periods from ch1 transitions]` + +### Step 5 — Decode UART 8N1 + +```python +import csv + +# Load capture +with open("capture.csv") as f: + reader = csv.DictReader(f) + rows = list(reader) + +timestamps = [float(r["timestamp_us"]) for r in rows] +ch1 = [int(r["ch1"]) for r in rows] + +BIT_PERIOD = 104.17 # microseconds at 9600 baud +chars = [] +i = 0 +while i < len(ch1) - 1: + # Find start bit (falling edge: HIGH → LOW) + if ch1[i] == 1 and ch1[i+1] == 0: + start_time = timestamps[i+1] + # Sample 8 data bits at center of each bit period + bits = [] + for b in range(8): + sample_time = start_time + BIT_PERIOD * (1.5 + b) + # Find closest sample + j = min(range(len(timestamps)), + key=lambda k: abs(timestamps[k] - sample_time)) + bits.append(ch1[j]) + # LSB first + byte = int("".join(map(str, reversed(bits))), 2) + if 32 <= byte <= 126: + chars.append(chr(byte)) + i += int(BIT_PERIOD * 10 / (timestamps[1] - timestamps[0])) + else: + i += 1 + +print("".join(chars)) +``` + +The decoded message contains the flag repeated three times. + +> 📸 `[screenshot: decoded UART output showing the flag repeated]` + +### Key concepts + +- **Logic analysis**: Reading digital waveforms and identifying protocols from timing patterns +- **UART 8N1**: Start bit (HIGH→LOW), 8 data bits LSB-first, no parity bit, 1 stop bit (HIGH) +- **Baud rate detection**: The shortest pulse width in the signal equals one bit period +- **Signal separation**: Channel 0 is a reference clock, channel 1 carries data, channel 2 is noise; + only ch1 has meaningful transitions + +--- ## Flag -`ESPILON{s1gn4l_t4p_l41n}` +`ESPILON{s1gn4l_t4p_d3c0d3d}`