# Challenge Overview: Mystery Call **Category:** Forensics **Event:** L3m0nCTF 2025 **Role:** Challenge Author > πŸ› οΈ **Author Note** > This challenge was authored by me for **L3m0nCTF 2025**. > The following explanation describes the **intended forensic analysis path**. image ## Intended Analysis Path The challenge was designed to test: - recognition of signaling methods beyond direct decoding - understanding that DTMF symbols may act as carriers, not data - analysis of temporal properties rather than frequency content - multi-channel signal combination to remove decoy information Single-channel or direct decoding approaches were intentionally misleading. ## Overview Files given : [mystery_call.tar.gz](https://github.com/rozariyomartin/L3m0nCTF2025-Writeups/blob/main/Forensics/LastCall/mystery_call.wav) We are given a single audio file, mystery_call.wav. The audio contains nothing except a sequence of repetitive electronic tones. There is no speech, no music, and no obvious audible message. At first listen, the tones resemble telephone beeps, but decoding them directly does not reveal any readable text. The goal is to determine **what information is hidden inside these tones**. ## Analysis Phase 1 β€” Initial File Inspection We begin by checking the file type. ``` file mystery_call.wav ``` image The output confirms: - WAV audio - Stereo - Fixed sample rate This is important β€” the file has two channels, not one. ## Analysis Phase 2 β€” Eliminating Direct DTMF Decoding Since the tones resemble telephone signals, we try a standard DTMF decoder. ``` multimon-ng -a DTMF -t wav mystery_call.wav ``` image This produces a long stream of same repeated digits. However: - The output does not resemble a flag - The sequence is far too long - No readable structure appears This tells us something important: **The decoded DTMF symbols themselves are not the message.** ## Analysis Phase 3 β€” Channel-Level Inspection On opening this file in audacity we can see that both left channel and right channel doesnt resemble same sound. image So, we separate the channels. ``` sox mystery_call.wav left.wav remix 1 ``` ``` sox mystery_call.wav right.wav remix 2 ``` Now we have: - left.wav - right.wav Each channel contains valid tones. Running a DTMF decoder on either channel alone still does not produce meaningful text. So: - The message is **not** stored in a single channel - The channels must be **used together** ## Analysis Phase 4 β€” Identifying the True Signal Property When visualizing the waveform or spectrogram, one key detail stands out: - The frequencies do not change meaningfully - The only variation is tone duration Each tone is either: - **Short** - **Long** This strongly suggests binary encoding. We treat: - Short tone β†’ 0 - Long tone β†’ 1 ## Analysis Phase 5 β€” Binary Extraction via Temporal Analysis For each channel independently: 1.Convert audio to mono signal 2.Compute short-time energy 3.Detect tone β€œon” segments 4.Measure duration of each segment 5.Convert duration to bits The extraction logic is implemented in a helper script **extract.py** ``` #!/usr/bin/env python3 import numpy as np from scipy.io import wavfile SHORT = 0.10 LONG = 0.22 THRESH = (SHORT + LONG) / 2 WINDOW = 256 def extract_bits(wav): sr, x = wavfile.read(wav) # mono safety if x.ndim > 1: x = x[:,0] x = x.astype(np.float32) x /= np.max(np.abs(x)) energy = np.convolve(x*x, np.ones(WINDOW)/WINDOW, mode="same") on = energy > (0.2 * energy.max()) bits = [] i = 0 while i < len(on): if on[i]: j = i while j < len(on) and on[j]: j += 1 dur = (j - i) / sr bits.append('1' if dur > THRESH else '0') i = j else: i += 1 return ''.join(bits) left = extract_bits("left.wav") right = extract_bits("right.wav") print("[LEFT bits]") print(left) print("Length:", len(left)) print("\n[RIGHT bits]") print(right) print("Length:", len(right)) n = min(len(left), len(right)) xor_bits = ''.join(str(int(left[i]) ^ int(right[i])) for i in range(n)) out = [] for i in range(0, len(xor_bits), 8): byte = xor_bits[i:i+8] if len(byte) == 8: out.append(chr(int(byte, 2))) print("".join(out)) ``` Running this script produces two binary streams: This produces two binary strings: image Neither stream alone forms valid ASCII. ## Analysis Phase 6 β€” Channel Combination via XOR Because both channels are synchronized and neither decodes meaningfully by itself, the next step is to **combine them.** The intended operation is a **bitwise XOR** between corresponding bits: `FINAL_BIT = LEFT_BIT βŠ• RIGHT_BIT` This operation removes the decoy structure present in each channel individually and reconstructs the original data. The XOR and decoding process is handled by the that code even: ## Final Output The resulting binary stream is grouped into 8-bit chunks and converted to ASCII. This yields the final message: `L3m0nCTF{DTMF_X0R_5T3R30_1S_N0T_4UD10_3V3RY0N3}`