Bölüm 08
Command Injection (Komut Enjeksiyonu)
Bölüm 1 (tehlikeli fonksiyonlar, güven sınırı), Bölüm 4 (beyaz liste).
Komut enjeksiyonunu, kabuğa (shell) veri gönderen her yolun bir risk olduğu bir sınıf olarak kavrayacak; escapeshellarg ile escapeshellcmd arasındaki hayati farkı, "kaçış" yaklaşımının neden çoğu zaman yanlış çözüm olduğunu ve kabuğu tamamen aradan çıkarmanın neden doğru çözüm olduğunu göreceksiniz. Ayrıca dolaylı komut enjeksiyonunu (bir kütüphane üzerinden) inceleyeceğiz.
1. Giriş
Komut enjeksiyonu, açıkların en tehlikeli sınıflarından biridir çünkü hedefi doğrudan işletim sistemidir. SQL Injection bir veritabanına, XSS bir tarayıcıya erişir; komut enjeksiyonu ise doğrudan sunucunun kabuğunda saldırganın komutunu çalıştırır — yani sonucu, tanım gereği, uzaktan kod çalıştırmadır (RCE). RCE, saldırganın erişebileceği en yüksek ödüldür: dosya sistemine erişim, ağa yanal hareket, kalıcılık (web shell, Bölüm 34) ve tüm sistemin ele geçirilmesi buradan başlar.
PHP, web ile işletim sistemi arasında tarihsel olarak çok "geçirgen" bir dildir. system, exec, shell_exec, passthru, proc_open, popen ve backtick (`) operatörü — dilin çekirdeğinde, doğrudan kabuğa erişim sunan bir avuç fonksiyon vardır. Bu erişim, meşru ihtiyaçlar için kullanışlıdır (bir görüntü dönüştürme aracını çağırmak, bir arşiv açmak, bir sistem aracını çalıştırmak) ama güvenilmeyen veriyle beslendiğinde felakete dönüşür.
Bu bölüm iki önemli inceliği vurgular: (1) komut enjeksiyonu dolaylı da olabilir — kodunuz hiç system() çağırmasa bile, kullandığınız bir kütüphane (ör. ImageMagick, Bölüm 11) sizin adınıza kabuğu çağırıyor olabilir; ve (2) "kaçış" fonksiyonları burada, SQL'de olduğu gibi, çoğu zaman yanlış araçtır.
2. Temel Teori
Komut enjeksiyonunun kök nedeni, tanıdık kalıptır: güvenilmeyen veri, bir kabuk komutu dizesine, komut sınırlarını değiştirebilecek biçimde gömülür ve kabuk onu ayrıştırırken verinin bir kısmını komut olarak yorumlar.
Kritik oyuncu kabuktur (shell). system("ping " . $host) çağrıldığında PHP, bu dizeyi bir kabuğa (/bin/sh -c "...") verir. Kabuk, dizeyi kendi meta-karakterlerine göre ayrıştırır. Kabuğun tehlikeli meta-karakterleri:
| Karakter | Anlamı | Sonuç |
|---|---|---|
; |
Komut ayracı | İkinci bir komut çalıştır |
&&, || |
Koşullu zincir | Koşula bağlı komut |
| |
Boru (pipe) | Çıktıyı başka komuta ver |
`, $(...) |
Komut ikamesi | İçteki komutu çalıştırıp sonucunu göm |
>, < |
Yönlendirme | Dosyaya yaz / dosyadan oku |
& |
Arka plan | Komutu arka planda çalıştır |
| yeni satır | Komut ayracı | Yeni komut |
ping 8.8.8.8; rm -rf / örneğinde kabuk, ;'yi bir ayraç olarak görür ve iki komutu da çalıştırır. Sorun, SQL'dekiyle birebir aynıdır: kod (komut) ile veri (girdi) tek bir dizede karışıyor ve ayrıştırıcı (kabuk) ikisini ayırt edemiyor.
İki savunma felsefesi vardır ve doğru olan çok net değildir:
-
Kabuğu aradan çıkar (doğru yaklaşım). Komutu ve argümanlarını kabuğa bir dize olarak değil, bir dizi olarak verirsen, hiç kabuk ayrıştırması olmaz.
proc_open, argümanları dizi olarak alabilir; bu durumda;,|gibi karakterler saf veri kalır çünkü onları yorumlayacak bir kabuk yoktur. Bu, SQL'deki parametreli sorgunun (Bölüm 6) tam karşılığıdır: kanalları ayır. -
Kaçış yap (kırılgan yaklaşım).
escapeshellarg/escapeshellcmdile meta-karakterleri kaçır. Bu, SQL'deki kaçış gibi, kenar durumlarda başarısız olur ve — daha önemlisi — argüman enjeksiyonunu (bkz. Bölüm 5) engellemez.
3. Mimarisel Bakış
GÜVENSİZ (kabuk aracıyla):
$_GET['host'] → "ping " . $host → system()
↓
PHP → /bin/sh -c "ping 8.8.8.8; rm -rf /" ← KABUK ayrıştırır
↓ ";" komut ayracı sayılır
İki komut da çalışır → RCE
GÜVENLİ (kabuk YOK, dizi argüman):
$_GET['host'] (doğrulanmış) → proc_open(['ping','-c','1', $host], ...)
↓
İşletim sistemi → ping çalıştırılır, argümanlar SAF VERİ
↓ "8.8.8.8; rm -rf /" tek bir argüman sanılır
ping başarısız olur, ikinci komut ASLA çalışmaz
DOLAYLI (ImageTragick türü):
Kullanıcı dosyası → $imagick->readImage() → kütüphane içinde system()
↓
Sizin kodunuz system() çağırmasa bile, KÜTÜPHANE çağırır → RCE
Üçüncü akış öğreticidir: kod incelemede system/exec aramak yetmez; kullandığınız kütüphanelerin sizin adınıza kabuğu çağırıp çağırmadığını da bilmelisiniz.
4. Güvensiz Kod
Gerçekçi bir "ağ tanılama" ve "görüntü küçültme" özelliği:
<?php
// ⚠️ GÜVENSİZ — komut enjeksiyonu (doğrudan + "kaçışlı ama hatalı")
declare(strict_types=1);
// 1) Doğrudan enjeksiyon — hiç kaçış yok
$host = $_GET['host'];
$output = shell_exec("ping -c 1 " . $host); // ; | && $() hepsi geçer
// 2) "Kaçış var" ama YANLIŞ fonksiyon
$file = $_GET['file'];
system("gzip " . escapeshellcmd($file)); // argüman enjeksiyonuna açık
// 3) Kaçışlı ama argüman enjeksiyonu (escapeshellarg yetmiyor)
$filename = $_GET['filename'];
system("tar -czf backup.tar.gz " . escapeshellarg($filename));
// filename = "--checkpoint=1 --checkpoint-action=exec=sh evil.sh" → tar seçeneği enjekte
echo $output;
5. Açığın Analizi
shell_exec("ping -c 1 " . $host) — Ders kitabı komut enjeksiyonu. $host hiç işlenmeden kabuk komutuna gömülüyor. 8.8.8.8; id, 8.8.8.8 | id, 8.8.8.8 $(id) — kabuğun her meta-karakteri işe yarar. Sonuç doğrudan RCE.
system("gzip " . escapeshellcmd($file)) — Yaygın ve sinsi bir hata: yanlış kaçış fonksiyonu. escapeshellcmd, tüm komut dizesini kaçırmak için tasarlanmıştır ve bireysel argümanları kaçırmaz. Meta-karakterleri kaçırır ama argüman/bayrak enjeksiyonunu engellemez: $file = "-S 1G archive" gibi bir değer, gzip'e ek bayraklar geçirerek davranışını değiştirebilir. escapeshellcmd neredeyse her zaman yanlış seçimdir.
system("tar ... " . escapeshellarg($filename)) — İşte en öğretici hata. escapeshellarg doğru fonksiyondur (argümanı tırnak içine alıp kabuk meta-karakterlerini nötrler), ama tek başına argüman enjeksiyonunu çözmez. $filename bir dosya adı gibi görünse de --checkpoint=1 --checkpoint-action=exec=... gibi bir değer, tar'a geçerli bir seçenek olarak geçer ve tar'ın kendi özelliğiyle komut çalıştırır. escapeshellarg bunu engelleyemez çünkü değer kabuk açısından geçerli tek bir argümandır — sorun kabukta değil, tar'ın onu bir bayrak olarak yorumlamasındadır. Çözüm: seçeneklerin bittiğini belirten -- ayracını koymak ve/veya girdiyi beyaz listeyle doğrulamak.
Kök sorun: Üç durumda da kabuk (veya hedef program) güvenilmeyen veriyi yorumluyor. Kaçış, bu yorumu sınırlar ama tümüyle ortadan kaldırmaz.
6. Hacker Bakış Açısı
Saldırgan komut enjeksiyonunu nasıl arar?
Sistem etkileşimi belirtileri arar. Bir özellik "ping at", "DNS sorgula", "dosya dönüştür", "PDF üret", "arşiv oluştur", "yedek al" gibi işler yapıyorsa, arkada büyük olasılıkla bir sistem aracı çağrılıyordur. Bunlar birincil hedeftir.
Meta-karakterlerle yoklar. Girdiye ;, |, `, $(...), yeni satır ekleyip yanıtın değişip değişmediğine bakar. Görünür çıktı yoksa (blind), bir gecikme enjekte eder (bir uyku komutuyla) ve yanıt süresinin ölçülebilir biçimde uzayıp uzamadığına bakar — tam olarak time-based blind SQLi mantığı (Bölüm 6).
Kaçış varsa argüman enjeksiyonuna geçer. Uygulama meta-karakterleri kaçırıyorsa (escapeshellarg), saldırgan bunu bilir ve hedef programın kendi bayraklarını istismar etmeye çalışır: tar --checkpoint-action, curl -o, wget --post-file, ffmpeg girdi protokolleri, find -exec gibi. Bu, "kaçış yeterli" yanılgısının kırıldığı yerdir.
Dolaylı yolları düşünür. Doğrudan komut alanı bulamazsa, bir dosya yükleme özelliğinin arkasında ImageMagick/Ghostscript/FFmpeg gibi bir işleyici olup olmadığını sınar (ImageTragick, Bölüm 11). Yüklenen dosya, doğrudan bir "komut alanı" olmasa da, kütüphane üzerinden kabuğa ulaşabilir.
Savunmacı dersi: Saldırgan yalnızca "komut kutusu" aramaz; kabuğa giden her yolu arar — doğrudan, argüman üzerinden veya kütüphane üzerinden.
7. Exploit Mantığı
Bu bölüm çalıştırılabilir saldırı dizeleri içermez. Komut enjeksiyonunun neden bu kadar yıkıcı olduğu kavramsaldır: saldırgan, uygulamanın çalıştığı OS kullanıcısının tüm yeteneklerini devralır.
- Anında RCE: Kabuk meta-karakteri enjekte edilebildiği an, saldırgan keyfi komut çalıştırır. Aracı bir aşama gerekmez; SQLi'de olduğu gibi "veri çıkarımı" değil, doğrudan yürütme söz konusudur.
- Blind çıkarım: Görünür çıktı olmasa bile, zamanlama (uyku) veya bir dış kanala istek (out-of-band) ile açık doğrulanır ve komut sonuçları dışarı sızdırılabilir.
- Argüman enjeksiyonu: Meta-karakter kaçırılsa bile, hedef programın kendi "kod çalıştıran" özellikleri (arşivleyicilerde
--exec, indiricilerde dosya yazma) istismar edilebilir. Yani kaçış, RCE'yi engellemek yerine bir programın özelliğine yönlendirebilir. - Yetki bağlamı: Etki, süreç hangi kullanıcıyla çalışıyorsa onunla sınırlıdır. PHP-FPM
rootçalışıyorsa RCE = tam sistem devri; en az yetkili, kısıtlı bir kullanıcıysa hasar sınırlanır. Bu, en az yetkinin (Bölüm 1) neden bir savunma katmanı olduğunu gösterir.
Araştırmacının çerçevesi: (a) kabuğa hangi yoldan ulaşılıyor (doğrudan/argüman/kütüphane), (b) çıktı görünür mü yoksa blind mı, (c) süreç yetkisi nereye kadar tırmanmaya izin veriyor. Savunma bu üç ekseni kapatır.
8. Güvenli Kod
Doğru yaklaşım: kabuğu tamamen aradan çıkar.
<?php
// ✅ GÜVENLİ — kabuk yok, dizi argümanlar, doğrulama
declare(strict_types=1);
/**
* proc_open, komut+argümanları DİZİ olarak alınca kabuk kullanmaz.
* Argümanlar OS'e doğrudan geçer; meta-karakterler saf veri kalır.
*/
function runNoShell(array $cmd): string
{
$descriptors = [1 => ['pipe', 'w'], 2 => ['pipe', 'w']];
// Dizi biçimi + bypass_shell → kabuk devreden çıkar
$proc = proc_open($cmd, $descriptors, $pipes, null, null, ['bypass_shell' => true]);
if (!is_resource($proc)) {
throw new RuntimeException('Süreç başlatılamadı');
}
$out = stream_get_contents($pipes[1]);
fclose($pipes[1]); fclose($pipes[2]);
proc_close($proc);
return $out;
}
// 1) Ping — önce girdiyi DOĞRULA (beyaz liste), sonra dizi argüman
$host = $_GET['host'] ?? '';
if (!filter_var($host, FILTER_VALIDATE_IP)) { // yalnızca geçerli IP kabul
http_response_code(422);
exit('Geçersiz IP');
}
$output = runNoShell(['ping', '-c', '1', '--', $host]);
// 2) Arşivleme — '--' ile seçenek sonu; kullanıcı girdisi ARGÜMAN olarak
$filename = basename($_GET['filename'] ?? ''); // yol bileşenlerini at (Bölüm 20)
$safeName = preg_match('/^[a-zA-Z0-9._-]{1,100}$/', $filename) ? $filename : null;
if ($safeName === null) {
http_response_code(422);
exit('Geçersiz dosya adı');
}
runNoShell(['tar', '-czf', 'backup.tar.gz', '--', $safeName]);
echo htmlspecialchars($output, ENT_QUOTES, 'UTF-8');
Eğer bir kabuk komutu kaçınılmazsa (dizi biçimi mümkün değilse), doğru kaçış:
// Zorunluysa: escapeshellarg (escapeshellcmd DEĞİL) + '--' + doğrulama
$arg = escapeshellarg($safeName);
system('tar -czf backup.tar.gz -- ' . $arg); // '--' argüman enjeksiyonunu keser
Öne çıkan modern kalıplar:
- proc_open dizi argümanla + bypass_shell: Kabuğu aradan çıkarır; en sağlam çözüm. (Symfony Process bileşeni bunu güvenli ve taşınabilir biçimde sarmalar; PHP'de tercih edilen yoldur.)
- Girdi doğrulama (beyaz liste): IP için FILTER_VALIDATE_IP, dosya adı için sıkı regex. Kabuğu çıkarsanız bile doğrulama derinlemesine savunmadır.
- -- (seçenek sonu işareti): Argüman enjeksiyonunu keser; kullanıcı girdisinin bayrak olarak yorumlanmasını engeller.
- escapeshellarg (asla escapeshellcmd): Kabuk zorunluysa; ama yine de tek başına argüman enjeksiyonunu çözmez, -- ile birlikte kullanılır.
9. Patch Analizi
Neden işe yarar? Dizi argümanla proc_open, komutu ve her argümanı OS'e ayrı öğeler olarak verir; hiç kabuk oluşmadığından ayrıştırılacak meta-karakter de yoktur. Bu, "veriyi düzeltme" (kaçış) değil, "kanalları ayırma" yaklaşımıdır ve bu yüzden eksiksizdir — tıpkı prepared statement gibi.
escapeshellarg vs escapeshellcmd — kritik ayrım:
| Fonksiyon | Ne yapar | Doğru kullanım | Hata |
|---|---|---|---|
escapeshellarg($s) |
Tek argümanı tırnaklayıp meta-karakterleri nötrler | Bireysel argümanlar | Argüman enjeksiyonunu çözmez → -- gerekir |
escapeshellcmd($s) |
Tüm komut dizesindeki meta-karakterleri kaçırır | Neredeyse hiç | Argümanları ayırmaz; sık yanlış kullanılır |
Kural: argüman kaçırıyorsanız daima escapeshellarg; escapeshellcmd'yi görürseniz kod incelemede kırmızı bayrak sayın.
Performans: Kabuk oluşturmamak (bypass_shell) aslında biraz daha hızlıdır (ekstra bir süreç yok). Doğrulama maliyeti ihmal edilebilir. Güvenlik kazancı, minimal maliyetin çok üzerindedir.
10. Gerçek Hayat Senaryosu
Kurgu — bir DevOps otomasyon paneli. İç ekipler için yazılan bir web aracı, "sunucu sağlık kontrolü" için bir hostname alıp ping ve nslookup çalıştırıyor. Geliştirici "bu araç yalnızca iç ağda, güvenilir kişiler kullanıyor" diye komut enjeksiyonunu önemsemiyor ve shell_exec("ping " . $host) yazıyor. Bir gün bu panel yanlış yapılandırmayla dış ağa açılıyor (ya da içeriden bir saldırgan erişiyor). Panel, container içinde ama yüksek yetkiyle çalıştığı için, tek bir host alanı üzerinden saldırgan container'da RCE elde ediyor, oradan orkestrasyon kimlik bilgilerine ulaşıp yanal hareketle üretim ortamına geçiyor. Dersler: (1) "iç araç" bir güvenlik sınırı değildir; (2) komut enjeksiyonu doğrudan RCE'dir, en yüksek önceliktir; (3) en az yetki ve container izolasyonu (Bölüm 29) hasarı sınırlardı.
11. Gerçek CVE Analizi — CVE-2016-3714 (ImageTragick)
MITRE, NVD, satıcı danışma belgeleri ve kaşiflerin (Mail.Ru Security Team / Nikolay Ermishkin ve stewie) açıklamalarıyla doğrulanmıştır. Silahlaştırılmış payload verilmez; mekanizma incelenir.
Özet. Mayıs 2016'da, yaygın kullanılan görüntü işleme kütüphanesi ImageMagick'te bir dizi açık açıklandı; en kritiği olan CVE-2016-3714, kabuk komut enjeksiyonu yoluyla uzaktan kod çalıştırmaya (RCE) izin veriyordu. ImageMagick, PHP'de Imagick uzantısı üzerinden ve pek çok CMS/eklenti tarafından kullanıldığından, açık PHP web ekosistemini doğrudan etkiledi.
Teknik neden — ve neden "dolaylı" komut enjeksiyonunun mükemmel örneği. ImageMagick, bazı formatları işlemek için harici araçlara (delegate) başvurur. Bu "delegate" mekanizması, delegates.xml yapılandırmasındaki bir komut dizesini bir system() çağrısıyla çalıştırır ve komut içine dosya adı/URL gibi parametreleri yerleştirir. Bir HTTPS kaynağını indiren varsayılan delegate, kavramsal olarak şuna benzer:
"wget" -q -O "%o" "https:%M" ← %M, kullanıcı girdisinden gelen bağlantı
Sorun, %M parametresinin yetersiz filtrelenmesiydi: bağlantı alanına kabuk meta-karakterleri (tırnak + |) içeren bir değer konduğunda, system()'e giden komut dizesi bölünüp ek komutlar çalıştırılabiliyordu. Yani ImageMagick, güvenilmeyen bir değeri bir kabuk komutuna gömüyor ve tam olarak Bölüm 5'teki hatayı yapıyordu.
Daha da tehlikelisi: ImageMagick, dosya türünü içeriğe (magic bytes) göre belirlediğinden, saldırgan kötü niyetli bir MVG/SVG içeriğini .png uzantısıyla yükleyerek uzantı tabanlı kontrolleri atlatabiliyordu. Böylece "yalnızca görüntü yükleniyor" sanan bir uygulama, aslında bir komut enjeksiyonu vektörü barındırıyordu. Aynı disclosure, ilgili başka açıkları da (SSRF, yerel dosya okuma, dosya taşıma/silme — ayrı CVE numaralarıyla) içeriyordu; hepsi ImageMagick'in "harici protokollerden dosya dahil etme" özelliğine dayanıyordu.
Etki. Kullanıcı görüntüsü işleyen ve savunmasız sürümü kullanan her servis etkilenebilirdi; profil fotoğrafı yükleme gibi en sıradan özellikler bir RCE vektörüne dönüştü. Açık, yamalandıktan sonra bile ilk düzeltmenin eksik olması nedeniyle birden çok tur gerektirdi.
Satıcı düzeltmesi ve mitigation. ImageMagick yeni sürümler yayımladı. Kritik ve hızlı bir mitigation ise policy.xml ile tehlikeli "coder"ların (MVG, MSL, HTTPS/HTTP/URL/FTP, EPHEMERAL, LABEL, TEXT vb.) devre dışı bırakılmasıydı — bu, açık sürümlerde bile saldırı yüzeyini kapatıyordu.
Çıkarılacak dersler:
1. Komut enjeksiyonu sizin kodunuzda system() olmasa bile var olabilir. Kullandığınız kütüphaneler sizin adınıza kabuğu çağırabilir. Kod incelemede bağımlılıkların davranışını da düşünün (Bölüm 30).
2. Uzantı/MIME kontrolü içerik-tabanlı algılamayı yenemez. "Sadece resim" varsayımı, dosya içeriği tür belirliyorsa geçersizdir (Bölüm 19).
3. Konfigürasyon tabanlı mitigation güçlüdür. Kod düzeltilene kadar policy.xml gibi bir yapılandırma, saldırı yüzeyini hemen daraltabilir — mitigation (Bölüm 14) ile kalıcı çözüm arasındaki farkın canlı örneği.
12. Detection
Kod incelemede: Kabuğa giden her yolu arayın — hem doğrudan çağrıları hem de dolaylı kütüphaneleri:
grep -rnE 'system|exec|shell_exec|passthru|popen|proc_open|`' src/
grep -rn 'escapeshellcmd' src/ # neredeyse her zaman yanlış → incele
grep -rn 'Imagick|->readImage|convert |ghostscript|ffmpeg' src/ # dolaylı vektör
Her bulguda: girdi kabuğa ulaşıyor mu? Dizi argüman mı, kabuk dizesi mi? -- var mı? Girdi beyaz listeden geçiyor mu?
SAST: Kaynaktan ($_GET) kabuk sink'ine (system) taint izini bulur; olgun bir tespit alanıdır. Dolaylı (kütüphane içi) vektörler için bağımlılık-farkında kurallar ve SCA (Bölüm 30) gerekir.
DAST: Meta-karakter ve zaman-tabanlı (uyku) yüklerle blind komut enjeksiyonunu tespit eder.
Loglar/SIEM: Web parametrelerinde ;, |, $(, `, %0a (newline) kalıpları; ve en değerlisi, web sunucusu sürecinden beklenmeyen alt süreçlerin (ör. www-data altında sh, curl, nc, whoami) doğması. Bir işlem-oluşturma (process creation) izleme (auditd, EDR), komut enjeksiyonu tespitinde en güçlü sinyaldir; SIEM'de "web sürecinin çocuk süreçleri" için alarm kurulmalıdır.
13. Prevention
- Kabuğu aradan çıkar:
proc_opendizi argümanla / SymfonyProcess; kabuk dizesi kurmaktan kaçının. - Mümkünse hiç harici komut çağırma: İhtiyacı yerel PHP fonksiyonlarıyla karşıla (görüntü için GD/
ImagickAPI'si — kabuk çağırmayan modda, arşiv içinZipArchive). - Beyaz liste doğrulama: Kabuğa ulaşan her değer sıkı bir sözleşmeden geçer (Bölüm 4).
--ile argüman enjeksiyonunu kes; kaçış gerekiyorsaescapeshellarg, aslaescapeshellcmd.- En az yetki + izolasyon: Süreç düşük yetkili kullanıcıyla, konteynerde, gereksiz sistem araçları olmadan çalışsın (Bölüm 28, 29).
- Kütüphane sertleştirme: ImageMagick için
policy.xmlile tehlikeli coder'ları kapat; bağımlılıkları tarayıp güncel tut (Bölüm 30).
14. Mitigation
- Acil: Etkilenen uç noktayı devre dışı bırak veya girdiyi sıkı beyaz listeye indir; kabuk dizesini dizi argümana çevir. ImageMagick türü dolaylı vektörlerde
policy.xmlsertleştirmesini hemen uygula. - Geçici: Süreç-oluşturma loglarını inceleyerek istismar kapsamını belirle (hangi komutlar çalışmış); web shell/backdoor izlerini tara (Bölüm 34); sızmış kimlik bilgilerini döndür.
- Kalıcı: Kabuğu aradan çıkaran mimariye geç; en az yetki + izolasyon; testler ve SCA taraması.
15. Checklist
- [ ] Güvenilmeyen veri bir kabuk komut dizesine gömülüyor mu? (Gömülmemeli.)
- [ ] Harici komut çağrıları dizi argümanla mı (
proc_open/Symfony Process), kabuksuz mu? - [ ] Kaçış gerekiyorsa
escapeshellargmı (aslaescapeshellcmd)? - [ ] Kullanıcı argümanlarından önce
--(seçenek sonu) konuyor mu? - [ ] Kabuğa ulaşan her değer beyaz listeden geçiyor mu?
- [ ] Kullanılan kütüphaneler (ImageMagick, Ghostscript, FFmpeg) sizin adınıza kabuğu çağırıyor olabilir mi? Sertleştirildi mi?
- [ ] Süreç en az yetkiyle ve izole (konteyner) mi çalışıyor?
- [ ] Web sürecinden beklenmeyen alt süreçler için SIEM alarmı var mı?
16. Laboratuvar
Lab 8.1 — Kabuk ayrıştırmasını gözlemle. İzole ortamda shell_exec("ping -c1 " . $x) kurup $x = "127.0.0.1; id" ile ikinci komutun çalıştığını gözlemle. Sonra proc_open dizi argümana geçip aynı girdinin neden artık tek argüman sanıldığını doğrula.
Lab 8.2 — İki kaçış fonksiyonunun farkı. Aynı girdiyi escapeshellarg ve escapeshellcmd ile işleyip çıktıyı karşılaştır. escapeshellcmd'nin argümanları neden ayıramadığını göster.
Lab 8.3 — Argüman enjeksiyonu ve --. escapeshellarg kullanan bir tar/curl çağrısında bir bayrak enjekte etmeyi dene (izole, benign bayrakla); sonra -- ekleyip enjeksiyonun kesildiğini gözlemle.
Lab 8.4 — Dolaylı vektör. Bir policy.xml ile ImageMagick coder'larını kapat; bir MVG/SVG işleme denemesinin nasıl reddedildiğini gözlemle (yerel, izole).
17. Quiz
- Komut enjeksiyonu neden doğrudan RCE'ye eşdeğerdir ve bu onu diğer açıklardan neden daha kritik yapar?
- Kabuğun beş tehlikeli meta-karakterini ve etkisini yazın.
- "Kabuğu aradan çıkarmak" ne demektir ve neden kaçıştan üstündür? SQL'deki hangi çözüme benzer?
escapeshellargileescapeshellcmdarasındaki fark nedir? Hangisi neredeyse her zaman yanlıştır?- Argüman (bayrak) enjeksiyonu nedir?
escapeshellargonu neden tek başına çözmez?--ne işe yarar? - Blind komut enjeksiyonu nasıl doğrulanır?
- "Dolaylı" komut enjeksiyonu nedir? ImageTragick bunu nasıl örnekler?
- ImageTragick'te uzantı/MIME kontrolü neden yeterli bir savunma değildi?
- En az yetki ve konteyner izolasyonu, komut enjeksiyonu önlenemediğinde hasarı nasıl sınırlar?
policy.xmlile mitigation, "mitigation vs kalıcı çözüm" ayrımını nasıl örnekler?- Kod incelemede komut enjeksiyonunu ararken neden yalnızca
system/execaramak yetmez? - SIEM'de komut enjeksiyonu için en güçlü tespit sinyali nedir ve neden?
18. Kaynakça
- OWASP, OS Command Injection Defense Cheat Sheet.
- OWASP, Testing for Command Injection (WSTG).
- MITRE, CWE-78: Improper Neutralization of Special Elements used in an OS Command; CWE-88: Argument Injection.
- PHP Manual,
escapeshellarg,escapeshellcmd,proc_openreferansları. - MITRE / NVD, CVE-2016-3714 kaydı; imagetragick.com resmî danışma sayfası.
- Red Hat Product Security, ImageTragick (CVE-2016-3714) ve
policy.xmlmitigation belgesi. - Symfony, The Process Component dokümantasyonu (kabuksuz süreç çalıştırma).