Главная / Блог / Bash скрипты для CTF: автоматизация перебора, обработки вывода и работы с файлами

14 мин.00

Bash скрипты для CTF: автоматизация перебора, обработки вывода и работы с файлами

Bash скрипты для CTF: автоматизация перебора, обработки вывода и работы с файлами

Bash скрипты для CTF: автоматизация перебора, обработки вывода и работы с файлами

Три минуты и 14 строк кода. Столько понадобилось bash-скрипту, чтобы перебрать 1200 эндпоинтов на веб-сервере задачи категории Web, обнаружить скрытый /backup/flag.txt и вытащить флаг — при том, что трое участников команды до этого 20 минут тыкали URL-ы вручную. На CTF-соревнованиях уровня PicoCTF, HTB и TryHackMe разница между первым и десятым местом часто определяется не глубиной знаний, а скоростью рутинных операций. Bash-скрипты — тот инструмент, который конвертирует знания в скорость.

Место Bash-скриптов в цепочке решения CTF-задач

Куда Bash вписывается в типовой workflow решения таска? В терминах MITRE ATT&CK Unix Shell (T1059.004, Execution) — это средство исполнения, через которое проходят остальные техники: от File and Directory Discovery (T1083) до Automated Collection (T1119). В CTF-контексте цепочка выглядит так:

  1. Разведка и перечисление. Сканирование портов, перебор директорий, сбор баннеров. Bash организует вызовы nmap, ffuf, gobuster и парсит их вывод.
  2. Анализ и фильтрация. Из гигабайта вывода нужно выдернуть одну строку с флагом или подсказкой. Тут работают grep, sed, awk в пайпах.
  3. Эксплуатация. Автоматические HTTP-запросы через curl, подбор паролей, перебор параметров. Password Guessing (T1110.001) и Password Spraying (T1110.003) на уровне скриптов.
  4. Извлечение данных. Поиск файлов, декодирование base64, XOR, hex. Data from Local System (T1005) в чистом виде.

Bash не заменяет специализированные инструменты — он их склеивает. Один пайп из curl | grep | base64 -d заменяет пять минут ручных действий.

Требования к окружению

Все примеры проверены на следующей конфигурации:

  • ОС: Kali Linux 2024.x, Ubuntu 22.04+ (подойдёт любой дистрибутив с bash 4.0+; macOS по умолчанию поставляет bash 3.2 — нужно обновление через brew install bash)
  • RAM: 2 ГБ минимум — сами скрипты нетребовательны
  • Утилиты из коробки: bash, grep, sed, awk, curl, find, base64, xxd, strings — входят в стандартную поставку coreutils
  • Дополнительно: nmap, ffuf, jq (для отдельных примеров, устанавливаются через apt install)
  • Сеть: онлайн — для веб-задач; офлайн — для форензики, крипто, реверса

Автоматизация CTF bash: циклы, подстановки и брутфорс

Перебор — хлеб CTF-игрока. Скрытые директории, параметры запросов, пароли из wordlist, числовые идентификаторы — всё это перемалывается циклами. Цикл for в bash с brace expansion — самый быстрый способ запустить перебор без установки чего-либо дополнительного.

Перебор директорий и эндпоинтов

Самый частый сценарий в задачах категории Web: есть URL, есть wordlist, нужно найти скрытый path. Да, есть ffuf и gobuster, но иногда задача требует нестандартной логики — кастомных заголовков, проверки содержимого ответа вместо статус-кода, или цепочки действий после обнаружения.

#!/bin/bash
set -euo pipefail
while IFS= read -r dir; do
  code=$(curl -s -o /dev/null -w "%{http_code}" "http://target.ctf/$dir")
  if [ "$code" != "404" ]; then
    echo "[${code}] /$dir"
  fi
done < wordlist.txt

Разберём построчно — тут три места, где начинающие спотыкаются. IFS= read -r корректно обрабатывает строки с пробелами и спецсимволами. Типичная ошибка новичков: писать for dir in $(cat wordlist.txt), а потом ловить баги на именах с пробелами. Флаг -s убирает прогресс-бар curl, -o /dev/null отбрасывает тело ответа, -w "%{http_code}" возвращает только HTTP-статус. Конструкция set -euo pipefail в начале — страховка от тихих ошибок (подробнее об этом ниже).

[Применимо: CTF-задачи категории Web, тренировочные платформы. На реальном внешнем пентесте используйте ffuf или gobuster — они многопоточные, поддерживают рекурсию и умеют фильтровать по размеру ответа.]

Для перебора числовых ID — частый паттерн в задачах на IDOR и broken access control (OWASP A01:2021) — достаточно brace expansion прямо в терминале: for i in {1..1000}; do curl -s "http://target/api/user/$i" | grep -q "flag{" && echo "Found at $i" && break; done. Команда grep -q работает в тихом режиме (без вывода), а оператор && запускает echo только при совпадении. Весь перебор — однострочник, который вставляется прямо в терминал без создания файла.

Bash скрипт перебор паролей CTF

Password Guessing (T1110.001) через Bash — не самый быстрый способ. Для серьёзного брутфорса есть hydra и john. Но на CTF часто попадаются задачи с кастомным форматом запроса, который ни один стандартный инструмент не переварит из коробки: нестандартный JSON, токен в ответе предыдущего запроса, проверка по содержимому, а не по статус-коду.

#!/bin/bash
while IFS= read -r pass; do
  resp=$(curl -s -X POST "http://target/login" \
    -H "Content-Type: application/json" \
    -d "{\"user\":\"admin\",\"pass\":\"$pass\"}")
  echo "$resp" | grep -qv "Invalid" && \
    echo "Found: $pass" && echo "$resp" && break
done < passwords.txt

Нюансы, на которых спотыкаются:

  • Спецсимволы в паролях. Если пароль содержит $, !, ", конструкция с прямой подстановкой сломается. Надёжнее формировать JSON через jq: jq -n --arg p "$pass" '{"user":"admin","pass":$p}' и передавать через curl -d @-.
  • Скорость. Однопоточный while-цикл — это 2-5 запросов в секунду. Для CTF-wordlist в 500 строк — хватит за глаза. Для 100k записей — категорически нет. Параллелизацию можно прикрутить через xargs -P 10 или GNU parallel, но на соревнованиях с ограниченным списком кандидатов это редко нужно.
  • Rate limiting. Некоторые CTF-площадки вводят ограничения по частоте. Добавьте sleep 0.1 внутри цикла, чтобы не словить бан или ложные срабатывания WAF.

В разборе AUCTF 2020 (Bash Level 3) участники перебирали значение $RANDOM (диапазон 0-32767), которое генерировалось в bash-скрипте на целевой машине. Подход: запустить целевой скрипт через sudo, параллельно в соседнем терминале перебрать все 32768 значений. На bash это решается за секунды через for i in $(seq 0 32767); do ... done — brace expansion {0..32767} работает аналогично.

Обработка вывода bash grep sed awk в CTF

Вывод инструментов в терминале — поток текста. Задача — превратить его в конкретный ответ. Тройка grep + sed + awk закрывает 95% сценариев парсинга.

Извлечение флагов из шумного вывода

Формат флага почти всегда известен заранее: flag{...}, CTF{...}, picoCTF{...}. Это делает grep с регулярным выражением идеальным инструментом. Базовый паттерн: grep -oE 'flag\{[A-Za-z0-9_]+\}' output.txt. Флаг -o выводит только совпадение, не всю строку, -E включает расширенные регулярки. Если формат нестандартный — адаптируйте: grep -oEi '[a-z]+\{[^\}]+\}' ловит любой prefix{content}.

Для рекурсивного поиска по файловой системе: grep -rn 'flag{' /path/to/challenge/. Флаг -r — рекурсия, -n — номер строки. На CTF-машине после получения shell первым делом стоит запустить grep -rn 'flag{' / 2>/dev/null — перенаправление 2>/dev/null подавляет ошибки доступа и не засоряет терминал.

Парсинг результатов сканеров и построение пайпов

nmap выдаёт развёрнутый отчёт, а нужны только открытые порты. Однострочник awk '/^[0-9]+\/tcp.*open/ {split($1,a,"/"); print a[1]}' scan.txt из строки 80/tcp open http вытаскивает 80. Якорь ^[0-9]+\/tcp исключает ложные срабатывания на строках вроде Not shown: 999 closed ports, а split заменяет отдельный вызов cut. Упрощённый вариант grep 'open' | awk | cut тоже работает, но может давать false positives на строках, содержащих слово «open» в описании сервиса.

Более жизненный пример — сканирование подсети с автоматическим запросом к найденным хостам. Задача: найти хосты с открытым портом 8080 и сразу проверить, отдают ли они флаг:

#!/bin/bash
for ip in 10.0.0.{1..50}; do
  nmap -p 8080 --open -T4 "$ip" 2>/dev/null | grep -q "open" && \
    flag=$(curl -s "http://${ip}:8080/flag" 2>/dev/null) && \
    [ -n "$flag" ] && echo "$ip: $flag"
done

Цепочка nmap (разведка) → grep (фильтрация) → curl (извлечение) — три этапа workflow в шести строках. Флаг --open у nmap показывает только открытые порты, -T4 ускоряет сканирование, а grep -q тихо проверяет наличие слова "open" без вывода на экран.

sed для трансформации. Классический CTF-паттерн: из ответа сервера нужно вырезать токен, обернуть в другой формат и отправить обратно. Сервер отдаёт Token: ABC123XYZ, ожидает ответ answer=ABC123XYZ. Извлечение: token=$(echo "$response" | sed -n 's/Token: \(.*\)/\1/p'). Конструкция sed -n 's/.../\1/p' совмещает поиск и извлечение — работает как grep с захватом группы.

awk для структурированных данных. Если CTF-задача отдаёт CSV или таблицу, awk -F',' '{print $3}' вытаскивает третью колонку. Для частотного анализа (полезно в форензике и крипто): awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10 — показывает 10 самых частых значений первого поля. Тот же паттерн работает для анализа IP-адресов в логах, частотности символов в шифротексте, повторяющихся строк в дампах.

curl bash автоматизация запросов для Web-категории

Категория Web в CTF почти всегда сводится к HTTP-запросам. Браузер удобен для первичной разведки, но для эксплуатации нужен curl — полный контроль над заголовками, cookies, методом и телом.

Манипуляция заголовками и cookies

Задачи на Broken Access Control (OWASP A01:2021) и Injection (OWASP A03:2021) требуют точной настройки запроса. Базовые паттерны, которые стоит держать наготове:

  • Подмена IP для обхода ограничений: curl -H "X-Forwarded-For: 127.0.0.1" http://target/admin — классический обход проверки "только для localhost"
  • Cookie-манипуляция: curl -b "role=admin" http://target/dashboard — если приложение доверяет cookie без серверной валидации
  • Отправка файла: curl -F "file=@payload.php" http://target/upload — для задач на file upload vulnerability
  • Кастомный User-Agent: curl -A "Googlebot/2.1" http://target/robots.txt — некоторые задачи прячут контент за проверкой User-Agent

Для поддержания сессии между запросами — cookie jar. Первый запрос с -c cookies.txt сохраняет cookies, последующие с -b cookies.txt отправляют их. Пример цепочки авторизация-запрос: curl -s -c jar.txt -X POST "http://target/login" -d "user=guest&pass=guest123"curl -s -b jar.txt "http://target/secret" | grep -oE 'flag\{[^}]+\}'. Два запроса, один пайп, флаг извлекается автоматически.

Автоматический перебор параметров через curl

Blind SQL injection, где ответ сервера — true/false (разные размеры страницы или разный текст), автоматизируется через bash-цикл с проверкой содержимого: for c in {a..z} {0..9}; do resp=$(curl -s "http://target/?id=1' AND substring(password,1,1)='$c'-- -"); echo "$resp" | grep -q "Welcome" && echo "Char: $c" && break; done. Этот однострочник перебирает первый символ пароля. Обратите внимание на -- - (с пробелом и дефисом): MySQL требует пробел после -- для распознавания комментария, иначе инъекция не сработает. Для PostgreSQL достаточно --, для MySQL также подойдёт %23 (URL-encoded #). Для полного извлечения — обернуть во внешний цикл по позиции.

[Ограничения: однопоточный Blind SQLi через bash — 1-2 запроса в секунду. Для паролей длиной больше 10 символов с широким алфавитом лучше переходить на sqlmap или Python с requests + concurrent.futures. Bash тут — первая помощь, а не финальное решение.]

Ещё один паттерн — извлечение данных из API с пагинацией: for page in {1..100}; do curl -s "http://target/api/data?page=$page" | jq -r '.items[].secret' 2>/dev/null; done | grep flag. Утилита jq парсит JSON и извлекает поле secret из каждого элемента массива. Если jq не установлен — grep -oP '"secret":"\K[^"]*' делает то же самое через PCRE-регулярку.

Bash скрипт работа с файлами: поиск, декодирование, анализ

Категории forensics, stegano и crypto завалены файлами. Bash даёт инструментарий для быстрого анализа без запуска тяжёлых GUI-приложений.

Автоматический поиск флагов в файловой системе

File and Directory Discovery (T1083) на CTF-машине — первое действие после получения shell. Набор команд find с разными фильтрами:

  • Файлы, изменённые за последний час: find / -mmin -60 -type f 2>/dev/null
  • По имени: find / -name "*flag*" -o -name "*secret*" 2>/dev/null
  • С SUID-битом (для privesc): find / -perm -4000 -type f 2>/dev/null
  • Принадлежащие конкретному пользователю: find / -user ctf_admin -type f 2>/dev/null

Комбинация find + xargs + grep — рабочая лошадка для поиска по содержимому: find /opt -name "*.txt" | xargs grep -l "flag{" 2>/dev/null находит все текстовые файлы, содержащие строку "flag{". Для бинарных файлов — strings. Утилита вытаскивает читаемые строки из бинарника: strings firmware.bin | grep -i flag. Как показано в разборах задач TryHackMe (CTF Collection Vol.1), strings -n 20 binary фильтрует короткий мусор и сразу показывает осмысленные строки вроде флагов или путей.

Побочный, но полезный приём — проверка Shell History (T1552.003). На CTF-машинах в ~/.bash_history предыдущих пользователей иногда валяются команды с паролями или путями к флагам: cat /home/*/.bash_history 2>/dev/null | grep -i "flag\|password\|secret". Быстрая проверка, которая иногда решает задачу за секунду.

Кодирование и декодирование на лету

Base64 — самая частая кодировка в CTF. Декодирование: echo "dGhpc19pc19mbGFn" | base64 -d. Кодирование: echo -n "payload" | base64. Флаг -n убирает перевод строки в конце — без него base64-результат будет отличаться от ожидаемого (частый источник ошибок, особенно при многократном кодировании).

Hex-операции через xxd: просмотр hex-дампа xxd suspicious.bin | head -20, обратная конвертация из hex-строки echo "666c61677b746573747d" | xxd -r -p (результат: flag{test}). Для задач, где нужно исправить заголовок повреждённого файла (частый forensics-паттерн), xxd с обратной конвертацией через xxd -r позволяет редактировать бинарники прямо в терминале.

ROT13: echo "synt{grfg}" | tr 'a-zA-Z' 'n-za-mN-ZA-M' — шифр Цезаря со сдвигом 13. Для произвольного сдвига N можно генерировать алфавиты через bash-переменные, но проще переключиться на python3 -c "import codecs; print(codecs.decode('...','rot_13'))".

Определение типа файла: file mystery_file покажет реальный формат независимо от расширения. На CTF файл с расширением .txt запросто окажется PNG-изображением или ZIP-архивом — file определяет по magic bytes. Связанная утилита binwalk -e firmware.bin автоматически находит и распаковывает вложенные архивы, файловые системы и изображения.

Сравнение файлов побайтово: diff <(xxd file1) <(xxd file2) использует process substitution — фишку bash, которая позволяет передать вывод команды как файл без создания временных файлов на диске. Незаменимо для стеганографии, где нужно найти разницу между оригиналом и модифицированной копией.

Защитное программирование и отладка bash-скриптов

Баг в скрипте посреди CTF — потеря драгоценных минут. Три строки в начале скрипта спасают от большинства проблем:

#!/bin/bash
set -euo pipefail
IFS=$'\n\t'

set -e — немедленный выход при ошибке любой команды (не продолжать на сломанных данных). set -u — ошибка при обращении к неопределённой переменной (ловит опечатки в именах). set -o pipefail — ошибка внутри пайпа не маскируется успехом последней команды. IFS=$'\n\t' — разделитель только перевод строки и табуляция, не пробел (защита от багов с пробелами в именах файлов).

Для отладки: bash -x script.sh запускает скрипт в debug-режиме, показывая каждую выполняемую команду с подставленными значениями переменных. На CTF это быстрее, чем расставлять echo "DEBUG: ..." по всему коду. Если debug-вывод слишком объёмный — добавьте set -x и set +x вокруг проблемного участка, чтобы трассировать только его.

Ещё один приём — trap для очистки при выходе. Если скрипт создаёт временные файлы (cookie jar, промежуточные результаты), конструкция trap "rm -f /tmp/ctf_*" EXIT гарантирует их удаление даже при ошибке или Ctrl+C.

Ограничения Bash-скриптов и когда переходить на Python

Bash — не универсальный язык. Есть чёткие границы, за которыми он становится обузой:

Сценарий Bash Python Когда переходить
Перебор до 1000 значений Достаточен Избыточен Bash справляется
Перебор 100k+ значений Однопоточный, медленно threading/asyncio При wordlist > 5000 записей
Парсинг JSON Через jq (внешняя утилита) Нативно (json модуль) Вложенный JSON с логикой
Бинарные операции (XOR, AES) Побайтово, медленно Нативно (pwntools, crypto) Любая криптозадача
Работа с сокетами Через netcat, ограниченно pwntools, полный контроль pwn/binary exploitation
HTTP с сессиями curl + cookie jar requests + session Цепочка > 3 зависимых запросов

Практическое правило: если скрипт вырос больше 50 строк или требует обработки ошибок сложнее, чем if [ $? -ne 0 ] — переписывайте на Python. Bash хорош для быстрых однострочников и скриптов-склеек длиной до 30 строк. Python — для логики, состояний и бинарных данных.

[Ограничения bash для реального пентеста, не CTF: однопоточность делает bash-брутфорс непригодным для production-сценариев. На внутреннем пентесте с доступом к тысячам хостов используйте crackmapexec, hydra или кастомные Python-скрипты. Bash остаётся полезным для быстрой разведки — один for ip in ... цикл с ping или curl — но не для массовой эксплуатации.]

Ещё одно ограничение — переносимость. Bash 4.0+ с associative arrays и brace expansion есть на Linux. На macOS по умолчанию стоит bash 3.2 из-за лицензии GPLv3 — нужно обновлять через brew. Проверяйте версию: bash --version. Если CTF-площадка даёт SSH-доступ к Linux-машине (OverTheWire, AUCTF, HTB), bash гарантированно доступен. Если работаете с macOS или Windows (WSL) — проверьте совместимость заранее.


На каждом CTF я вижу одну и ту же картину: команды, которые решают больше задач, не обязательно знают больше техник. Они быстрее автоматизируют рутину. Скрипт на 10 строк, написанный за 2 минуты, экономит 20 минут ручной работы. На дистанции 10 задач за 24-часовой CTF разница между командами составляет 3 часа чистого времени. Три часа — это ещё два-три решённых таска и место в топ-10.

Но есть ловушка, в которую попадают многие: чрезмерная автоматизация до старта. Участники тратят 40 минут на написание «универсального скрипта перебора всего» вместо того, чтобы за 5 минут решить конкретную задачу руками. Автоматизируйте то, что повторяется, — перебор, парсинг, кодирование. Не автоматизируйте то, что делается один раз. Набор из пяти проверенных шаблонов (перебор по wordlist, парсинг вывода, curl с cookies, поиск по ФС, декодирование) покрывает 80% ситуаций. Остальные 20% решаются быстрее вручную или на Python.

Отдельно про set -euo pipefail: в CTF-среде принято писать «грязные» скрипты без обработки ошибок. Для одноразового однострочника — нормально. Но если скрипт длиннее 10 строк и вы планируете переиспользовать его на следующем CTF — strict mode экономит больше времени на отладке, чем тратит на написание. Проверено на собственных CTF-шаблонах, которые пережили полгода и десяток соревнований без переписывания. Если хочешь не просто скрипты на бумаге, а пройти полную цепочку веб-атаки от разведки до флага — WAPT на codeby.school/wapt закрывает эту задачу с лабами на каждый этап.

🚀 Хочешь закрепить на практике? Реши задачи по теме на HackerLab — категория «pentest-machines».

Поделиться

0 комментариев

Пожалуйста, войдите, чтобы оставить комментарий.

Загрузка комментариев...