Sızma Testlerinde Python Kullanımı: Requests Kütüphanesi




“Hangi yazılım dilini öğrenmeliyim?” sorusuyla sıkça karşılaşıyorum ve genelde verdiğim cevap “tabii ki Python” oluyor. Kullanım kolaylığının yanında Özellikle web uygulaması sızma testlerinde uygulama ile aramızdaki iletişimi tam olarak anlamak önemlidir. Parolanın açık halde gönderilmesi, gizli parametreler veya sunucudan gelecek cevabın içerisinde bulabilecek ipuçları güvenlik açısından sorun oluşturabilecek noktaların tespit etmesini kolaylaştırır. 

Bu amaçla Burp Suite gibi bir Proxy kullanılabilir. Ancak, özellikle karmaşık veya çok parametreli uygulamalarda sunucuya hızlıca bir istek gönderip dönen cevabı görmek isteyebiliriz. Bunun için kolay kullanılabilecek bir Python kütüphanesi olan Requests işimize yarayabilir. 

Python Requests Nedir?
Python ile HTTP istekleri göndermeye yarayan Requests kütüphanesi başlık (header), form veya benzeri parametrelerin “insanın okuyabileceği şekilde” ayarlanmasını ve sunucudan gelen cevapların görüntülenebilmesine imkân verir. 
pip install requests ile kurulabilen kütüphane daha sone “import requests”  ile her türlü Python uygulması içerisinde kullanılabilir. 

Python Requests Nasıl Kullanılır?
Meslek icabı bu yazı elbette bir “Python öğreniyoruz” yazısı değildir, böyle bir beklentiniz varsa internette bulunan sayısız kaynağa bakmanız daha doğru olacaktır. Aşağıdakiler uygulama testleri sırasında faydalandığım kullanım şekillerinden bazılarıdır. 

Cevapların önemi
Uygulama sunucusunun çeşitli isteklere nasıl yanıtlar döndüğünü görmek uygulamanın çalışma mantığı ve sunucu konfigürasyonu hakkında bilgi edinmemizi sağlayabilir. Bu nedenle farklı türde talepler gönderip yanıtları incelemek gerekir. Sunucu ve istemci arasındaki iletişimi düzenleyen HTTP gönderdiği her cevabı bir durum kodu (HTTP Status Code) ekler. Bu kodların amacı karşıdaki sisteme isteğinin akıbeti hakkında bilgi vermektedir. 

HTTP bağlantıları kısaca aşağıdaki gibi yapılır (DNS talepler ve 3’lü el sıkışma gibi detaylar burada gösterilmemiştir). 

HTTP isteklerine ve sunucu cevaplarına ayrıntılı olarak bakacak olursak aşağıdaki bilgileri içerdiklerini görebiliriz;

HTTP isteği: 
HTTP isteğinde talep edilen alanadı (www.alperbasaran.com), talebi yapan tarayıcının bilgileri, sunucudan hangi türde cevapları kabul edebileceği, vb. bazı bilgiler görülebilir. 

HTTP cevabı: 

Sunucundan gelen cevapta çerez bilgileri, vb. görülebilir. İlk satırın sonunda yer alan “200 OK” ise sunucunun gönderilen isteğe nasıl yanıt verdiğini belirtir. 

HTTP Durum Kodları Nedir?
5 kategoride dönebilecek HTTP durum kodları aşağıdaki ana başlıklara göre sınıflandırılabilir;
  • 100’lü kodlar: Bilgilendirme amaçlı gönderilen yanıtlardır. Örn: “100 Continue”
  • 200’lü kodlar: Sunucunun isteği başarıyla yanıtladığını gösterir. Örn: “200 OK”
  • 300’lü kodlar: İsteğin başka bir adrese yönlendirildiğini gösterir. Örn: “301 Moved Permanently”
  • 400’lü kodlar: İstekte bir hata olduğunu gösterir. Örn: “404 Not Found”
  • 500’lü kodlar: Sunucu kaynaklı bir hata olduğunu gösterir. Örn: “503 Service Unavailable”
Gelen HTTP durum kodları tarayıcının yeni bir istekte bulunmasını veya hatanın kullanıcıya gösterilmesini sağlayabilir. 
Hata kodları uygulama testleri sırasında bizlere birkaç konuda bilgi verebilir:
  • Uygulamanın kullandığı sayfalar, dizinler veya altdizinler: Örn. Geçerli bir sayfa için yapılan talep “200 OK” yanıtını dönerken olmayan bir sayfa “404 Not Found” yanıtı verecektir.
  • Uygulamanın çalışma mantığı: Örn. Giriş işlemi sonrası sunucu “302 Found” kodu ile kullanıcıyı yönlendirebilir. 
  • Uygulamanın nasıl yapılandırıldığı: Örn. Talep edilen adrese eklenen özel karaktere “500 Internal Server Error” yanıtının alınması sunucunun kurulumu sırasında bazı güvenlik ayarlarının devreye alınmadığını gösterebilir. 
Uygulamayı test ederken çok sayıda talep göndermek ve sunucunun gönderdiği HTTP durum kodlarını görmek süreci hızlandırabilir. 

Python Requests ile İstek Göndermek
Kullanımı oldukça kolay olan Python Requests ile istekler aşağıdaki gibi gönderilebilir;

requests.get('http://www.alperbasaran.com/')
Görüldüğü gibi var olan bir sayfaya yapılan bir isteğin sonucu “<Response [200]>” olarak görülürken var olmayan sayfaya yapılan istek “<Response [404]>” olarak yanıtlanmıştır. 

HTTP cevaplarını Kullanmak
Sunucunun gönderdiği yanıtları daha etkin biçimde kullanabilmek için bir değişken tanımlamak işimizi kolaylaştırabilir. cevap = requests.get('http://www.alperbasaran.com/') ile sunucunun gönderdiği cevabı ekranda göstermek yerine değişken olarak saklayabilirsiniz. Aşağıdaki örnekte olduğu gibi sadece dönen HTTP kodlarını toparlayıp hangi sayfaların var olduğunu gösteren kısa bir betik geliştirilebilir.

Sunucudan gelen yanıt bir kere “cevap” olarak kaydedildikten sonra kolaylıkla işlenebilir.
Bu arada cevapta gelen HTTP durum kodunun en son gelen durum kodu olduğunu unutmamakta fayda var. Aşağıdaki örneğe bakacak olursak http://alperbasaran.com için gönderilen isteğe “200 OK” yanıtı alındığı görülebilir. Ancak cevap.history bize arada bir “301 Moved Permanently” cevabı olduğunu gösteriyor.  

Bu durumda http://www.alperbasaran.com adresine bir yönlendirme yapılmış ve yönlendirmenin sonucunda yapılan ikinci istek “200 OK” cevabı almıştır. 

Yönlendirmeleri takip etmek isteyip istemediğinizi belirtebilirsiniz. Bu durumda gönderilen isteğe “allow_redirects” parametresini ekleyerek Python Requests’in nasıl davranacağını belirleyebilirsiniz. Aşağıda görüldüğü gibi sunucudan gelen yönlendirme kodu takip edilmezse istek bir 301 koduyla sonlanmaktadır.  

HTTP Header Bilgisi
Cevap.headers ile HTTP yanıtının header (başlık) bilgisi görüntülenebilir.

Özellikle HTTP başlığında bir güvenlik cihazı tespit edilen uygulamalarda hangi sayfa veya alanadlarının bu sistem tarafından korunmadığını tespit etmekte faydalı olacaktır. Çok sayıda istek gönderecek bir döngü yazıldığında isteğin gönderildiği adresi takip etmeyi unutmamak gerekir. 

Bunun için cevap.url kullanılabilir.

HTTP İstek Türleri
Python Requests kullanılarak GET ve POST gibi farklı türlerde istekler gönderilebilir. Kullanım yukarıda anlatılanla benzer. 

Farklı türde istek göndermek için;
  • GET isteği: requests.get('http://alperbasaran.com/')
  • POST isteği: requests.post('http://alperbasaran.com/')
  • OPTIONS isteği: requests.options('http://alperbasaran.com/')
  • DELETE isteği: requests.delete('http://alperbasaran.com/')
  • PUT isteği: requests.put('http://alperbasaran.com/')

HTTP Cevap Süreleri

Gönderilen isteğe yanıtın ne kadar sürede geldiği bize uygulamanın nasıl çalıştığı ve “enumeration” denilen bilgi teyidi konularında bilgi verebilir. Yaygın olarak bulunabilecek bir durum giriş ekranın var olan bir kullanıcı adı ile var olmayan bir kullanıcı adına verdiği cevapların sürelerdir. Var olmayan bir kullanıcı giriş denemesinde sistem önce kullanıcı adının var olup olmadığını teyit edecek, varsa parolanın doğruluğunu kontrol edecektir. Bunun sonucunda var olmayan bir kullanıcı için yanıtların daha kısa sürede dönmesi muhtemeldir.

Bunun için “cevap.elapsed.total_seconds()” kullanılabilir. 

URL Parametresi Göndermek
Uygulamanın kabul ettiği parametrelerle oynamak uygulamanın hata vermesine veya davranışlarında değişikliklere neden olabilir. Bu nedenle fuzzing olarak bilinen teknik zaman kazandırabilir. Fuzzing sırasında uygulamaya önceden belirlenmiş içerikler göndererek hangilerine nasıl tepki verdiğine bakılır. Uygulama çok uzun, çok kısa, özel karakter içeren vs. beklemediği bir girdi aldığında davranışlarında (cevap süresi, cevap header bilgisi, cevap içeriği, vb.) herhangi bir farklılık varsa ilgili parametre üzerinde çalışılmaya değer gibi görünüyor. 

Örnek sayfayı ele aldığımızda arama için bir parametre girildiğinde adres çubuğunda da bu görülebilmektedir. “test” kelimesi için bir arama yaptığımızda adres çubuğunda “http://www.alperbasaran.com/search?q=test” görülebilmektedir. 

Bu durumda “q” arama parametresi olarak karşımıza çıkmaktadır. Requests kütüphanesi ile bunun gibi parametreleri içeren istekler de gönderilebilmektedir. Bunun için istek “requests.get('http://www.alperbasaran.com/search',params=b'q=siber',)” şeklinde gönderilebilir. 

Çerez Bilgilerini İşlemek
Özellikle uygulamaların giriş yapılarak erişilen bölümlerine istek gönderebilmek için çerez bilgisine ihtiyaç vardır. Bunun yanında uygulamanın farklı çerezlere nasıl tepki verdiğini anlamak bazı kullanıcı giriş mekanizmalarının atlatılmasını veya gizli işlevlerin tespit edilmesine imkân verebilir.

Aşağıdaki görüldüğü gibi DVWA (Damn Vulnerable Web Application) uygulamasının komut çalıştırma zafiyetini barındıran sayfasına istek göndermeyi denediğimizde, uygulamaya giriş yapmadığımız için, 302 durum koduyla bizi giriş sayfasına yönlendiriyor. 

İsteğe çerez değerlerini eklediğimizde ise sayfaya ulaşılabildiği görülmektedir. 
İster özel olarak geliştirilmiş EBYS, HBYS veya ERP uygulamalarını test edin, ister yaygın olarak kullanılan Wordpress veya Joomla gibi platformları özel istekler gönderip uygulamadan gelen yanıtları işleyebilmek gerekir. Requests kütüphanesi, kolay kullanımı ve iyi performansıyla işinizi kolaylaştıracaktır.

Comments