WordPress + NGINX Güvenliği

Uzun zamandır blog siteme birşeyler karalamıyordum. Bugün ise birkaç haftadır uğraştığım bir konuyu kaleme almak istedim. Öncelikle belirtmek isterim ki ben güvenlik uzmanı değilim; sadece sunucu yönetimini öğrenmek için fiziksel bir sunucu alıp, tüm sitelerimi bu sunucuya taşıyıp & çalıştırıp, bir noktada sunucu yönetimini tek başına öğrenmeye çalışan bir SEO’cuyum 🙂 Dolayısıyla sürçü lisan edersem affola. Hatta şuralara da bi bak Uğur diyebileceğiniz yorumlarınız olursa da muhakkak bekliyorum.

Efendim bundan yaklaşık 1 ay önce sunucuya ciddi saldırılar almaya başladım. Aslında sürekli saldırı alıyorum (4, 5 yıldır) ama bu seferki arkadaş kafaya fena takmışa benziyor ki, sürekli her gün yoklamaktan geri kalmıyor. Sunucuda çalışan sitelerin %95’i wordpress olduğu için muhtemelen kurulu eklentilerin birisinde mevcut bir açıktan faydalanarak kendisine bir backdoor yaratmış olsa gerek. Sunucuda tanımadığım onlarca php dosyaları + wordpress’in çekirdek dosyalarını da değiştirdiğini gözlemledim.

Yazım genel olarak nginx konfigürasyonu ve wordpress güvenliği ile ilgili. Bu süreçte neler yaptım, hergün kapımı çalan bu arkadaşı nasıl durdurdum; biraz bundan bahsetmek istiyorum. Ama öncesinde uğraştığım şeyden bahsedeyim. Sunucuma yerleştirdiği shell, b374k-shell yani http üzerinden file manager, komut ve scriptleri çalıştırma ve hatta SQL sunucusuna kadar erişip, DB’lerinizle misket gibi oynamasını sağlayan bir backdoor yazılımı. Zaten dosya yönetimini yapmaya başladığı an, sunucunuza örümcek ağı gibi çöküp temizlemesi de bir hayli zor olan bir süreçle yüzyüze bırakabiliyor sizi. Eğer sizin de başına geldiyse, bu illetten nasıl kurtuldum, anlatmaya başlıyorum. Sunucum Centos, anlatımım buna göredir.

Öncelikle FTP servisini sunucudan komple kaldırdım. Bunun yerine sftp yapmaya başladım. Eğer yok ben illa FTP kullanıcam diyorsanız da muhakkak güçlü bir şifre kullanın ve hemen şimdi tüm FTP şifrelerinizi update edin. Ayrıca SSH şifrenizi değiştirin.

Bilgisayarıma kurduğum secureCRT, terminal kullanmaya aşina olanların zorlamadan kullanabileceği bir secure dosya transfer uygulaması. İlk başta kullanması zor olsa da temel fonksiyonlar ile dosya al-ver işlemlerini kolayca yapabiliyorsunuz. FTP üzerinden şifreleriniz kolayca çalınabileceği için kullanmanın pek de aklıselim bir iş olmadığını 5 yıl sonra acı tecrübeyle yaşadım. FTP’den kurtarıp SFTP’ye yönlendiren sevgili Cihad Çavuş‘a buradan da selam olsun 🙂 Kendisi sunucu taraması ve yönlendirmeleri ile epey yardımcı oldu.

Sonrasında gelelim SSH’a. SSH default olarak 22’inci portu kullanıyor. Bu portu da önce bi değiştirelim 🙂

vim /etc/ssh/sshd_config

ile SSH config dosyamızı açıyoruz. Ardından hangi porttan SSH yapmak isterseniz şu şekilde yeni bir satıra tanımlama yapıyoruz (örnek olarak 2549 dedim):

Port 2549

Portunuzu sakın unutmayın; keza giriş yaparken kullanacaksınız. Ardından SSH’ı restart edelim:

/etc/init.d/ssh restart

Şimdi SSH’dan tekrar bağlanmayı deneyelim:

ssh username@hostname.com -p 2549

Bağlandıysanız süper! Yola devam ediyoruz. Hata alıyorsanız muhtemelen hatalı bir işlem yaptınız, yukarıdaki adımları okuyup tekrar kontrol edin.

Sitelerimin tüm dosyalarını bilgisayarıma indirdim ve ardından sunucudaki tüm sitelerin dosyalarını sildim. Sitelerin %95’i WP olduğu için, wp-content klasörü ve wp-config.php haricindeki tüm dosyaları yine bilgisayarımdan silip, indirdiğim temiz wordpress dosyaları ile yeniledim. Ardından gerekli olmayan –gerçekten gerekli olmayan– tüm eklentileri sildim. Ardından kullanmak zorunda olduğum eklentileri de yine silip, tekrardan indirip, temiz dosyaları ile yeniledim. uploads, themes, language klasörleri başta olmak üzere wp-content altındaki tüm klasörleri manuel tek tek dolaşıp backdoor ile yaratılan bir çok php dosyası var mı yok mu kontrol ettim. Vardı; bulduklarımı sildim. Bu işlem oldukça yorucu bir süreç. Özellikle çok fazla dosya ve klasörlere sahip siteler için 1 saat kadar sürebiliyor. Kafayı kırdığım için açıkçası tüm sitelerim için bu işlemleri tek tek yapıp, temizledim.

Tüm dosya ve klasörlerin temiz olduğundan emin olduktan sonra gelelim wordpress’i biraz daha güvenli hale getirmeye. İşe wp-content ve plugins klasörünün adını değiştirmekle başlayalım.

Öncelikle wp-config.php dosyanızı açın ve aşağıdaki kodları kendinize göre düzenleyerek, wp-settings.php ‘nin include edildiği kod bloğunun üzerine yapıştırın:

define('WP_CONTENT_FOLDERNAME', 'icerik');
define('WP_CONTENT_DIR', ABSPATH . WP_CONTENT_FOLDERNAME );
define('WP_CONTENT_URL', 'http://www.ugureskici.com/'.WP_CONTENT_FOLDERNAME);
define('WP_PLUGIN_DIR', WP_CONTENT_DIR . '/eklenti' );
define('WP_PLUGIN_URL', WP_CONTENT_URL.'/eklenti');

Burada yer alan “icerik”, “wp-content” klasörünüzün yeni adıdır -siz istediğiniz başka bir isim verebilirsiniz- , “eklenti” olarak belirtilen kısım ise wp-content altında yer alan “plugins” klasörün yeni ismidir. Tabii “WP_CONTENT_URL” değişkenini sitenizin adresi ile değiştirmeyi de sakın unutmayın.

Bu işlemi yaptıktan sonra dosya dizininde yer alan wp-content’i “icerik”, plugins’i ise “eklenti” olarak yeniden adlandırmayı unutmayın.

wp-config.php dosyamızı kapatmadan bir kaç ekleme daha yapalım 🙂 Aşağıdaki kod bloğunu yine wp-settings.php ‘nin include edildiği kod bloğunun üzerine yapıştırın:

define('DISALLOW_FILE_EDIT', true);
define('WP_AUTO_UPDATE_CORE', true );
define('FS_METHOD','direct');
error_reporting(0);
@ini_set('display_errors', 0);

Gelelim bu kodlar ne işe yarıyor:

  • define(‘DISALLOW_FILE_EDIT’, true); = wp-admin içinde tema düzenleme ekranı üzerinden dosyaların düzenlenmesini engeller. Bence de zaten wp-admin üzerinden düzenleme işlemi yapmanıza gerek yok, güvenli de olduğu söylenemez. Uğraşmayın, kapatın.
  • define(‘WP_AUTO_UPDATE_CORE’, true ); = WordPress için bir güncelleme geldiğinde otomatik olarak güncelleme işlemene imkan veriyor. Bırakın güncelleme geldiği anda wordpress’iniz otomatik olarak kendisini güncellesin. Tabii wordpress’in çekirdek dosyalarında düzenleme yaptıysanız, bu ayarı kullanmanızı önermem. Keza otomatik güncelleme esnasında custom yazdığınız tüm kodlar ezilecektir.
  • define(‘FS_METHOD’,’direct’); = WordPress dosyalarınızın, sunucu üzerindeki bir user’ın direkt olarak düzenleme yapabilmesi, bunun dışındaki kullanıcıların bir işlem yapamamasını sağlayan ufak bir tanımlamadır. Bu tanımlama mevcut dosya sistemine düzenleme yetkisi verir. “FS_METHOD” şu değerleri alabilir: “direct”, “ssh2”, “ftpext”, ya da “ftpsockets”. Biz bunlardan “direct” olanını kullanacağız. “direct” tanımı ile PHP üzerinden gelen tüm I/O istekleri gerçekleşecek, diğerleri uygulanmayacaktır. Özellikle wordpress için gerek core güncellemeleri, gerekse eklenti güncellemesi ile ilgili hata alıyorsanız, yine sorununuzu bu tanım çözecektir.
  • error_reporting(0); ve @ini_set(‘display_errors’, 0); tanımlamaları yazılımsal olarak bir hata gerçekleştiğinde hata ve detaylarını PHP’nin ekrana olduğu gibi dökmesini engelleyecektir. Böylece saldırganın sunucu üzerinde debug yapmasının önüne geçebilirsiniz.

Sıra geldi tabloların prefixini değiştirmeye. WordPress kurulumu yaptığınızda veritabanınızdaki tüm tablolar varsayılan olarak “wp_” prefixi (ön tanımlaması) ile adlandırılır. Örneğin: “wp_comments”. Bu tür ön tanımlı gelen default kullanımlardan kurtulmak gerekiyor. Bunun için öncelikle güzelce bir DB backup alıyoruz. Bir sorun çıkarsa rollback atmak farzdır 🙂 Başınıza birşey gelirse sorumluluk kabul etmem, efendi gibi yedek alın sonrasında çalışın 🙂 Durduk yere aksiyona gerek yok değil mi? Sonrasında ise wp-config.php dosyamıza şu tanımlamayı yapıyoruz:

$table_prefix  = 'ouc11vd_';

Burada yer alan “ouc11vd_” stringi tablolarımızın yeni prefixidir. Siz istediğiniz herhangi bir başka isim de koyabilirsiniz. Örneğimize “ouc11vd_” üzerinden devam ediyorum. wp-config.php dosyamızı kaydettikten sonra SQL sunucumuza bağlanıp aşağıdaki SQL’leri tek tek çalıştırmamız gerekli:

RENAME table 'wp_commentmeta' TO 'ouc11vd_commentmeta';
RENAME table 'wp_comments' TO 'ouc11vd_comments';
RENAME table 'wp_links' TO 'ouc11vd_links';
RENAME table 'wp_options' TO 'ouc11vd_options';
RENAME table 'wp_postmeta' TO 'ouc11vd_postmeta';
RENAME table 'wp_posts' TO 'ouc11vd_posts';
RENAME table 'wp_terms' TO 'ouc11vd_terms';
RENAME table 'wp_term_relationships' TO 'ouc11vd_term_relationships';
RENAME table 'wp_term_taxonomy' TO 'ouc11vd_term_taxonomy';
RENAME table 'wp_usermeta' TO 'ouc11vd_usermeta';
RENAME table 'wp_users' TO 'ouc11vd_users';

Ardından gelelim options tablosunu update etmeye. Bunun için de yukarıdaki sorguları çalıştırdıktan sonra aşağıdaki sorguyu çalıştırmak gerekiyor:

SELECT * FROM 'ouc11vd_options' WHERE option_name LIKE 'wp_%'

Bu sorgu sonrasında gelen “option_name” alanındaki tüm sonuçlarda gördüğünüz “wp_” ile başlayan tüm tanımlamaları, “ouc11vd_” olarak elle yani manuel olarak güncellemeniz gerekiyor.

Ve son olarak usermeta tablosunu da güncellemek gerekli:

SELECT * FROM 'ouc11vd_usermeta' WHERE meta_key LIKE 'wp_%'

Bu sorgu sonrasında da gelen “meta_key” alanındaki tüm sonuçlarda gördüğünüz “wp_” ile başlayan tüm tanımlamaları, “ouc11vd_” olarak elle yani manuel olarak güncellemeniz gerekiyor.

Gelelim wp-config.php dosyasına yapacağımız son eklemeye. Burada yer alan kodları yine wp-settings.php ‘nin include edildiği kod bloğunun üzerine yapıştırın. Bu güvenlik anahtarları (WordPress Security Keys) sitenize ekstra güvenlik sağlayacaktır. Bu anahtarlar rastgele tanımlanan değerleri ile, kullanıcıların cookilerine bilgi yazarken bilgilerin şifrelenmesini artıran ve veri güvenliğini sağlayan ek bir protokoldür diyebiliriz. Sayfada yer alan kodlar, sayfayı her refresh ettiğinizde değişicektir. Tüm siteleriniz için sayfayı yenileyerek yeni anahtar almanız gerekiyor. Yani aldığın anahtarları tüm sitelerinize uygulamayın, her siteniz için yeni bir key yaratın. Örnek bir secret-key tanımı şu şekildedir (sakın aşağıdaki kullanmayın, buradan kendinize yenisini yaratın):

define('AUTH_KEY',         'LrGTqe8HK;uZs%k.NNnRhjM9,o4_uD?[SZd1z?hsV7Wf,g#4K* U4jYTO10m');
define('NONCE_KEY',        '^`h*{Fgt;mP-`#W7|z|puKbzD[y,F:R{!2vj)+aapyf]71q(-CVDcn3m2]70d&,|');
define('AUTH_SALT',        'V4Qt4S;UL1!$wFCJ!V,J0+9!|vXbT6[^u<&Md%Q;9+VNM,~CX^|sf#K1F6,@](QP');
define('SECURE_AUTH_SALT', '2{|jlBu8Bmuc>|vPLh0&ba?`]7ot!gqXuT{{w&d4t|+m|l@VbeU+;3~E.u|iM~Sv');
define('LOGGED_IN_SALT',   '  8geL:.!kgX7h,l|09Wd9J~ AE:TtA5Tb5rHPp#ZF~uMc/#U&jAT?6`5fGALiVt');
define('NONCE_SALT',       'D9=s].*v/Fkk{wn7eNFay5!hUo-1}[OMbJ!?@-&|jEd.n:)lm@ t7S3V(f);QS z');

Böylece wp-config.php içinde yaptığım geliştirmelerin sonuna geldik. Şimdi sıra geldi NGINX geliştirmelerine. NGINX özellikle static içerikleri serve ederken apache’ye göre çok daha hızlı ve stabil çalışan, gerekirse load-balancer olarak bile kullanabileceğiniz pratik bir uygulamadır.

Öncelikle nginx’in main konfigürayon dosyasını açıyoruz:

vim /etc/nginx/nginx.conf

http { .. } bloğunun içinde eğer yoksa şu kod bloklarını yerleştiriyoruz:

        
        server_tokens off;
        add_header X-Frame-X-XSS-Protection "1;mode=block";
        add_header X-Frame-Options SAMEORIGIN;
        add_header X-Content-Type-Options nosniff;
        add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; ";

Ayrıca gzip’iniz açık değilse onu da açalım (bende her zaman açık ama sizlerde değilse diye hazır configimi paylaşıyorum):

        gzip on;
        gzip_disable "msie6";
        gzip_vary on;
        gzip_proxied any;
        gzip_comp_level 6;
        gzip_min_length 1100;
        gzip_buffers 16 8k;
        gzip_http_version 1.1;
        gzip_types      text/plain application/xml text/css text/js text/xml application/x-javascript text/javascript application/javascript application/json application/xml+rss;

Sonrasında ise tüm sitelere ait nginx konfigürasyonlarına aşağıdaki tanımlamaları tek tek uygulayalım. Aşağıda sırasıyla açıklayarak yazdığım kodları alt alt tanımlayabilirsiniz.

vim /etc/nginx/conf.d/sitenizin_config_dosyasinin_adi.conf

ile dosyamızı açıyoruz. Aşağıdaki config’i server { .. } bloğu içine yerleştiriyoruz. Bu blok “wp-content/uploads” dizini içerisine “.php”, “.pl” gibi dosyaların yüklenmesini engelliyor. Özellikle uploads klasörü wordpress’in arka bahçesi, genelde bu dizine dosya yükleme girişimi ile defalarca kez karşılaştım.

location ~* ^/wp-content/uploads/.*.(php|pl|py|jsp|asp|htm|html|shtml|sh|cgi)$ {
    types { }
    default_type text/plain;
}

Tabii hatırlarsanız yukarıdaki wp-config.php’de wp-content klasörümüzü “icerik” olarak değiştirmiştik. Bu yüzden kodumuz şöyle olmalı:

location ~* ^/icerik/uploads/.*.(php|pl|py|jsp|asp|htm|html|shtml|sh|cgi)$ {
    types { }
    default_type text/plain;
}

Bir diğer saldırı metodlarında kullanılan dosya xmlrpc.php Bu dosyaya gelen istekleri de bir güzel bloklayalım:

location ~ xmlrpc.php { deny all; }

Sık gelen spam yorumlar nedeniyle, spam yorumları azaltan ve bazılarını direkt bloklayan kodumuzu da yerleştirelim:

location /wp-comments-post.php {
        limit_except POST { deny all; }
        if ($http_user_agent ~ "^$") { return 403; }
}

Böylece user-agent bilgisi boş olan herkesi 403 yanıtı ile postaladık. Gelelim ufak rötuşlara. Kodlardan da anlayacağınız üzere wp-config.php, readme.html, wp-includes ve wp-admin içine direkt erişimleri bloklayalım:

location ~ /\.ht { deny all; }
location ~ wp-config.php { deny all; }
location ~ readme.html { deny all; }
location ~ readme.txt { deny all; }
location ~ /install.php { deny all; }
location ^wp-includes/(.*).php { deny all; }
location ^/wp-admin/inc:qludes(.*)$ { deny all; }

Eğer istek metodları içerisinde trace, delete ya da track geçiyorsa muhtemelen sitemizi tarayan birileri var, direkt 403 yanıtı ile postalıyoruz:

if ($request_method ~* "^(TRACE|DELETE|TRACK)") { return 403; }

Ve geldik en can alıcı noktaya. Eğer URL’de parametre ya da valuelarda zararlı stringler varsa bu arkadaşları da direkt şutluyoruz. Bu tanımlama ile sitenizde bir açık tarayan arkadaşları şutlamış oluyoruz:

if ($args ~* "\.\./") { set $susquery 1; }
if ($args ~* "\.(bash|git|hg|log|svn|swp|cvs)") { set $susquery 1; }
if ($args ~* "etc/passwd") { set $susquery 1; }
if ($args ~* "boot.ini") { set $susquery 1; }
if ($args ~* "ftp:") { set $susquery 1; }
if ($args ~* "http:") { set $susquery 1; }
if ($args ~* "https:") { set $susquery 1; }
if ($args ~* "(<|%3C).*script.*(>|%3E)") { set $susquery 1; }
if ($args ~* "mosConfig_[a-zA-Z_]{1,21}(=|%3D)") { set $susquery 1; }
if ($args ~* "base64_encode") { set $susquery 1; }
if ($args ~* "(%24&x)") { set $susquery 1; }
if ($args ~* "(127.0)") { set $susquery 1; }
if ($args ~* "(globals|encode|localhost|loopback)") { set $susquery 1; }
if ($args ~* "(request|insert|concat|union|declare)") { set $susquery 1; }
if ($args !~ "^loggedout=true") { set $susquery 0; }
if ($args !~ "^action=jetpack-sso") { set $susquery 0; }
if ($args !~ "^action=rp") { set $susquery 0; }
if ($http_cookie !~ "^.*wordpress_logged_in_.*$") { set $susquery 0; }
if ($http_referer !~ "^http://maps.googleapis.com(.*)$") { set $susquery 0; }
if ($susquery = 1) { return 403; }

Bu güvenlik önlemine ek olarak URL’de ingilizce olmayan karakterleri de 403 kodu ile gönderelim:

if ($args ~* "(%0|%A|%B|%C|%D|%E|%F)") { return 403; }

Yalnız burada şöyle bir sorun var. Özellikle akismet’in yakaladığı spam yorumlar içerisinde geçen bazı non-english karakterler, admin panelinizde “tüm istenmeyenleri sil” dediğinizde sizin de 403 sayfasını görmenize sebep oluyor. Bu yüzden böyle bir problem yaşarsanız bu config’in başına # işareti koyarak commentleyin; spamları temizledikten sonra commenti tekrar kaldırmayı unutmayın.

# if ($args ~* "(%0|%A|%B|%C|%D|%E|%F)") { return 403; }

NGINX düzenlemelerinden sonra gelelim dosya izinlerine. Ben tüm yetkiyi nginx kullanıcısına veriyorum. Başka bir user kullanıyorsanız lütfen komutu düzenleyin. Bunun için sunucuya SSH yaptıktan sonra sırasıyla aşağıdaki komutları çalıştırıyoruz:

chown -R nginx:nginx /www/domain.com
chmod -R g+w /www/domain.com

Sonrasında ise SQL sunucunuza bağlanıp (ben MySQL Workbench kullanıyorum) tüm tablolarınızı kontrol edin. Tanımadığınız bir tablo varsa uçurun. Benim tablolarım arasında backdoor ile yaratılmış birkaç tablo bile vardı. Çay ve çiğdem eşliğinde hepsini tek tek sildim 🙂 Sunucuya temiz dosyalarınızı yüklemeden önce veritabanlarınızı muhakkak kontrol etmeniz lazım.

Ayrıca backdoor ile “/TMP/” dizinine php kod betiklerinin txt formatında atıldığını, belli periyotta buradan kodların çekilip PHP dosyasına çevirilip çalıştırıldığını farkettim. Bu yüzden hemen “/TMP/” dizinini de bir güzel temizledim. Genelde TMP’yi pek ellememeniz gerekir ama burada mevcut binlerce dosya içinden hangisinin zararlı olduğunu kestiremediğim ve tek tek kontrol edemeyeceğim için boşalttım. Eğer “/TMP/” dizininde bir sorun olmadığından eminseniz bu adımı pas geçebilirsiniz:

rm -rf /TMP/*

Gelelim sunucuya ufak bir antivirüs yazılımı kurmaya. Genelde pek birşey yakalamıyorlar ama bu saldırı sonrasında yaptığım tarama sonrasında 22 shell dosyası bulup sildi. Bu yüzden tarama yapmanın zararı yok. Bunun için de hemen Clamav kuralım (kurulum için önce şuradan kendim öğrendim):

cd /etc/yum.repos.d
wget http://blog.centoshost.com/uploads/dag-clamav.repo
yum install clamav clamav-devel clamd

Kurulum sonrasında bazı klasörler oluşmayabiliyor. Bunun için elle oluşturuyoruz:

touch /var/log/freshclam.log
chmod 600 /var/log/freshclam.log
chown clamav /var/log/freshclam.log

Kurulum sonrasında hemen bir güncelleme yapalım:

freshclam

Güncelleme sonrasında tarama yapabilirsiniz. Tarama için kullanım örnekleri:

/www/ dizini altındaki tüm dosyaları taramak ve her bir dosyanın ismini görmek için:

clamscan /www/ --recursive

/www/ dizini altındaki tüm dosyaları taramak ve sadece etkilenmiş olan dosyaları ismini görmek için:

clamscan /www/ --recursive --infected

/www/ dizini altındaki tüm dosyaları taramak ve sadece etkilenmiş olan dosyaları başka bir yere taşımak için:

clamscan --recursive --move=/www/VIRUS /www/

/www/ dizini altındaki tüm dosyaları taramak ve etkilenmiş olan dosyaları direkt silmek için:

clamscan /www/ --recursive --remove

Log tutarken sorun yaşıyorsanız aşağıdaki dosyadan LogFileMaxSize 0 yazıyor olabilir. Buradaki değeri 1M veya daha büyük yapabilirsiniz.

vim /etc/clamd.conf

Bu işlemden sonra ise muhakkak yapmanız gereken en önemli adım PHP’nin tehlikeli fonksiyonlarını disable etmek. Bunun için php.ini dosyamızı açıyoruz:

vim /etc/php.ini

Ardından disable_functions tanımının karşısına aşağıdaki fonksiyon isimlerini giriyoruz. Benim php.ini dosyamda ortalama 300. satırlarda:

disable_functions = _getppid,apache_child_terminate,apache_setenv,define_syslog_variables,diskfreespace,dl,escapeshellarg,escapeshellcmd,eval,exec,fpaththru,ftp_raw,ftp_rawlist,getmypid,getmyuid,highlight_file,ignore_user_abord,ini_alter,ini_get_all,ini_restore,inject_code,leak,link,listen,openlog,parse_ini_file,passthru,pcntl_exec,php_uname,phpAds_remoteInfo,phpAds_XmlRpc,phpAds_xmlrpcDecode,phpAds_xmlrpcEncode,phpinfo,popen,posix,posix_ctermid,posix_getcwd,posix_getegid,posix_geteuid,posix_getgid,posix_getgrgid,posix_getgrnam,posix_getgroups,posix_getlogin,posix_getpgid,posix_getpgrp,posix_getpid,posix_getpwnam,posix_getpwuid,posix_getrlimit,posix_getsid,posix_getuid,posix_isatty,posix_kill,posix_mkfifo,posix_setegid,posix_seteuid,posix_setgid,posix_setpgid,posix_setsid,posix_setuid,posix_times,posix_ttyname,posix_uname,proc_close,proc_get_status,proc_nice,proc_open,proc_terminate,shell_exec,show_source,socket_accept,socket_bind,socket_clear_error,socket_close,socket_connect,source,syslog,system,tmpfile,virtual,xmlrpc_entity_decode

php.ini dosyanızın nerde olduğunu bilmiyorsanız:

whereis php.ini

Siteye ait dosyaları sunucuya yüklemeden önce serverı tekrar güzelce taradım. Ardından tüm site dosyalarımı sunucuya geri yükledim. Şimdi ise yapmamız gereken ilk işlem dosya ve klasör +rw yetkilerini doğru bir şekilde vermek. WordPress için tüm klasörlere CHMOD 755, dosyalara ise 644 vermek uygun olacaktır. Bunun için her bir siteniz için sırasıyla şu iki komutu çalıştırın:

find /www/ugureskici.com/ -type d -exec chmod 755 {} \;
find /www/ugureskici.com/ -type f -exec chmod 644 {} \;

Bu komutlar /www/ dizini altında çalışan blog dizinimin içindeki tüm klasörlere 755, dosyalara 644 vermekte. Dosya pathlerini kendinize göre düzenleyiniz.

Gözden kaçırmış olma ihtimalimize karşı, dosya sistemimi bir de manuel konrol edelim. Sitelerin icerik klasörü altındaki uploads dizinlerinde “.php” uzantılı dosya var mı bakalım:

find /www/*/html/icerik/uploads -name "*.php" -print

Varsa ve tanımıyorsak hemen siliyoruz.

Ufak bir düzeltme. Sevgili Salim Dervişoğlu‘nun yorumlarını yazıya eklemek isterim. Kendisi der ki: “Kullandığın find + chmod kombosu upload/tmp dizinlerinin izinlerini bozabilir eğer dizinler web server processini çalıştıran kullanıcı değilse” uyarısını yaptı. Kendisine düzeltmesi için çok teşekkür ederim 🙂 Yorumunu aynen yazıya ekliyorum:

Eğer web serverın bir dizine yazması gerekiyorsa onun ya ownerı olması gerekir ya da yazma izni olan bir grupta olması gerekir. Eğer permissionları 777 yaparak çözdüysen ve sonrasında bunu değiştirirsen patlatır. Bunların dışında SELinux ile gücüne güç katabilirsin ama yönetmesi biraz zor.

Tabii benim uygulamamda hiçbir yere 777 vermediğim için bozmadım sanıyorum 🙂 SELinux güzel bir zamazingo. Hiç kullanmadığım için bu konuya girmiyorum. Yazımıza devam edelim.

Bu işlemleri yaptıktan sonra shell bulaştırılan ama trafiği hiç olmayan bir sitem için access loglarını açtım. Bunun için sitemin nginx config dosyamı açtım:

vim /etc/nginx/conf.d/sitem.conf

access loglarını açmak için server { .. } kod bloğu içine şunu tanımlıyoruz:

access_log   /var/log/access_vikvik.log;

Bir de ne göreyim, shell’e ait dosyalara istek atan IP 🙂

80.87.205.104 - - [xx/xxx/20xx:04:19:20 +0300] "POST /adodb.class.php HTTP/1.1" 200 20 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36"

Hemen iptables ile blokluyoruz:

iptables -A INPUT -s 80.87.205.104 -j DROP

Sonrasında save’lemeyi unutmayalım:

service iptables save

Bir de varsa sunucuda kullandıklarımızın güncellemeleri, kontrol ettikten sonra güncelleyelim:

yum update

Bu saldırılarda şu isimlerde dosyalar mevcuttu:

  • adodb.class.php
  • news_parser.class.php
  • user-info.php
  • db_update.php
  • data.bin
  • site-widgets.php

Bunları da kurulumdan sonra tek tek arayıp, bulduklarımı sildim. İlk temizlik operasyonumda temizlemiştim aslında; size bu yazıyı hazırlarken yaptığım temizlikte ise çıkmadı (süper!). Dosyaları örnek olarak şu şekilde arayabilirsiniz:

find /www/ -name "adodb.class.php"

Son olarak tekrar clamav ile /www/ dizinimizi taradıktan sonra hadi geçmiş olsun 🙂

Bütün bunlara ilaveten alabileceğiniz ek güvenlik önlemleri:

  • Tüm sitelerinizi SSL’e geçirmek.
  • Evinize bir statik IP satın almak ve wp-login.php ve wp-admin dizinlerine sadece bu IP’ye izin vermek.
  • Statik IP aldıysanız sadece bu IP’nin SSH yapabilmesi için gerekli firewall kuralları tanımlamak.
  • Şuradaki uygulamayı gerçekleştirmek. Henüz ben yapmadım, ilk fırsatta muhakkak yapacağım.
  • Ayrıca buradaki eklentiyi kurarak, ek bir kaç güvenlik önlemi daha alabilirsiniz. Kullandığım güzel bir security eklentisi.

Kaynak göstermek ve link verme koşulu ile yazımı istediğiniz yerde kullanabilirsiniz. Yazıyı hazırlamak ve edindiğim tecrübeleri buraya dökmek için baya emek verdim 🙂 Yazmak, uygulamaktan daha zor 🙂

Adım uğur eskici, hakkımda daha çok bilgi verdiğim yazıya buradan ulaşabilirsiniz. Lütfen yapacağınız yorumlarda, kişi ve kurumlara hakaret etmeden ve kişilik haklarına zarar vermeden düşüncelerinizi yazınız.

Türkiye’deki SEO Durumu – SEMrush Webinar

15 Mart 2017 tarihinde SEMrush’ın önderliğinde ve Türkiye’de ilk defa gerçekleşen bir SEO webinarı düzenledik. Moderatörlüğünü sevgili Aykut Aslantaş’ın yaptığı ve konuk olarak GittiGidiyor’dan sevgili Ümit Yılmaz ve bendeniz Uğur Eskici, Türkiye’deki SEO sektörü geçmişten…

Google Alışveriş Reklamları için GTIN Zorunluluğu

Google, alışveriş reklamları için 2015 yılında GTIN’i özellikle belirlemiş olduğu 50 özel markada zorunlu tutmaya başlamıştı. 2016 yılında ise sadece 50 marka için değil, GTIN numarasına sahip tüm ürünler şeklinde kapsamını genişletti. Nedir bu 50…

15 yorum

    Çok teşekkürler Nebi ve Murat; vakitsizlik sorununu aşabilirsem güncel tutmaya çalışacayım ama şu sıralar pek mümkün değil gibi 🙂 Elimden geleni yapacağım..

    WordPress Nginx Rewrite ayarları konusunda bilginiz var mı peki? Bu konuda büyük bir yardıma ihtiyacım var 🙂

    Detaylı anlatımın ve bu kadar fazla emek verip son derece can alıcı bilgilerin de yer aldığı bu değerli yazıyı paylaştığın için çok teşekkürler. Eline koluna sağlık abi.

    Evet, mümkündür. Biraz config yazmanız lazım. htaccess kurallarının nginx’e uyarlanması gerekli.

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir