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

15 мин.02

Bash скрипты для CTF: сканер, брутфорс, парсинг

Bash скрипты для CTF: сканер, брутфорс, парсинг

За два последних CTF-сезона я хронометрировал каждое рутинное действие: ручной запуск nmap, копипаст открытых портов в блокнот, запуск gobuster по каждому HTTP-порту — 7-8 минут на одну цель. При 12 машинах в соревновании это полтора часа, потраченные не на анализ уязвимостей, а на набивание одних и тех же команд. Один bash-скрипт на 9 строк сократил цикл разведки до 20 секунд на машину.

Bash скрипты для CTF — не программирование в классическом смысле, а склейка утилит, которые вы и так запускаете руками, в автоматическую цепочку. Ниже — три рабочих скрипта с разбором каждого флага, набор one-liner-ов для парсинга и конкретные ошибки, на которых буксует каждый новичок.

Автоматизация пентеста bash: зачем скрипты на CTF

Bash есть на любой Linux-системе. На урезанных CTF-контейнерах и минимальных Docker-образах Python может отсутствовать, но sh, grep, awk и sed найдутся даже в BusyBox. На одном из недавних заданий удалённая машина содержала только sh и awk — этого хватило, чтобы прошерстить файловую систему, вытянуть конфиги и обнаружить SUID-бинарники. Подробнее — в нашем статье о создание ctf заданий.

Скорость создания — второй аргумент. Связать nmap, извлечение портов и gobuster — шесть строк на bash. Аналогичная штука на Python с argparse, обработкой исключений и вызовами subprocess.run() — проект на 50+ строк. Когда таймер показывает два часа на десять задач, этот разрыв решает всё.

Третий момент — прямое соответствие техникам MITRE ATT&CK. Запуск shell-скриптов на целевой системе маппится на T1059.004 Unix Shell (тактика Execution). Разведка файловой системы через find и ls — T1083 File and Directory Discovery (тактика Discovery). Сбор системных данных через uname, id, cat /etc/os-release — T1082 System Information Discovery. Перебор паролей через curl в цикле — T1110.001 Password Guessing (тактика Credential Access).

В репозитории Atomic Red Team для T1059.004 есть тесты «Create and Execute Bash Shell Script» и «Harvest SUID executable files» — оба выполняются через sh на Linux. На CTF вы делаете ровно то же: пишете скрипт, запускаете, собираете данные. Понимание маппинга помогает не только на соревнованиях, но и при написании отчётов по реальным пентестам — вы сразу указываете TTP, а не просто «запустил nmap».

Автоматизация CTF задач через bash экономит когнитивный ресурс. Вместо набивания одних и тех же команд вы думаете над логикой задачи. Это отличает участника, закрывающего 12 заданий за соревнование, от того, кто закрывает 4.

Подготовка окружения

Перед первым скриптом проверьте три вещи. Версия bash: bash --version — подойдёт любая 4.x и выше. На macOS по умолчанию стоит 3.2 из-за лицензии — обновите через brew install bash. На Windows — WSL2 с любым дистрибутивом.

Утилиты: скрипты из статьи работают с nmap, gobuster, curl, grep, awk, sed и wc. В Kali и Parrot OS всё стоит из коробки. На минимальных дистрибутивах доставьте через apt install nmap curl gobuster.

Рабочая директория: mkdir ~/ctf && cd ~/ctf. Каждый скрипт начинается с shebang-строки #!/bin/bash — она указывает системе интерпретатор. После создания файла — chmod +x script.sh, иначе получите Permission denied. Альтернатива — запуск через bash script.sh, но при частом использовании это менее удобно. Редактор — любой: nano для начинающих, vim для готовых к модальному режиму.

Перебор портов скрипт: автоматическая разведка с nmap

Самая частая рутина на CTF — просканировать порты, определить сервисы, проверить веб-директории. Три команды, которые всегда идут друг за другом, — идеальный кандидат для автоматизации. Логика: принимает IP-адрес, создаёт папку под результаты, запускает nmap. Находит HTTP-порт — автоматически натравливает gobuster. Не находит — ограничивается nmap-этапом.

#!/bin/bash
set -euo pipefail
[ -z "${1:-}" ] && echo "Использование: $0 <IP>" && exit 1
IP="$1"; DIR="recon_$IP"; mkdir -p "$DIR"
nmap -sV -sC -oN "$DIR/nmap.txt" "$IP"
WEBPORT=$(grep -E '/tcp.*http' "$DIR/nmap.txt" | grep -oE '^[0-9]+' | head -1 || true)
[ -n "$WEBPORT" ] && gobuster dir -u "http://$IP:$WEBPORT" \
  -w /usr/share/wordlists/dirb/common.txt -o "$DIR/dirs.txt" 2>/dev/null
echo "[+] Результаты: ./$DIR/"

Разберём построчно.

set -euo pipefail — страховка от тихих ошибок. Флаг -e завершает скрипт при любой команде с ненулевым кодом возврата. Флаг -u ловит обращения к неопределённым переменным — без него опечатка в имени переменной вернёт пустую строку вместо ошибки. Флаг -o pipefail ловит сбои в пайпах: без него false | echo ok молча вернёт успех. По данным hadess.io, эти три флага «prevent silent failures that lead to incorrect results». На CTF такие «тихие» сбои особенно мерзкие — вы не замечаете проблему и парсите пустой файл.

Конструкция [ -z "${1:-}" ] проверяет, передан ли аргумент. Обратите внимание: ${1:-} вместо голого $1. Конструкция :- возвращает пустую строку, если переменная не задана, и предотвращает ошибку при активном set -u. Без этой проверки nmap запустится без цели и зависнет в ожидании ввода.

Переменная DIR формирует имя папки вида recon_10.10.10.5 — результаты каждой машины хранятся раздельно. mkdir -p создаёт директорию без ошибки, если она уже существует.

Флаги nmap -sV -sC — определение версий сервисов плюс дефолтные NSE-скрипты. Без них nmap покажет только номера открытых портов без контекста — для CTF этого мало. Флаг -oN сохраняет вывод в текстовом формате (Normal output), пригодном для парсинга.

Ключевая конструкция — извлечение HTTP-порта. grep -E '/tcp.*http' находит строки вида 80/tcp open http. Затем grep -oE '^[0-9]+' вытаскивает номер порта из начала строки. head -1 берёт первый HTTP-порт. Если nmap HTTP не нашёл, || true гарантирует, что pipeline не уронит скрипт из-за pipefail — переменная WEBPORT останется пустой и блок с gobuster просто не выполнится.

Перенаправление 2>/dev/null подавляет прогресс-бар gobuster, который засоряет терминал при автоматическом запуске. Результаты при этом сохраняются в dirs.txt.

Для запуска на нескольких целях: while read -r ip; do ./recon.sh "$ip"; done < targets.txt. Файл targets.txt — по одному IP на строку. Запускаете команду и читаете условия задач, пока автоматизация пашет в фоне.

Замечание о переносимости

Флаг grep -E использует расширенные регулярные выражения (ERE). В BusyBox он доступен только если grep собран с соответствующей опцией. На урезанных системах альтернатива: grep '/tcp.*http' "$DIR/nmap.txt" | awk '{print $1}' | cut -d/ -f1 | head -1 — awk переносимее и работает даже в минимальных BusyBox-сборках.

Парсинг вывода nmap bash: one-liners на awk и sed

Nmap генерирует текстовый вывод со стабильной структурой — идеальная мишень для парсинга. Русскоязычные материалы обычно ограничиваются базовым grep, но awk и sed открывают совсем другой уровень. Разберём конкретные задачи.

Извлечение всех открытых портов. Конструкция grep -oE '^[0-9]+/tcp' nmap.txt | cut -d/ -f1 | paste -sd, вытаскивает номера портов и склеивает через запятую. Результат вида 22,80,443,8080 — готовый аргумент для прицельного повторного сканирования: nmap -p 22,80,443,8080 -A $IP. Обратите внимание на paste -sd, — она делает то же, что tr '\n' ',' | sed 's/,$//', но в одну команду вместо двух.

Версии сервисов — чистая таблица. Команда awk '/^[0-9]+\/tcp/{print $1, $3, $4, $5}' nmap.txt вытаскивает порт, статус и название сервиса с версией. awk делит строку на поля по пробелам: $1 — первое поле, $NF — последнее, $(NF-1) — предпоследнее. Для вывода nmap $1 — это 80/tcp, $3 — http, $4 и $5 — название и версия сервера.

Фильтрация по типу сервиса. Для SSH-портов: grep -E '^[0-9]+/tcp.*ssh' nmap.txt | awk '{print $1}'. Для HTTP — замените ssh на http. Связка grep для фильтрации и awk для извлечения — базовый паттерн, который работает с любым текстовым выводом.

# Открытые порты через запятую
grep -oE '^[0-9]+/tcp' nmap.txt | cut -d/ -f1 | paste -sd,
# Версии сервисов
awk '/^[0-9]+\/tcp/{print $1, $3, $4, $5}' nmap.txt
# HTTP-порты для gobuster
grep '/tcp.*http' nmap.txt | grep -oE '^[0-9]+'
# Уникальные IP из access.log
awk '{print $1}' access.log | sort -u
# Неудачные SSH-входы — top по IP
grep "Failed password" auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn

Последний one-liner стоит разобрать. NF в awk — количество полей в строке. $(NF-3) — третье поле с конца. В строке Failed password for admin from 192.168.1.100 port 22 ssh2 IP-адрес стоит именно на третьей позиции с конца. Эта конструкция из реальной практики анализа /var/log/auth.log — hadess.io описывает её для задач SOC-аналитика.

Пайп sort | uniq -c | sort -rn — классическая тройка: сортировка, подсчёт уникальных вхождений, сортировка по убыванию количества. Запомните эту связку — она всплывает в каждом втором задании, связанном с анализом логов.

XML-формат nmap

Текстовый вывод (-oN) удобен для простого парсинга, но для сложных запросов лучше XML. Запускайте nmap с -oX nmap.xml. Для извлечения номеров портов: grep -oP 'portid="\K[^"]+' — конструкция \K (Perl-совместимый lookbehind) отбрасывает всё до значения атрибута. Если grep -P недоступен, альтернатива: awk -F'"' '/portid/{print $2}' — awk делит строку по кавычкам, второе поле содержит номер порта.

По данным hadess.io, xmllint --xpath '//port[@protocol="tcp"]/state[@state="open"]/..' nmap_output.xml позволяет делать полноценные XPath-запросы к XML-выводу nmap. Но xmllint не всегда стоит на CTF-стендах — я бы не рассчитывал на него.

Работа с JSON

Если API отвечает JSON-ом, используйте jq. Конструкция curl -s http://api/endpoint | jq -r '.token' извлечёт значение ключа token. Для вложенных структур: jq -r '.data.users[].name'.

Если jq не установлен (частая ситуация на CTF), простейшие JSON-поля вытаскиваются через grep -oP '"key":"\K[^"]+' — грубый метод, но на CTF работает. Для структурированных логов в JSON-формате jq незаменим: cat app.log | jq -r 'select(.level == "ERROR") | "\(.timestamp) \(.message)"' фильтрует только ошибки и выводит их с таймстампами.

Брутфорс скрипт bash: перебор веб-форм на CTF

Веб-форма авторизации без rate-limiting и CSRF-защиты — классика CTF начального уровня. Четырёхзначный PIN или пароль из короткого вордлиста. По OWASP это A07:2021 Identification and Authentication Failures — на CTF такая слабость намеренная, в продакшене это дыра размером с ворота.

Перед запуском полного перебора убедитесь вручную, что сервер не возвращает HTTP 429/503 после серии запросов — если rate-limiting всё же есть, скрипт ниже этого не обрабатывает.

Перед написанием скрипта разберите запрос руками. Откройте Developer Tools (вкладка Network), введите заведомо неверный пароль и зафиксируйте четыре вещи: URL формы (например, http://target:8080/login), метод (POST или GET), имена полей (user, pass) и текст ответа при ошибке (Access denied). Без этой ручной подготовки скрипт стреляет вслепую.

#!/bin/bash
# set -euo pipefail здесь не используется: grep -q возвращает non-zero при каждом неверном пароле,
# что при set -e прервало бы цикл перебора на первой же попытке.
URL="http://target:8080/login"; FAIL="Access denied"
WORDLIST="${1:-/usr/share/wordlists/rockyou.txt}"
while read -r pass; do
  resp=$(curl -s -d "user=admin" --data-urlencode "pass=${pass}" "$URL")
  echo "$resp" | grep -q "$FAIL" || { echo "[+] Пароль: $pass"; exit 0; }
done < "$WORDLIST"
echo "[-] Совпадений нет"

Переменная FAIL содержит маркер неверного пароля — строку из Developer Tools. Конструкция ${1:-/usr/share/wordlists/rockyou.txt} берёт путь к вордлисту из аргумента. Если аргумент не передан — подставляет дефолтный путь к rockyou.txt из Kali.

Цикл while read -r pass читает файл построчно, не загружая в память целиком. Это критично: rockyou.txt весит более 140 МБ. Конструкция for pass in $(cat rockyou.txt) попытается загрузить весь файл в оперативную память и убьёт оболочку (проверено — не повторяйте). Флаг -r предотвращает интерпретацию обратных слешей — без него пароль pa\ss превратится в pass.

curl -s -d ... --data-urlencode отправляет POST-запрос. curl автоматически объединяет несколько -d и --data-urlencode параметров через & в теле запроса. --data-urlencode кодирует спецсимволы в значении пароля — без этого флага пароль с & или = сломает структуру запроса. Флаг -s (silent) подавляет прогресс-бар.

Конструкция grep -q "$FAIL" || { ...; } — инвертированная проверка. Если grep НЕ находит строку ошибки в ответе — пароль подошёл. Оператор || выполняет блок справа только при неудаче команды слева. Компактнее, чем if ! echo "$resp" | grep -q "$FAIL"; then.

Ограничения и расширения

Скрипт работает с простыми формами без CSRF-токенов. Если форма генерирует токен в скрытом поле — сначала заберите страницу curl-ом, извлеките токен через sed -n 's/.*value="\([^"]*\)".*/\1/p' и подставьте в POST-запрос. Это добавляет 3-4 строки, но логика та же.

Для генерации вордлистов на лету: seq -w 0000 9999 > pins.txt создаёт список четырёхзначных PIN-кодов. Флаг -w обеспечивает ведущие нули (0001, 0002 вместо 1, 2). Для шестнадцатеричных значений: printf "%04x\n" $(seq 0 65535) > hex.txt.

По MITRE ATT&CK перебор через curl в цикле маппится на T1110.001 Password Guessing (тактика Credential Access). Все три публичных теста Atomic Red Team для T1110.001 ориентированы на Windows (SMB, LDAP, Kerberos) — Linux/bash-тестов для этой техники в репозитории нет, curl-based брутфорс веб-форм не покрыт официальными atomic tests. Маппинг на технику при этом корректен: принцип перебора паролей по словарю одинаков на любой платформе.

Shell scripting для хакинга: связка инструментов через пайпы

Сила bash — в пайпах. Каждая утилита делает одну вещь хорошо, а bash склеивает их в цепочку. По данным hadess.io, «the real power of Bash in security is piping output between tools». Разберём типовые связки.

nmap → nikto. После обнаружения HTTP-портов нужно проверить веб-сервер на известные уязвимости. Цепочка: grep '/tcp.*http' nmap.txt | grep -oE '^[0-9]+' | while read -r port; do nikto -h "http://$IP:$port" -o "nikto_$port.txt"; done. Каждый HTTP-порт из вывода nmap автоматически проходит через nikto. На выходе — отдельный файл на каждый порт.

Массовый поиск флагов в архиве. На CTF часто нужно прошерстить скачанный архив: find . -type f -exec grep -lH "flag{" {} \; 2>/dev/null. find рекурсивно находит файлы, grep -lH выводит имя файла с совпадением. Перенаправление 2>/dev/null подавляет ошибки на бинарных файлах.

Проверка целостности файлов. В задачах на forensics: find /etc -type f -exec sha256sum {} \; создаёт базовый снимок, а diff baseline.txt current.txt | grep "^[<>]" обнаруживает изменения. Этот приём работает и в реальном incident response — hadess.io описывает аналогичный скрипт для File Integrity Check.

Мониторинг сертификатов. На длительном пентесте полезно отслеживать сроки TLS-сертификатов: echo | openssl s_client -servername "$domain" -connect "$domain:443" 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2 извлекает дату истечения. Оберните в цикл по списку доменов — готовый мониторинг.

Subdomain enumeration → live check. На CTF с реалистичной инфраструктурой: subfinder -d target.com -silent | sort -u | while read -r sub; do curl -s -o /dev/null --max-time 5 -w "%{http_code} $sub\n" "http://$sub"; done | grep -v "^000". subfinder находит субдомены, curl -w "%{http_code}" проверяет код ответа, grep -v "^000" фильтрует недоступные хосты.

Bash скрипты для хакеров: пять ошибок новичков

Каждая из этих ошибок стоила мне или знакомым от 20 минут до часа на CTF. Собрал пять самых болезненных.

1. Забытые кавычки вокруг переменных. Команда grep $PATTERN file.txt сломается, если PATTERN содержит пробел. Правильно: grep "$PATTERN" file.txt. Аналогично с путями: cd $DIR при DIR="my folder" попытается перейти в my. Привычка: всегда оборачивайте переменные в двойные кавычки.

2. for line in $(cat file) вместо while read -r line. Конструкция for загружает файл в память целиком и разбивает по пробелам — строка hello world станет двумя итерациями. while read -r line; do ...; done < file читает построчно, сохраняя пробелы. На вордлистах размером в десятки мегабайт это разница между рабочим и мёртвым скриптом.

3. Игнорирование кодов возврата. Если nmap завершился с ошибкой, а скрипт продолжает работать — вы парсите пустой файл и не понимаете, почему ничего не находится. Решение: set -e в начале скрипта или ручная проверка $? после критичных команд. set -euo pipefail покрывает три типа сбоев одновременно.

4. Неэкранированные спецсимволы в regex. Точка в regex — любой символ. Поиск grep 192.168.1.1 совпадёт и с 192X168Y1Z1. Правильно: grep -F '192.168.1.1' (фиксированная строка) или grep '192\.168\.1\.1' (экранированные точки). На CTF с парсингом логов эта ошибка приводит к ложным совпадениям и потерянному времени.

5. Useless Use of Cat. cat file | grep pattern — лишний процесс. grep принимает файл аргументом: grep pattern file. В единичном вызове разница незаметна, но в цикле по 14 миллионам строк rockyou.txt суммарные потери ощутимы. Если утилита принимает файл аргументом — не кормите его через cat.

Автоматизация CTF задач: что видит защита

Bash-скрипты на CTF — атакующая техника, но полезно понимать, как выглядит ваша активность с другой стороны. Sigma-правила из репозитория SigmaHQ покрывают обнаружение подозрительной shell-активности: lnx_shell_susp_commands.yml ловит типичные reconnaissance-команды (перечисление пользователей, сетевая разведка). lnx_shell_susp_rev_shells.yml — попытки создания обратных шеллов. lnx_shell_priv_esc_prep.yml — подготовку к повышению привилегий: поиск SUID-бинарников, чтение /etc/shadow, перечисление sudo-прав. Всего по тегу T1059.004 в SigmaHQ 20 правил детекции.

Для T1082 System Information Discovery — 36 правил, включая lnx_auditd_system_info_discovery.yml, отслеживающее запуск uname, hostname, cat /etc/os-release через auditd. Те самые команды, которые на CTF запускаются первыми.

Зная, что детектируется, вы лучше ориентируетесь на защищённой инфраструктуре. На CTF-стендах обычно нет EDR, и эти правила не активны. Но на реальном пентесте осознание детекции меняет подход: вместо шумного nmap -sV -sC по всем портам — точечные проверки конкретных сервисов.

Контрмеры из MITRE D3FEND дополняют картину. Против T1059.004 Unix Shell: Executable Allowlisting (D3-EAL) — разрешение запуска только одобренных бинарников; File Analysis (D3-FA) — анализ содержимого файлов до выполнения; File Integrity Monitoring (D3-FIM) — отслеживание изменений критических файлов. Против T1110.001 Password Guessing: Password Rotation (D3-PR), One-time Password (D3-OTP), Operational Process Monitoring (D3-OPM) — мониторинг логов аутентификации на аномальное количество попыток.

Связь с AbuseIPDB: если ваш IP засветился массовым сканированием портов (категория #14 Port Scan) или SSH-брутфорсом (категория #22 SSH), он попадёт в базу с определённым abuseConfidenceScore. При значении выше 75 многие организации блокируют такие IP автоматически. На CTF это не проблема — стенды изолированы. Но если вы случайно направили скрипт на реальный хост вместо целевого — последствия будут.


Bash-автоматизация на CTF — порог входа, а не потолок. Я вижу две крайности: одни решают каждую задачу руками, теряя время на копипаст между терминалами, другие пытаются до начала соревнований собрать универсальный фреймворк на Python. Первые упираются в скорость, вторые — в overengineering.

Рабочий путь — набор из 5-7 bash-скриптов, каждый под конкретную рутину: разведка, брутфорс, парсинг логов, обработка файлов. Не фреймворк, а коллекция заточенных инструментов.

На практике 80% CTF-задач решаются связкой nmap + grep + awk и парой curl-ов в цикле. Остальные 20% — нестандартные вещи: криптография, бинарная эксплуатация, работа с сетевыми протоколами на уровне байтов. Тут bash уже не тянет и нужен Python или специализированные инструменты. Но без базовой bash-автоматизации вы тратите первые 80% времени на рутину и не добираетесь до тех самых интересных 20%.

Навык переносится на реальные задачи напрямую. Связка grep | awk | sort | uniq -c работает в SOC при анализе логов. set -euo pipefail — стандарт в DevSecOps-пайплайнах. curl в цикле — основа автоматизированного тестирования API. CTF — тренировочная площадка, но навыки из неё живут в продакшене. Если хочешь не ковыряться в Kali в одиночку, а системно разобраться с основами — на IB Basics это выстроено от нуля до первых рабочих задач без академического тона.

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

Поделиться

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

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

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

Читайте также

Wireshark CTF pcap анализ: от фильтров до флага

14 мин.

9

Wireshark CTF pcap анализ: от фильтров до флага

Разбор pcap для CTF за 10 минут: display-фильтры, Follow TCP Stream, Export Objects, DNS exfiltration и tshark-автоматизация. Проверено на десятках заданий.

15 НОЯБРЬ, 2026

OSINT с нуля: флаги CTF через username и EXIF

15 мин.

9

OSINT с нуля: флаги CTF через username и EXIF

Три вектора OSINT для CTF — username, email, метаданные фото. Sherlock, exiftool, holehe: конкретные команды, цепочка действий и ловушки организаторов.

14 НОЯБРЬ, 2026

Regex и grep для поиска флагов CTF в дампах

11 мин.

8

Regex и grep для поиска флагов CTF в дампах

Пошаговые grep-команды и regex-паттерны для извлечения CTF-флагов из дампов: PCRE, Base64-декодирование, оптимизация на файлах 2+ ГБ, ripgrep и конвейеры

14 НОЯБРЬ, 2026