← Back to Writeups
CUSTOMMediumSteganography

ASCII Art Image

XESXOR9/2/20262 min read
#steganography#custom#medium#ascii-art-to-image-conversion#character-to-brightness-mappin#image-rotation-for-text-recove

ASCII Art Image

Platform: hackerlab | Category: Steganography | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2025-12-22 | Status: Solved Techniques: ASCII art to image conversion, Character-to-brightness mapping, Image rotation for text recovery

Summary

Task: Text file with ASCII art characters representing brightness levels. Solution: Convert characters to grayscale pixels using brightness mapping and rotate 180 degrees to reveal the flag.

ASCII Art Image — hackerlab.pro

Description

"Иногда мы не видим всей полноты картины..."

Task: a1e6e8a9-0ea3-4605-880e-c7cf528d2980

Analysis

  1. File file.txt — text file with dimensions 400x141 characters
  2. Content — characters @#BG&P5Y7J?!~^:. — standard ASCII art palette
  3. Principle — each character represents different brightness:
    • @ — darkest (most "ink")
    • . — lightest (minimal "ink")
    • Intermediate characters — grayscale gradations

Solution

Step 1: Understanding ASCII Art Palette

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

ASCII art uses characters with different "density" to represent brightness:

  • Characters with more pixels (@, #, B) appear darker
  • Characters with fewer pixels (., :, ^) appear lighter

Step 2: Converting to Image

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

# Read ASCII art
with open('file.txt', 'r') as f:
    lines = [line.rstrip('\n') for line in f.readlines()]

# ASCII art palette from dark to light
ascii_order = "@#BG&P5Y7J?!~^:."
char_to_brightness = {c: int(255 * i / (len(ascii_order) - 1)) for i, c in enumerate(ascii_order)}
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

# Create image array
height = len(lines)
width = max(len(line) for line in lines)
img_array = np.zeros((height, width), dtype=np.uint8)

# Fill pixels
for y, line in enumerate(lines):
    for x, char in enumerate(line):
        img_array[y, x] = char_to_brightness.get(char, 255)

# Rotate 180 degrees (text was upside down)
img_array = np.rot90(img_array, 2)

# Save
img = Image.fromarray(img_array)
img.save('output.png')

Step 3: Improving Readability (Optional)

python
# Binarization for better contrast
threshold = 128
binary = np.where(img_array > threshold, 255, 0).astype(np.uint8)
Image.fromarray(binary).save('output_binary.png')

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

Step 4: Reading the Flag

After conversion and rotation, the flag text is readable on the image.

Important: Note the digit 1 instead of letter I in the word FR1END.

Standard ASCII Art Palettes

Short (10 characters): @%#*+=-:. 
Medium (16 characters):  @#BG&P5Y7J?!~^:.
Long (70 characters):  $@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,"^`'. 

Alternative Approaches

  1. Palette inversion — if image is negative, reverse the character order
  2. Different rotations — try 90°, 180°, 270°
  3. Mirroring — horizontal or vertical
  4. Scaling — ASCII art may be stretched along one axis ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍