
Forensics-задача на CTF: pcap-дамп на 140 МБ, внутри тысячи строк HTTP-логов, а флаг формата flag{...} зарыт в base64-кодированном теле одного из ответов. Без регулярных выражений это полчаса ручного скроллинга через Wireshark с надеждой, что глаз зацепится за нужную строку. С тремя командами в bash и одним вызовом re.findall в Python — меньше минуты от открытия файла до сдачи флага.
Я постоянно вижу, как люди на CTF тратят время на то, что решается одной регуляркой. Регулярные выражения CTF-игроку нужны не реже, чем nmap для сканирования или binwalk для анализа бинарей: они превращают хаотичный вывод инструментов в структурированные данные и вытаскивают флаги из любой каши — текстовой, бинарной, кодированной. Ниже — конкретные паттерны, готовые команды grep и Python-скрипты, которые работают прямо во время таймера соревнования.
Прежде чем писать регулярку, нужно точно знать, что ищем. Каждая CTF-платформа использует свой формат флага, но структура почти всегда одинаковая: префикс, фигурные скобки, содержимое внутри.
| Платформа | Формат | Пример |
|---|---|---|
| Стандартный | flag{...} | flag{r3gex_m4ster} |
| HackTheBox | HTB{...} | HTB{p4rs3d_1t} |
| TryHackMe | THM{...} | THM{fl4g_f0und} |
| PicoCTF | picoCTF{...} | picoCTF{s1mpl3_f1nd} |
| Произвольный | FLAG{...}, ctf{...} | FLAG{UPPER_CASE_TOO} |
Согласно Capture The Flag Cheatsheet, типичные места хранения флагов — /root/root.txt, домашние директории пользователей, переменные окружения (env), HTTP-заголовки, cookies, исходный код JavaScript и дампы баз данных. Зная формат и расположение, уже можно собирать паттерн regex.
Универсальный паттерн для поиска флагов: [A-Za-z0-9_]+\{[^\}]+\}. Разберём по кускам. [A-Za-z0-9_]+ ловит префикс — одну или более букв, цифр или подчёркиваний. Сюда попадут и flag, и HTB, и picoCTF. \{ и \} — экранированные фигурные скобки (в regex они означают квантификатор, поэтому без экранирования нельзя). [^\}]+ — один или более любых символов, кроме закрывающей скобки. Именно «кроме» — если написать .+, жадный квантификатор проглотит всё до последней } в строке и захватит лишнее.
Для автоматизации часто нужно не просто найти флаг целиком, а вытащить его содержимое отдельно. Тут работают захватывающие группы — круглые скобки вокруг нужной части паттерна. Выражение flag\{([^\}]+)\} вернёт только содержимое внутри скобок, без самого flag{ и }.
Второй частый случай — поиск флагов нескольких платформ одним паттерном. Тут помогает чередование через | внутри незахватывающей группы: (?:flag|CTF|HTB|THM|picoCTF)\{[^\}]{1,100}\}. Квантификатор {1,100} ограничивает длину содержимого — защита от ситуации, когда жадный квантификатор захватывает половину файла при отсутствии закрывающей скобки в ожидаемом месте.
Элементы regex, которые постоянно нужны на CTF:
| Элемент | Что делает | Типичное применение |
|---|---|---|
[A-Fa-f0-9] |
Hex-символ | Поиск хешей, hex-строк |
[A-Za-z0-9+/]=* |
Base64-символ | Обнаружение кодированных данных |
\b |
Граница слова | Отсечение ложных срабатываний |
(?i) |
Игнорировать регистр | Поиск FLAG и flag одновременно |
(...) |
Захват группы | Извлечение содержимого флага |
[^\}]+ |
Всё кроме } |
Содержимое внутри фигурных скобок |
(?:...\|...) |
Чередование без захвата | Поиск по нескольким префиксам |
Этого набора хватает, чтобы закрыть большинство задач на flag extraction. Для отладки паттернов прямо во время соревнования — regex101.com. Вставляете тестовые данные, пишете regex, видите совпадения в реальном времени с пояснением каждого элемента. Быстрее, чем перезапускать скрипт на каждое изменение в паттерне.
-P для PCRE), strings из пакета binutils, base64 из coreutilsre (стандартная библиотека, установка не нужна)Самый быстрый способ найти флаг на CTF — grep прямо в терминале. Не нужно открывать Python, не нужен Jupyter Notebook, не нужен даже текстовый редактор. Три команды покрывают 90% ситуаций.
# Рекурсивный поиск флагов всех платформ в директории
grep -rEo '[A-Za-z0-9_]+\{[A-Za-z0-9_!@#$%^&*()+,.\-]+\}' ./files/
# Поиск в бинарном файле через strings
strings binary.elf | grep -Ei 'flag|ctf|htb|thm'
# Извлечение флага из pcap-дампа (текстовые протоколы)
strings dump.pcap | grep -oP '(?:flag|CTF|HTB)\{[^\}]+\}'
# Найти все файлы с подстрокой flag{ в файловой системе
find / -name "*.txt" 2>/dev/null | xargs grep -l 'flag{'
Разберём флаги grep, которые превращают его в CTF-инструмент. -r — рекурсивный поиск по всем файлам в директории, не нужно угадывать, в каком файле спрятан флаг. -E активирует расширенные регулярные выражения (Extended Regex), где +, | и () работают без экранирования. -o выводит только совпавшую подстроку, а не целую строку — критично, когда строка содержит тысячи символов. -i отключает чувствительность к регистру. А -P переключает движок на PCRE (Perl-Compatible Regular Expressions) и открывает доступ к незахватывающим группам (?:...), lookahead и lookbehind.
Типичная ошибка новичков — запускать grep по бинарным файлам напрямую. Бинарник содержит нечитаемые символы, и grep либо пропустит совпадение, либо выведет мусор. Решение — пропустить файл через strings, которая извлекает все ASCII-последовательности длиннее 4 символов, и уже по этому выводу искать флаг. Конвейер strings file | grep -oP 'pattern' — один из самых частых приёмов на CTF, особенно в категориях forensics и reverse engineering. Тот же подход рекомендуется в Capture The Flag Cheatsheet.
Для pcap-дампов strings тоже годится — извлечёт текстовые фрагменты без необходимости разбирать пакеты на уровне протоколов. Если нужна точность, tshark -r dump.pcap -T fields -e http.response.body выдаст тела HTTP-ответов, к которым применяется тот же grep -oP.
Команда find / -name "*.txt" 2>/dev/null | xargs grep -l 'flag{' заслуживает отдельного внимания. Флаг -l выводит только имена файлов, без содержимого — удобно для быстрой разведки по файловой системе скомпрометированной машины. По классификации MITRE ATT&CK это аналог техники File and Directory Discovery (T1083, Discovery) — тот же приём используют атакующие для поиска чувствительных данных.
Ограничение grep: на файлах свыше 1 ГБ поиск может занять десятки секунд. Помогает предварительная фильтрация через head -n 50000 или поиск только в конкретных поддиректориях. Ещё одно ограничение — grep работает только с текстом. Если флаг закодирован в base64 или hex, grep найдёт кодированную строку, а не сам флаг. Для декодирования нужен Python.
Когда задача сложнее, чем однострочник в bash, открывается Python. Модуль re входит в стандартную библиотеку и не требует установки. Три функции закрывают все потребности: re.findall() возвращает список всех совпадений, re.search() находит первое совпадение и возвращает объект Match с доступом к группам, а re.sub() заменяет совпадения — полезно для очистки данных перед следующим этапом.
Разница между re.findall и re.search на практике ощутима. Если в дампе десять флагов (такое бывает в misc-задачах), re.findall вернёт все десять за один вызов. А re.search остановится на первом — зато даст доступ к именованным группам и позиции совпадения в строке.
import re
data = open("dump.txt", "r", errors="ignore").read()
# Универсальный паттерн для всех популярных платформ
pattern = r'(?:flag|CTF|HTB|THM|picoCTF)\{[^\}]{1,100}\}'
flags = re.findall(pattern, data, re.IGNORECASE)
for f in flags:
print(f"[+] Найден: {f}")
# С захватом содержимого: re.search + именованная группа
m = re.search(r'flag\{(?P<content>[^\}]+)\}', data)
if m: print(f"[+] Содержимое: {m.group('content')}")
Параметр errors="ignore" при открытии файла — обязателен. Без него Python упадёт на бинарных или смешанных файлах с ошибкой декодирования. re.IGNORECASE ловит все варианты регистра: FLAG{}, Flag{}, flag{}. Квантификатор {1,100} — явное ограничение длины, предотвращает захват мусора при отсутствии закрывающей скобки.
Именованная группа (?P<content>...) — штука для читаемости. Вместо m.group(1) пишется m.group('content') — через три часа после старта CTF это реально спасает от путаницы в собственных скриптах. Для работы с сетевым взаимодействием в CTF-задачах библиотека pwntools (активно поддерживается, репозиторий Gallopsled/pwntools на GitHub) позволяет комбинировать regex с отправкой и приёмом данных через сокеты — r.recvline() + re.search() дают возможность парсить ответ сервера и автоматически формировать следующий запрос.
Самая частая ситуация на forensics-тасках: флаг закодирован в base64 или hex и спрятан внутри большого текстового файла. Ручной подход — копировать каждый подозрительный блок в CyberChef и декодировать по одному. Нудно и медленно. Автоматический — написать скрипт на десять строк.
import re, base64, sys
raw = open(sys.argv[1], "rb").read()
text = raw.decode("utf-8", errors="ignore")
# Ищем base64-блоки длиной от 20 символов
b64_chunks = re.findall(r'[A-Za-z0-9+/]{20,}={0,2}', text)
for chunk in b64_chunks:
try:
decoded = base64.b64decode(chunk).decode("utf-8", errors="ignore")
found = re.findall(r'[A-Za-z0-9_]+\{[^\}]+\}', decoded)
if found: print(f"[+] Base64 -> {found}")
except Exception: pass
Логика простая: regex [A-Za-z0-9+/]{20,}={0,2} вытаскивает все строки, похожие на base64 — минимум 20 символов из алфавита base64 с необязательными паддинговыми = в конце. Потом каждый кусок декодируется, и по результату ещё раз прогоняется поиск флагов. try/except тут обязателен — далеко не все строки, похожие на base64, реально ею являются, и b64decode выбросит исключение на мусоре.
Тот же подход работает для hex-строк. Паттерн [0-9a-fA-F]{20,} вытаскивает подозрительные hex-последовательности, а bytes.fromhex(chunk).decode() декодирует их в текст. CyberChef решает ту же задачу через GUI — полезно для разовой отладки, но не для автоматизации десятков фрагментов в одном файле.
По классификации MITRE ATT&CK скрипт реализует технику Deobfuscate/Decode Files or Information (T1140) — ровно то, что делают атакующие при работе с обфусцированными payload'ами. Навык декодирования через regex напрямую переносится из CTF в реальную работу: парсинг логов, извлечение IOC из образцов малвари, анализ C2-трафика с кодированием Standard Encoding (T1132.001, Command and Control).
Флаги — только часть CTF-задач. Вторая половина рабочего времени уходит на парсинг вывода инструментов: вытащить IP-адреса из nmap, извлечь URL из HTML-страницы, отфильтровать интересные строки из вывода strings. Regex справляется с этим быстрее любого GUI. По MITRE ATT&CK это техника Automated Collection (T1119, Collection) — автоматизированный сбор данных, только в CTF-контексте.
Для извлечения IP-адресов из текстового вывода: \b\d{1,3}(?:\.\d{1,3}){3}\b. Конструкция \b (граница слова) отсекает ложные срабатывания, когда числа через точку встречаются внутри длинных строк. grep -oP '\b\d{1,3}(\.\d{1,3}){3}\b' nmap_output.txt — чистый список IP, готовый для подстановки в следующую команду.
Для парсинга открытых портов из вывода nmap работает grep -oP '\d+/open' — ловит строки вроде 22/open, 80/open, 443/open. Нужны только номера без /open? grep -oP '\d+(?=/open)' с lookahead. Результат можно сразу подставить в прицельное сканирование: nmap -sV -p $(grep -oP '\d+(?=/open)' scan.txt | tr '\n' ',') target — два конвейера заменяют ручное копирование портов.
Для извлечения URL из HTML-страниц или HTTP-заголовков: https?://[^\s"'<>]+. Ловит протокол http или https, двоеточие с двойным слешем, затем всё до первого пробела, кавычки или угловой скобки. На CTF это полезно при анализе web-задач: скачать страницу через curl -s, прогнать regex и найти скрытые эндпоинты, которые не видны в браузере.
Паттерны для поиска специфичных артефактов через grep -oP:
| Артефакт | Паттерн | Где встречается |
|---|---|---|
[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,} |
OSINT, forensics | |
| MD5-хеш | \b[a-fA-F0-9]{32}\b |
Crypto, forensics |
| SHA256-хеш | \b[a-fA-F0-9]{64}\b |
Password cracking |
| JWT-токен | eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+ |
Web-задачи |
| IPv4-адрес | \b\d{1,3}(\.\d{1,3}){3}\b |
Network, recon |
| MAC-адрес | ([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2} |
Forensics |
Про JWT отдельно: он всегда начинается с eyJ — это base64url-кодированный {". Найти JWT в дампе трафика — частый шаг в web-задачах, потому что внутри токена могут лежать как флаг, так и данные для следующего этапа. Декодируется просто: разделить по точкам, декодировать первые две части (header и payload) из base64url. Через Python или base64 -d.
Для forensics-задач с анализом логов полезен контекстный поиск — grep -B2 -A2 'pattern' logfile.txt выводит две строки до и две после каждого совпадения. Помогает понять, откуда пришёл запрос с подозрительным payload, какой ответ вернул сервер, что произошло вокруг.
Regex — штука хорошая, но не всесильная. Есть сценарии, где регулярки либо не работают, либо дают ложные результаты. Знать эти границы не менее важно, чем знать сами паттерны.
Зашифрованные и сжатые данные. Если файл зашифрован (AES, XOR с неизвестным ключом) или упакован (gzip, bzip2 внутри бинаря), текстовый поиск бесполезен до расшифровки или распаковки. Тут нужен binwalk -e (автоматическая распаковка встроенных архивов) или xortool для XOR-шифрования. Regex применяется уже к результату.
Вложенные фигурные скобки. Паттерн [^\}]+ сломается на флаге вида flag{json{"key":"value"}} — остановится на первой }, не захватив содержимое целиком. Для таких случаев нужен рекурсивный regex, который поддерживается в PCRE (GNU grep с флагом -P), но не в стандартном модуле Python re. Альтернатива — модуль regex для Python (pip install regex), поддерживающий рекурсивные паттерны. На практике вложенные скобки в CTF-флагах встречаются редко — обычно содержимое состоит из алфавитно-цифровых символов и подчёркиваний.
Производительность на больших файлах. Файлы больше 1 ГБ могут вызвать проблемы при загрузке целиком через open().read(). Решение — построчное чтение (for line in open(file)) или потоковая обработка через модуль mmap. Для grep это не проблема — он обрабатывает файл построчно по умолчанию.
Стеганография. Данные, спрятанные в младших битах (LSB) пикселей PNG или в метаданных EXIF, невидимы ни для grep, ни для strings. Тут нужны steghide, zsteg, exiftool. Regex применяется уже после извлечения скрытых данных — к тексту, полученному из стего-контейнера.
Ложные срабатывания. Универсальный паттерн [A-Za-z0-9_]+\{[^\}]+\} ловит не только флаги, но и фрагменты C/C++ кода (main{...}), CSS-правила (body{...}), JSON-фрагменты. Если в дампе много кода, лучше сузить паттерн до конкретного префикса: (?:flag|CTF|HTB)\{[^\}]+\}. Точность здесь важнее универсальности — ложное срабатывание на CTF стоит потерянного времени на проверку.
Навык работы с regex переносится из CTF в работу напрямую. Аналитик SOC использует те же паттерны для извлечения IOC из логов. Пентестер — для парсинга вывода инструментов разведки. Разработчик detection-правил пишет Sigma-правила с regex-условиями. Разница не в технике, а в масштабе: на CTF ищем flag{...} в одном файле, на проекте — адреса C2-серверов в терабайтах событий.
Часто вижу, как новички на CTF тратят час на написание «красивого» парсера с обработкой ошибок, логированием и argparse. На соревновании это антипаттерн. Скрипт живёт ровно до сдачи флага — десять строк в Python, три пайпа в bash, никакой архитектуры. Рефакторить можно потом, в writeup-блоге. Привычка писать regex на скорость — одна из тех вещей, которая отделяет участников, застревающих на первых задачах, от тех, кто стабильно закрывает forensics за первый час.
Три паттерна для флагов, два конвейера в bash, один скрипт-декодер — этого хватает для 80% задач. Остальные 20% приходят с практикой и разбором чужих writeup'ов. Если хочется пройти базу системно от терминала до первых задач — на IB Basics в Codeby School эту цепочку разбирают с нуля.
🚀 Хочешь закрепить на практике? Реши задачи по теме на HackerLab — категория «pentest-machines».
0 комментариев
Пожалуйста, войдите, чтобы оставить комментарий.
Загрузка комментариев...