Web uygulamalarına yönelik sızma testlerinde dosya yükleme nesneleriyle karşılaşılabilmektedir. Geliştiriciler, kullanıcıların sisteme dosya yükleyebilmeleri için bu nesneleri kullanmaktadırlar. Bir sisteme kayıt olan kullanıcıların profil fotoğrafı yüklemeleri, kullanıcıların bir kuruma CV göndermek için özgeçmiş bilgileri içeren dosyaları kurumun sistemine yüklemeleri gibi birçok dosya yükleme sebeplerine dair örnekler bulunmaktadır. Çoğu zaman sisteme yüklenen dosyalar, web uygulaması üzerinden erişilebilir bir dizine yerleştirilmektedir. Ancak bu durum saldırganların dosya yükleme nesnelerini kötüye kullanmalarına ve işletim sistemi üzerinde komut çalıştırmak için sisteme zararlı dosyalar yüklemelerine neden olabilir.
Resim 1.1’de fotoğraf yükleme amacıyla oluşturulmuş bir web sayfası görülmektedir.
Sayfada yazan uyarıya göre sadece resim dosyası yüklenebilmektedir. Ancak arka planda dosya kontrolü yapan hiçbir kısıtlama bulunmamaktadır. Dolayısıyla sisteme resim dosyası yerine, sistem üzerinde komut çalıştırmaya yarayan bir dosya yüklenebilir ve işletim sistemi komutları çalıştırılabilir.
Resim 1.2’de, işletim sistemi üzerinde komut çalıştırmak amacıyla kullanılan “shell_exec” fonksiyonunu içeren tek satırlık kod bulunmaktadır.
Dosya yükleme nesnesi kullanılarak, fotoğraf yüklemek yerine bu dosya yüklenirse saldırganlar işletim sistemi üzerinde komut çalıştırabilirler.
Resim 1.3’de PHP dosyası sisteme yüklenmiştir ve önceki fotoğrafın yerini almıştır.
Dosyaya erişim sağladıktan sonra GET metodu kullanılarak “cmd” parametresine herhangi bir işletim sistemi komutu yazıldığında dönen sonuç ekrana yazılacaktır. Resim 1.4’te sisteme yüklenen dosya ile işletim sistemi üzerinde komut çalıştırılmıştır.
Bu örnekte dosya yükleme ve komut çalıştırma işlemleri oldukça kolay bir şekilde yapılmış olsa da komut çalıştırmak için sisteme zararlı dosya yüklemek her zaman bu kadar kolay değildir. Çünkü geliştiriciler kod düzeyinde birtakım önlemler alabilirler ve bu önlemler sisteme her türden dosyanın yüklenmesine izin vermeyebilir. Ancak, kod düzeyinde alınmış olan bazı önlemleri atlatmak ve sisteme istenen formatlarda dosya yüklemek mümkündür.
Bu yazıda, dosya yükleme işlemlerine PHP ve Javascript dilleri kullanılarak getirilmiş kısıtlamaların nasıl atlatılacağı, uygulamalı bir şekilde anlatılacaktır. Uygulama için Apache sunucusu çalışan ve Apache üzerinde farklı türden kısıtlamalar getirilmiş dosya yükleme sayfaları içeren Windows Server 2016 makine bulunmaktadır. Yazı boyunca kısıtlamaların atlatılması ve atlatıldıktan sonra işletim sistemi üzerinde komut çalıştırmak için dosya yükleme işlemleri uygulamalı bir şekilde anlatılacaktır.
Dosya Yükleme Kısıtlamalarının Atlatılması
Web uygulamaları üzerinden, sisteme dosya yüklemek için kullanılan dosya yükleme nesneleri, önceki bölümde anlatıldığı üzere herhangi bir kısıtlama bulunmadığı durumlarda saldırganlar tarafından kötüye kullanılabilmektedir. Geliştiriciler, bu tür risklere karşı kod seviyesinde kontroller yaparak, sisteme farklı türden dosyaların yüklenmesini engelleyebilirler. Ancak alınan bazı önlemler birtakım yöntemlerle atlatılabilir. Aşağıda dosya yükleme işlemi için kod seviyesinde alınan önlemler ve bu önlemlerin nasıl atlatılabileceği anlatılmıştır.
İstemci Tabanlı Kontrol
İstemci tabanlı kontrol, kullanıcılar tarafından yapılan istekler sunucuya gönderilmeden önce gerçekleşmektedir. Geliştiriciler, kullanıcılara hızlı yanıtlar vermek ve daha iyi kullanıcı deneyimi sağlamak için Javascript, HTML ve VBScript dillerini kullanarak tarayıcı düzeyinde kontrol gerçekleştirebilirler. Resim 2.1.1’de yüklenen dosyalar için uzantı kontrolü yapan Javascript kodları yer almaktadır.
Resim 2.1.2’de PHP dosyası yüklendiği sırada, Javascript kontrolü sonucunda uyarıyla karşılaşılmıştır ve bu uyarıya göre “bmp, gif, png, jpg, jpeg” uzantıları dışında farklı bir uzantıya sahip olan dosyalar sisteme yüklenememektedir.
Uzantı kontrolü Javascript ile yapıldığı için henüz sunucuya bir istek gitmemiştir. Bu durumda bir proxy uygulaması kullanılarak sunucuya giden istek yakalanabilir ve üzerinde değişiklik yapılabilir. Bunun için ilk olarak Javascript kontrolüne takılmamak adına, istenilen uzantılardan birine sahip olan bir dosya yüklenmelidir. Daha sonra sunucuya istek giderken araya girilerek dosya uzantısı değiştirilebilir ve sunucuya bir resim dosyası yerine PHP uzantılı dosya gönderilebilir. Ancak bir resim dosyasının uzantısının PHP olarak değiştirilmesi ve sunucuya gönderilmesi işe yaramayacaktır. Bu nedenle içerisinde PHP kodları yer alan bir dosyanın uzantısı, kabul edilen uzantılardan biri ile değiştirilebilir ve Javascript uzantı kontrolü atlatıldıktan sonra dosya uzantısı yeninden PHP yapılarak, dosya sunucuya gönderilebilir.
Resim 2.1.3’te, az önce sisteme yüklemeye çalışılan “shell.php” adlı dosyanın uzantısı “gif” olarak değiştirilmiştir ve dosya yüklenmek üzere seçilmiştir.
Ardından “Upload” butonuna tıklandıktan sonra isteği yakalamak için proxy uygulaması olarak “Burp Suite” çalıştırılmıştır. Burp Suite, web uygulama sızma testlerinde; araya girme, istek gönderme, zafiyet tarama, kaba kuvvet saldırıları gerçekleştirme gibi işlevsel özellikler sağlayan oldukça geniş çaplı bir uygulamadır. Resim 2.1.4’te Burp Suite uygulamasının proxy özelliği 8080 portunda aktif edilmiştir ve isteklerin yakalanması için Mozilla Firefox üzerinde kurulu olan “FoxyProxy” eklentisi ile tüm istekler yerel makinenin 8080 portuna yönlendirilecek şekilde ayarlanmıştır.
Resim 2.1.5’te “Upload” butonuna tıklandıktan sonra, Burp Suite uygulaması ile giden istek yakalanmıştır.
Görüldüğü üzere dosya adı “shell.gif” olmasına rağmen dosya içeriği tek satırlık PHP kodundan oluşmaktadır. Dosya uzantısı “.php” olarak değiştirilebilir ya da ismin sonuna “.php” getirilerek dosya “shell.gif.php” ismiyle sisteme kaydedilebilir. Resim 2.1.6’da dosya uzantısı değiştirilerek istek sunucuya gönderilmiştir.
Resim 2.1.7’de PHP dosyası sisteme yüklenmiştir ve işletim sistemi üzerinde komut çalıştırılmıştır.
Dosya Uzantı Kontrolü
Sisteme yüklenecek olan dosyaların, saldırganların komut çalıştırmalarına olanak verecek türden dosyalar olmaması için, geliştiriciler sunucu taraflı uzantı kontrolü yapabilirler. Uzantı kontrolü “whitelisting (beyaz liste)” ve “blacklisting (kara liste)” olmak üzere 2 farklı şekilde gerçekleştirilebilir. Beyaz liste yöntemi uygulanarak, sadece belirli uzantılara sahip olan dosyaların yüklenmesine izin verilir. Kara liste çözümü ise belirli uzantılara sahip olan dosyaların yüklenmesine izin verilmemesi için kullanılır. Resim 2.2.1’de beyaz liste ve kara liste yöntemleri uygulanarak, yüklenecek olan dosyalar için uzantı kontrolü yapan PHP kodları yer almaktadır.
Kara liste çözümünü atlatmak için pek bilinmeyen dosya uzantıları kullanılarak yükleme yapılabilir. Örneğin; PHP programlama dili için pht, phpt, phtml, php3, php4, php5, php6 dosya uzantıları da kullanılabilmektedir. Ancak bu uzantılar pek bilinmediği için kontrol edilmemektedir. Resim 2.2.2’de kara liste çözümü uygulanmış bir web sayfasına PHP dosyası yüklemek için dosya uzantısı “.php5” olarak güncellenmiştir.
Beyaz liste çözümlerini atlatmak için ise sistemi kandırabilecek teknikler uygulanmalıdır. Örneğin; “null byte injection” tekniği uygulanarak PHP dosyası yüklenebilir. Null Byte Injection, giden veriler arasına “null” karakteri yerleştirmek için kullanılır. Null karakteri, 0 ASCII koduyla ifade edilmektedir. Programlama dilleri kullanılarak tanımlanan “string” değişkenler belleğe yerleştirilirken, değişkenin sonunu ifade etmek için bellekte ayrılan son alana null karakteri yani %00 değeri yerleştirilir. Örneğin; PHP programlama dilinde string bir ifade “$a= ‘PHP’” şeklinde tanımlanabilirken, C programlama dili üzerinde “char” tipinde bir dizi tanımlanarak dizinin her elemanına bir karakter atanır ve dizinin son elemanı string ifadenin sonlandığını belirtmek için null değeri alır.
- char a[3];
- a[0]= ‘P’;
- a[1]= ‘H’;
- a[2]= ‘P’;
- a[3]= ‘\0’;
Saldırganlar dosya yükleme sırasında beyaz liste çözümlerini atlatmak için bu yöntemden yararlanabilirler. Bunun için, içerisinde zararlı kodlar bulunan “shell.phpA.png” adında desteklenen bir uzantıya sahip dosya oluşturabilirler ve istek sunucuya gitmeden önce ASCII değeri 0x41 olan ‘A’ karakteri yerine null karakteri yazabilirler. Böylece null karakterinden sonra gelen “.png” kısmı atılır ve dosya “shell.php” adıyla sisteme yüklenir.
Ayrıca beyaz liste çözümünü atlatmak için farklı bir yöntem olarak, yüklenecek olan dosya çift uzantı kullanılarak sisteme yüklenebilir. Örneğin; dosya “shell.png.php” ismiyle yüklendiğinde, ilk uzantı olan “.png” uzantısı baz alınabilir ve bu dosyanın yüklenmesine izin verilebilir.
Bu bölümde PHP uzantılı dosya yüklemek için “null byte injection” tekniği uygulanarak beyaz liste kontrolü atlatılmıştır. Resim 2.2.3’ de giden istek proxy uygulaması ile yakalanmıştır ve dosya ismindeki “A” karakteri null karakteri ile değiştirilmiştir.
İstek gönderildikten sonra yüklenen dosya sisteme “shell.php” adıyla kaydedilmiştir. Resim 2.2.4’te sisteme yüklenen PHP dosyası kullanılarak işletim sistemi üzerinde komut çalıştırılmıştır.
Dosya Tipi Kontrolü
Geliştiriciler, yüklenen dosyaları kısıtlamak için “MIME type” kontrolü yapabilirler. MIME type (MIME tipi), medya dosyalarının biçimlerini ve bu dosyaların türlerini ifade eden iki bölümlü bir tanımlayıcıdır. Örneğin “.png” uzantılı bir dosyanın, resim dosyası ve PNG formatında bir resim olduğunu belirtmek için MIME tipi “image/png” olarak ifade edilir. Resim 2.3.1’de MIME tipi kontrolü yapan kod yer almaktadır.
Bu şekilde kontrol sağlayan bir sisteme PHP dosyası yüklenmek istendiği zaman dosya yükleme işlemi başarısız olacaktır. Çünkü, PHP dosyasının MIME tipi “application/octet-stream” olduğundan dolayı eşleşme sağlanamadığından hata alınacaktır. Ancak, proxy uygulaması kullanılarak istek yakalanabilir ve dosya tipi kontrolden geçecek şekilde ayarlanarak PHP dosyası sisteme yüklenebilir. Resim 2.3.2’de dosya yükleme esnasında proxy uygulaması ile istek yakalanmıştır ve MIME tipi değiştirilerek istek sunucuya gönderilmiştir.
Böylece MIME tipi kontrolü atlatılmıştır ve PHP dosyası sisteme yüklenmiştir. Resim 2.3.3’ de sisteme yüklenen PHP dosyası kullanılarak işletim sistemi üzerinde komut çalıştırılmıştır.
İçerik Uzunluk Kontrolü
Web üzerinden sunucuya gönderilen HTTP isteklerinin içerik uzunluğu “Content-Length” ile ifade edilmektedir. Geliştiriciler, isteklerin içerik uzunuluğunu kontrol ederek, uzunluğun sınırı aşması durumunda isteği olumsuz sonuçlandırabilirler. İçerik uzunluğu kontrolü yaygın olarak kullanılan bir yöntem değildir. Ancak bazı durumlarda geliştiriciler uzunluk kontrolüne başvurabilirler. Resim 2.4.1’de uzunluk kontrolü yapan kod yer almaktadır.
Bu kontrole göre sisteme yüklenmeye çalışan bir dosyanın içerik uzunluğu 30 byte ve üstüyse dosya sisteme yüklenmeyecektir. Resim 2.4.2’de içerik uzunluğu 38 byte olan bir PHP dosyası sisteme yüklenememiştir.
Böyle bir durumda PHP dosyasının içeriği Resim 2.4.3’te olduğu gibi düzenlenebilir ve dosya sisteme yüklenebilir. Resimde görülen “<?=`$_GET[x]`?>” kodu, PHP programlama dilinde yapılan kod kısaltma örneklerinden biridir. PHP kodlarına yönelik kısaltmalar birçok operatöre uygulanmaktadır ve bu yöntem PHP 5.4 sürümünden sonraki tüm sürümlerde aktif bir şekilde çalışmaktadır. Bu kod, GET metodu ile gelen x parametresine atanmış olan işletim sistemi komutunu sistemde çalıştırır ve sonucu sayfaya yazar.
Sayfa içeriği kısaltıldıktan sonra dosya sisteme başarıyla yüklenmiştir. Resim 2.4.4’de sisteme yüklenen PHP dosyası kullanılarak işletim sistemi üzerinde komut çalıştırılmıştır.