← Back to Writeups
CUSTOMEasySteganography

Sherlock

XESXOR9/2/20262 min read
#steganography#custom#easy#binary-to-ascii-conversion#lsb-(least-significant-bit)-ex#linux

Sherlock

Platform: hackerlab | Category: Steganography | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2025-12-22 | Status: Solved Techniques: Binary to ASCII conversion, LSB (Least Significant Bit) extraction from RGB channels

Summary

Task: PNG image with hint about 'persistent effort'. Solution: LSB steganography extraction from RGB channels using Python/PIL or zsteg tool.

Sherlock — hackerlab.pro

Description

Говорят, гений – это прежде всего способность неустанно прилагать усилия

File: sherlock.png (PNG image, 816x490, RGB)

Analysis

  1. Metadata check — exiftool showed nothing interesting
  2. String search — strings didn't find the flag in plaintext
  3. Visual analysis — image looks normal, no visible artifacts
  4. Task description — hint about "persistent effort" = need to try different steganography methods

Classic LSB steganography is the first thing to check for PNG images. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

Method: LSB (Least Significant Bit) Steganography

LSB steganography hides data in the least significant bits of each color channel. Changing the least significant bit is practically invisible to the eye (changes brightness by 1/256).

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

img = Image.open('sherlock.png')
pixels = np.array(img)

# Extract LSB from each RGB channel
lsb_r = pixels[:,:,0] & 1  # Red channel LSB
lsb_g = pixels[:,:,1] & 1  # Green channel LSB
lsb_b = pixels[:,:,2] & 1  # Blue channel LSB
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Collect bits from all pixels (row by row, RGB order)
bits = []
for y in range(pixels.shape[0]):
    for x in range(pixels.shape[1]):
        bits.append(str(lsb_r[y,x]))
        bits.append(str(lsb_g[y,x]))
        bits.append(str(lsb_b[y,x]))

# Convert bits to bytes (8 bits = 1 character)
bitstring = ''.join(bits[:8000])  # First 8000 bits should be enough
chars = []
for i in range(0, len(bitstring), 8):
    byte = bitstring[i:i+8]
    if len(byte) == 8:
        chars.append(chr(int(byte, 2)))
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

result = ''.join(chars)
print(result)

Alternative method: zsteg

bash
# Automatic LSB analysis
zsteg sherlock.png

# Or specifically RGB LSB
zsteg -e 'b1,rgb,lsb,xy' sherlock.png

Theory: LSB Steganography

How it works

  1. Each RGB pixel has 3 channels of 8 bits each (0-255)
  2. The least significant bit (LSB) of each channel is replaced with a bit of the secret message
  3. Changing 0→1 or 1→0 changes the channel value by ±1 (imperceptible)
  4. 1 pixel = 3 bits of data (R, G, B)
  5. 8 pixels = 24 bits = 3 bytes = 3 characters ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Extraction order

Standard order: row-by-row, left-to-right, RGB order

  • Pixel(0,0): R_lsb, G_lsb, B_lsb
  • Pixel(1,0): R_lsb, G_lsb, B_lsb
  • ...

Tools for LSB

ToolCommand
zstegzsteg image.png
stegsolveGUI tool
Python/PILManual extraction
steghidesteghide extract -sf image.png

Notes

  • The flag contains a leet speak hint: "don't forget to check the lsb"
  • The task description ("persistent effort") hinted at the need to try different methods
  • LSB is the first method to check in PNG steganography ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍