Ders 23 - Stored XSS (Medium Level) | |||||
Bu yazıda güvenlik düzeyi Medium seviyesine yükseltilmiş DVWA'da Stored XSS'e karşı ne gibi bir güvenlik önlemi alındığı incelenecektir ve alınan güvenlik önlemine rağmen yine Stored XSS saldırısı düzenlenebilir mi sorusuna yanıt aranacaktır.
Konuya giriş yapmadan önce bu yazının dahil olduğu dvwa eğitim serisindeki tüm makalelere şu adresten bu yazının ilintili olduğu dvwa eğitim serisindeki diğer makalelere ise şu adreslerden erişebilirsiniz. Dersin HedefiHedefiniz Medium seviyesindeki güvenliği keşfedip nasıl aşabileceğinizi öğrenmektir.Stored XSS'e Karşı ÖnlemGeçen ders nasıl Stored XSS saldırısı yapılırı hem teorik hem de pratik olarak görmüştük. O derste bizim Stored XSS saldırısı düzenleyebilmemizin nedeni aşağıdaki kaynak kodun sayfada kullanılıyor olmasından dolayıydı:Low Level: <?php if( isset( $_POST[ 'btnSign' ] ) ) { // Get input $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); // Sanitize message input $message = stripslashes( $message ); $message = mysql_real_escape_string( $message ); // Sanitize name input $name = mysql_real_escape_string( $name ); // Update database $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );"; $result = mysql_query( $query ) or die( '' . mysql_error() . '' ); //mysql_close(); } ?> 5. satırdaki $message değişkeni DWVA ekranındaki ilk metin kutusunun değerini tutmaktadır. 6. satırdaki $name değişkeni ise DWVA ekranındaki ikinci meitn kutusunun (textarea'nın) değerini tutmaktadır. 8. satırdan 13. satıra kadar sanitizing, yani ayıklama işlemi yapılmaktadır. Bu ayıklama işlemleri sadece SQL Injection saldırılarını önlemek için yapılmıştır. Fakat Stored XSS saldırısı için herhangi bir önlem yer almamaktadır. İşte bu yüzden geçen ders Stored XSS saldırısında bulunabilmiştik. Şimdi güvenlik seviyesi Medium'ken ne yapılmış bir bakalım: Medium Level: <?php if( isset( $_POST[ 'btnSign' ] ) ) { // Get input $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); // Sanitize message input $message = strip_tags( addslashes( $message ) ); $message = mysql_real_escape_string( $message ); $message = htmlspecialchars( $message ); // Sanitize name input $name = str_replace( '<script>', '', $name ); $name = mysql_real_escape_string( $name ); // Update database $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );"; $result = mysql_query( $query ) or die( '' . mysql_error() . '' ); //mysql_close(); } ?> Bu kaynak kodda ilk planda görünen iki güvenlik açığı vardır. İlki 14. satırda yer almaktadır. O satıra göre kullanıcıdan gelen veride eğer <script> kelimesi varsa silinmektedir. Bu görünüşte saldırganları köşeye sıkıştıran bir hamledir. Çünkü saldırgan XSS saldırılarında javascript kodu kullanabilmek için illaki <script> tag'a ihtiyaç duyacaktır. Onun için bu tag olmazsa olmazdır. Fakat bundan daha önceki derslerde gördüğümüz üzere str_replace() fonksiyonu recursive çalışmadığı için iç içe <script> kullanımıyla str_replace() barikatı atlatılabilmektedir. Yani str_replace()'e girmeden önce: <scr<script>ipt> Buraya Javascript kodları gelecek </script> str_replace()'e girdikten sonra: <script> Buraya Javascript kodları gelecek </script> str_replace()'den geçen veriden arta kalanlar yine <script> tag'ını oluşturacak ve saldırgan hedefine varabilmiş olacaktır. Kaynak koddaki ikinci güvenlik açığı ise ekrandaki metin kutularına istemci taraflı karakter limiti konmuşken sunucu taraflı karakter limitinin konulmayışıdır. Daha açık konuşacak olursak ekranda yer alan metin kutularına html ile karakter limiti konmuşken PHP ile karakter limiti konulmamıştır. Bu bir hatadır. Çünkü istemciye yollanan her veri manipule edilebilirdir. Dolayısıyla istemci taraflı barikatlara asla güvenilmemelidir. Hatırlarsanız geçen ders textArea'nın maxlength="50" değerini maxlength="1000" yaparak karakter limitinden kurtulmuştuk ve zararlı kodu kutuya sığdırabilmiştik. Halbuki html'le olduğu kadar PHP ile de karakter limiti konsaydı bu durumda saldırgan belki istemci taraflı barikatı aşacaktı ama sunucuyu geçemeyecekti. Böylece gelen veri limiti aştığı için mesela veritabanına kaydolmayacaktı. Bu yüzden yukarıdaki kaynak koda en basitinden bir if - else yapısıyla limit aşıldığında uyarı ver, limit sağlandığında ise veritabanına kaydet gibi kodlar eklenebilir. Medium güvenlik seviyesinin iyi yaptığı bir iş varsa o da ikinci girdi alanı olan textarea kutusuna uygulanan filtredir. Textarea kutusundan gelen veriye 9. satırda strip_tags() fonksiyonu ile kusursuz bir sanitizing (ayıklama) işlemi uygulamaktadır. Bu fonksiyon kullanıcıdan gelen verideki tüm html tag'larını silmektedir. Böylece saldırgan yazacağı tek bir tag'ı dahi veritabanına kaydettiremeyecektir. Fakat medium seviyesinde ilk girdi alanı olan textbox kutusuna uygulanan filtre ise yetersiz durumdadır. Atlatılabilir. Stored XSS (Medium Level) Atlatmaİkinci girdi kutusu düzgün filtrelenmekte. Ama ilk girdi kutusu düzgün filtrelenmemekte. Dolayısıyla ilk girdi kutusuna şu payload girilebilir:
Uyarı: İlk metin kutusunun istemci taraflı karakter limiti arttırılmalı veya silinmelidir.
![]() ![]() Input: <scr<script>ipt>alert('Sayfa XSS açığına sahip!');</script> kırmızı renkli <script> kelimesi silinecektir ve geride arta kalanlar birleştiğinde yine <script> kelimesini oluşacaktır. Böylece güvenlik barikatı aşılmış ve <script> tag'ı sisteme sokulmuş olacaktır. Çıktı: <script>alert('Sayfa XSS açığına sahip!');</script> Ayrıca str_replace() fonksiyonu büyük küçük harf duyarlı bir kıyaslama ve kırpma işlemi yapıyor. Bu nedenle <script kodundaki karakterlerin birini veya tamamını büyük harf yaparak güvenlik önlemini atlatabiliriz. Input: <Script>alert('Sayfa XSS açığına sahip!');</script> Çıktı: <Script>alert('Sayfa XSS açığına sahip!');</script> Böylece javascript kodları kusursuzca çalışacaktır. Sonuçİkinci girdi alanı textarea kutusunda düzgün filtreleme yapıldığından stored xss saldırısı düzenlenememiştir. Fakat ilk girdi alanı textbox kutusunda düzgün filtreleme yapılmadığından stored xss saldırısı düzenlenebilmiştir. Bu şu şekilde olmuştur:İç içe kelime kullanımı ile str_replace() fonksiyonu atlatılabilmiştir. Çünkü str_replace() fonksiyonu yaptığı tarama ve silme işlemini recursive olarak yapmamaktadır. Bu ifadeyi biraz açıcak olursak str_replace() fonksiyonu <script> tag'ını gördüğünde silmektedir, fakat bunun akabinde tarama işlemine "kaldığı yerden" devam etmektedir. Yani başa sarmamaktadır. Tekrar başa gelip taramasına o şekilde devam etmediği için, kaldığı yerden devam ettiği için arta kalan karakterler birleştiğinde oluşan yeni <script> tag'ını str_replace() fonksiyonu göremeyecektir. Böylelikle güvenlik aşılmış olacaktır. Ayrıca str_replace() fonksiyonu büyük küçük harf duyarlı şekilde kıyaslama ve kırpma yapar halde tanımlandığından kıyaslamadaki karşılık gelen kodun karakterlerden birini büyük yaparak eşleşmeden kaçınılabilir ve güvenlik yine aşılabilir. Güvenlik seviyesi Medium iken belli ölçüde güvenlik sağlandı gibi görünse de tekniği bilen için bu güvenlik önlemi hiçbir zorlayıcılığa sahip değildir. |
|||||
![]() |
|||||
|
|||||
Yorumlar |
|||||
|
|||||
|
|||||
|
|||||
|
|||||
Yorum Ekle | |||||