
На Dojo CTF challenge #36 от YesWeHack участникам подкинули веб-форму с пингом — классическая точка входа для OS command injection. Фильтр на стороне приложения пропускал payload только если в нём не было ни одной латинской буквы: регулярка [a-zA-Z_*^@%+=:,./-] отправляла ввод в санитайзер при первом совпадении. Решением стала ANSI-C нотация $'\143\141\164' — восьмеричные коды символов вместо букв. Из сотен участников таск решили единицы.
Проблема не в сложности уязвимости. Проблема в том, что большинство игроков знают один payload ; cat flag.txt и теряются, когда он не проходит. Дальше — полный разбор эксплуатации command injection в CTF: от первого теста до слепой инъекции и обхода фильтров, которые режут пробелы, буквы и спецсимволы.
Command injection (CWE-78, Improper Neutralization of Special Elements used in an OS Command) возникает, когда пользовательский ввод попадает в системную команду без нейтрализации спецсимволов. По OWASP Top 10:2021, инъекции (A03:2021) — в тройке критичных рисков веб-приложений. В CTF успешная эксплуатация — это флаг. В продакшене — полный контроль сервера: чтение /etc/shadow (T1552.001), загрузка инструментов через curl или wget (T1105) и закрепление в инфраструктуре. Подробнее — в нашем обзоре пентест веб-приложений.
Три CVE в Nagios XI — CVE-2021-25296, CVE-2021-25297, CVE-2021-25298 — все с CVSS 8.8 (HIGH); CVE-2021-25297 и CVE-2021-25298 классифицированы как CWE-78 в NVD, для CVE-2021-25296 CWE не указан. Все три активно эксплуатировались в дикой природе и попали в каталог CISA KEV. EPSS для CVE-2021-25296 — 0.7154 (top 1% по вероятности эксплуатации). По механике каждая из этих CVE идентична тому, что встречается в среднем web CTF: пользовательский ввод попадает в PHP-функцию exec() через вызов ping без валидации. Разница — в масштабе последствий.
Первый шаг — определить, какой пользовательский ввод доходит до системной команды. Типичные точки входа в CTF-тасках:
ping -c 1 <input>nslookup <input> или dig <input>ffmpeg, convert, pandoc с пользовательскими аргументамиmail -s "..." -aFrom:<input>Если таск содержит исходный код, ищите вызовы system(), exec(), shell_exec(), os.system(), subprocess.run() с параметром shell=True, child_process.exec(). Согласно OWASP OS Command Injection Defense Cheat Sheet, именно эти API создают поверхность атаки, потому что вызывают оболочку ОС как посредника. Без исходного кода — тестируйте каждый input-параметр (GET, POST, заголовки, cookie) последовательно, подставляя разделители команд.
Начните с простого — отправьте 127.0.0.1; id и проверьте, появится ли uid=... в ответе. Нет? Перебирайте альтернативные разделители.
| Оператор | Поведение | Linux | Windows |
|---|---|---|---|
; |
Выполняет команды последовательно | Да | Нет |
& |
Выполняет обе в фоне | Да | Да |
&& |
Вторая — только при успехе первой | Да | Да |
\| |
Stdout первой → stdin второй | Да | Да |
\|\| |
Вторая — только при ошибке первой | Да | Да |
%0a |
Перевод строки как разделитель | Да | Нет |
`cmd` |
Inline-подстановка (backticks) | Да | Нет |
$(cmd) |
Inline-подстановка (modern) | Да | Частично |
Каждый разделитель ведёт себя по-разному, и в CTF это критично. && выполнит вторую команду только при успехе первой — если ping завершается ошибкой из-за невалидного хоста, payload не сработает. || наоборот — сработает именно из-за ошибки. По данным PortSwigger, размещение & после инъецированной команды (& whoami &) снижает вероятность того, что хвост оригинальной команды помешает выполнению.
Inline-подстановка — `id` и $(id) — заслуживает отдельного внимания. Результат команды подставляется в строку как значение, и это основа для DNS-эксфильтрации при blind injection (об этом ниже).
Предусловия и ограничения: разделитель ; работает только в Unix-шеллах (bash, sh, ash, zsh, dash). В Windows cmd.exe — нет. Backtick-подстановка и $() требуют POSIX-совместимого интерпретатора — не работают в cmd.exe, но работают в PowerShell через $(). Если ввод попадает внутрь одинарных кавычек в оригинальной команде (например, ping -c 1 '<input>'), ни один разделитель не сработает без предварительного закрытия кавычки символом '.
[Применимо: CTF (web), внешний пентест, внутренний пентест — Unix/Windows в зависимости от оператора]
Базовые payload не проходят — значит, есть фильтр. В CTF встречаются три типа: чёрный список символов, чёрный список команд и регулярные выражения. По MITRE CWE-184 (Incomplete List of Disallowed Inputs), denylist-подход систематически проваливается, потому что атакующий находит обходной путь. Именно это делает CTF-таски с фильтрами интересными — по сути, вы ломаете не приложение, а воображение разработчика фильтра.
Пробел — первый символ, который режут. Шесть работающих альтернатив:
$IFS — переменная Internal Field Separator, по умолчанию содержит пробел, табуляцию и перевод строки. Payload cat${IFS}/etc/passwd или cat$IFS/etc/passwd выполняет cat /etc/passwd без единого пробела.
{cmd,arg} — brace expansion в bash: {cat,/etc/passwd} раскрывается шеллом в cat /etc/passwd.
< — перенаправление ввода: `cat
0 комментариев
Пожалуйста, войдите, чтобы оставить комментарий.
Загрузка комментариев...