← Back to Writeups
CUSTOMEasySteganography

496 отличий (496 differences)

XESXOR9/2/20263 min read
#steganography#custom#easy#image_difference_decoding#green_channel_lsb_extraction#zsteg_bitplane_identification#overlooked_asset_favicon#linux

496 отличий (496 differences)

Platform: bug-makers | Category: Steganography | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-01-01 | Status: Solved Techniques: image_difference_decoding, green_channel_lsb_extraction, zsteg_bitplane_identification, overlooked_asset_favicon

Summary

Task: a 'spot the 496 differences' web page with two near-identical anime images and a favicon; the flag is hidden in an image. Solution: the pixel diff decodes to a decoy hint message; the real flag is green-channel LSB steganography in the overlooked favicon.png, found with zsteg (b1,g,lsb,xy).

496 отличий (496 differences) — bug-makers (БАГодельня 2026)

Description

Найдите 496 отличий. Флаг внутри картинки. (Find 496 differences. The flag is inside the picture.)

A "spot the differences" web page at https://496-differences.t1.bug-makers.ru shows two visually identical anime-style images side by side: /images/pixie-1.png and /images/pixie-2.png (both 1024×1365 8-bit RGB PNG). The page also references /images/favicon.png (100×100 RGB PNG). The girl wears a "BugCTF" cap and a ladybug ("bug") necklace. Goal: recover the BugCTF{...} flag. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Analysis

The number 496 is the key structural hint: 496 = 62 × 8, i.e. 62 ASCII characters at 8 bits per character.

Diffing the two main images pixel-by-pixel reveals exactly 496 differing pixels, all located on the last row (y=1364) at even x positions 0, 2, 4, …, 990 (496 positions). In pixie-2.png those pixels are set to pure black (0,0,0) or pure white (255,255,255); everything else is byte-identical between the two images.

Mapping white=1, black=0, MSB-first, 8 bits/char decodes the full 496 bits to: ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Great! All differences have been found, and now find the flag.

This is exactly 62 bytes and consumes the entire diff — but it is only a decoy / hint, NOT the flag.

Exhaustive analysis of pixie-1/pixie-2 (single- and multi-channel LSB, 2-bit LSB, reversed bit order, all 8 bit-planes, row/column order, PNG chunks, trailing data, filter bytes, high-pass visual enhancement, exiftool, binwalk, strings) found nothing else — they are clean AI-generated images apart from the painted hint row. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

The hint "the flag is inside the picture" points at the overlooked third image: the favicon. Running zsteg -a favicon.png flagged the channel b1,g,lsb,xy (1-bit, green channel, LSB, row-major xy order).

Solution

Stage 1 — Decode the decoy hint from the image diff

python
#!/usr/bin/env python3
from PIL import Image
import numpy as np

a = np.array(Image.open('pixie-1.png').convert('RGB'))
b = np.array(Image.open('pixie-2.png').convert('RGB'))

row = 1364
xs = [x for x in range(1024) if (a[row, x] != b[row, x]).any()]   # 0,2,...,990 (496)
bits = ''.join('1' if (b[row, x] == 255).all() else '0' for x in xs)
msg = ''.join(chr(int(bits[i:i+8], 2)) for i in range(0, len(bits), 8))
print(msg)
# -> Great! All differences have been found, and now find the flag.

‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Stage 2 — Extract the real flag from the favicon (green-channel LSB)

python
#!/usr/bin/env python3
from PIL import Image
import numpy as np

a = np.array(Image.open('favicon.png').convert('RGB'))
ch = a[:, :, 1].flatten() & 1                 # green channel LSB, row-major
bs = np.packbits(ch.astype('uint8')).tobytes()  # MSB-first packing
print(bs.split(b'\x00')[0].decode())
# -> BugCTF{REDACTED}

zsteg setup and confirmation:

bash
gem install --user-install zsteg
~/.gem/ruby/2.6.0/bin/zsteg -a favicon.png   # flags channel b1,g,lsb,xy

‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

The flag text _tREDACTED self-confirms the result and explicitly contrasts with the decoy hint. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍