1337book: writeup
1337book
| Category | Stegano |
| Difficulty | Easy |
| Technique | PDF text extraction + Base64 |
| Flag | flag{U_REALLY_CAN_READ_TH1$} |
Recon
Тебе вручили файл 1337book.pdf. Где-то внутри спрятан флаг.
Артефакт: 1337book.pdf.
file 1337book.pdf
wc -c 1337book.pdf
1337book.pdf: PDF document, version 1.3
157822 1337book.pdf
Ключевые наблюдения:
- Название намекает на leet-число 1337 — это классика хакер-культуры, вероятно количество страниц.
- Открыть в просмотрщике: 1337 страниц, практически все пустые.
- Перелистать вручную нереально — нужна автоматизация.
Проверяем: не лежит ли флаг прямо в тексте файла (быстрая разведка):
strings 1337book.pdf | grep "flag{"
(нет вывода)
Результат: пусто. Вывод: flag{...} в открытом виде в файле нет — значит флаг закодирован.
PDF Text Scan
Парсинг PDF — программное извлечение текстового содержимого страниц, в обход ручного листания.
Образ: открыть 1337-страничную книгу и прочитать каждую страницу — занимает часы. Написать скрипт — занимает секунды: цикл просматривает страницу за страницей и сразу сообщает, на какой из них есть непустой текст.
Ключевой вопрос: на каких страницах вообще есть текстовый контент?
python3 parse_pypdf.py
Pages: 1337
Page 136: 'ZmxhZ3tVX1JFQUxMWV9DQU5fUkVBRF9USDEkfQ\n'
Extraction complete. Extracted length: 41
Одна страница из 1337 содержит непустой текст — страница 136 (нумерация с 0, то есть 137-я по счёту).
Строка ZmxhZ3tVX1JFQUxMWV9DQU5fUkVBRF9USDEkfQ — верхний регистр, цифры, без спецсимволов. Это классический облик Base64 — схемы перевода произвольных байт в печатные ASCII-символы.
Decryption
| Шаг | Действие | Команда / данные |
|---|---|---|
| 1 | Запустить pypdf-скрипт, найти непустую страницу | Page 136 |
| 2 | Получить Base64-строку с этой страницы | ZmxhZ3tVX1JFQUxMWV9DQU5fUkVBRF9USDEkfQ |
| 3 | Декодировать Base64 | echo "ZmxhZ3..." | base64 -d |
| 4 | Получить флаг | flag{U_REALLY_CAN_READ_TH1$} |
Ручная проверка шага 3:
echo "ZmxhZ3tVX1JFQUxMWV9DQU5fUkVBRF9USDEkfQ" | base64 -d
flag{U_REALLY_CAN_READ_TH1$}
Root cause:
# Генератор таска: флаг кодируется в Base64 и вставляется текстом на страницу TARGET_PAGE
import base64
FLAG_B64 = base64.b64encode(b"flag{U_REALLY_CAN_READ_TH1$}").decode().rstrip("=")
# → ZmxhZ3tVX1JFQUxMWV9DQU5fUkVBRF9USDEkfQ
if page_num == TARGET_PAGE: # страница 136 (1-based)
pdf.cell(0, 10, txt=FLAG_B64, ln=1, align="C")
# остальные 1336 страниц — пустые
Паддинг == убран намеренно — строка распознаётся как Base64 без него, но grep flag по PDF не находит ничего.
Правильный подход (как усложнить сокрытие):
- Спрятать текст белым шрифтом на белом фоне — визуально невидим, но
pypdfизвлекает. - Заполнить каждую страницу ложными Base64-строками — только одна декодируется в
flag{...}. - Встроить флаг в метаданные PDF (XMP / DocInfo) вместо текста страницы.
- Использовать нестандартный шрифт-замену: глифы подменены, OCR выдаёт флаг, копипаст — мусор.
Automation
import base64
from pypdf import PdfReader
def main() -> None:
reader = PdfReader("1337book.pdf")
print(f"Всего страниц: {len(reader.pages)}")
for page_num, page in enumerate(reader.pages):
text = page.extract_text()
if not text or not text.strip(): # пропускаем пустые страницы
continue
candidate = text.strip()
print(f"[+] Страница {page_num}: {candidate}")
try:
# базовый декодировщик: добавляем паддинг на случай, если он обрезан
decoded = base64.b64decode(candidate + "==").decode()
print(f"[+] Base64 → {decoded}")
except Exception:
print("[-] Не Base64, пропускаем")
if __name__ == "__main__":
main()
python3 solve.py
# Всего страниц: 1337
# [+] Страница 136: ZmxhZ3tVX1JFQUxMWV9DQU5fUkVBRF9USDEkfQ
# [+] Base64 → flag{U_REALLY_CAN_READ_TH1$}
Key Takeaways
- PDF — не монолит, а набор объектов. Текст на каждой странице хранится в отдельном потоке и легко извлекается библиотеками
pypdf/PyMuPDF. Просмотрщик скрывает структуру, парсер — раскрывает. - Base64 узнаётся по алфавиту. Строка только из
A–Z,a–z,0–9,+,/,=(и длина, кратная 4 или без паддинга) — немедленный сигнал дляbase64 -d. Это не шифр, а транспортная кодировка. - Ловушка задачи:
strings | grep flag— привычная команда, которая здесь молчит. Участники, доверившись ей, решают, что флага нет, и бросают разведку. Флаг присутствует в файле в виде читаемых ASCII-символов — просто без словаflag{в открытом виде.
