Getting Started

So when getting started the first thing I did was look that the file in a hex editor. I used HxD on Windows but you could have used xxd like I show below.


$ xxd pic.png2 | head -5


00000000: 504e 4732 7769 6474 683d 05cf 6865 6967  PNG2width=..heig
00000010: 6874 3d02 887f 7f7f 7f7f 7f7f 7f7f 7f7f  ht=.............
00000020: 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f  ................
00000030: 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f  ................
00000040: 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f  ................


So from this we can interpret that the two bytes after the width and the two bytes after the height are a 16 bit integer containing the width and height of the image in pixels. The bigest question is if those bytes are stored little-endian or big-endian. So lets take the width 0x05CF and height 0x0288 and convert them to decimal integers.


Big Endian:0x05CF = 1487 Little Endian:0xCF05 = 52997


Big Endian:0x0288 = 648 Little Endian:0x8802 = 34818

I then used those sizes to calculate the number of pixels in the image from which we could guess the size - the header size.

The Big Endian Size 1487*34943=963576 which when multiplied by the 3 bytes per color results in a size of 2890728 when the actual file size is 2890749. From this even without doing the little endian math we can guess that these sizes were stored in big endian.

So now that we know how to get the size of the image we can guess the formatting of the pixels. The hint on the challenge was that the first pixel was #7F7F7F. From that I guessed that this was going to be a 1 byte per color RGB image meaning 3 bytes per pixel. The only thing left was to figure out the pixel storage order.

I just sort of brute forced my way through the pixel storage order by accidentally doing the math wrong and doing column by column first which lead to a interesting but incorrect image. Then I tried the logical row from left to right pixel layout and was able to successfuly convert the png2 into a bitmap image that I then saved.


I have written alot of code for past employers in C# working with images so I was the most familiar with its image api. I used a dotnet core plugin called dotnet-script to be able to run c# code as scripts. The following is what I was able to come up with that lead to the fist solve of the challenge.

#!/usr/bin/env dotnet-script

#r "nuget:System.Drawing.Common,4.7.0"

// Read the whole image into ram. This is a waste of memory but compared to chrome who cares...
byte[] data = System.IO.File.ReadAllBytes("pic.png2");

// Calculate the width and height of the image.
int width = (data[0x0A] << 8) + (data[0x0B]);
int height = (data[0x13] << 8) + (data[0x14]);

Console.WriteLine($"Image Size: w{width}*h{height}={width*height}pixels");

// Setup a blank image to write our pixels to with the height and width we found above.
System.Drawing.Bitmap output = new System.Drawing.Bitmap(width, height);

// This is the postition of the first byte of pixel data in the image.
int i = 0x15;

Console.WriteLine($"NUM PIXELS: {((data.Length - i) * 1.0) / 3}");

try {
  // Loop through the file reading bytes 3 at a time.
  while (i < width * height * 3) {
    // Retrieve the red, green, and blue values from the file.
    byte r = data[i];
    byte g = data[i+1];
    byte b = data[i+2];

    // Calculate which pixel we are talking about.
    // There is probably a better way to do this but it works...
    int x = (i / 3) % width;
    int y = (i / 3) / width;

    // .net's image api requires you to create a color before drawing it.
    System.Drawing.Color c = System.Drawing.Color.FromArgb(0xFF, r, g, b);

    // Set the pixel at x,y to the color.
    output.SetPixel(x, y, c);

    // Increment our position in the file.
    i += 3;
catch (Exception ex) {

Console.WriteLine("Saving Image");

// Save the output




Thank you to the UTCTF admins who despite some server issues put on a very fun CTF.