← Back to Writeups
CUSTOMEasyMisc

Blind Hens

XESXOR9/2/20263 min read
#misc#custom#easy#base64_decode#binary_whitespace_decode#single_byte_xor#trailing_whitespace_extraction

Blind Hens

Platform: bluehens_ctf_2026 | Category: Misc | Type: Challenge | Difficulty: Easy | OS: NA | Author: XESXOR | Date: 2026-04-17 | Status: Solved Techniques: base64_decode, binary_whitespace_decode, single_byte_xor, trailing_whitespace_extraction

Summary

Task: a plain-text internal memo hides data in trailing spaces and tabs. Solution: extract end-of-line whitespace, decode SPACE=0 and TAB=1 into bytes, base64-decode the recovered string, then XOR with 0x23 from the policy #23 hint to reveal the flag.

Blind Hens — BlueHens CTF 2026

Description

We recovered a routine internal memo from a workstation flagged during an investigation. Nothing in the visible contents appears unusual, but analysts believe a message was hidden in plain sight. Review everything carefully even the smallest details can be important. Some internal policies may hold the key.

The artifact is a text memo that looks harmless at first glance. The goal is to inspect the file carefully, identify the hidden channel, and recover the concealed flag. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Analysis

Overview

This is a whitespace-steganography challenge. The visible memo text is a decoy; the real payload is stored in the trailing whitespace at the ends of selected lines.

Key observations

  • The description says a message was hidden "in plain sight" and that "the smallest details" matter.
  • Opening memo.txt shows many lines with extra whitespace after the visible text.
  • The suspicious whitespace is not random: it consists of spaces and tabs, which naturally suggests a binary encoding.
  • The line Oh btw please ensure compliance with policy #23 is an explicit hint that the final step should use 0x23. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Whitespace extraction

For each line with trailing whitespace, read exactly the spaces and tabs at the end of the line:

  • SPACE = 0
  • TAB = 1

Concatenating those bits and grouping them into 8-bit chunks produces bytes. Decoding those bytes as ASCII yields:

text
dmdgd2VYE04VfFRLEhQQfBZTF0AQfEcQQBNHEk0VfBIWfBd8FEsSTRUcXg=

This is not the flag yet, but it clearly looks like base64 text.

Base64 step

The extracted string needs normal base64 padding:

text
dmdgd2VYE04VfFRLEhQQfBZTF0AQfEcQQBNHEk0VfBIWfBd8FEsSTRUcXg==

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

Base64-decoding it gives a byte string that is still not human-readable. That means one more transformation is required.

Policy #23 → XOR with 0x23

The memo explicitly mentions policy #23, which is the clue for a single-byte XOR key of 0x23. XORing every decoded byte with 0x23 reveals the plaintext flag.

Solution

  1. Read memo.txt line by line.
  2. Extract only the trailing spaces/tabs from each line that has them.
  3. Convert whitespace to bits with SPACE=0, TAB=1.
  4. Group bits into bytes and convert them to characters.
  5. Add missing base64 padding and decode the string.
  6. XOR the resulting bytes with 0x23 based on the policy #23 hint.
  7. Read the recovered flag. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍
python
#!/usr/bin/env python3
import base64
from pathlib import Path

data = Path("tasks/BlueHens CTF 2026/Blind Hens/memo.txt").read_text()

bits = ""
for line in data.splitlines():
    trail = line[len(line.rstrip(" \t")):]
    bits += "".join("0" if ch == " " else "1" for ch in trail)

hidden = "".join(chr(int(bits[i:i+8], 2)) for i in range(0, len(bits), 8) if len(bits[i:i+8]) == 8)
decoded = base64.b64decode(hidden + "=" * (-len(hidden) % 4))
flag = bytes(b ^ 0x23 for b in decoded).decode()

print(hidden)
print(flag)

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

Running the solver prints the intermediate base64-looking string and then the final flag. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍