Just a Text
Just a Text
Platform: spbctf | Category: Steganography | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2017-08-31 | Status: Solved Techniques: binary_character_substitution, cyrillic_latin_detection, homoglyph_steganography
Summary
Task: UTF-8 text file with hidden message using Cyrillic/Latin homoglyphs. Solution: Identified visually identical characters with different Unicode codepoints, decoded Latin=1/Cyrillic=0 as binary to reveal the flag.
Just a Text — SPbCTF
Description
Ыж перехватил кусок текста из переписки сотрудников разведки. Выглядит как обычный текст, но есть подозрение, что в нём они скрытно передали флаг! Достаньте.
Download: https://fyrkbomb.ru/files/2017-08-31_flag.txt
Analysis
The downloaded file flag.txt is UTF-8 text (with BOM), containing ordinary English text about biography, genius, aesthetics, etc. Visually the text looks completely normal.
Initial analysis:
bash read-only • copy allowed$ file flag.txt flag.txt: Unicode text, UTF-8 (with BOM) text, with very long lines (728), with no line terminators
Hex analysis reveals an anomaly:
When viewing through xxd, two-byte UTF-8 sequences are found where single-byte ASCII characters should be. For example, Cyrillic е (U+0435, bytes d0 b5) instead of Latin e (U+0065).
Identified homoglyph pairs:
| Latin | Cyrillic |
|---|---|
| a (U+0061) | а (U+0430) |
| e (U+0065) | е (U+0435) |
| o (U+006F) | о (U+043E) |
| p (U+0070) | р (U+0440) |
| c (U+0063) | с (U+0441) |
| y (U+0079) | у (U+0443) |
| x (U+0078) | х (U+0445) |
| A (U+0041) | А (U+0410) |
| B (U+0042) | В (U+0412) |
| E (U+0045) | Е (U+0415) |
| K (U+004B) | К (U+041A) |
| M (U+004D) | М (U+041C) |
| H (U+0048) | Н (U+041D) |
| O (U+004F) | О (U+041E) |
| P (U+0050) | Р (U+0420) |
| C (U+0043) | С (U+0421) |
| T (U+0054) | Т (U+0422) |
| X (U+0058) | Х (U+0425) |
| |
Solution
Steganography technique: for each character that has both Latin and Cyrillic variants, the choice of variant encodes one bit of information:
- Latin character → bit
1 - Cyrillic character → bit
0
Collect all bits, group by 8 and decode as ASCII.
python read-only • copy allowed#!/usr/bin/env python3 """ Homoglyph steganography decoder Decodes hidden message from Cyrillic/Latin character substitution """ with open('flag.txt', 'r', encoding='utf-8-sig') as f: content = f.read() # Cyrillic homoglyphs (lowercase and uppercase) cyrillic_all = set( '\u0430' # а '\u0435' # е '\u043e' # о '\u0440' # р '\u0441' # с '\u0443' # у '\u0445' # х '\u0410' # А '\u0412' # В '\u0415' # Е '\u041a' # К '\u041c' # М '\u041d' # Н '\u041e' # О '\u0420' # Р '\u0421' # С '\u0422' # Т '\u0425' # Х ) # Latin homoglyphs latin_all = set('aeopycxABEKMHOPCTX') bits = '' for ch in content: if ch in cyrillic_all: bits += '0' elif ch in latin_all: bits += '1' # Decode bits to ASCII result = '' for i in range(0, len(bits), 8): byte = bits[i:i+8] if len(byte) == 8: result += chr(int(byte, 2)) print(result) # Output: THE FL@G IS: REDACTED
Note: The @ character instead of A in the word "FLAG" is the result of the letter A in that position being encoded as Cyrillic А (U+0410), which gave bit 0 instead of 1. This yields 0x40 (@) instead of 0x41 (A). This is an intentional leet-speak style.