
На прошлом jeopardy-CTF организаторы выдали дамп в 1.8 ГБ — системные логи, перемешанные с base64-мусором и обрывками бинарных данных. Из двухсот участников первый флаг за 40 секунд сдали четверо. Все использовали одну команду: grep -Eo с правильным regex-паттерном. Остальные открывали файл в less или nano, которые благополучно зависали, пытаясь отрисовать два миллиона строк.
Разница между «сдал таск» и «потерял час» на CTF часто сводится к одной строке в терминале. Ниже — пошаговый разбор regex и grep для поиска флагов CTF: от простейшего текстового совпадения до PCRE-паттернов, конвейеров декодирования и оптимизации на файлах размером в гигабайты.
Перед тем как что-то запускать, разберёмся с форматом того, что ищем. Подавляющее большинство CTF-соревнований используют шаблон PREFIX{содержимое}, где PREFIX — имя платформы или стандартный маркер: Подробнее — в нашем материале про создание ctf заданий.
flag{some_text_here} — самый распространённый формат на jeopardy-CTFCTF{...}, picoCTF{...}, HTB{...}, codeby{...} — привязка к конкретной платформеFLAG{...} или Flag{...} — вариации регистра, иногда намеренныеkey{...}, secret{...}, иногда просто хеш-строка без скобокПервая ошибка новичка — команда grep "flag" dump.txt. В двухгигабайтном логе слово «flag» встретится тысячи раз: в аргументах командной строки (--flag), в именах переменных, в комментариях. Получите страницы мусора. Поиск флага в дампе CTF требует regex-паттерна, который точно описывает формат флага — с фигурными скобками, с конкретным содержимым.
Базовая логика: нам нужно регулярное выражение для flag{}, которое матчит слово flag, за ним открывающую фигурную скобку, затем произвольное содержимое и закрывающую скобку. На языке regex это flag\{[^}]+\} — буквальные символы flag, экранированная \{ (потому что { — метасимвол в regex), один или более символов кроме } ([^}]+) и закрывающая \}. Экранирование обязательно: без обратных слешей grep интерпретирует фигурные скобки как квантификатор повторения, а не как часть искомого текста.
Два флага утилиты grep, которые решают 70% CTF-тасков — -E и -o. Без них работать можно, но заметно больнее.
Флаг -E переключает grep в режим Extended Regular Expressions (ERE). В ERE метасимволы +, ?, | и группирующие скобки () работают напрямую, без экранирования обратным слешем. Без -E пришлось бы писать grep 'flag\{[^}]\+\}' — обратите внимание на \+ вместо +. С -E паттерн чище: grep -E 'flag\{[^}]+\}'.
Флаг -o выводит только совпавшую часть строки, а не всю строку целиком. Без -o grep покажет строку лога длиной в тысячу символов, внутри которой где-то спрятан флаг. С -o получаете ровно flag{ваш_ответ} — и ничего лишнего. На CTF это экономит нервы.
Команда grep -Eo 'flag\{[^}]+\}' dump.txt — базовая рабочая лошадка. Её стоит запускать первой на любом CTF-таске, где дан текстовый файл.
Если формат флага заранее неизвестен, паттерн расширяется: grep -Eoi '[a-zA-Z0-9_]+\{[^}]+\}' dump.txt. Здесь [a-zA-Z0-9_]+ матчит любое «слово» перед фигурными скобками, а флаг -i добавляет нечувствительность к регистру. Такая команда поймает FLAG{}, CTF{}, Key{} и любой другой формат с фигурными скобками.
На практике regex-паттерны приходится адаптировать под конкретное соревнование. Вот набор, который покрывает большинство сценариев:
grep -Eo 'flag\{[^}]+\}' dump.txt
grep -Eo 'picoCTF\{[^}]+\}' dump.txt
grep -Eoi '(flag|ctf|key|secret|hack)\{[^}]+\}' dump.txt
grep -Eo '[A-Fa-f0-9]{32}' dump.txt
grep -Eo '[A-Fa-f0-9]{64}' dump.txt
grep -Po 'flag\{.+?\}' dump.txt
Первые три строки — поиск по конкретному или обобщённому формату PREFIX{...}. Четвёртая и пятая — поиск MD5 и SHA-256 хешей, когда флаг — голый хеш без скобок (32 или 64 шестнадцатеричных символа). Шестая использует -P (PCRE) с нежадным квантификатором .+? — об этом ниже.
Чередование через | позволяет искать несколько форматов за один проход по файлу. Команда grep -Eoi '(flag|ctf|key|secret)\{[^}]+\}' dump.txt найдёт flag{...}, CTF{...}, key{...} и secret{...} одновременно. Вместо четырёх проходов grep делает один — на файле в гигабайт это ощутимо.
Отдельная ловушка — жадные квантификаторы. Если в строке лога встречается flag{abc} мусор flag{real_answer}, паттерн с жадным .+ захватит всё от первой открывающей до последней закрывающей скобки: flag{abc} мусор flag{real_answer}. Нежадный .+? (доступен только с флагом -P) вернёт два отдельных результата: flag{abc} и flag{real_answer}. Мелочь, а на CTF может стоить 15 минут.
Флаг -P в GNU grep открывает доступ к Perl-Compatible Regular Expressions. Для CTF тут два ключевых инструмента:
Нежадные квантификаторы. Уже упомянутый .+? вместо .+. В ERE (режим -E) нежадных квантификаторов нет — это главная причина переключаться на -P для сложных тасков.
Lookahead/lookbehind. Если нужно вытащить только содержимое флага без скобок, пригодится конструкция grep -Po '(?<=flag\{)[^}]+(?=\})' dump.txt. Ретроспективная проверка (?<=flag\{) означает «перед совпадением должно стоять flag{», опережающая (?=\}) — «после совпадения должно стоять }». Результат — только текст между скобками. Удобно, когда платформа принимает ответ без обрамления flag{...}.
Ограничение, о котором забывают: -P — расширение GNU grep. На macOS стоит BSD grep, где -P не поддерживается. Варианты: поставить GNU grep через brew install grep (команда станет ggrep -P) или использовать pcregrep, который умеет PCRE нативно.
Парсинг логов Linux регулярными выражениями в CTF-контексте выходит за рамки простого flag{}. Организаторы прячут флаги в HTTP-заголовках, cookie, в base64-строках внутри JSON. Для таких случаев конвейерный подход работает лучше монолитного regex: сначала grep вычленяет подозрительные строки, потом cut или awk извлекает нужное поле, потом base64 -d декодирует. Об этом — в разделе про кодировки.
CTF-дампы бывают большими. 500 МБ — обычное дело для forensics. 2 ГБ и больше — встречается на продвинутых соревнованиях. Обработка больших логов командной строкой требует нескольких трюков, и вот какие реально работают:
LC_ALL=C — переключает grep в однобайтовую локаль вместо UTF-8. На файлах без кириллицы (а большинство CTF-дампов на английском) это даёт ускорение в 5-10 раз. Причина простая: в UTF-8 grep проверяет валидность многобайтовых последовательностей на каждом символе. В локали C каждый байт — отдельный символ, проверка не нужна. Используется так: LC_ALL=C grep -Eo 'flag\{[^}]+\}' huge_dump.txt. Я всегда начинаю с этого.
-m 1 — остановиться после первого совпадения. Если знаете, что флаг в файле один (а в большинстве CTF-тасков так и есть), grep -Eom1 'flag\{[^}]+\}' dump.txt прекратит чтение файла сразу после первого матча. На файле в 2 ГБ разница — минуты, потому что grep не дочитывает оставшийся хвост.
-a (он же --binary-files=text) — заставляет grep обрабатывать бинарные файлы как текстовые. Без этого grep выдаст Binary file matches и остановится, не показав совпадение. В CTF-дампах часто попадаются бинарные вкрапления — забытые заголовки, обрывки изображений.
strings перед grep — утилита strings извлекает из файла только печатные последовательности (по умолчанию от 4 символов). Конвейер strings dump.bin | grep -Eo 'flag\{[^}]+\}' работает быстрее и чище, чем grep -a по бинарному файлу, потому что grep получает на вход только текстовые фрагменты.
ripgrep (команда rg) — написан на Rust, и для CTF у него три козыря: автоматический пропуск бинарных файлов, рекурсивный поиск по умолчанию и скорость — на файлах свыше 1 ГБ ripgrep стабильно обгоняет GNU grep в 2-5 раз за счёт параллельного чтения.
Синтаксис почти идентичен: rg -o 'flag\{[^}]+\}' dump.txt. Для PCRE-паттернов: rg -Po '(?<=flag\{)[^}]+(?=\})' dump.txt (требуется сборка ripgrep с поддержкой PCRE2, в большинстве пакетных менеджеров она включена по умолчанию).
Установка: apt install ripgrep на Debian/Ubuntu, brew install ripgrep на macOS. На CTF-машинах ripgrep часто не стоит — поэтому владеть GNU grep обязательно, а ripgrep держать как ускоритель на своей рабочей станции.
Комбинация strings и rg особенно хороша для бинарных дампов: strings -n 8 firmware.bin | rg -o 'flag\{[^}]+\}'. Параметр -n 8 у strings поднимает минимальную длину извлекаемых строк до 8 символов, отсекая мусорные короткие фрагменты.
Организаторы CTF прячут флаги в кодировках — и это напрямую пересекается с реальной практикой ИБ. Техника Deobfuscate/Decode Files or Information (T1140) по классификации MITRE ATT&CK описывает тот же сценарий: злоумышленники обфусцируют данные для обхода детектирования, аналитики — декодируют обратно.
Base64. Строка flag{hello_world} в Base64 превращается в ZmxhZ3toZWxsb193b3JsZH0=. Глазами не распознать. Стратегия: найти все base64-подобные строки в дампе, декодировать массово, искать паттерн уже в декодированном тексте.
grep -Eo '[A-Za-z0-9+/]{20,}={0,2}' dump.txt \
| base64 -d 2>/dev/null \
| grep -Eo 'flag\{[^}]+\}'
Первый grep находит кандидатов — строки из base64-алфавита длиной от 20 символов с опциональным padding (=). Порог {20,} отсекает слишком короткие совпадения. base64 -d декодирует каждую строку (ошибки подавляются через 2>/dev/null). Второй grep ищет флаг в декодированном тексте.
Hex-кодировка. Флаг flag{abc} в hex — 666c61677b6162637d. Конвейер аналогичен: grep -Eo '[0-9a-fA-F]{20,}' dump.txt | xxd -r -p 2>/dev/null | grep -Eo 'flag\{[^}]+\}'. Утилита xxd -r -p выполняет обратное преобразование из hex в ASCII.
ROT13. Классический шифр подстановки. Строка flag после ROT13 — synt. Ищем напрямую: grep -Eo 'synt\{[^}]+\}' dump.txt | tr 'A-Za-z' 'N-ZA-Mn-za-m'. Команда tr применяет обратную ROT13-подстановку (ROT13 симметричен — двойное применение возвращает оригинал).
Извлечение данных из текстовых дампов часто требует комбинации нескольких декодирований. Встречаются задачи с двойным base64 (base64 от base64), hex-encoded base64 и другие вложенные кодировки — этакая матрёшка. Подход один: строить конвейер из pipe-символов, пропуская данные через цепочку декодеров.
Теория без практики — пустой звук. Разберём полный workflow: таск категории forensics, файл challenge.log размером 800 МБ.
file challenge.log
wc -l challenge.log
LC_ALL=C grep -Eom1 '[a-zA-Z0-9_]+\{[^}]+\}' challenge.log
grep -Eo '[A-Za-z0-9+/]{20,}={0,2}' challenge.log | head -20
grep -rEo 'flag\{[^}]+\}' ./extracted/ --include='*.txt'
grep -n -C 3 'подозрительная_строка' challenge.log
strings -n 6 challenge.log | grep -Eoi 'flag'
Шаг 1 — разведка. file покажет тип файла (ASCII text, UTF-8 Unicode text, data), wc -l — количество строк. Две секунды, но сразу понимаешь масштаб: текстовый или бинарный, тысяча строк или два миллиона.
Шаг 2 — быстрый grep. Универсальный паттерн с LC_ALL=C и -m1: если флаг лежит в открытом виде, ответ появится за доли секунды. Этот шаг решает примерно половину тасков. Серьёзно — половину.
Шаг 3 — проверка кодировок. Прямой поиск ничего не дал? Ищем base64-блоки. head -20 показывает первых 20 кандидатов — оцениваем глазами, похоже ли на base64 или это случайный набор символов. Потом пропускаем через base64 -d и ищем паттерн.
Шаг 4 — рекурсивный поиск. Если таск дал архив с множеством файлов: grep -rEo 'flag\{[^}]+\}' ./extracted/. Опция --include='*.txt' ограничивает поиск текстовыми файлами — grep не тратит время на картинки и бинарники.
Шаг 5 — контекст. Нашли подозрительную строку, но не уверены? Флаг -C 3 покажет по три строки до и после совпадения, -n добавит номера строк. Потом можно открыть файл точно на нужной строке: vim +номер challenge.log.
Шаг 6 — strings для бинарных вкраплений. Если file показал data вместо text, предварительно прогоняем через strings.
Этот workflow покрывает примерно 70-80% задач на jeopardy-CTF в категориях misc, forensics и crypto. Кстати, picoCTF прямо включает задачу «First Grep» для новичков — она устроена ровно так: дан файл, найди строку picoCTF{...} одной командой.
Grep работает построчно — это его сильная сторона и одновременно ограничение. Если флаг разбит на несколько строк (hex-дампы, многострочные логи), grep его не увидит.
awk для извлечения полей. Допустим, лог имеет формат timestamp | level | message, и флаг спрятан в поле message. Конвейер awk -F'|' '{print $3}' access.log | grep -Eo 'flag\{[^}]+\}' сначала через awk вырежет третье поле (разделитель |), потом grep найдёт в нём флаг.
sed для предобработки. Иногда организаторы разбивают флаг пробелами: f l a g { h e l l o }. Убрать пробелы перед поиском: sed 's/ //g' dump.txt | grep -Eo 'flag\{[^}]+\}'. Другой вариант — склеить все строки файла в одну: tr -d '\n' < dump.txt | grep -Eo 'flag\{[^}]+\}'. Команда tr -d '\n' удалит переносы строк. Осторожно с большими файлами — вся строка загружается в память.
pcregrep для многострочного поиска. pcregrep поддерживает флаг -M (multiline): pcregrep -Mo 'flag\{[^}]+\}' dump.txt. Единственный вариант без предварительной склейки строк — pcregrep сам обработает совпадения, пересекающие границу строки.
Всё, что описано выше, применяется за пределами CTF без изменений. В incident response аналитик ищет индикаторы компрометации в логах теми же конвейерами. Техника Credentials In Files (T1552.001) по MITRE ATT&CK — это буквально grep по паттернам password=, api_key=, secret= в файловой системе. Data from Local System (T1005) — сбор данных из локальных файлов, тот же рекурсивный grep -r по директориям. Shell History (T1552.003) — поиск утечек credentials в .bash_history.
Команда grep -rEi '(password|passwd|api_key|secret|token)=' /var/log/ — рабочий инструмент и для CTF-таска, и для аудита конфигурации продакшн-сервера. Разница только в паттерне: на CTF ищем flag{}, в жизни — утечки данных.
На собеседованиях в SOC дают задачу «вот лог, найдите аномалию» — и ждут осмысленный grep, а не ручной скролл в текстовом редакторе. Навык быстрого парсинга текстовых данных регулярными выражениями — то, что отделяет специалиста от человека, прочитавшего книгу.
Есть мнение, что CTF — это игрушки, не имеющие отношения к реальной работе. Я с этим категорически не согласен. Каждый решённый таск на поиск флага в дампе тренирует ровно тот мышечный рефлекс, который нужен при разборе инцидента: увидел артефакт — сформулировал паттерн — нашёл в данных. Проблема в том, что большинство новичков распыляются: учат десятки инструментов поверхностно вместо того, чтобы довести до автоматизма три базовых — grep, awk и strings. Один точный grep-конвейер решает задачу быстрее, чем десять минут в GUI-анализаторе. На сотне задач это разница в десятки часов. Если хочется пройти этот фундамент системно, а не собирать по кускам — на IB Basics от Codeby как раз упор на практические навыки, а не на запоминание терминологии.
🚀 Хочешь закрепить на практике? Реши задачи по теме на HackerLab — категория «pentest-machines».
0 комментариев
Пожалуйста, войдите, чтобы оставить комментарий.
Загрузка комментариев...