
На позапрошлом jeopardy-CTF наша четвёрка закрыла 11 задач за восемь часов — неплохо для университетской команды без рейтинга в топ-100 CTFtime. Через две недели я открыл заметки и не смог восстановить ход решения ни одной задачи сложнее medium. Три скриншота без подписей, обрывок Python-скрипта без единого комментария и строка «попробовать SSTI в Jinja2». Одиннадцать флагов сданы, ноль полезного опыта зафиксировано.
После этого провала я стал относиться к документированию решений CTF как к части соревнования, а не как к опциональному бонусу «для тех, кому не лень». Этот гайд по написанию write-up — конденсат набитых шишек за два года: что записывать, как структурировать и каких ошибок избегать, когда садишься за свой первый или двадцатый разбор.
Первая причина — память. CTF-задачи эксплуатируют повторяющиеся паттерны: SQL-инъекции через UNION-based вектор, SSRF через перенаправление на cloud metadata-эндпоинт, buffer overflow с перезаписью return address. Если решение не задокументировано, через месяц аналогичная задача съест те же четыре часа на повторное ковыряние. Write-up превращает разовое озарение в воспроизводимую методологию CTF — твой справочник, к которому можно вернуться перед следующим соревнованием. Подробнее — в нашем статье о создание ctf заданий.
Вторая — портфолио. На собеседовании строчка «участвовал в CTF» мало что говорит рекрутеру. А ссылка на десять-пятнадцать опубликованных разборов CTF заданий, где виден ход мысли и логика эксплуатации — конкретное доказательство навыков. По материалам appsecmaster.net, работодатели в offensive security всё чаще оценивают кандидатов по публичным writeup-материалам — они показывают то, чего не покажет сертификат: как человек думает под давлением. Портфолио пентестера CTF строится из таких публикаций, а не из перечисления пройденных курсов.
Третья — вклад в сообщество. По данным CTFtime.org, ежегодно проходит более 400 соревнований, и тысячи участников публикуют свои walkthrough CTF после каждого ивента. Для новичка, застрявшего на задаче из категории web или crypto, чужой разбор может стать тем моментом, когда щёлкает понимание не конкретного решения, а подхода к целому классу уязвимостей. Культура открытых write-up — одна из причин, почему CTF-сообщество растёт быстрее любой академической программы по кибербезопасности.
И наконец — процесс написания сам по себе обучает. Пока формулируешь, почему payload {{7*7}} дал ответ 49 и это указывает на SSTI, а не на обычный отражённый вывод, — укладываешь в голову разницу между template injection и XSS. Документирование решений CTF — не бюрократия, а способ перевести навык из «видел один раз» в «могу воспроизвести и объяснить».
Главная ошибка — надеяться на bash history и собственную память. Через шесть часов непрерывного решения задач ты не вспомнишь, почему переключился с SQLi на SSRF и какой HTTP-заголовок дал 302-й редирект. Записывать нужно прямо во время CTF — это инвестиция в будущий write-up, которая окупается уже на стадии оформления.
Минимальный набор для каждой задачи:
' OR 1=1-- → 500 Internal Server Error», «попробовал {{config}} → вернул конфигурацию Flask». Фиксируй и неудачные попытки — при написании write-up они покажут ход мысли.Совет из практики: на командных CTF назначьте одного участника «документатором» для каждой задачи. Или договоритесь, что каждый записывает свою часть решения сразу в общий документ. Звучит как бюрократия — на деле экономит часы при написании разбора.
Для CTF для начинающих подойдёт любой текстовый редактор с поддержкой Markdown — этот формат станет основой готового write-up без дополнительного переформатирования.
.md-файл на задачу, live preview рядом с терминалом.Ключевой принцип: инструмент должен быть настроен и протестирован до начала CTF. Тратить 20 минут на установку плагинов в разгар соревнования — верный способ потерять задачу, а не задокументировать её.
Хороший write-up — не хронологический дамп всех набранных команд, а структурированный разбор задачи с логикой «что видел → что думал → что делал → что получил». Ниже — шаблон, который можно скопировать в Obsidian или HackMD и использовать как основу. Адаптирован из рекомендаций Elite Era Security и чеклиста pequalsnp-team, проверен на десятках собственных разборов.
Заголовок: [Название задачи] — [Название CTF] [Год]
Метаинформация — категория (Web / Crypto / Pwn / Forensics / OSINT / Reverse), сложность или очки (Easy / 100 pts), платформа (picoCTF / HackTheBox / Codeby Games), время решения (~35 минут).
Блок 1 — Условие задачи. Полный текст задания и приложенные файлы. Если задание на платформе — скриншот с описанием. Не пересказывай своими словами, дай оригинал: через полгода детали забудутся, а оригинальная формулировка восстановит контекст.
Блок 2 — Первичный анализ. Что увидел, впервые открыв задачу. Для web — интерфейс приложения, доступные эндпоинты, серверные заголовки. Для pwn — результат file и checksec. Для crypto — формат данных и предполагаемый тип шифра. Для forensics — file, strings, exiftool.
Блок 3 — Гипотезы и разведка. Какие векторы рассмотрел и почему. Здесь описываются и тупиковые пути — они демонстрируют методологию CTF. «Сначала проверил XSS — входные данные экранируются. Переключился на SSTI, потому что заголовок X-Powered-By: Flask указывает на Python-шаблонизатор.»
Блок 4 — Эксплуатация. Пошаговое описание: что сделал, какие инструменты применил, какие payload отправил. Код — с комментариями к каждому значимому фрагменту. Команды — с пояснением аргументов и флагов.
Блок 5 — Флаг. Итоговый флаг и подтверждение его принятия (скриншот платформы).
Блок 6 — Выводы и уроки. Что нового узнал. Какой паттерн уязвимости встретил. Что бы сделал иначе при повторном решении. Альтернативные подходы, если они есть. Этот блок — тот самый «reusable pattern» из рекомендаций Elite Era Security, который превращает единичный разбор в переиспользуемое знание.
Каркас универсален, но секция «Первичный анализ» меняется в зависимости от категории:
nmap для разведки портов.checksec, file, дизассемблер (Ghidra или IDA), поиск уязвимых функций вроде gets и strcpy.file, binwalk, exiftool, strings, анализ метаданных и встроенных объектов.gdb или ltrace, поиск условий проверки флага.Понимание этих различий помогает и оформить решение CTF задачи быстро, и сделать write-up полезным для читателей конкретной категории.
Оформление write-up CTF — не про эстетику, а про читаемость. Блестящий эксплойт, похороненный в стене неформатированного текста, бесполезен и для читателя, и для тебя через три месяца.
Правило простое: код оформляется в fenced-блоке с указанием языка, нетривиальные строки сопровождаются комментариями. Не весь вывод терминала на 200 строк, а ключевые команды и результаты.
Пример хорошего оформления:
# SSTI payload для Jinja2: раскрываем конфигурацию Flask
import requests
url = "http://target.ctf/search"
payload = {"q": "{{config.items()}}"}
r = requests.get(url, params=payload)
print(r.text) # Ищем SECRET_KEY в ответе
Плохой вариант — тот же код без комментариев, а ниже — полный HTTP-ответ на 40 строк. Читатель не поймёт, зачем отправлен конкретный payload, и потеряет нить рассуждения.
Если скрипт длинный (больше 15-20 строк), вынеси его в GitHub Gist или репозиторий и дай ссылку. В тексте write-up оставь только ключевой фрагмент с объяснением логики — этого хватит за глаза.
Каждый скриншот сопровождается подписью: что изображено и на что обратить внимание. «Ответ сервера на SSTI-payload: раскрытый SECRET_KEY в третьей строке» — хорошо. Скриншот без подписи — бесполезная картинка: читатель сам гадает, что ты хотел показать.
Скриншоты терминала предпочтительнее копипаста текста, когда важна визуальная структура — вывод nmap, интерфейс Burp Suite с подсвеченным параметром. Но если данные текстовые — вставляй как блок кода: он индексируется поиском и его можно скопировать. Как рекомендует learnhacking.io, опирайся на скриншоты для визуального контекста, а текст используй для объяснения рассуждений — экономит силы и повышает читаемость.
nmap -sV, /etc/passwd, --script vuln.Финальная проверка: открой write-up на мобильном. Длинные строки кода не должны уезжать за край экрана, скриншоты должны быть читаемы без увеличения.
Этот список — из чтения чужих разборов и анализа собственных ранних текстов. Все ситуации реальные.
Самая распространённая ошибка новичков CTF: «Открыл страницу → нашёл SQL-инъекцию → достал флаг». Между «открыл» и «нашёл» — цепочка рассуждений, которую автор пропустил. Почему именно SQLi? Что навело на мысль? Какой payload не сработал? Без этого write-up бесполезен: читатель получает ответ, но не метод. А метод — главная ценность любого разбора CTF задания.
Пять скриншотов подряд без единой подписи. Читатель видит окно Burp Suite с десятком вкладок и не понимает, куда смотреть. Каждый скриншот в write-up — утверждение: «на этом шаге произошло вот это, и это важно, потому что...». Без текстовой обвязки скриншот — картинка, которая занимает место и ничего не объясняет.
Вставить Python-скрипт на 30 строк и написать «запустите — получите флаг» — это не write-up, это ответ из задачника. Как оформить решение CTF задачи правильно: объясни, что делает каждый значимый блок. Не построчно, но логическими группами: «строки 3-7 перебирают возможные значения байта и сравнивают с зашифрованным массивом», «функция exploit() формирует payload и парсит ответ». Читатель должен понять принцип, а не просто скопировать скрипт.
40 минут ушло на XSS, прежде чем стало ясно: реальный вектор — SSTI. В итоговом write-up об этом ни слова, будто правильный путь угадан с первой попытки. Тупики — самая ценная часть разбора. Они показывают, как отсекать нерабочие гипотезы и переключаться между векторами. По чеклисту pequalsnp-team, описание неудачных попыток — один из маркеров качественного writeup, отличающий его от «solution dump».
Write-up без указания названия CTF, категории и количества очков — потерянный контекст. Через полгода не вспомнишь: это была easy-задача на 50 очков или hard на 500. Для портфолио пентестера CTF метаинформация необходима — она позволяет оценить уровень задач и динамику роста.
На платформах с постоянными задачами (HackTheBox, Root-Me) публикация решений до деактивации — нарушение правил. Learnhacking.io напоминает: перед публикацией проверяй политику площадки. HackTheBox разрешает write-up только по retired-машинам. Для одноразовых jeopardy-CTF публикация после завершения — стандартная практика, приветствуемая организаторами.
Write-up на 2000 слов сплошным абзацем без заголовков, списков и блоков кода. Читатель теряется на второй странице и закрывает вкладку. Структура write-up с навигационными заголовками и визуальным разделением — базовое требование к читаемости, которое экономит время и автору, и аудитории.
Покажу, как выглядит готовый write-up по описанному шаблону. Задача демонстрационная, но паттерн типичен для реальных web-категорий на CTF для начинающих.
Simple Search — ExampleCTF 2025
Условие: «Наш новый поисковик знает всё. Найдите секрет.» Дан URL веб-приложения с формой поиска.
Первичный анализ. Открыл страницу — единственная форма поиска, результаты отображаются на той же странице. В исходном коде нашёл комментарий <!-- TODO: fix template rendering -->. Заголовок ответа содержит X-Powered-By: Flask. Два факта — Flask и упоминание шаблонов — основание для проверки SSTI.
Гипотезы и разведка. Первая гипотеза — XSS: ввёл <script>alert(1)</script>. Вывод экранирован, скрипт не исполнился. Тупик. Переключился на SSTI: ввёл {{7*7}}, в выдаче получил 49 вместо текста запроса. Шаблонизатор Jinja2 подтверждён. По классификации OWASP это A03:2021 — Injection: пользовательский ввод обрабатывается шаблонизатором без санитизации.
Эксплуатация. Прочитал конфигурацию через {{config.items()}} — в ответе SECRET_KEY и переменные окружения. Далее — RCE через стандартную цепочку Jinja2:
{{request.application.__globals__.__builtins__.__import__('os').popen('cat /flag.txt').read()}}
Ответ содержит содержимое /flag.txt с искомым флагом.
Флаг: flag{s1mpl3_sst1_jinja2_rce}
Выводы. HTML-комментарий и заголовок X-Powered-By — достаточные индикаторы для проверки SSTI. В реальных приложениях SSTI в Jinja2 приводит к полной компрометации сервера через RCE. Паттерн регулярно встречается на CTF-платформах в категориях Easy и Medium.
Обрати внимание на каркас: метаинформация → первый контакт с задачей → тупиковый путь (XSS) → рабочая гипотеза → пошаговая эксплуатация → осмысление. Даже для easy-задачи структура остаётся полной. Со временем заполнение шаблона занимает 10-15 минут — привычка, а не подвиг.
Где публиковать — зависит от цели.
Тематические форумы. На Codeby есть раздел для writeup-разборов с тегированием по категориям (web, pwn, crypto, forensics). Публикация на площадке с живой аудиторией сразу даёт обратную связь: комментарии, вопросы, альтернативные решения от более опытных участников. Habr — вариант с широкой технической аудиторией за пределами ИБ-сообщества.
GitHub. Создай репозиторий ctf-writeups с папочной структурой CTF-name/challenge-name/README.md. Плюсы: полный контроль, версионирование через git, Markdown рендерится автоматически. Минус: органической аудитории нет, привлекать придётся через ссылки в профилях и чатах. Зато ссылка на репозиторий удобно ложится в резюме.
CTFtime. Основная международная платформа для публикации write-up после соревнований. Разбор привязывается к конкретному ивенту, учитывается в рейтинге команды и виден всему международному сообществу.
Личный блог. GitHub Pages, Hugo, Jekyll — максимальный контроль над дизайном. Имеет смысл, когда накопится 15-20 write-up и можно выстроить полноценное портфолио пентестера CTF с фильтрацией по категориям и сложности.
Практическая рекомендация: начни с Codeby или GitHub — порог входа минимален. Первый десяток write-up покажет собственные слабые стороны в оформлении — и это нормально. Тридцать опубликованных разборов через год-полтора — и на собеседовании достаточно дать ссылку вместо длинного рассказа о своём опыте.
Большинство новичков бросают писать write-up после второго-третьего разбора. Причина не в лени — в перфекционизме. Кажется, что write-up обязан быть идеальным: безупречный код, литературный язык, скриншоты как из учебника. На практике write-up, написанный за 15 минут сразу после решения, в десять раз ценнее идеального разбора, который так и не будет дописан. Первые тексты будут корявыми — и это нормально. Через двадцать штук структура станет привычной, Markdown — автоматическим, а способность объяснить сложную цепочку эксплуатации в трёх абзацах — твоим конкурентным преимуществом.
Есть неудобная правда, которую мало кто проговаривает: навык документирования ценится на рынке выше, чем навык эксплуатации. Пентестер, нашедший RCE, но неспособный оформить отчёт так, чтобы заказчик понял масштаб проблемы — головная боль для команды, а не актив. Write-up после CTF учит именно этому: переводить техническое действие в понятный текст. Это граница между «решил задачу для себя» и «стал специалистом, которому доверяют проект». Если только начинаешь и хочется разобраться в фундаменте ИБ системно — на codeby.school есть IB Basics, который закрывает базу без академического занудства, и от него проще перейти к CTF и к первым рабочим задачам.
🚀 Хочешь закрепить на практике? Реши задачи по теме на HackerLab — категория «pentest-machines».
0 комментариев
Пожалуйста, войдите, чтобы оставить комментарий.
Загрузка комментариев...