Bir gün müşteri panelinize giriyorsunuz ve sitenizin ziyaretçilerini bambaşka sayfalara yönlendirdiğini, Google'ın "bu site zararlı yazılım içeriyor" uyarısı verdiğini ya da hosting sağlayıcınızın hesabınızı spam gönderdiği için askıya aldığını görüyorsunuz. Bu senaryoların büyük çoğunluğunun arkasında tek bir sessiz suçlu vardır: sunucuya bırakılmış bir web shell. Web shell, saldırganın tarayıcısından ya da basit bir HTTP isteğiyle sizin sunucunuzda komut çalıştırmasına, dosya okuyup yazmasına ve veritabanınıza uzanmasına imkân veren bir arka kapıdır. Çoğunlukla masum görünen tek bir .php dosyasına sıkıştırılmıştır ve haftalarca fark edilmeden durur.
Bu rehberde bir web shell'in tam olarak ne olduğunu, saldırganın onu sunucunuza nasıl yerleştirdiğini, hangi PHP kalıplarının alarm zili çaldırması gerektiğini ve komut satırında grep ile find kullanarak bu arka kapıları nasıl avlayacağınızı adım adım anlatacağım. Ardından temiz bir kurtarma yapıp sunucuyu tekrar aynı yoldan girilmeyecek şekilde nasıl sertleştireceğinizi göstereceğim. Anlatımın tamamı, yıllardır paylaşımlı hosting ve VDS ortamlarında bu tip olaylara müdahale etmiş bir sistem yöneticisinin gözünden, elinizi kirletmeye hazır komutlarla birlikte ilerliyor.
Web Shell Tam Olarak Nedir ve Nasıl Çalışır?#
Web shell, web sunucusunun (Apache, Nginx + PHP-FPM) çalıştırabileceği bir betik dosyasıdır ve tek amacı saldırgana sunucu üzerinde uzaktan kontrol vermektir. Normal bir PHP sayfası önceden tanımlı bir iş yapar; bir web shell ise dışarıdan gelen komutu alıp doğrudan işletim sistemine geçirir. En basit haliyle şu iki satır bir arka kapıdır:
<?php
// Tek satırlık klasik arka kapı
system($_GET['cmd']);
Bu dosya arka.php adıyla sitenizin bir dizinine bırakıldığında, saldırgan tarayıcısına https://siteniz.com/arka.php?cmd=id yazması yeterlidir. Sunucu id komutunu çalıştırır ve web sunucusunun hangi kullanıcı olarak koştuğunu (www-data, apache vb.) ekrana döker. Buradan sonra ls, cat /etc/passwd, hatta veritabanı şifrelerinizin durduğu wp-config.php dosyasını okumaya kadar her şey mümkündür.
Gerçek dünyadaki web shell'ler bu kadar dürüst değildir. r57, c99, WSO, b374k gibi isimlerle bilinen "hazır" shell'ler; dosya yöneticisi, SQL istemcisi, e-posta gönderici ve şifre kırıcı barındıran binlerce satırlık paneller sunar. Kendilerini gizlemek için içeriklerini base64 ile kodlar, gzinflate ile sıkıştırır ve değişken adlarını okunamaz hale getirir. Amaç, hem sizin göz taramanızdan hem de basit imza tabanlı antivirüslerden kaçmaktır.
Web shell'in tehlikeli yanı kalıcı olmasıdır. Saldırgan asıl açığı (örneğin eski bir eklenti zafiyetini) kullanarak bir kez içeri girer, arka kapıyı bırakır ve o açık kapansa bile web shell üzerinden istediği zaman geri döner. Bu yüzden "eklentiyi güncelledim, sorun çözüldü" demek çoğu zaman yanıltıcıdır; asıl temizlenmesi gereken şey geride bırakılan arka kapıdır.
Saldırgan Web Shell'i Sunucuya Nasıl Bırakır?#
Bir web shell'i etkili şekilde avlamak için önce nereden geldiğini anlamak gerekir. Deneyimime göre yerleştirme yolları birkaç ana başlıkta toplanır:
- Zafiyetli eklenti veya tema: WordPress, Joomla ya da özel yazılımlardaki güncellenmemiş bileşenler en yaygın giriş noktasıdır. Bir dosya yükleme formundaki eksik doğrulama, saldırganın
.phpuzantılı dosyayı doğrudan sunucuya atmasına izin verir. - Güvensiz upload alanları: "Profil fotoğrafı" ya da "belge yükle" gibi alanlar yalnızca istemci tarafında uzantı kontrolü yapıyorsa, saldırgan
resim.phpdosyasını rahatça yükler. - Çalınmış FTP/SSH/panel bilgileri: Kötü amaçlı yazılım bulaşmış bir bilgisayardan sızdırılan FTP şifresi, saldırgana dosyaları doğrudan koyma imkânı verir.
- Komşu hesap sıçraması: Aynı sunucudaki başka bir zayıf sitenin ele geçirilmesi, yanlış dosya izinleri yüzünden sizin dizininize de bulaşabilir. Bu konuda Linux dosya izinleri rehberimiz izinlerin neden kritik olduğunu ayrıntısıyla anlatıyor.
Saldırgan çoğu zaman arka kapıyı tek bir yere koymaz. Asıl büyük shell'i gizlerken, header.php ya da functions.php gibi meşru dosyaların içine tek satırlık ikinci bir "damla" (dropper) yerleştirir. Böylece siz ana dosyayı bulup silseniz bile, ikinci arka kapı üzerinden geri döner. Bu yüzden temizlik her zaman "tek dosya sil" değil, kapsamlı bir tarama olmalıdır. WordPress kullanıyorsanız WordPress güvenliği rehberimizdeki sertleştirme adımları bu giriş noktalarının çoğunu baştan kapatır.
Şüpheli PHP Kalıpları ve grep ile Tarama#
İşin en pratik kısmı burası. Bir web shell'i ele veren şey, meşru kodda nadiren bir arada bulunan belirli PHP fonksiyonlarıdır. Aşağıdaki tablo, tarama sırasında öncelik vermeniz gereken fonksiyonları ve neden şüpheli olduklarını özetliyor:
| Kalıp / Fonksiyon | Ne İşe Yarar | Neden Şüpheli |
|---|---|---|
eval() | String'i PHP kodu olarak çalıştırır | Shell'lerin kalbi; gizlenmiş kodu çalıştırmak için kullanılır |
system, exec, shell_exec, passthru | İşletim sistemi komutu çalıştırır | Sunucuda komut çalıştırmanın doğrudan yolu |
base64_decode() | Base64 metni çözer | Kötü amaçlı yükü göz taramasından gizler |
gzinflate, gzuncompress, str_rot13 | Sıkıştırılmış/karışık kodu açar | base64 ile birlikte katmanlı gizleme yapar |
assert() | String'i kod gibi değerlendirir | eval alternatifi olarak kullanılır |
preg_replace('/.../e') | /e bayrağıyla kod çalıştırır | Eski PHP'de gizli kod çalıştırma yöntemi |
$_POST, $_GET, $_REQUEST + eval | Dış girdiyi çalıştırır | Girdinin doğrudan koda dönüşmesi klasik arka kapı |
Şimdi bunları gerçekten arayalım. SSH ile sunucuya bağlanın ve site kök dizinine geçin. En yüksek getirili tek komut, tehlikeli fonksiyonları PHP dosyalarında toplu aramaktır:
# En riskli çalıştırma fonksiyonlarını tara
grep -rEn --include="*.php" \
"(eval|assert|system|exec|shell_exec|passthru|popen|proc_open)\s*\(" \
/var/www/html
Ardından gizleme kalıplarını arayın. Meşru bir eklenti nadiren base64_decode çıktısını eval ile çalıştırır:
# Gizlenmiş yük kalıbı: base64_decode + gzinflate + eval yakınlığı
grep -rEln --include="*.php" \
"base64_decode|gzinflate|gzuncompress|str_rot13|preg_replace.*/e" \
/var/www/html
En güçlü tek satırlık ipucu ise "dış girdiyi çalıştırma" kombinasyonudur. Aşağıdaki komut $_GET/$_POST gibi bir istek değişkeninin hemen ardından bir çalıştırma fonksiyonu gelen satırları bulur ki bu neredeyse her zaman arka kapı demektir:
grep -rEn --include="*.php" \
"(eval|system|exec|shell_exec|passthru|assert)\s*\(\s*\\\$_(GET|POST|REQUEST|COOKIE)" \
/var/www/html
Bulduğunuz her sonucu tek tek açıp bakın. Örneğin şöyle bir satırla karşılaşırsanız, tereddüt etmeyin, bu bir web shell'dir:
<?php $x = base64_decode($_POST['data']); eval(gzinflate($x)); ?>
Buradaki mantık şudur: dosyanın adı ne olursa olsun (favicon.php, wp-cache.php, index_old.php), içinde "dışarıdan gelen veriyi çöz ve çalıştır" kalıbı varsa, o dosya meşru değildir. Yanlış pozitiflere karşı dikkatli olun; bazı meşru şablon motorları eval kullanabilir, ama bunlar dış girdiyle beslenmez. Şüpheniz varsa dosyanın son değişiklik tarihine ve o dizindeki diğer dosyalarla uyumuna bakın.
Son Değişen Dosyaları Listeleyerek İz Sürmek#
Grep taraması içerikten yakalar; zaman analizi ise davranıştan yakalar. Bir saldırı genellikle belirli bir tarihte gerçekleşir ve o gün birden fazla dosya değişir ya da eklenir. find komutuyla son değişen PHP dosyalarını listelemek, saldırının zaman çizelgesini çıkarmanın en hızlı yoludur:
# Son 7 günde değişmiş PHP dosyalarını, tarih sırasıyla listele
find /var/www/html -name "*.php" -mtime -7 -printf "%TY-%Tm-%Td %TH:%TM %p\n" \
| sort
Çıktıda, sizin hiçbir güncelleme yapmadığınız bir tarihte aniden değişmiş wp-includes/ ya da wp-content/uploads/ altındaki dosyalar en güçlü şüphelilerdir. Özellikle uploads dizininde herhangi bir .php dosyası olması başlı başına alarm sebebidir, çünkü orada normalde yalnızca görsel ve belge bulunur:
# Upload dizininde HİÇ olmaması gereken PHP dosyaları
find /var/www/html/wp-content/uploads -name "*.php" -type f
Zaman damgalarını yorumlarken bir inceliğe dikkat edin: değiştirme zamanı (mtime) dosyanın içeriğinin son değiştiği andır, ama değişim zamanı (ctime) izin/sahiplik değişikliklerini de kapsar ve touch komutuyla taklit edilmesi daha zordur. Akıllı saldırganlar touch -r ile arka kapının mtime değerini komşu meşru dosyalarla eşitleyerek gizlenmeye çalışır. Bu yüzden ctime'a da bakmak faydalıdır:
# Değişim zamanına (ctime) göre son 3 gün — touch ile gizlemeyi yakalar
find /var/www/html -name "*.php" -ctime -3 -printf "%CY-%Cm-%Cd %CH:%CM %p\n" \
| sort
Elinizde temiz bir referans (aynı sürümün orijinal dosyaları) varsa, en kesin yöntem bütünlük karşılaştırmasıdır. WordPress için wp core verify-checksums gibi araçlar çekirdek dosyalarının değişip değişmediğini birebir söyler. Kendi kodunuzda bir Git deposu tutuyorsanız, git status ve git diff size hangi satırların eklendiğini net olarak gösterir; sürüm kontrolü olay müdahalesinde altın değerindedir. Düzenli yedekleme alıyorsanız, temiz bir günle bugünü karşılaştırmak dakikalar içinde farkı ortaya koyar.
Upload Dizininde PHP Çalıştırmayı Engelleme#
Arka kapıları bulup silmek yaranın kabuğunu almaktır; asıl tedavi, o dosyaların bir daha çalıştırılamamasını sağlamaktır. En kritik sertleştirme, kullanıcıların dosya yükleyebildiği dizinlerde PHP yürütmeyi tamamen kapatmaktır. Saldırgan uploads dizinine bir shell atsa bile, sunucu onu çalıştırmayı reddederse arka kapı işe yaramaz.
Nginx kullanıyorsanız, upload dizinine giden istekleri PHP-FPM'e hiç iletmeyin:
# uploads altındaki hiçbir PHP dosyası çalıştırılmasın
location ~* /wp-content/uploads/.*\.php$ {
deny all;
return 403;
}
Apache (paylaşımlı hosting genelinde) kullanıyorsanız, ilgili dizine bir .htaccess bırakarak aynı sonucu alırsınız:
# uploads/.htaccess — PHP yürütmeyi bu dizinde kapat
<FilesMatch "\.php$">
Require all denied
</FilesMatch>
Ek olarak, PHP tarafında bazı tehlikeli fonksiyonları tamamen devre dışı bırakabilirsiniz. Sitenizin bunlara ihtiyacı yoksa php.ini içinde disable_functions ile kapatmak, ele geçirilseniz bile saldırganın komut çalıştırmasını engeller:
; php.ini — sunucu komutu çalıştıran fonksiyonları kapat
disable_functions = system,exec,shell_exec,passthru,popen,proc_open,pcntl_exec
Bu ayarları yapmadan önce sitenizin bu fonksiyonları gerçekten kullanmadığından emin olun; bazı yedekleme veya görüntü işleme eklentileri exec'e ihtiyaç duyabilir. Test ortamında (mümkünse ayrı bir VDS sunucuda) doğruladıktan sonra üretime alın. Yönetimini bize bırakmak isterseniz, sunucu yönetimi hizmetimiz bu sertleştirmeleri sizin adınıza uygular ve izler.
Web Shell Temizliği ve Kurtarma Adımları#
Bir arka kapı bulduğunuzda içgüdüsel tepki "sil ve geç" olur, ama profesyonel müdahale bir sıra izler. Aceleyle silmek, kanıtları ve diğer arka kapıların izlerini yok edebilir. Şu sırayı öneririm:
- Yalıtım: Mümkünse siteyi bakım moduna alın ya da geçici olarak erişimi kısıtlayın. Böylece saldırgan temizlik sırasında yeni bir shell atamaz.
- Kanıt toplama: Silmeden önce şüpheli dosyaların bir kopyasını ve web sunucusu erişim loglarını saklayın. Loglar, arka kapının ne zaman ve hangi IP'den kullanıldığını gösterir.
- Erişim loglarını analiz: Bulduğunuz shell dosyasının adını loglarda arayın; bu, saldırının kapsamını ve varsa diğer arka kapıları ortaya çıkarır.
# Erişim loglarında şüpheli dosyaya yapılan istekleri bul
grep -E "arka\.php|wso\.php|c99\.php" /var/log/nginx/access.log \
| awk '{print $1, $4, $7}'
- Tüm arka kapıları temizle: Yukarıdaki
grepvefindtaramalarını tekrar çalıştırıp bulduğunuz her arka kapıyı kaldırın. Tek bir dosyayla yetinmeyin. - Meşru dosyalardaki enjeksiyonları düzelt:
header.php,functions.php,index.phpgibi dosyaların başına ya da sonuna eklenmiş gizli kod satırlarını temizleyin. Burada temiz bir yedekle karşılaştırma paha biçilmezdir. - Tertemiz geri yükleme: En güvenli yol, olaydan önceki temiz bir yedekten geri dönmektir. Yedeğinizin bulaşma tarihinden önceki bir güne ait olduğundan emin olun.
Temizliğin ardından mutlaka tüm parolaları değiştirin: hosting paneli, FTP/SFTP, SSH, veritabanı ve wp-config.php içindeki güvenlik anahtarları. Saldırgan büyük olasılıkla bu bilgileri okumuştur. WordPress'te tüm kullanıcıların oturumlarını sonlandırın ve yönetici hesaplarını gözden geçirin; saldırganlar sıklıkla gizli bir admin hesabı ekler.
Temizlik Sonrası Sunucuyu Sertleştirmek#
Aynı olayı ikinci kez yaşamamak, temizlikten daha önemlidir. Kurtarmadan sonra atmanız gereken kalıcı adımlar şunlardır:
- Her şeyi güncel tutun: WordPress çekirdeği, tema ve eklentileri, ayrıca sunucudaki PHP ve işletim sistemi paketlerini güncel tutun. Giriş noktalarının büyük kısmı bilinen ve yamalanmış zafiyetlerdir. WordPress bakım hizmetimiz bu güncellemeleri düzenli olarak sizin yerinize yapar.
- En az ayrıcalık ilkesi: Dosya izinlerini sıkılaştırın; dizinler
755, dosyalar644olmalı,wp-config.phpgibi hassas dosyalar640ya da daha kısıtlı olabilir. Web sunucusu kullanıcısının yazamayacağı dizinlere shell atılamaz. Ayrıntı için dosya izinleri rehberimize bakın. - WAF katmanı ekleyin: Bir web uygulaması güvenlik duvarı, bilinen shell yükleme ve komut çalıştırma isteklerini sunucuya ulaşmadan engeller. WAF çözümümüz ve DDoS koruma katmanı, otomatik saldırı botlarının büyük bölümünü daha kapıda durdurur.
- HTTPS ve güncel sertifikalar: Trafiğin şifreli olması oturum çalınmasını zorlaştırır; ücretsiz ya da ücretli SSL sertifikası her sitede standart olmalıdır.
- Düzenli tarama ve izleme: Periyodik
grep/findtaramalarını bir betiğe alıp haftalık çalıştırın. Dosya bütünlüğü izleme (FIM), yeni bir.phpdosyası eklendiğinde sizi uyarır.
Aşağıdaki gibi basit bir izleme betiğini cron'a ekleyerek yeni arka kapıları erken yakalayabilirsiniz:
#!/bin/bash
# haftalik-tarama.sh — şüpheli kalıpları rapor et
ROOT="/var/www/html"
grep -rEln --include="*.php" \
"(eval|assert|system|exec|shell_exec|passthru).*\\\$_(GET|POST|REQUEST)" \
"$ROOT" > /root/shell-raporu.txt
find "$ROOT/wp-content/uploads" -name "*.php" >> /root/shell-raporu.txt
Güvenlik tek seferlik bir iş değil, sürekli bir alışkanlıktır. Güncelleme, yedekleme, izleme ve en az ayrıcalık ilkesini bir araya getirdiğinizde, bir açık zaman zaman ortaya çıksa bile saldırganın kalıcı bir arka kapı bırakması neredeyse imkânsız hale gelir.
Sıkça Sorulan Sorular#
Web shell ile virüs arasındaki fark nedir?#
Klasik bir virüs kendini çoğaltıp yayılmaya odaklanırken, web shell hedefli ve pasif bir arka kapıdır. Sunucunuza yerleştirilir ve saldırgan onu bir HTTP isteğiyle tetikleyene kadar sessizce bekler. Amacı yayılmak değil, saldırgana o sunucu üzerinde kalıcı ve gizli bir kontrol sağlamaktır; bu yüzden çoğu genel amaçlı antivirüs, tek başına bir web shell'i her zaman yakalayamaz.
Sitem WordPress ise nereden başlamalıyım?#
WordPress kurulumlarında en verimli başlangıç noktası wp-content/uploads, wp-content/plugins ve wp-content/themes dizinlerinde grep ile şüpheli fonksiyon taraması yapmak ve find ile son değişen dosyaları listelemektir. Ardından wp core verify-checksums çalıştırarak çekirdek dosyalarının değişip değişmediğini kontrol edin. Konunun tamamını WordPress güvenliği rehberimizde adım adım bulabilirsiniz.
Bir dosyanın gerçekten web shell olduğundan nasıl emin olurum?#
Dosyayı bir editörde açıp içeriğini okuyun; dış girdinin ($_GET, $_POST) doğrudan bir çalıştırma fonksiyonuna (eval, system, base64_decode + eval) beslendiğini görüyorsanız bu neredeyse kesin bir arka kapıdır. Meşru kod bu kalıbı nadiren kullanır. Emin olamıyorsanız dosyayı silmek yerine önce yeniden adlandırıp .txt uzantısı verin; site çalışmaya devam ediyorsa o dosyanın gerekli olmadığını anlarsınız.
Antivirüs ya da tarama eklentisi yeterli mi?#
Tarama araçları iyi bir ilk katmandır ve bilinen shell imzalarını hızla yakalar, ancak gizlenmiş (base64 + gzinflate katmanlı) yeni varyantları kaçırabilir. En güvenilir yaklaşım, otomatik taramayı manuel grep/find incelemesi ve temiz bir yedekle bütünlük karşılaştırmasıyla birleştirmektir. Tek bir araca güvenmek yerine katmanlı doğrulama yapmak, gözden kaçan arka kapı riskini ciddi ölçüde azaltır.
Web shell'i temizledim ama site tekrar bulaştı, neden?#
Bu durum neredeyse her zaman iki nedenden kaynaklanır: ya asıl giriş açığı (güncellenmemiş bir eklenti ya da çalınmış bir parola) hâlâ açıktır, ya da ilk temizlikte gözden kaçan ikinci bir arka kapı vardır. Kalıcı çözüm için tüm arka kapıları eksiksiz temizleyin, tüm parolaları değiştirin, yazılımları güncelleyin ve upload dizininde PHP çalıştırmayı engelleyin. Tekrar bulaşma sürüyorsa, olaydan önceki temiz bir yedekten sıfırdan geri yükleme yapmak en temiz seçenektir.
Paylaşımlı hostingte de web shell riski var mı?#
Evet, hatta paylaşımlı ortamlarda risk daha yüksek olabilir çünkü aynı sunucudaki başka bir zayıf site, yanlış izinler yüzünden sizin hesabınıza da sıçrayabilir. Yönetilen ve düzenli güncellenen bir hosting altyapısı bu riski azaltır. Daha fazla izolasyon isteyen projeler için kendi kaynaklarınıza sahip olduğunuz bir sanal sunucu ya da VDS, komşu hesap sıçraması riskini büyük ölçüde ortadan kaldırır.
Kapanış#
Web shell'ler, tek bir dosyaya sığan ama koca bir sunucuyu ele geçirmeye yeten sinsi arka kapılardır. İyi haber şu ki, çalışma mantıklarını bir kez anladığınızda tespitleri de temizlikleri de belirli bir disipline oturur: içerikten grep ile şüpheli kalıpları avlamak, zamandan find ile son değişen dosyaları izlemek, upload dizinlerinde PHP yürütmeyi kapatmak ve olaydan sonra parolaları değiştirip yazılımları güncel tutmak. Bu adımları bir kez alışkanlık haline getirdiğinizde, arka kapıların çoğu daha yerleşemeden engellenir.
Bu sertleştirmelerin bir kısmını sizin adınıza üstlenmemizi isterseniz, Clou.TR olarak güncel ve izlenen hosting paketleri, yönetilen WordPress hosting, tam kontrol sunan VDS ve sanal sunucular, WAF ve DDoS koruma katmanları, otomatik yedekleme ve uçtan uca sunucu yönetimi hizmetiyle yanınızdayız. Güvenli bir altyapıyla büyümeye bugün başlayın.