
На последнем CTF-турнире команда убила 40 минут на один сетевой таск — вручную листали TCP-стримы в Wireshark, переключая вкладки между сотнями HTTP-сессий. Когда я показал, что флаг вытаскивается за три команды в терминале через tshark — фильтр frame matches, экспорт полей и grep — в чате наступила тишина. С тех пор GUI открываю только для визуальной сверки, а весь боевой анализ pcap-дампов идёт через командную строку. Ниже — конкретные приёмы, однострочники и пайплайны, которые позволяют решать сетевые CTF-таски быстрее соперников.
Wireshark — мощная штука для визуального анализа, но на CTF у него три системных ограничения. Первое: ресурсы. Дамп на 500 МБ загружается в оперативку целиком. На слабой виртуалке с 2 ГБ RAM это превращается в слайд-шоу. Tshark обрабатывает тот же файл потоково и не пытается отрисовать миллион строк в интерфейсе. Подробнее — в нашем руководстве по создание ctf заданий.
Второе — повторяемость. Нужно проверить гипотезу на десяти дампах подряд? В GUI это ручная рутина: открыл — отфильтровал — посмотрел — закрыл — открыл следующий. В CLI пишешь for f in *.pcap; do tshark -r "$f" -Y 'frame matches "flag"'; done и получаешь результат за секунды.
Третье — скриптуемость. Вывод tshark — обычный текст. Его можно прогнать через grep, awk, sort | uniq -c | sort -rn и получить статистику мгновенно. Результат GUI — скриншот или ручное копирование. На CTF, где время определяет место в таблице, разница убийственная.
Tshark входит в пакет Wireshark. На Kali и Parrot стоит из коробки. На Ubuntu — sudo apt install tshark. Синтаксис display-фильтров полностью совпадает с Wireshark: знаешь один — знаешь оба. Tshark использует ту же библиотеку libpcap и тот же движок разбора протоколов, что и графическая версия — разница только в способе взаимодействия.
Первое действие с любым дампом — общая картина, а не чтение пакетов по одному. Команда tshark -r challenge.pcap -q -z io,phs выдаёт иерархию протоколов (Protocol Hierarchy Statistics): процентное распределение TCP, UDP, HTTP, DNS, TLS. Если 95% трафика — TLS, а 0.3% — HTTP в открытом виде, именно эти 0.3% нужно ковырять первыми. То же самое окно, что в Wireshark через Statistics → Protocol Hierarchy, но без GUI.
Для списка участников (кто с кем разговаривал) — tshark -r challenge.pcap -q -z conv,tcp. Выводит все TCP-разговоры с объёмом переданных данных и количеством пакетов. Аномалия бросается в глаза сразу: один хост отправил 50 КБ на порт 1337, тогда как остальные работали на 80 и 443. Это признак нестандартных портов — техника Non-Standard Port (T1571 по MITRE ATT&CK). Разбивка по интервалам — tshark -r challenge.pcap -q -z io,stat,10 — покажет количество пакетов каждые 10 секунд. Всплеск на конкретной отметке маркирует начало интересной активности.
Ещё один полезный флаг на старте — tshark -r challenge.pcap -q -z endpoints,ip. Покажет все IP-адреса в дампе с количеством отправленных и полученных байт. Хост, который отправил значительно больше, чем получил — потенциальный источник эксфильтрации (T1041, Exfiltration Over C2 Channel).
Фильтры чтения через опцию -Y — основной инструмент отсеивания шума. По протоколу: tshark -r challenge.pcap -Y "http". По IP-адресу: tshark -r challenge.pcap -Y "ip.addr == 10.0.2.15". Комбинация: tshark -r challenge.pcap -Y "http.request.method == POST and ip.dst == 192.168.1.100" — только POST-запросы к конкретному серверу.
Для CTF критически полезен фильтр frame matches. Он ищет строку по всему содержимому пакета, включая payload. Команда tshark -r challenge.pcap -Y 'frame matches "(?i)flag\{"' находит любой пакет, где встречается паттерн «flag{» в любом регистре. Именно этот фильтр решил задачу за 90 секунд вместо 40 минут ручного листания. В CTF-writeup'ах по PicoCTF frame matches описывается как первый шаг анализа простых сетевых тасков — и не зря.
Другой вариант — contains, который работает на уровне конкретного поля протокола: tshark -r challenge.pcap -Y 'http.file_data contains "CTF{"' ищет паттерн флага внутри тела HTTP-ответов. Для бинарных сигнатур — hex-литералы: tshark -r challenge.pcap -Y 'data contains 50:4b:03:04' находит ZIP-сигнатуру в data-payload.
DNS-анализ: dns.qry.type == 16 отфильтровывает только TXT-записи — частый канал DNS-эксфильтрации (T1071.004 по MITRE ATT&CK). Фильтр dns.qry.name.len > 50 выцепит запросы с аномально длинными доменными именами — маркер DNS-туннелирования. В CTF-тасках DNS-канал встречается настолько часто, что проверку длины поддоменов стоит включать в стандартный чеклист.
HTTP: фильтр http.response.code == 200 and http.content_type contains "octet-stream" показывает успешные загрузки бинарных файлов. Выражение http.request.uri contains ".php" ловит запросы к PHP-скриптам — часто это веб-шеллы или точки вывода данных. Нестандартный User-Agent вроде python-requests/2.28 или curl/7.88 в трафике, где доминирует обычный браузер — маркер автоматизированных запросов (T1071.001, Web Protocols).
FTP: ftp.request.command == "PASS" — перехват паролей в открытом виде. Тут даже комментировать нечего — FTP гоняет credentials plain text'ом, и это подарок на CTF.
ICMP: icmp.type == 8 — echo-запросы. В CTF payload ICMP-пакетов часто содержит скрытые данные (T1095, Non-Application Layer Protocol).
Флаг -T fields в сочетании с -e — то, что превращает tshark из просмотрщика пакетов в генератор структурированных данных. Вместо полного текстового дампа получаешь только нужные поля в табличном формате, готовом для обработки unix-утилитами.
Извлечение всех DNS-запросов одной командой: tshark -r challenge.pcap -Y "dns.qry.name" -T fields -e dns.qry.name. Каждая строка — один запрошенный домен. Дальше | sort | uniq -c | sort -rn | head -20 выстраивает топ-20 запрашиваемых доменов по частоте. Если один домен запрошен 500 раз, а остальные — по 1-5, это красный флаг.
DNS-туннелирование в CTF обычно реализовано так: данные закодированы в поддоменах. Запрос к aGVsbG8gd29ybGQ.evil.com — это base64-строка «hello world», упакованная в поддомен. Полный пайплайн для извлечения и декодирования:
tshark -r challenge.pcap -Y "dns.qry.name contains evil.com" \
-T fields -e dns.qry.name | \
awk -F. '{print $1}' | \
tr -d '\n' | base64 -d
Разбор по элементам: tshark фильтрует запросы к evil.com и выводит полное доменное имя. awk -F. разрезает по точкам и берёт первый фрагмент (закодированные данные). tr -d '\n' склеивает строки. base64 -d декодирует результат. В зависимости от задания может потребоваться hex-декодирование (xxd -r -p) вместо base64 — определяется по виду данных.
Для TXT-ответов (когда сервер возвращает данные через DNS TXT records): tshark -r challenge.pcap -Y "dns.txt and dns.flags.response == 1" -T fields -e dns.txt. TXT-записи — второй по популярности канал DNS-эксфильтрации: сервер кладёт порцию данных в TXT-ответ, клиент собирает фрагменты.
Полный лог HTTP-запросов в CSV-формате, готовый для импорта в таблицу или обработки через awk:
tshark -r challenge.pcap -Y "http.request" \
-T fields -e frame.time -e ip.src -e ip.dst \
-e http.request.method -e http.host \
-e http.request.uri -e http.user_agent \
-E header=y -E separator=,
Опция -E header=y добавляет строку с названиями колонок, -E separator=, задаёт разделитель. На выходе — структурированная таблица: кто, куда, каким методом и с каким User-Agent обращался. Для извлечения уникальных User-Agent: tshark -r challenge.pcap -Y "http.user_agent" -T fields -e http.user_agent | sort -u.
POST-данные (отправленные формы, credentials, загруженные файлы): tshark -r challenge.pcap -Y "http.request.method == POST" -T fields -e http.file_data. Всё, что передавалось в теле POST-запроса, окажется в выводе. Если в задании есть логин-форма, отправленная по HTTP без TLS — credentials будут тут в чём мать родила.
Tshark умеет делать то же, что Wireshark через File → Export Objects → HTTP, но из терминала: tshark -r challenge.pcap --export-objects http,./exported/. Команда создаёт директорию exported и складывает туда все файлы, переданные по HTTP — картинки, архивы, скрипты, HTML-страницы. Дальше стандартная проверка: file exported/* покажет реальные типы файлов (расширение может врать), а strings exported/* | grep -i flag пробежит по текстовым данным в поисках флага. Аналогично работают --export-objects smb,./smb_files/ и --export-objects tftp,./tftp_files/ для SMB и TFTP-передач.
Каждое TCP-соединение в дампе имеет номер стрима. Список уникальных номеров: tshark -r challenge.pcap -T fields -e tcp.stream | sort -un. Просмотр конкретного стрима в ASCII: tshark -r challenge.pcap -q -z follow,tcp,ascii,0 — покажет содержимое стрима номер 0 как текст. Для бинарных данных ascii заменяется на hex или raw. Экспорт сырого payload стрима в файл: tshark -r challenge.pcap -q -z follow,tcp,raw,5 | xxd -r -p > stream5.bin — полезно, когда файл передавался без HTTP-обёртки (через FTP-data или кастомный протокол).
Отдельный блок — credential hunting (T1040, Network Sniffing по MITRE ATT&CK). Для FTP: tshark -r challenge.pcap -Y "ftp.request.command == USER or ftp.request.command == PASS" -T fields -e ftp.request.command -e ftp.request.arg выведет пары логин/пароль. Для HTTP Basic Auth: tshark -r challenge.pcap -Y "http.authorization" -T fields -e http.authorization — результат вида Basic dXNlcjpwYXNzd29yZA==, который декодируется через echo "dXNlcjpwYXNzd29yZA==" | base64 -d. SMTP-credentials: tshark -r challenge.pcap -Y "smtp.req.command == AUTH" -T fields -e smtp.req.parameter. В CTF флаг нередко зашит именно в перехваченный пароль.
Классика CTF — данные, спрятанные в payload ICMP echo-запросов. Извлечение: tshark -r challenge.pcap -Y "icmp.type == 8" -T fields -e data.data выводит hex-содержимое каждого пакета. Конвертируем в текст: пайплайн | tr -d ':\n' | xxd -r -p склеит куски и переведёт из hex в ASCII. Если данные побайтовые (один символ на пакет), каждый ICMP-пакет несёт ровно одну букву, порядок определяется по timestamp. Если блоками — конкатенация без разделителей. По данным ctf.support, ICMP и DNS tunneling — два самых частых вектора скрытых каналов в сетевых CTF-задачах.
Для DNS TXT-эксфильтрации (данные в ответах сервера) команду уже привёл выше. Нюанс: иногда данные раскиданы по нескольким TXT-ответам с порядковыми номерами в поддоменах (1.exfil.evil.com, 2.exfil.evil.com). Тут нужно сортировать по номеру перед конкатенацией — bash-однострочник уже не справляется, нужен Python.
Кастомные протоколы. Если tshark -r challenge.pcap -q -z conv,tcp показывает активность на порту 1337 или 31337, с вероятностью 90% это кастомный протокол задания. Просматриваем стрим: tshark -r challenge.pcap -Y "tcp.port == 1337" -q -z follow,tcp,ascii,N, где N — номер стрима. Часто внутри обнаруживается текстовый протокол с командами и ответами, среди которых прячется флаг. Я на таких портах ни разу не видел ничего легитимного — 1337 и 31337 в CTF это как неоновая вывеска «копай сюда».
На каждом CTF запускаю команды в фиксированном порядке. Алгоритм выработан за десятки тасков по network forensics:
Шаг 1 — грубый поиск флага: tshark -r task.pcap -Y 'frame matches "(?i)(flag|ctf)\{"' -x. Флаг -x добавляет hex-дамп для контекста. Удивительно, как часто флаг валяется в открытом виде.
Шаг 2 — иерархия протоколов: tshark -r task.pcap -q -z io,phs. Определяем доминирующие и редкие протоколы.
Шаг 3 — экспорт HTTP-объектов: tshark -r task.pcap --export-objects http,./objects/. Проверяем через file и strings.
Шаг 4 — DNS-аномалии: tshark -r task.pcap -Y "dns.qry.name" -T fields -e dns.qry.name | sort | uniq -c | sort -rn | head -20.
Шаг 5 — список TCP-стримов: tshark -r task.pcap -T fields -e tcp.stream | sort -un. Каждый подозрительный стрим просматриваем через -z follow,tcp,ascii,N.
Шаг 6 — ICMP payload: tshark -r task.pcap -Y "icmp" -T fields -e data.data.
Шаг 7 — credentials: tshark -r task.pcap -Y "ftp.request.command == PASS or http.authorization or smtp.req.command == AUTH".
Шаг 8 — файловые сигнатуры в payload: tshark -r task.pcap -Y 'data contains 50:4b:03:04 or data contains 89:50:4e:47 or data contains ff:d8:ff' — ZIP, PNG и JPEG соответственно.
Этот алгоритм покрывает большинство сетевых CTF-задач уровня Easy–Medium. Выглядит банально, но экономит 70% времени, потому что покрывает типовые сценарии до того, как начнёшь думать. Для Hard — добавляется TLS-расшифровка (если в задании дан ключ через -o tls.keylog_file:keys.log) и разбор кастомных бинарных протоколов.
Пакетная обработка серии дампов: for f in challenges/*.pcap; do echo "=== $f ===" && tshark -r "$f" -Y 'frame matches "(?i)flag"' 2>/dev/null; done. Перенаправление 2>/dev/null подавляет предупреждения о формате файла.
Когда bash-однострочников уже не хватает — например, нужно собрать данные из DNS-поддоменов в правильном порядке или декодировать многоступенчатую обфускацию — подключаю Python с subprocess:
import subprocess, base64
result = subprocess.run(
["tshark", "-r", "challenge.pcap", "-Y",
"dns.qry.name contains evil.com",
"-T", "fields", "-e", "dns.qry.name"],
capture_output=True, text=True
)
parts = [line.split(".")[0]
for line in result.stdout.strip().split("\n") if line]
print(base64.b64decode("".join(parts)).decode())
Скрипт делает то же, что bash-пайплайн, но с полным контролем над порядком фрагментов и обработкой ошибок. Для продвинутых тасков — когда данные идут не в порядке DNS-запросов, а привязаны к sequence number'у или timestamp'у — Python незаменим. Достаточно добавить поле -e frame.number или -e frame.time_epoch в вызов tshark и отсортировать результат перед конкатенацией.
Вариант для ICMP-канала: заменяем фильтр на icmp.type == 8, поле на data.data, а вместо base64 используем bytes.fromhex() для конвертации hex-payload. Логика та же — tshark извлекает, Python собирает и декодирует.
Бывают ситуации, где формула «tshark → текст → grep/awk» ломается: бинарные протоколы с кастомными заголовками, где нет стандартного диссектора. Тогда экспортируем сырой стрим через tshark -r challenge.pcap -q -z follow,tcp,raw,N, парсим hex в Python и разбираем структуру вручную. Не самая приятная работа, но на Hard-тасках без этого никуда.
На практике 80% сетевых тасков укладываются в формулу «tshark + 2-3 стандартные unix-утилиты». Оставшиеся 20% требуют Python-обвязки или подключения NetworkMiner для автоматической реконструкции файлов, Zeek для генерации структурированных логов. Но стартовая точка всегда одна — tshark и его флаг -T fields.
Главная проблема с сетевыми тасками на CTF — не нехватка инструментов, а привычка к GUI. Wireshark учат первым, и участники застревают в нём. На тренировках это допустимо, на соревнованиях — нет. За два года я не встретил ни одного CTF-таска по network forensics, который решался бы быстрее через графический интерфейс, чем через tshark с тремя-четырьмя утилитами в пайплайне. Отдельная беда — отсутствие системного подхода. Новичок открывает pcap и листает пакеты сверху вниз, надеясь наткнуться на что-то интересное. На дампе в 200 пакетов это работает, на 50 000 — путь в никуда. Чеклист из восьми шагов выше экономит 70% времени, потому что покрывает типовые сценарии до того, как начнёшь думать. DNS-эксфильтрация (T1071.004) и ICMP-каналы (T1095) — два самых частых вектора в сетевых CTF-тасках, но русскоязычных разборов с конкретными командами tshark по ним до сих пор почти нет. Если хочешь не просто один writeup, а пройти всю атаку самому и закрепить навык — на WAPT есть лаба с этим вектором и ментор в чате при затыке.
🚀 Хочешь закрепить на практике? Реши задачи по теме на HackerLab — категория «forensics».
0 комментариев
Пожалуйста, войдите, чтобы оставить комментарий.
Загрузка комментариев...