“Egg” kahvaltıda insan için ne kadar önemliyse, exploit geliştirme işleminde de o kadar önemli rol oynar. Varsayalım ki, bir uygulamada stack tabanlı buffer overflow zafiyeti tespit ettiniz ve reverse shell almak istiyorsunuz. Memory’de yeteri kadar yer varsa shellcode’unuzu buraya yerleştirerek kendinize reverse shell’i kolay bir şekilde alabilirsiniz. Peki ya memory’de reverse shell shellcode’unu koyacak kadar yeterli ardışık hafıza alanı yoksa ne yaparsınız?
İşte tam da bu noktada imdadımıza egghunter yetişiyor. Egghunter, shellcode çalıştırmak için yeterli ardışık hafıza alanı olmadığı durumlarda memory’i belirtilen bir etikete göre tarayıp uygun yer buldugunda shellcode’u buraya yerleştirmemize ve çalıştırmamıza imkan tanıyan bir tekniktir.
Egghunter tekniğinin neden ve ne zaman kullanıldığını tanım olarak anlattığımıza göre şimdi bir görselle stack tabanlı buffer overflow örneği üzerinden durumu daha anlaşılır bir şekilde ortaya koyalım. Klasik stack tabanlı buffer overflow işleminde çoğunlukla shellcode’u yerleştirmek için kullanılan buffer oldukça büyük olmakta. Ancak EIP registerı üzerine yazdıktan sonra shellcode yerleştirmek için kullanacağımız alan yeteri kadar büyük olmadığı durumlarla karşılaştığımızda ne olacak? Durumu özetleyen görsel şu şekildedir.
Yukarıdaki görselde 220 byte veri gönderdikten sonra EIP register’ı üzerine yazıp 365 byte’lık shellcode yerleştirmemize rağmen hala 120 byte’lık kullanabileceğimiz alan olduğu görülmektedir.
Sağdaki görselde ise 515 byte veri gönderdikten sonra EIP register’ı üzerine yazıp 365 byte’lık shellcode yerleştirmek istiyoruz ancak yeterli alana sahip değiliz var olan alan 190 byte bizim ekstra 175 byte a daha ihtiyacımız var. Bu kadar alanı nasıl bulacağız sorularını sormaya başladıysanız egghunter tekniği bu zor durumun üstesinden gelmek için imdadınıza yetişiyor.
Egghunting tekniği için geliştirilmiş “IsBadReadPtr”, “NtDisplayString” gibi bazı shellcode’lar mevcut biz bunlardan “NtDisplayString” olanını kullanacağız. Biri 37 byte’lık bir alan diğeri ise 32 byte’lık bir alan istiyor. Daha küçük olduğu için ben “NtDisplayString” olanını kullanacağım.
Kullanacağımız egghunter shellcode kısaca şu işlemi gerçekleştiriyor. Kendisine “w00t” diye bir etiket belirliyor. Bu etikete egg deniyor. Tüm memory’i geziyor ve bu etiketi bulmaya çalışıyor. Etiketin hemen arkasına yapmak istediğimiz shellcodu(reverse shell, bind shell, pop up, hesap makinesi çalıştırma vs.) yerleştiriyor ve eğer başardıysa jmp edi komutuyla oraya sıçrıyor ve shellcodumuzu çalıştırıyor. Yaptığı işlemi daha iyi anlayabilmek için kodu ve açıklamalarını aşağıda paylaşıyorum. Açıklamaları okuyarak yaptığı işlemi kafanızda netleştirebilirsiniz.
Yukarıda paylaşılan kodun hex kısmını aldığımızda
"\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74\xef\xb8\x90\x50\x90\x50x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7" kullanacağımız egghunter kodu ortaya çıkıyor.
Buradaki "\x90\x50\x90\x50" değeri bizim etiketimiz(egg) olan “w00t” değeridir.
Yani yukarıdaki shellcode memory’i “w00tw00t” etiketi için geziyor, uygun yer bulduğunda bu etiketin hemen devamına shellcodumuzu yerleştiriyor ve bizi shellcodumuzun başına sıçratıyor.
Şimdi öğrendiğimiz bu teorik bilgiyi pratiğe dökme zamanı. Peki gereksinimlerimiz neler?
- Windows XP-SP3 Sanal Makine (Kurban)
- Kali Linux Sanal Makine (Saldırgan)
- XP üzerinde kurulu herhangi bir debugger (ben ollydbg’ı seçtim.)
- XP üzerinde kurulu zafiyetli uygulama Eureka Email Client (https://www.exploit-db.com/apps/2b0e55c58e1355c4bd0143d06ce3d239-EurekaEmailSetup.exe)
- Temel Seviye Assembly Bilgisi
- Temel Seviye Python Bilgisi
- Sabır :)
1-) Email Client’ı kurduktan sonra uygulamayı çalıştırıp “Options -> Connection Settings” adımlarını izleyerek açılan ekrandan oluşturacağımız fake email server’ın IP adresini giriyoruz. Ben server’ı kali üzerinde oluşturacağım için onun IP adresini giriyorum. POP username ve POP password alanına test, test girebilirsiniz çok önemli değil bu kısım. Son durumda aşağıdaki gibi bir görüntüye sahip olmalısınız. Kaydedip çıkıyoruz.
2-) Email Client’ı ayarladıktan sonra kali makinemizde bu uygulamayı crash edecek kodu yazıyoruz. Python kodumuz kali makinede fake bir server oluşturuyor ve gelen bağlantılar için dinlemeye başlıyor. Kendisine bağlanmaya çalışan client’a 5000 tane “A” karakterini gönderiyor.
3-) Python kodumuzu Kali makinesinin IP adresini yazarak kaydediyoruz ve çalıştırıyoruz.
4-) XP tarafında ise “File -> Send and receive emails” adımları izlenerek uygulamanın crash olduğunu görüyoruz. Toparlayacak olursak kali tarafında çalışan python kodu ile fake bir email server oluşturuyoruz ve 110 portundan dinlemeye başlıyoruz. XP tarafında ise daha önce ayar olarak kali IP adresini verdiğimizden dolayı client kalide çalışan fake servera bağlanmaya çalışıyor. Kalide çalışan python kodu ise gelen bağlantı isteğine 5000 tane “A” karakterini göndererek cevap veriyor. XP tarafındaki email client beklediğinden daha fazla sayıda input aldığı için crash alıyor.
5-) Bu adımda artık bir debugger açıp meydana gelen crash’in sebebini bulmaya çalışacağız. Uygulamayı çalıştırıp aynı zamanda ollydbg uygulamasını da çalıştırıyoruz. Ollydbg “File -> Attach” adımlarını izleyerek çalışmakta olan eureka email client processini bulup onu debuggera attach ediyoruz. Aşağıdaki gibi bir görüntü alıyoruz. Debuggerda sol üst köşedeki alanda uygulamaya ait assembly kodları, sağ üst köşedeki alanda CPU registerları ve durumları, sağ alt köşedeki alanda stack ve sol alt köşedeki alanda ise dump alanı görülüyor.
6-) Yukarıdaki ekran görüntüsünde sağ alt köşede görüldüğü gibi uygulama pause durumunda. Bu durumda uygulama çalışmaz ve tüm kontrol debuggerdadır. Üst menüden play butonuna basıyoruz ve kali tarafındaki python kodumuzu tekrar çalıştırıyoruz. Yine aynı şekilde uygulamamız üzerinden “File -> Send and receive emails” adımlarını izleyerek uygulamanın tekrar crash olmasını sağlıyoruz. Aşağıdaki ekran görüntüsünde görüldüğü üzere EIP registerı 41414141 ile overwrite edilmiş gözüküyor.
7-) Sıradaki işlem bu register gönderdiğimiz 5000 karakterden kaçıncısından sonra overwrite edilmiş bunu tespit etmek. Bunun için kali makinemizden pattern_create.rb kodunu kullanıyoruz. Bu kod bize unique 5000 tane değer üretiyor. Üretilen bu değeri kodumuza yerleştiriyoruz ve tekrar gönderiyoruz.
8-) 5. ve 6. adımdaki işlemleri tekrar yaptığımızda EIP registerının aşağıdaki gibi bir değerle overwrite edildiğini görüyoruz.
9-) Bu değer oluşturduğumuz 5000 karakterlik unique değerden kaçıncısına denk geliyormuş bunu tespit etmek için aşağıdaki işlemi yapıyoruz. 710 karakterden sonra EIP üzerine yazabildiğimizi tespit etmiş olduk.
10-) Kodumuzu bu bilgiye göre düzenliyoruz. 710 tane A gönderip sonraki 4 byte’a B yazarak EIP registerını B karakteri ile yazdığımızı görmeyi bekliyoruz. Geriye kalan sayı kadar da C gönderiyoruz. Aynı adımları tekrar uyguladığımızda gerçekten de beklediğmiz gibi EIP register’ı B karakterinin hexadecimal karşılığı olan 42424242 ile overwrite edilmiş.
11-) Aynı zamanda stack’e baktığımızda gönderdiğimiz C karakterinin hexadeximal karşılığı olan 43’ler ile dolduğunu görüyoruz. EIP registerını stack’e sıçramak için JMP ESP gibi bir komutun adresi ile değiştiriyoruz. Bu komutu bulabilmek için debugger üzerinde sağ tıklayıp “search for -> command” adımları ile açılan kutucuğa JMP ESP yazılır. USER32.dll içerisinde bu komut ve adresi bulunur. Bu adresi little endian’dan dolayı ters sıra ile BBBB yerine yazıyoruz.
12-) Bu adresi debuggerda aratıp buraya F2 tuşu ile bir breakpoint koyuyoruz ve uygulama buraya geldiğinde bizi beklesin diyoruz. ESP registerına sağ tıklayıp follow in dump diyoruz. Son durum aşağıdaki gibi. F7 ile devam etmek istediğimizde uygulama akışının ESP registerının olduğu adrese sıçradığını görüyor olacağız.
13-) Artık stack’teyiz ancak bir problem var bind shell alabilmek için oluşturacağımız shellcode’un boyutu yaklaşık olarak 350-400 byte ancak bizim şuan sahip olduğumuz alan daha küçük. İşte tam olarak egghunter tekniği burada devreye girecek.
14-) Kodu tekrar düzenlemeye başlıyoruz. Yukarıda anlattığımız egghunter shellcodu koda ekliyoruz sonrasında belirli sayıda NOP ekliyoruz. Sonrasında egghunter tekniği için etiketimizi ve hemen sonrasına çalıştırmak istediğimiz shellcodumuzu yazıyoruz. Şuan için shellcode yerine C karakterlerini gönderiyoruz. Sonra bu kısma bindshell shellcodeunu yerleştireceğiz.
15-) Kodu yazıp aynı işlemleri tekrarladığımızda JMP ESP işlemi gerçekleştikten sonra debuggerda egghunter kodumuzu görebiliyoruz. Egghunter kodundaki JMP EDI kısmına breakpoint koyup run dediğimizde işlemin biraz uzun sürdüğünü sonra breakpointe gelip durduğunu görüyoruz. Bunun sebebi daha önce de belirttiğimiz gibi egghunter kodunun tüm memory’i tarayıp shellcodu yerleştirmek için uygun alanı bulmaya çalışması. JMP EDI kısmında F7 ile devam ettiğimizde C karakteri ile başlayan shellcodumuzu görüyoruz.
16-) Şimdi C yerine bindshell shellcodumuzu yerleştirme zamanı. Aşağıdaki gibi msfvenom aracı ile bindshell shellcode’unu oluşturuyoruz. Default olarak 4444 portunu açmak için bir shellcode oluşuyor.
17-) Kodun son hali aşağıdaki gibi oldu. Özetlemek gerekirse, 710 tane A karakterinden sonra EIP registerına yazıldığını gördük. Bu adrese stack’e de yazabildiğimiz için JMP ESP komutunun adresini yazarak program akışının ESP ye sıçrayıp oradan devam etmesini istedik. ESP’ye sıçradıktan sonra bind shell alabilmek için yeterli alanın olmadığını farkettik. Bunun için sırayla önce egghunter shellcodunu sonra araya belirli sayıda NOP opcode’u ve sonra da “w00tw00t” etiketinin ardına bindshell shellcodumuzu yerleştirdik. Bu şekilde kodu kaydedip çalıştırdığımızda uygulamanın XP makinesi üzerinde 4444 portunu açmasını bekliyoruz.
18-) Bu sefer debugger açmadan email client uygulamamızı çalıştırıyoruz. Kali tarafında python kodumuzu çalıştırıyoruz. XP tarafında ise “File -> Send and receive emails” adımlarını izliyoruz. Sonrasında kali tarafında “nc XP IP ADDRESS 4444” komutu ile bağlantı sağlayıp sağlayamadığımızı test ediyoruz.
19-) Ve işlem başarılı. Eureka email client uygulamasındaki buffer overflow zafiyeti kullanılarak XP makinesi üzerinden bind shell alınıp komut çalıştırılabildi.
Bu makale developer tarafından yazılmış veya yayınlanmıştır.