in Exploit

Belajar Membuat Shellcode (I): Local Exploit Shellcode

Seringkali shellcode terlihat dalam source code exploit berbentuk untaian kode-kode hexa. Sebenarnya apa itu shellcode dan apa makna di balik kode-kode hexa itu? Dalam artikel ini saya akan menjelaskan tentang shellcode dan kita juga akan praktek belajar membuat shellcode sendiri.

Shellcode, Exploit dan Vulnerability

Shellcode, exploit dan vulnerability adalah 3 saudara kandung. Semua berawal dari keteledoran sang  programmer sehingga programnya mengandung vulnerability yang bisa di-exploit untuk membuat program tersebut menjalankan code apapun yang diinginkan hacker (arbitrary code execution), code ini disebut dengan shellcode.

Dalam kondisi normal, program mengikuti instruksi yang dibuat oleh penciptanya (programmer). Hacker bisa membuat program mengikuti perintahnya dan mengabaikan perintah penciptanya dengan mengexploit vulnerability yang mengakibatkan arbitrary code execution

Kenapa disebut shellcode? Bila hacker bisa membuat program mengeksekusi code apapun yang dia mau, maka code apakah yang dipilihnya? Pilihan terbaik adalah code yang memberikan dia shell sehingga dia bisa memberi perintah lain yang dia mau dengan leluasa. Oleh karena itu code itu disebut shell-code.

Bila diibaratkan misile: exploit adalah misilnya, sedangkan shellcode adalah warhead yang bisa diisi dengan apa saja seperti bahan peledak, nuklir, senjata kimiawi atau senjata biologis terserah keinginan penyerang.

Walaupun umumnya shellcode memberikan shell, shellcode tidak selalu memberikan shell. Attacker bebas menentukan code apa yang akan dieksekusi di komputer korban. Shellcode bisa melakukan apa saja mulai dari menghapus file, memformat hardisk, mengirimkan data, menginstall program baru dsb terserah keinginan attacker.

Arbitrary Code Execution

Arbitrary code execution adalah kondisi dimana attacker dapat menginjeksi sembarang code/instruksi ke dalam suatu proses yang sedang running, kemudian code tersebut dieksekusi. Code yang diinjeksi itu disebut dengan shellcode. Code dalam shellcode adalah dalam bentuk bahasa mesin atau opcode. Biasanya opcode ini tidak dituliskan dalam nilai binary karena akan menjadi sangat panjang, melainkan memakai nilai hexa yang lebih kompak.

Antara Code dan Data

Sebenarnya code adalah data juga yang isinya adalah instruksi yang bisa dieksekusi komputer. Dalam memori, secara internal, data dan code tidak ada bedanya karena keduanya hanyalah untaian simbol 1 dan 0.

Saya beri contoh simple: Apakah nilai 50 hexa atau 01010000 binary di suatu lokasi memori adalah code atau data?

  • Bila 50 hexa dianggap sebagai data bertipe karakter, maka itu adalah kode ascii untuk huruf ‘P’.
  • Bila 50 hexa dianggap sebagai code, maka itu adalah instruksi PUSH EAX (dalam mode 32 bit) atau PUSH AX (dalam mode 16 bit).

Begitu juga dengan string “ABCD”, bisa dianggap sebagai data maupun code, perhatikan contoh di bawah ini:

Dalam contoh di atas ABCD secara internal disimpan sebagai 0x41, 0x42, 0x43 dan 0x44, yaitu kode ASCII dari karakter ‘A’,’B’,’C’,’D’ (lihat baris ke-2). Namun data yang sama bisa juga dianggap sebagai code 16 bit atau 32 bit seperti pada baris ke-4 s/d ke-7 untuk code 16 bit dan baris ke-9 s/d ke-12 untuk code 32 bit.

Sekarang pertanyaannya adalah kapan suatu data diperlakukan sebagai data dan kapan diperlakukan sebagai code? Jawabannya adalah ketika suatu data ditunjuk oleh instruction pointer, atau program counter yang biasanya ada pada register EIP (IP pada sistem 16 bit), maka data di lokasi itu adalah code yang akan dieksekusi.

Data apapun yang berada di lokasi memori yang alamatnya disimpan pada EIP akan dianggap sebagai code.

Sebagai demonstrasi, program kecil di bawah ini menunjukkan bahwa sebuah data bisa juga dianggap sebagai code bila ditunjuk oleh EIP.

Ada yang menarik dari program kecil di atas, yaitu pada variabel str yang berisi string ABCHIJK plus karakter berkode ASCII 0xc3. Pada baris ke-4, variabel str digunakan sebagai argument untuk fungsi printf(), dalam hal ini berarti str dianggap sebagai data. Sedangkan pada baris ke-5, str dipanggil seperti halnya fungsi, dalam hal ini str dianggap sebagai code. Perhatikan bahwa str sejatinya adalah bertipe pointer to char, namun bisa dipanggil seperti fungsi karena telah dicasting ke pointer to function dengan (void (*)(void)).

Dalam contoh di atas kita mengeksekusi code yang ada di variabel str, berarti kita mengeksekusi code yang berada di area data (bukan area code). Kernel sekarang banyak yang menerapkan proteksi sehingga kita tidak bisa mengeksekusi code yang tidak berada di area memori yang khusus untuk code. Dalam lingkungan windows, dikenal sebagai Data Execution Prevention, dan di Linux juga ada dikenal sebagai Exec-Shield.

Agar contoh dalam artikel ini bisa bekerja, anda harus mematikan Exec-Shield :
echo “0” > /proc/sys/kernel/exec-shield

Perhatikan gambar di bawah ini. Gambar tersebut adalah hasil disassemble dengan gdb. Terlihat bahwa str terletak di lokasi 0x8049590. Pada <main+24> ada instruksi CALL yang merupakan pemanggilan fungsi printf() dengan str (0x8049590) sebagai argumen fungsi. Dalam hal ini berarti str dianggap sebagai data bertipe string. Namun pada <main+34> ada instruksi CALL ke lokasi str, hal ini berarti program akan lompat (jump) ke lokasi str dan mengeksekusi instruksi yang ada di lokasi str. Dalam hal ini berarti str dianggap sebagai code. Perhatikan pula bahwa pada str saya menambahkan \xc3 di akhir str karena \xc3 adalah opcode instruksi RET sehingga program akan kembali ke fungsi main dan melanjutkan fungsi main sampai selesai.

strascodeanddata

Mulai Membuat Shellcode

Sebenarnya isi variable str pada program di atas adalah shellcode, jadi sebenarnya kita sudah berhasil membuat shellcode pertama. Selamat! 🙂 Namun shellcode yang kita buat tersebut tidak melakukan sesuatu yang berarti karena isinya hanya INC dan DEC kemudian RET. Namun dari contoh tersebut setidaknya kita sudah memahami bahwa shellcode tidak lain hanyalah string, yaitu kumpulan karakter yang juga merupakan opcode instruksi bahasa mesin.

Sekarang kita akan mulai membuat shellcode yang benar-benar spawn sebuah shell. Dalam artikel sebelumnya mengenai belajar assembly saya sudah menjelaskan cara memanggil system call dengan interrupt 80 hexa. Shellcode yang akan kita buat berisi instruksi untuk memanggil system call. Perhatikan source bahasa C di bawah ini yang jika dieksekusi akan spawn shell.

Program di atas hanya memanggil system call setreuid() dan execve(). Shellcode yang akan kita buat juga akan melakukan hal yang sama seperti source di atas, bedanya hanya dibuat dalam assembly.

System Call setreuid()

setreuid() digunakan untuk mengeset userID real dan efektif. System call ini sangat penting sebab program yang memiliki SUID bit, biasanya men-drop root privilege bila sudah tidak dibutuhkan lagi. Oleh karena itu kita harus mengembalikan privilege itu sebelum spawn shell. Deklarasi system call setreuid() adalah:

Berdasarkan deklarasi system call tersebut, maka register yang harus diisi sebelum melakukan interrupt adalah:

  • EAX: 0x46 atau 70 (Nomor system call dari file unistd.h)
  • EBX: 0x0 (Parameter pertama, real uid yaitu 0)
  • ECX: 0x0 (Parameter kedua, effective uid yaitu 0)

Potongan assembly di bawah ini adalah instruksi untuk memanggil system call setreuid(0,0).

System Call execve()

Execve adalah system call untuk mengeksekusi suatu executable. Semua data, variable, heap, stack dsb milik proses yang memanggil execve akan hilang dan digantikan dengan program yang baru dieksekusi. Namun processID, dan open file handle (termasuk stdout,stdin,stderr) diwariskan ke program yang baru dieksekusi. Deklarasi system call execve adalah seperti di bawah ini:

Ada 3 argumen yang diperlukan, namun kita hanya akan memakai 2 argumen. Argumen envp kita isi dengan NULL karena kita tidak membutuhkan variabel environment. Berdasarkan deklarasi system call tersebut, maka register yang harus diisi sebelum memanggil interrupt adalah:

  • EAX: 0xb atau 11 (nomor system call)
  • EBX: alamat string “/bin/sh”
  • ECX: alamat array of string, {“/bin/sh”,NULL}
  • EDX: 0 karena envp diisi NULL.

Potongan assembly di bawah ini memanggil system call execve untuk mengeksekusi /bin/sh.

stackfilename

EBX harus diisi dengan address string berisi nama file executable yang akan dieksekusi. Kita gunakan stack untuk membuat string “/bin//sh” seperti pada gambar di atas. Dengan cara ini kita akan mendapatkan address string executable filename pada register ESP. Isi ESP ini kemudian disalin ke register EBX. Mungkin ada yang mengira ada kesalahan ketik dalam string tersebut, karena ada double slash sebelum “sh”. Ini bukan kesalahan ketik, namun sengaja agar pada saat push tepat mempush 4 byte (“//sh”), dan kelebihan satu slash tidak jadi masalah.

stackfilename

ECX harus diisi dengan array of string {“/bin//sh”,NULL}. Sekali lagi kita juga memakai stack dan register EBX yang sebelumnya sudah berisi address string “/bin//sh”. Pada gambar di atas pertama kita harus mempush NULL (0x0) ke dalam stack sebagai elemen array index ke-1, kemudian diikuti dengan mempush address string “/bin//sh” dari EBX sebagai elemen array index ke-0. Dengan cara ini ESP akan berisi address array of string {“/bin//sh”,NULL}. Nilai ESP inilah yang disalin ke register ECX.

Shellcode dalam Assembly

Mari kita gabungkan potongan-potongan assembly di atas untuk membentuk shellcode yang utuh seperti pada source code assembly di bawah ini.

Mari kita compile dan link source assembly di atas.

Converting OBJDUMP Output to Shellcode

Hore berhasil! Sekarang tahap finishing, yaitu mengambil opcode dari program di atas. Kita gunakan objdump untuk ini.

Dari output objdump di atas, kita hanya perlu mengambil opcode dalam kolom yang ditengah kemudian menggandengnya menjadi sebuah string. Untuk memudahkan mengambil opcode saya membuat script satu baris berikut:

Mari kita verifikasi sekali lagi dengan perl dan ndisasm.

Hasilnya sama, berarti shellcode tersebut benar. Sekarang kita lanjutkan dengan mengeksekusi shellcode tersebut dengan program C di bawah ini:

Oke, selamat kita telah berhasil membuat shellcode yang menghasilkan shell di local. Pada bagian ke-2, saya akan menjelaskan pembuatan shellcode untuk remote exploit.

Write a Comment

Comment

This site is using OpenAvatar based on

30 Comments

  1. wah keren banget mas…
    klo cara melihat shellcode itu dan mengeksekusinya gimana mas…

    maklum klo pertanyaan saya krng bermutu..
    saya baru mengenal intenet ….
    dan ingin memperdalam lagi…

  2. cybermuttaqin@whitecyber:~/Documents/shellexploit$ gdb codedata
    GNU gdb (GDB) 7.0-ubuntu
    Copyright (C) 2009 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law. Type “show copying”
    and “show warranty” for details.
    This GDB was configured as “x86_64-linux-gnu”.
    For bug reporting instructions, please see:

    Reading symbols from /home/cybermuttaqin/Documents/shellexploit/codedata…done.
    (gdb) disassemble main
    Dump of assembler code for function main:
    0x0000000000400524 : push %rbp
    0x0000000000400525 : mov %rsp,%rbp
    0x0000000000400528 : mov $0x601020,%edi
    0x000000000040052d : callq 0x400418
    0x0000000000400532 : mov $0x601020,%eax
    0x0000000000400537 : callq *%rax
    0x0000000000400539 : mov $0x0,%eax
    0x000000000040053e : leaveq
    0x000000000040053f : retq
    End of assembler dump.
    (gdb) disassemble &str
    Dump of assembler code for function str:
    0x0000000000601020 : rex.B
    0x0000000000601021 : rex.X
    0x0000000000601022 : rex.XB
    0x0000000000601023 : rex.W
    0x0000000000601024 : rex.WB
    0x0000000000601025 : rex.WX
    0x0000000000601026 : rex.WXB retq
    0x0000000000601028 : add %al,(%rax)
    End of assembler dump.
    (gdb) x/s &str
    0x601020 : “ABCHIJK”,
    (gdb)

    Ko jadinya kaya gitu ya master punya ane klo pake gdb…. ?

    • hahahahahahahahahaa

      ente msih muda banget neh pasti,,
      msih menggebu-gebu..wkwkwkwk
      ng-hack cuma buat jago-jagoan..

      mending belajar deh ketimbang mikirin facebook,, bsok ada ujian kan…

  3. wah..
    luar biasa ni artikel nya
    tapi yang luar biasa lgi saya gx ngerti…
    he…
    coz sya anak managemant jdi gx ngerti dach..
    tpi saya tertarik di dunia hacking…
    bsa bimbing saya mempelajarin hack gx mas…
    ya.. bisa di mulai hal2 yg basic dengan menulis artikel tentang bagaimana hack lewat dos, cara instal nmap n cara menggunakan nya gitu…

  4. mas, waktu aku jalanin pake user biasa yang muncul tetap shell user biasa, koq g shell nya root y??, tapi klo jalaninnya pake root baru deh yg muncul shell nya root.
    gmana tu mas? jadi bingung..
    hehehe, maklum nubie.

  5. mas, shellcode nya tu berlaku untuk kernel versi brapa y?, soalnya aq cuba di ubuntu 10.04 g bisa mas, klo d jalanin pake user biasa, shell yg muncul juga shell user biasa bukan shell root.

  6. masih berkabut ni, ini jalan gk sih di windows
    ” #include
    char str[] = “ABCHIJK\xc3”;
    int main(void) {
    printf(“%s\n”,str); // str as argument of printf()
    ((void (*)(void))str)(); // str()
    return 0;

    setealha gw kompile dan dijalanin jdi

    C:\Documents and Settings\Administrator\My Documents\c>cmd.exe
    Microsoft Windows XP [Version 5.1.2600]
    (C) Copyright 1985-2001 Microsoft Corp.

    C:\Documents and Settings\Administrator\My Documents\c>Project1.exe
    ABCHIJK├

    • mas tuh bahasa c++ ya

      tpi klo aku baca tujuan programna hanya menampilkan isi dari str

      tpi klo diblang jalan, kayakna g deh.. soalna includena g didefinisikan
      hehehehe.. just kidding (mungkin ja sengaja disembunyikan)

    • yup diatas emang cuman menampilkan isi dari char[]. sedangkan di ((void (*)(void))str)() merupakan tempat dimana isi dari char[] dijalankan (implementasi langsung ke address)

  7. terima kasih atas artikelnya, membantu sekali, tapi yang saya ingin tanyakan, ketika mendeklarasikan char* args[] = {“/bin/sh”,NULL}; itu ga perlu dirubah menjadi assembly ya? otomatis ya pas kita convert ke assemblynya.????,

    mudah-mudahan dijawab?

  8. gan ada yang tau gak coding buat keluarin nama distro atau kernel, username, tanggal dan waktu, sama direktori yang di pakai secara otomatis, kalo ada mohon bantuan nya gan, secara simple aja, maklum msh newbie ane… thx sblm nya 😀

  9. Mas, ane pake kali-linux 64-bit ngga ada /proc/sys/kernel/exec-shield nya. gimana nih? kalo cobain shell code nya selalu segmentation fault. ada solusi mas?

Webmentions

  • Stripe Capture The Flag Level 1-5 | Info BackTrack June 23, 2013

    Mas, ane pake kali-linux 64-bit ngga ada /proc/sys/kernel/exec-shield nya. gimana nih? kalo cobain shell code nya selalu segmentation fault. ada solusi mas?

  • membuat shellcode yang dipakai untuk exploit secara remote « Expression Of My Love June 23, 2013

    Mas, ane pake kali-linux 64-bit ngga ada /proc/sys/kernel/exec-shield nya. gimana nih? kalo cobain shell code nya selalu segmentation fault. ada solusi mas?

  • Belajar Membuat Shellcode Part 2: Remote Exploit Shellcode | Exploit | Ilmu Hacking June 23, 2013

    Mas, ane pake kali-linux 64-bit ngga ada /proc/sys/kernel/exec-shield nya. gimana nih? kalo cobain shell code nya selalu segmentation fault. ada solusi mas?