PICOCTF 2019 • REVERSE ENGINEERING • INTERLEAVED LSB

Investigative Reversing 3: 9-Byte Stride & Interleaved Dummy Carving

By AbdoAug 31, 2026
Investigative Reversing 3 Analysis
Official Challenge Prompt

“We have recovered yet another binary and image. See what the third variation does.”

Category: Forensics / Reverse EngineeringPoints: 400 PTSFlag Format: picoCTF{...}
Provided Files (Download & Practice)
Stride: 8 Data + 1 Dummy

💡 THE INTUITIVE ANALOGY (The 9th Dummy Spacer)

Imagine writing secret letters into a book where every 8 words contain 1 secret letter, but between every sentence you intentionally insert 1 random, meaningless filler word to throw off automated decoders. If an automated script reads continuously without accounting for that 1 filler word, all subsequent letters get desynchronized into complete gibberish!

DECOMPILATION ANALYSIS

1. Inspecting the `mystery` Binary

// Ghidra Decompilation: mystery (main)
int main(void) {
    FILE *orig_bmp = fopen("original.bmp", "r");
    FILE *enc_bmp  = fopen("encoded.bmp", "a");

    // 1. Copy first 723 bytes directly (Offset 0x2D3)
    for (int i = 0; i < 723; i++) {
        char b = fgetc(orig_bmp);
        fputc(b, enc_bmp);
    }

    char flag[50];
    fread(flag, 50, 1, flag_file);

    // 2. 100 iterations: Interleaving data with dummy filler bytes
    for (int j = 0; j < 100; j++) {
        if (j % 2 == 0) {
            // EVEN iterations (j = 0, 2, 4, ...): Encode 1 character into 8 LSB bytes
            char val = flag[j / 2];
            for (int bit = 0; bit < 8; bit++) {
                char orig_b = fgetc(orig_bmp);
                char enc_b  = codedChar(bit, val, orig_b);
                fputc(enc_b, enc_bmp);
            }
        } else {
            // ODD iterations (j = 1, 3, 5, ...): Write 1 unmodified dummy byte
            char orig_b = fgetc(orig_bmp);
            fputc(orig_b, enc_bmp);
        }
    }
}
METHOD A: STEP-BY-STEP MANUAL STRIDE DECODING

2. Manual Stride Decoding Table

Starting from offset 723 (Hex: 0x2D3), read 8 bytes for Character 0, skip the 9th byte (C5), and continue to Character 1 at offset 732 (0x2DC):

Character 0 ('p') at Offset 0x2D3:

PositionHex ByteEven or Odd?LSB BitWeightValue
Bit 0BCEven02⁰ = 10
Bit 1C1Odd12¹ = 22
Bit 2BCEven02² = 40
Bit 3BDOdd12³ = 88
Bit 4BCEven02⁴ = 160
Bit 5BDOdd12⁵ = 3232
Bit 6C1Odd12⁶ = 6464
Bit 7BCEven02⁷ = 1280
Byte 8 (Dummy)C5DUMMY[SKIP]

Calculation: 0 + 2 + 0 + 8 + 0 + 32 + 64 + 0 = 112 = 'p'.

METHOD B: AUTOMATED PYTHON PARSER & ONELINER

3. Automated Extraction Script (`solve.py`)

# Read the encoded BMP image
with open('encoded.bmp', 'rb') as f:
    data = f.read()

start_offset = 723  # Starting offset from binary decompilation
flag = []

# 50 characters, 9-byte stride (8 data bytes + 1 dummy byte)
for i in range(50):
    char_offset = start_offset + i * 9
    val = 0
    for bit in range(8):
        byte = data[char_offset + bit]
        lsb = byte & 1
        val |= (lsb << bit)
    flag.append(chr(val))

print("🎉 Decoded Flag:", ''.join(flag))
⚡ Terminal One-Liner (PowerShell / Bash):
python -c "d=open('encoded.bmp','rb').read(); print(''.join(chr(sum(((d[723+i*9+b]&1)<<b) for b in range(8))) for i in range(50)))"

4. Decoded Flag

Extracted Secret Flag:

picoCTF{4n0th3r_L5b_pr0bl3m_0000000000000743a2607}

5. The Complete Investigation Path & Mental Roadmap

Here is the step-by-step mental roadmap from binary decompilation to interleaved stride extraction:

STEP 1
Decompilation & Stride Detection

Opened mystery in Ghidra. Traced the 723-byte header copy loop and spotted the j % 2 == 0 modulo condition inserting 1 dummy byte every 8 data bytes.

STEP 2
Mathematical Stride Formula

Formulated the exact character starting offset: Offset(i) = 723 + (i * 9).

STEP 3
Bit Assembly & Dummy Skipping

Extracted 8 LSB bits per character without applying mathematical shifts and skipped the 9th filler byte.

STEP 4
Flag Capture

Submitted verified flag string: picoCTF{4n0th3r_L5b_pr0bl3m_0000000000000743a2607}.

Cyber Amber
#f59e0b
PresetsClick to lock