Description
Fix this corrupted PNG file and read the flag: c0rrupt.png.
Setup
Download the file and inspect it with pngcheck and a hex editor.
wget <url>/c0rrupt.pngpngcheck c0rrupt.pngxxd c0rrupt.png | head -4Solution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Identify corruption with pngcheck
ObservationThe file is described as corrupted. That calls for a structured validator that reports exactly which chunks and fields break the PNG specification, before touching any bytes by hand.Run pngcheck on the file to see which parts are corrupt. It will report errors such as bad magic bytes, invalid chunk signatures, incorrect chunk lengths, or failed CRC checks.bashpngcheck -v c0rrupt.pngExpected output
c0rrupt.png CRC error in chunk hIHD (computed 6efeef73, expected 51490945) ERROR: c0rrupt.png invalid chunk name "CgBI" (43 67 42 49) FATAL: c0rrupt.png is not a PNG image
What didn't work first
Tried: Open the file directly in an image viewer to see what is broken
Most image viewers either refuse a corrupted PNG or quietly show a blank or partial image, with no diagnostics. They will not tell you which bytes are wrong or which chunk failed. pngcheck reads the raw structure and names the exact offset and field for each violation, which is what targeted edits need.
Tried: Run 'file c0rrupt.png' to diagnose what is wrong with the file
The file command only reads the magic bytes to guess a type, so it happily reports 'PNG image data' even when every internal chunk is broken. It catches nothing about bad CRCs, invalid chunk names, or a corrupted IHDR. pngcheck does the full structural validation instead.
Learn more
A valid PNG file has a specific structure: 8 magic bytes at the start (
89 50 4E 47 0D 0A 1A 0A), followed by chunks. Each chunk has a 4-byte length, a 4-byte type name (like IHDR, IDAT, IEND), the data, and a 4-byte CRC32 checksum.pngcheck validates all of these fields and reports exactly where the file deviates from the PNG specification.
Step 2Fix the magic bytes
Observationpngcheck reports an invalid file type before it even reaches the chunks. That points at the first 8 bytes, which need overwriting with the canonical PNG magic number.Use a hex editor (ghex, hexedit, or bless) to open c0rrupt.png. Check bytes 0-7. If they do not match 89 50 4E 47 0D 0A 1A 0A, overwrite them with the correct values.bashhexedit c0rrupt.pngWhat didn't work first
Tried: Use 'strings c0rrupt.png' to find the correct magic bytes
strings only prints printable ASCII runs above a minimum length. The PNG magic bytes include non-printable control characters (0x89, 0x0D, 0x0A, 0x1A) that strings skips entirely. Use a hex editor such as hexedit or xxd to view and edit raw bytes at specific offsets.
Tried: Patch the magic bytes with sed or a text editor
Text editors and sed work in text mode and can silently alter or strip non-printable bytes on save. The PNG header contains bytes outside printable ASCII, so any text-mode tool will damage it. Use a binary-aware tool: hexedit, ghex, or a Python script opening the file with 'rb'.
Learn more
The PNG magic number is deliberately chosen to be hard to confuse with text files: byte 0x89 is non-ASCII, the next four bytes spell PNG in ASCII, and the remaining bytes include CR, LF, and SUB control characters that behave differently across text-mode file transfers - helping detect corruption.
Step 3Fix chunk signatures and CRCs
Observationpngcheck lists a CRC mismatch in the hIHD chunk alongside an invalid chunk name. So the chunk type bytes and their checksums were both tampered with, and both need correcting with zlib.crc32.After fixing the magic bytes, run pngcheck again. Fix any remaining chunk type name errors (e.g., a corrupted IHDR signature). Recompute and fix any CRC32 values using Python.pythonpython3 -c " import struct, zlib # To compute correct CRC for a chunk: # chunk_type = b'IHDR' # chunk_data = b'...' # chunk data bytes # crc = zlib.crc32(chunk_type + chunk_data) & 0xFFFFFFFF # print(hex(crc)) "What didn't work first
Tried: Compute the CRC with zlib.crc32(chunk_data) without including the chunk type bytes
The PNG spec computes each CRC over the chunk type and the chunk data joined together, not the data alone. Pass only the data to zlib.crc32 and you get a checksum pngcheck rejects. Use zlib.crc32(chunk_type + chunk_data), where chunk_type is the 4-byte name like b'IHDR'.
Tried: Skip fixing CRC values and just open the PNG, hoping the viewer ignores checksum errors
Lenient viewers like eog may render the image despite bad CRCs, but pngcheck still fails it and the file is technically invalid. More to the point, a wrong IHDR CRC makes some decoders reject the file outright before they read the dimensions. Fixing the CRCs is also how you confirm the chunk data is right: if the recomputed value matches nothing, the data is still corrupted.
Learn more
CRC32 (Cyclic Redundancy Check) is a hash function used to detect accidental changes. The PNG spec requires that each chunk's CRC be computed over the chunk type and data bytes combined. If the data is correct but the CRC is wrong, recomputing and overwriting fixes the error.
In Python,
zlib.crc32(data)computes the CRC32 value. Always AND with0xFFFFFFFFto get an unsigned 32-bit result, then pack withstruct.pack('>I', crc)for big-endian byte order.Step 4Open the repaired PNG
Observationpngcheck reports no errors once the magic bytes and CRCs are fixed. The structure is valid again, so the image will decode and display the flag.Once pngcheck reports no errors, open the file in an image viewer. The flag will be visible in the image.bashxdg-open c0rrupt.png
Interactive tools
- File Magic IdentifierIdentify file types from magic numbers. Paste hex bytes or drop a file to detect PNG, JPEG, ZIP, PDF, ELF, PCAP, SQLite, and dozens of other formats.
Flag
Reveal flag
picoCTF{c0rrupt10n_...}
Fix the PNG magic bytes and repair chunk CRC values with a hex editor to restore the image.