miscfreeeasy

Dust to Dust

dawgctf

Task: a C encoder compresses a binary image by packing each 2x3 pixel block into one printable ASCII byte, with `}` as row separators and `~` as EOF. Solution: subtract `0x20`, expand every byte back to 6 bits, rebuild paired bitmap rows, and render the recovered image to read the handwritten flag.

$ ls tags/ techniques/
reverse_custom_encodingsix_bit_unpackingbitmap_reconstruction_from_packed_textsource_guided_decoder_reimplementation

Dust to Dust — DawgCTF SP26

Description

File: chal.zip

The repository entry only exposes the archive, so the practical challenge is to reverse the included encoder and decode output.txt. The recovered data is not normal plaintext: it is a packed monochrome bitmap that must be reconstructed into an image before the flag becomes readable.

Summary

encoder.c shows that the challenge takes a binary image, packs every 2x3 pixel block into one printable ASCII character, separates compressed rows with }, and terminates the stream with ~. Reversing that packing reconstructs the original bitmap, and rendering it reveals a handwritten DawgCTF flag.

Analysis

1. Read the encoder instead of guessing the format

The key artifact is encoder.c. Its input validation immediately tells us what the original data looked like:

  • input.txt must contain only 0 and 1
  • every row length must be a multiple of 3
  • all rows must have equal length
  • the number of rows must be a multiple of 2

That is a strong sign that the encoder is treating the file as a binary image or bitmap, not as text.

2. Understand the 2x3 packing rule

Inside compressArray, the encoder reads pixels in this order:

buffer[0] = arr[l*2][w*3]; buffer[1] = arr[l*2][w*3 + 1]; buffer[2] = arr[l*2][w*3 + 2]; buffer[3] = arr[l*2 + 1][w*3]; buffer[4] = arr[l*2 + 1][w*3 + 1]; buffer[5] = arr[l*2 + 1][w*3 + 2];

So each encoded character represents a 2-row by 3-column block:

top row: b0 b1 b2 bottom row: b3 b4 b5

The six bits are parsed as a binary integer and shifted into the printable ASCII range:

long bin = strtol(buffer, NULL, 2); c = (char)(0b00100000 + bin);

So the mapping is:

...

🔒

Permission denied (requires auth)

Sign in to read this free writeup

This writeup is free — just sign in with GitHub to read it.

$ssh [email protected]