← Back to Writeups
CUSTOMMediumSteganography

Admin Vibes

XESXOR9/2/20264 min read
#steganography#custom#medium#hidden_data_extraction#lsb_steganography#reversed_bit_order#wav_structure_analysis

Admin Vibes

Platform: grodno_new_year_2026 | Category: Steganography | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2026-01-10 | Status: Solved Techniques: hidden_data_extraction, lsb_steganography, reversed_bit_order, wav_structure_analysis

Summary

Task: WAV file with hidden PNG containing LSB steganography. Solution: Extract PNG from after audio data, then extract flag from Blue channel LSB with reversed bit order.

Admin Vibes - Grodno New Year 2026

Description

Author: @vvanuss

"Я всегда пытаюсь сохранять адекватность во время создания тасок. Так ведь?" "I always try to be serious while creating tasks. Right?"

Files: Danika_House.wav (63 MB, 6 minutes duration)

Analysis

Step 1: WAV File Analysis

Initial analysis of the WAV file:

  • Metadata: Artist: "unhealthy zoglin", Title: "Danika House"
  • Standard spectrogram analysis - regular music, no hidden text visible
  • LSB audio steganography check - negative (random distribution ~50% ones) ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Step 2: Hidden PNG Discovery

When analyzing the WAV file structure, additional data was found after the "data" chunk:

  • 178,622 bytes of extra data after the audio ends
  • Found custom header "PNG0" + size (178614) + PNG signature
  • Extracted PNG image (648x705 pixels) - meme with Dmitry Nagiev and text "КУПАТЫ"
python
import wave
import struct

with open('Danika_House.wav', 'rb') as f:
    data = f.read()

# Find end of audio data and start of hidden data
# Look for PNG signature after "data" chunk
png_sig = b'\x89PNG\r\n\x1a\n'
pos = data.find(png_sig)
if pos != -1:
    # Before PNG there's a header "PNG0" + 4 bytes size
    header_pos = pos - 8
    custom_header = data[header_pos:pos]
    print(f"Custom header: {custom_header}")  # b'PNG0' + size
    
    # Extract PNG
    png_data = data[pos:]
    with open('hidden.png', 'wb') as out:
        out.write(png_data[:178614])

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

Step 3: Image Analysis

Standard steganography methods yielded no results:

  • LSB extraction from RGB channels - flag not found
  • Bit plane analysis - looks like noise
  • XOR between channels - unreadable text
  • MSB extraction - negative

Step 4: Key Discovery

The problem was in the bit order when converting to bytes!

Standard order: bit[0] → position 0, bit[1] → position 1... Used order: bit[0] → position 7, bit[1] → position 6... (reversed)

The flag was hidden only in the Blue channel with reversed bit order. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Solution

python
#!/usr/bin/env python3
"""
Admin Vibes - Grodno New Year 2026 CTF
Multi-layer steganography: WAV -> hidden PNG -> LSB with reversed bit order
"""

from PIL import Image
import numpy as np

# Step 1: Extract hidden PNG from WAV (done separately)
# The PNG is hidden after the audio data with custom "PNG0" header

# Step 2: Extract flag from PNG using LSB with reversed bit order
img = Image.open('hidden.png')
pixels = np.array(img)

# Extract LSB from Blue channel only (index 2)
bits = []
for row in pixels:
    for pixel in row:
        bits.append(pixel[2] & 1)  # Blue channel
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

# Convert bits to bytes with REVERSED bit order
# This is the key trick - instead of standard LSB order,
# bits are placed in reverse: bit[0] -> position 7, bit[1] -> position 6, etc.
bytes_data = []
for i in range(0, len(bits) - 7, 8):
    byte = 0
    for j in range(8):
        byte |= bits[i + j] << (7 - j)  # Key: reverse bit order!
    bytes_data.append(byte)

result = bytes(bytes_data)

# Find and print the flag
flag_start = result.find(b'grodno{')
if flag_start != -1:
    flag_end = result.find(b'}', flag_start) + 1
    print(result[flag_start:flag_end].decode())
else:
    print(result[:100])

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

Full PNG Extraction Script from WAV

python
#!/usr/bin/env python3
"""Extract hidden PNG from WAV file"""

def extract_png_from_wav(wav_path, output_path):
    with open(wav_path, 'rb') as f:
        data = f.read()
    
    # Find PNG signature
    png_sig = b'\x89PNG\r\n\x1a\n'
    pos = data.find(png_sig)
    
    if pos == -1:
        print("PNG signature not found")
        return False
    
    # Check for custom header before PNG
    header = data[pos-8:pos]
    if header[:4] == b'PNG0':
        size = int.from_bytes(header[4:8], 'little')
        print(f"Found custom header: PNG0, size={size}")
    
    # Extract PNG data
    # Find PNG end marker (IEND chunk)
    iend = data.find(b'IEND', pos)
    if iend != -1:
        png_data = data[pos:iend+8]  # IEND + CRC
    else:
        png_data = data[pos:pos+size]
    
    with open(output_path, 'wb') as out:
        out.write(png_data)
    
    print(f"Extracted {len(png_data)} bytes to {output_path}")
    return True
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

extract_png_from_wav('Danika_House.wav', 'hidden.png')

Flag Connection to Description

Flag grodno{REDACTED} = "I'm sane, I promise" - an ironic answer to the question from the description "Я всегда пытаюсь сохранять адекватность... Так ведь?" (I always try to be serious... Right?)

Red Herrings

  • Name "Admin Vibes" - not related to the solution
  • Meme with "КУПАТЫ" on the image - distraction
  • WAV metadata (Artist, Title) - contains no hints
  • Audio spectrogram - clean music with no hidden data ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Lessons

  1. Always check file structure for data after the main content
  2. When standard LSB fails - try variations:
    • Different channels individually
    • Reversed bit order
    • Different reading directions (row-major vs column-major)
  3. Multi-layer challenges require patience and a systematic approach ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍