Average: 3.60
Rating Count: 5
You Rated: Not rated
Points
121
Solves
24
Category
ForensicDescription
p1ng is ASIS hand-drawn PNG.
http://asis-ctf.ir/tasks/p1ng.txz_76eca77720a65d95557a3850929abd0a8a18c636
We have a png file inspecting with binwalk we can see this strange compressed data:
kinyabitch@Debian ~/h/c/a/f/p1ng> binwalk p1ng/p1ng DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 PNG image, 180 x 76, 8-bit/color RGBA, non-interlaced 99 0x63 Zlib compressed data, best compression 4987 0x137B Zlib compressed data, best compression 9484 0x250C Zlib compressed data, best compression 17713 0x4531 Zlib compressed data, best compression 22512 0x57F0 Zlib compressed data, best compression 29380 0x72C4 Zlib compressed data, best compression 36947 0x9053 Zlib compressed data, best compression 43723 0xAACB Zlib compressed data, best compression 51878 0xCAA6 Zlib compressed data, best compression 58000 0xE290 Zlib compressed data, best compression 65549 0x1000D Zlib compressed data, best compression 72231 0x11A27 Zlib compressed data, best compression 79133 0x1351D Zlib compressed data, best compression 85159 0x14CA7 Zlib compressed data, best compression 92012 0x1676C Zlib compressed data, best compression 98842 0x1821A Zlib compressed data, best compression 105524 0x19C34 Zlib compressed data, best compression 113043 0x1B993 Zlib compressed data, best compression 119801 0x1D3F9 Zlib compressed data, best compression 127259 0x1F11B Zlib compressed data, best compression 134259 0x20C73 Zlib compressed data, best compression 139926 0x22296 Zlib compressed data, best compression 146983 0x23E27 Zlib compressed data, best compressionif we inspect with a hex editor or even easier using pngsplit to split the png chunks we can find some unusual type chunks like fdAT, fcTL and acTL:
kinyabitch@Debian ~/h/c/a/f/p1ng> ls p1ng/qwe/ p1ng.0000.sig p1ng.0004.IDAT p1ng.0008.fdAT p1ng.0012.fdAT p1ng.0016.fdAT p1ng.0020.fdAT p1ng.0024.fdAT p1ng.0028.fdAT p1ng.0032.fdAT p1ng.0036.fdAT p1ng.0040.fdAT p1ng.0044.fdAT p1ng.0048.fdAT p1ng.0001.IHDR p1ng.0005.fcTL p1ng.0009.fcTL p1ng.0013.fcTL p1ng.0017.fcTL p1ng.0021.fcTL p1ng.0025.fcTL p1ng.0029.fcTL p1ng.0033.fcTL p1ng.0037.fcTL p1ng.0041.fcTL p1ng.0045.fcTL p1ng.0049.IEND p1ng.0002.acTL p1ng.0006.fdAT p1ng.0010.fdAT p1ng.0014.fdAT p1ng.0018.fdAT p1ng.0022.fdAT p1ng.0026.fdAT p1ng.0030.fdAT p1ng.0034.fdAT p1ng.0038.fdAT p1ng.0042.fdAT p1ng.0046.fdAT p1ng.0003.fcTL p1ng.0007.fcTL p1ng.0011.fcTL p1ng.0015.fcTL p1ng.0019.fcTL p1ng.0023.fcTL p1ng.0027.fcTL p1ng.0031.fcTL p1ng.0035.fcTL p1ng.0039.fcTL p1ng.0043.fcTL p1ng.0047.fcTLAfter some search on google I found this links https://wiki.mozilla.org/APNG_Specification and http://fileformats.wikia.com/wiki/Animated_Portable_Network_Graphics , this is a APNG it’s a png but animated! So our job here is to split the animation images and then maybe we can find the flag. There is a lot of tools online to do this but for the curiosity I managed to write one in python, some images were broken I needed to do some adjustments to the IDHR header to fix it:
import os import sys import struct import binascii directory = "outp/" signature = "" ihdr_header = "" fdat_chunk = "" idat_chunk = "" iend_chunk = "" ihdrs = [] parts = [] PNG_SIGN = b"\x89\x50\x4E\x47\x0D\x0A\x1A\x0A" def is_png(png): """Test if @png is valid png file by checking signature @png can be str of the filename, a file-like object, or a bytes object. """ if isinstance(png, str): with open(png, "rb") as f: png = f.read(8) if hasattr(png, "read"): png = png.read(8) return png[:8] == PNG_SIGN def chunks(png): """Yield chunks from png. @png can be a string of filename, a file-like object, or a bytes bject. """ if not is_png(png): # convert to png if isinstance(png, bytes): with io.BytesIO(png) as f: with io.BytesIO() as f2: PIL.Image.open(f).save(f2, "PNG", optimize=True) png = f2.getvalue() else: with io.BytesIO() as f2: PIL.Image.open(png).save(f2, "PNG", optimize=True) png = f2.getvalue() if isinstance(png, str): # file name with open(png, "rb") as f: png = f.read() if hasattr(png, "read"): # file like png = png.read() return chunks_read(png) def make_chunk(type, data): """Create chunk with @type and chunk data @data. It will calculate length and crc for you. Return bytes. @type is str and @data is bytes. """ out = struct.pack("!I", len(data)) data = type.encode("latin-1") + data a = '%08x' % (binascii.crc32(data) % (1<<32)) out += data + a.decode('hex') return out def chunks_read(b): """Parse PNG bytes into different chunks, yielding (type, data). @type is a string of chunk type. @data is the bytes of the chunk. Including length, type, data, and crc. """ # skip signature i = 8 # yield chunks while i < len(b): data_len, = struct.unpack("!I", b[i:i + 4]) type = b[i + 4:i + 8].decode("latin-1") yield type, b[i:i + data_len + 12] i += data_len + 12 # 6 if __name__ == '__main__': i = 0 t = 0 frame_chunks = [] frames = [] for ctype, data in list(chunks('p1ng/p1ng')): if ctype == "IHDR": ihdr_header = data hdr = ihdr_header elif ctype == "acTL": # ignore Animation Control Chunk continue elif ctype == "fcTL": # https://wiki.mozilla.org/APNG_Specification#.60fcTL.60:_The_Frame_Control_Chunk """ """ c = struct.unpack("!IIIIHHbb", data[12:-4]) width = 180 height = 76 if i in [11,12,13,2,9]: width = c[0] height = c[1] if i in [7,13,21,22]: width -= 1 #height = c[1] if i == 6: width -= 2 print c ihdr = make_chunk("IHDR", struct.pack("!II", width + c[2], height+ c[3]) + hdr[16:-4]) ihdrs.append(ihdr) #i += 1 elif ctype == "IDAT": parts.append(("IDAT", data)) i += 1 elif ctype == "fdAT": # https://wiki.mozilla.org/APNG_Specification#.60fdAT.60:_The_Frame_Data_Chunk parts.append(("IDAT", make_chunk("IDAT", data[12:-4]))) i += 1 elif ctype == "IEND": iend_chunk= data break if not os.path.exists(directory): os.makedirs(directory) for i in range(len(parts)): #parts[i] = PNG_SIGN + parts[0] + pallets[i] + parts[i] + parts[-1] f = open(directory + 'p1ng%d.png' % i, 'w+') if i == 0: ihdrs[i] = ihdr_header f.write(PNG_SIGN + ihdrs[i] + parts[i][1] + iend_chunk) f.close()After running the script you can get 22 imgs splited into a directory, after joining them you can construct the flag:
ASIS{As_l0n9_4s_CTF_3x1sts_th3r3_w1ll_b3_ASIS_4nd_4s_l0n9_4s_ASIS_3x1sts_th3r3_w1ll_b3_PNG!}