PICOCTF 2019 • REVERSE ENGINEERING • FILE OVERLAY CARVING

Investigative Reversing 0: Appended Byte Math & PNG Overlay Extraction

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

“We have recovered a binary and an image. See if you can figure out what it did to hide the flag.”

Category: Forensics / Reverse EngineeringPoints: 300 PTSFlag Format: picoCTF{...}
Provided Files (Download & Practice)
Dissector: Ghidra + HxD

💡 THE INTUITIVE ANALOGY (The Envelope Sticky Note)

Imagine you seal a letter inside an envelope (a valid PNG file). After sealing the envelope with wax (the IEND marker), you tape a sticky note onto the outside back of the envelope with a message where some letters are shifted by $+5$ in the alphabet. Standard mail scanning machines only look at the address on the front and ignore anything taped past the seal. To read the secret, we just look past the seal and shift the letters back!

DECOMPILATION ANALYSIS

1. Inspecting the `mystery` Binary

Opening the ELF binary in Ghidra reveals that it reads a 26-byte flag from flag.txt and writes it directly to mystery.png using append mode ("a"):

int main(void) {
    FILE *flag_file = fopen("flag.txt", "r");
    FILE *png_file  = fopen("mystery.png", "a"); // "a" = Append to end of file!

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

    // 1. First 6 characters written as-is: "picoCT"
    for (int i = 0; i < 6; i++) {
        fputc(flag[i], png_file);
    }

    // 2. Characters 6 to 14 have 5 added to their ASCII values
    for (int i = 6; i <= 14; i++) {
        fputc(flag[i] + 5, png_file);
    }

    // 3. Character 15 has 3 subtracted from its ASCII value
    fputc(flag[15] - 3, png_file);

    // 4. Remaining characters (indices 16..25) written as-is
    for (int i = 16; i <= 25; i++) {
        fputc(flag[i], png_file);
    }

    fclose(png_file);
    fclose(flag_file);
    return 0;
}
METHOD A: STEP-BY-STEP MANUAL CARVING

2. Manual Hex Extraction & Arithmetic Table

Open mystery.png in HxD or HexEd.it, scroll past the IEND marker (49 45 4E 44 AE 42 60 82), and inspect the 26 trailing bytes:

70 69 63 6F 43 54 4B 80 6B 35 7A 73 69 64 36 71 5F 33 35 66 36 39 64 61 62 7D

Character-by-Character Reverse Mathematics:

IndexEncoded ByteASCII DecimalOperationDecoded DecimalDecoded Char
070 ('p')112Unchanged112p
169 ('i')105Unchanged105i
263 ('c')99Unchanged99c
36F ('o')111Unchanged111o
443 ('C')67Unchanged67C
554 ('T')84Unchanged84T
64B ('K')75- 570F
780128- 5123{
86B ('k')107- 5102f
935 ('5')53- 5480
107A ('z')122- 5117u
1173 ('s')115- 5110n
1269 ('i')105- 5100d
1364 ('d')100- 595_
1436 ('6')54- 5491
1571 ('q')113+ 3116t
16..25_35f69dab}Unchanged_35f69dab}
METHOD B: AUTOMATED PYTHON PARSER & ONELINER

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

# Open mystery.png and read the raw trailing bytes
with open('mystery.png', 'rb') as f:
    data = f.read()

# Grab last 26 bytes appended past the PNG IEND marker
encoded = data[-26:]

# Reconstruct flag using inverse mathematics
flag = (
    ''.join(chr(encoded[i]) for i in range(6)) +          # Unchanged: "picoCT"
    ''.join(chr(encoded[i] - 5) for i in range(6, 15)) +   # Subtract 5
    chr(encoded[15] + 3) +                                 # Add 3
    ''.join(chr(encoded[i]) for i in range(16, 26))        # Unchanged: "_35f69dab}"
)

print("🎉 Decoded Flag:", flag)
⚡ Terminal One-Liner (PowerShell / Bash):
python -c "d=open('mystery.png','rb').read()[-26:]; print(''.join(chr(d[i]) for i in range(6)) + ''.join(chr(d[i]-5) for i in range(6,15)) + chr(d[15]+3) + ''.join(chr(d[i]) for i in range(16,26)))"

4. Decoded Flag

Extracted Secret Flag:

picoCTF{f0und_1t_35f69dab}

5. Forensic Key Takeaways

ConceptIndicatorReversing Strategy
Append Mode ("a")fopen(..., "a")Check for bytes after PNG IEND terminator (49 45 4E 44 AE 42 60 82).
Shift Encodingflag[i] + 5Apply exact inverse mathematical operation (subtract 5).

6. The Complete Investigation Path & Mental Roadmap

Here is the step-by-step mental roadmap from binary decompilation to flag recovery:

STEP 1
Decompiling the Binary

Loaded mystery in Ghidra. Located main() and identified fopen(..., "a") writing 26 bytes to the end of mystery.png.

STEP 2
Carving Trailing Bytes

Opened mystery.png in HxD, navigated past the IEND marker, and extracted the raw 26 bytes.

STEP 3
Applying Inverse Arithmetic

Subtracted 5 from characters 6..14, added 3 to character 15, and preserved the remaining characters unchanged.

STEP 4
Flag Capture

Constructed and verified the final flag: picoCTF{f0und_1t_35f69dab}.

Cyber Amber
#f59e0b
PresetsClick to lock