← Back to Writeups
CUSTOMMediumSteganography

Pixels Secret

XESXOR9/2/20265 min read
#steganography#custom#medium#pixel-color-filtering-for-anom#x-coordinate-to-ascii-characte#y-coordinate-based-character-o

Pixels Secret

Platform: hackerlab | Category: Steganography | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2025-12-22 | Status: Solved Techniques: Pixel color filtering for anomaly detection, X-coordinate to ASCII character mapping, Y-coordinate based character ordering

Summary

Task: Image with dark background containing hidden dust pixels. Solution: X-coordinates of anomalous pixels encode ASCII characters, Y-coordinates determine character order.

Pixels Secret - hackerlab.pro

Description

На цифровых фотографиях тоже иногда оседает "пыль" (On digital photos, "dust" sometimes settles too)

File: pixels_secret.zip contains pixels_secret.jpg

Analysis

1. Image Investigation

Unpack the archive and analyze the image:

  • Size: 4300x1800 pixels
  • Format: JPEG
  • Metadata indicates creation in GIMP

The image has an almost completely black background with RGB ≈ (1, 2, 4).

2. Hint Interpretation

The hint about "dust" on digital photos suggests looking for individual pixels that differ from the main background - like dust particles on a dark surface. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

3. Finding Anomalous Pixels

Analysis showed that in the first 11 rows of the image (Y from 0 to 10) there are "dust particles" - pixels with a characteristic pattern:

  • R ≤ 10
  • G ≤ 10
  • 20 ≤ B ≤ 30

These pixels stand out against the dark background due to a higher blue channel value.

4. Decoding

Key observation: The X-coordinate of each "dust" pixel corresponds to an ASCII character code.

When sorting pixels by Y-coordinate (then by X), the X-values decode to flag characters:

YX-coordinatesCharacters
067, 79C, O
168, 69D, E
266, 89, 123B, Y, {
399, 104c, h
451, 99, 1073, c, k
595, 116_, t
6104h
7101e
895, 112_, p
949, 1201, x
1051, 108, 115, 1253, l, s, }
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Solution

python
#!/usr/bin/env python3
"""
Pixels Secret - Coordinate-based steganography solver
Flag is encoded in X-coordinates of "dust" pixels
"""

from PIL import Image
import numpy as np

def solve_pixels_secret(image_path):
    img = Image.open(image_path)
    arr = np.array(img)
    
    print(f"Image size: {img.size}")
    print(f"Array shape: {arr.shape}")
    
    # Find dust pixels with specific RGB pattern in first 20 rows
    dust_pixels = []
    for y in range(20):  # Dust is in first 11 rows, check 20 for safety
        for x in range(arr.shape[1]):
            r, g, b = int(arr[y, x, 0]), int(arr[y, x, 1]), int(arr[y, x, 2])
            # Dust pixels have low R, low G, but elevated B (20-30)
            if r <= 10 and g <= 10 and b >= 20 and b <= 30:
                dust_pixels.append((x, y, (r, g, b)))
    
    print(f"\nFound {len(dust_pixels)} dust pixels")
    
    # Sort by Y coordinate (row), then by X coordinate
    dust_pixels.sort(key=lambda p: (p[1], p[0]))
    
    # Print pixel details
    print("\nDust pixels (sorted by Y, then X):")
    for x, y, rgb in dust_pixels:
        char = chr(x) if 32 <= x < 127 else '?'
        print(f"  Y={y:2d}, X={x:3d} -> '{char}' (RGB: {rgb})")
    
    # Decode: X coordinate = ASCII code
    flag = ''.join([chr(x) for x, y, rgb in dust_pixels if 32 <= x < 127])
    
    print(f"\n{'='*50}")
    print(f"FLAG: {flag}")
    print(f"{'='*50}")
    
    return flag
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

if __name__ == "__main__":
    solve_pixels_secret("pixels_secret.jpg")

Script Output

Image size: (4300, 1800)
Array shape: (1800, 4300, 3)

Found 22 dust pixels

Dust pixels (sorted by Y, then X):
  Y= 0, X= 67 -> 'C' (RGB: (1, 2, 25))
  Y= 0, X= 79 -> 'O' (RGB: (1, 2, 25))
  Y= 1, X= 68 -> 'D' (RGB: (1, 2, 25))
  Y= 1, X= 69 -> 'E' (RGB: (1, 2, 25))
  Y= 2, X= 66 -> 'B' (RGB: (1, 2, 25))
  Y= 2, X= 89 -> 'Y' (RGB: (1, 2, 25))
  Y= 2, X=123 -> '{' (RGB: (1, 2, 25))
  Y= 3, X= 99 -> 'c' (RGB: (1, 2, 25))
  Y= 3, X=104 -> 'h' (RGB: (1, 2, 25))
  Y= 4, X= 51 -> '3' (RGB: (1, 2, 25))
  Y= 4, X= 99 -> 'c' (RGB: (1, 2, 25))
  Y= 4, X=107 -> 'k' (RGB: (1, 2, 25))
  Y= 5, X= 95 -> '_' (RGB: (1, 2, 25))
  Y= 5, X=116 -> 't' (RGB: (1, 2, 25))
  Y= 6, X=104 -> 'h' (RGB: (1, 2, 25))
  Y= 7, X=101 -> 'e' (RGB: (1, 2, 25))
  Y= 8, X= 95 -> '_' (RGB: (1, 2, 25))
  Y= 8, X=112 -> 'p' (RGB: (1, 2, 25))
  Y= 9, X= 49 -> '1' (RGB: (1, 2, 25))
  Y= 9, X=120 -> 'x' (RGB: (1, 2, 25))
  Y=10, X= 51 -> '3' (RGB: (1, 2, 25))
  Y=10, X=108 -> 'l' (RGB: (1, 2, 25))
  Y=10, X=115 -> 's' (RGB: (1, 2, 25))
  Y=10, X=125 -> '}' (RGB: (1, 2, 25))
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

==================================================
FLAG: CODEBY{REDACTED}
==================================================

Alternative Approaches

  1. Visual analysis: Increasing image contrast can make "dust particles" visible
  2. Histogram: Analyzing color distribution will show anomalous values
  3. Channel filtering: Separate analysis of R, G, B channels

Lessons

The challenge demonstrates an interesting coordinate-based steganography technique where information is encoded not in pixel color, but in pixel position. The X-coordinate determines the ASCII character code, and the Y-coordinate determines the order of characters in the message. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍