Investigative Reversing 0: Appended Byte Math & PNG Overlay Extraction

“We have recovered a binary and an image. See if you can figure out what it did to hide the flag.”
picoCTF{...}💡 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!
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;
}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:
Character-by-Character Reverse Mathematics:
| Index | Encoded Byte | ASCII Decimal | Operation | Decoded Decimal | Decoded Char |
|---|---|---|---|---|---|
| 0 | 70 ('p') | 112 | Unchanged | 112 | p |
| 1 | 69 ('i') | 105 | Unchanged | 105 | i |
| 2 | 63 ('c') | 99 | Unchanged | 99 | c |
| 3 | 6F ('o') | 111 | Unchanged | 111 | o |
| 4 | 43 ('C') | 67 | Unchanged | 67 | C |
| 5 | 54 ('T') | 84 | Unchanged | 84 | T |
| 6 | 4B ('K') | 75 | - 5 | 70 | F |
| 7 | 80 | 128 | - 5 | 123 | { |
| 8 | 6B ('k') | 107 | - 5 | 102 | f |
| 9 | 35 ('5') | 53 | - 5 | 48 | 0 |
| 10 | 7A ('z') | 122 | - 5 | 117 | u |
| 11 | 73 ('s') | 115 | - 5 | 110 | n |
| 12 | 69 ('i') | 105 | - 5 | 100 | d |
| 13 | 64 ('d') | 100 | - 5 | 95 | _ |
| 14 | 36 ('6') | 54 | - 5 | 49 | 1 |
| 15 | 71 ('q') | 113 | + 3 | 116 | t |
| 16..25 | _35f69dab} | — | Unchanged | — | _35f69dab} |
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)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:
5. Forensic Key Takeaways
| Concept | Indicator | Reversing Strategy |
|---|---|---|
| Append Mode ("a") | fopen(..., "a") | Check for bytes after PNG IEND terminator (49 45 4E 44 AE 42 60 82). |
| Shift Encoding | flag[i] + 5 | Apply 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:
Loaded mystery in Ghidra. Located main() and identified fopen(..., "a") writing 26 bytes to the end of mystery.png.
Opened mystery.png in HxD, navigated past the IEND marker, and extracted the raw 26 bytes.
Subtracted 5 from characters 6..14, added 3 to character 15, and preserved the remaining characters unchanged.
Constructed and verified the final flag: picoCTF{f0und_1t_35f69dab}.