PICOCTF 2019 • REVERSE ENGINEERING • FILE OVERLAY CARVING

Investigative Reversing 0: Appended Byte Math & PNG Overlay Extraction

By Abdo•Aug 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 Engineering● Points: 300 PTS● Flag Format: picoCTF{...}
Provided Files (Download & Practice)
Dissector: Ghidra + HxD

Forensic Analysis: Trailing Overlay Injection

Standard image parsers terminate processing once the IEND trailer chunk (49 45 4E 44 AE 42 60 82) is reached, ignoring any data appended past that marker. The compiled mystery binary reads flag.txt, applies an arithmetic shift (+5) to byte indices 6 through 15, and appends the transformed stream to the end of mystery.png as an unparsed trailing overlay.

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}.