Disable Edilmiş Sistem Fonksiyonları Umrumda Değildir

Ziyahan Albeniz - 26 Kasım 2018 -

Sunucunızda, sistem seviyesinde kod çalıştırılmasınığı sıkılaştırma (hardening) amacıyla devre dışı bırakmış olabilirsiniz. Fakat Hackerlar boş durmuyor ve Imap PHP kütüphanesi kullanılan sunucularda bir bypass ile karşımızdalar.

Disable Edilmiş Sistem Fonksiyonları Umrumda Değildir

Bir senaryo hayal edin.

Unrestricted File Upload zafiyeti bulmuş, shell dosyasını sunucuya göndermişsiniz. Yahut LFI ya da RFI ile sistem üzerinde komut çalıştırabileceğiniz payload hazır!

Sunucuda çalışmasını beklediğiniz komutu gönderdiğinizde, bir sürpriz sizi bekliyor:

www.example.com/shell.php?cmd=whoami

Warning: system() has been disabled for security reasons in /var/www/html/shell.php on line 6.

PHP'nin ayarları arasında yer alan disable_functions seçeneği kimi PHP fonksiyonlarını devre dışı bırakabileceğiniz bir özellik. Nitekim önerilen sıkılaştırma pratiklerinden (hardening) biri de system, exec, shell_exec, passthru gibi fonksiyonları bu ayar ile birlikte devre dışı bırakmak.

Sistem yöneticisinin yapacağı böyle bir sıkılaştırmanın saldırganın elini ayağını bağlayacağı aşikar.

Fakat geçtiğimiz hafta Rus antichat forumunda Twoster isimli kullanıcı yeni bir bypass yöntemini açıkladı.

Bypass temel olarak PHP'de imap extension'ı kurulduktan sonra aktif hale gelen imap_open fonksiyonuna dayanıyor.

Antichat forumundaki açıklamalardan sonra Anton Lopanitsyn adlı başka bir kullanıcı Github reposunda exploit kodunu yayınladı.

<?php
# CRLF (c)
# echo '1234567890'>/tmp/test0001

$server = "x -oProxyCommand=echo\tZWNobyAnMTIzNDU2Nzg5MCc+L3RtcC90ZXN0MDAwMQo=|base64\t-d|sh}";

imap_open('{'.$server.':143/imap}INBOX', '', '') or die("\n\nError: ".imap_last_error());

Şimdi bypass'ın ayrıntılarına ve nedenlerine değinebiliriz.

imap_open()

imap_open() fonksiyonu PHP çekirdeğinde olan bir fonksiyon değil, Washington üniversitesi tarafından geliştirilen imapd için bir wrapper. Yukarıda da sözünü ettiğimiz gibi IMAP extension'ı kurulduktan sonra PHP imap_open() fonksiyonuna sahip olmuş olacak.

Fonksiyonun sentaksı ise şöyle:

resource imap_open ( string $mailbox , string $username , string $password [, int $options = 0 [, int $n_retries = 0 [, array $params = NULL ]]] )

Biz burada dikkatlerimizi fonksiyonun aldığı ilk parametre olan mailbox parametresine yoğunlaştırıyor olacağız.

Şimdi biraz daha yakından bakalım.

Bu parametre sunucu adı ve sunucudaki mail kutusunun dosya yolundan oluşmaktadır. Özel bir isim olarak INBOX hali hazırdaki kullanıcının kişisel posta kutusunu temsil eder.

Sunucu adı ise köşeli parantezler {} arasına yazılan sunucu adı ya da IP adresi, opsiyonel bir değer olarak port numarası (: karakterinden sonra yazılmalı) ve yine başka bir opsiyonel parametre olan protokol adı.

Protokol isminden sonra kullanıcı dilerse üçüncü bir opsiyonel parametre olarak bir flag belirtebilir.

$mbox = imap_open ("{localhost:993/PROTOCOL/FLAG}INBOX", "user_id", "password");

PHP'nin resmi dokümantasyonunda imap_open fonksiyonu sayfasında bir uyarı dikkatinizi çekiyor olmalı:

Warning

enable_insecure_rsh disable edilmedikçe kullanıcıdan alınan datanın mailbox parametresine doğrudan aktarılmaması gerektiğine dair bir ikaz var.

Şimdi işler biraz daha karıştı. Rsh nedir, neden disable etmek lazım?

Sanırım biraz daha geriye gitmekte ve IMAP sunucuları dizayn edilirken verilen kimi kararlara değinmekte fayda var…

Yaygın olarak kullanılan Unix-tabanlı iki farklı IMAP sunucusu olduğunu söyleyebiliriz. Washington Üniversitesi tarafından geliştirilen imapd ve Cyrus tarafından geliştirilen IMAP sunucusu.

Cyrus, kullanıcı e-postalarını kendi içerisindeki bir database'de tutar. Cyrus'a bu sebeple ulaşmak sadece IMAP protokolü ile mümkündür. Bu sebeple IMAP'in kurulu olduğu Unix sistemindeki kullanıcı hesapları ile IMAP account'ları arasında herhangi bir ilişki yoktur.

Fakat imapd e-postaları doğrudan Unix sistem dosyaları içerisinde örneğin /var/spool/mail şeklinde bir klasörde, mail kullanıcılarının Unix sistem hesaplarının sahibi olduğu dosyalarda saklar. Bu yüzden imapd söz konusu olduğunda kullanıcı hesap ve erişim yetkileri, Unix sunucu ile doğrudan alakalıdır. Şayet mailleriniz sizin yetkili olduğunuz spool dosyasında saklanıyorsa, SSH üzerinden login olabilir ve dosyalar üzerindeki hakkınızı bu şekilde doğrulayabilirsiniz.

IMAP ile tekrar bir bağlantı seremonisi gerçekleştirmeye neden gerek olsun?

İşte bu yüzden imap_open fonksiyonu önce bir SSH bağlantısı yapıyor ve kullanıcının yetkisi varsa yukarıda anlattığımız şekilde tekrar IMAP bağlantısı kurmadan devam ediyor. Buna IMAP preauthenticated modu deniyor.

mailbox parametresine atanacak değere dair PHP manual'inde yapılan uyarının sebebi de bu. SSH bağlantısı kurma işleminde mailbox değeri SSH komutuna parametre olarak verilecek.

-oProxyCommand

SSH komutu pek çok parametre alıyor. Aldığı parametrelerden biri de -o parametresi.

-o parametresi ile SSH komutuna bağlantı esnasında kullanabileceği seçenekleri belirtebiliyorsunuz. ProxyCommand de bu seçeneklerden biri. SSH bağlantısı yapılmadan hemen önce çalıştırılacak komutu belirtebilirsiniz.

Örneğin:

ssh -oProxyCommand="touch tmp.txt" localhost

Yukarıdaki komutu çalıştırdığınızda tmp.txt dosyasının, localhost'a SSH bağlantısı yapılmasa bile oluşturulduğunu göreceksiniz:

txt.tmp

İşte bütün bu noktaların birleşmesi sayesinde sunucuda system, passthru gibi fonksiyonlar kapatılmış olsa dahi komut çalıştırabilmek mümkün olacak.

Peki ya çözüm?

mailbox parametresi ile beraber kimi flag'ler kullanılabileceğinden söz etmiş idik. /norsh flag'i de bunlardan biri. IMAP sunucuları ile ilgili sözünü ettiğimiz preauthenticated modunun devredışı bırakılmasını sağlıyor.

php.ini dosyasından imap.enable_insecure_rsh seçeneğini "0" değeri ile disable edebilirsiniz. PHP'nin 5 sürümünde bu ayar olmadığı için doğrudan /norsh flagini kullanabilirsiniz.