Timing Side Channel Attack
Oleh
chmood
Dalam tulisan kali ini saya akan membahas tentang side channel attack khususnya timing attack. Kita tentu sering mendengar kata pepatah bahwa ‘Time is money”, ternyata selain dianggap uang, waktu juga bisa dijadikan senjata maut untuk memecahkan kode, kriptografi atau mendapatkan informasi rahasia lainnya.
Side Channel Attack
Timing attack adalah bagian dari keluarga besar side channel attack. Side channel attack adalah serangan yang memanfaatkan kebocoran informasi yang ditimbulkan karena aktivitas yang dilakukan mesin atau program. Seperti halnya di dunia fisik, setiap aktivitas yang dilakukan program sebenarnya menimbulkan “efek samping” atau jejak yang bisa diamati. Seperti menyelesaikan puzzle, dengan mengumpulkan kepingan-kepingan informasi yang bocor ini kita bisa menyelesaikan puzzle.
Kebocoran informasi yang bisa dimanfaatkan untuk side channel attack antara lain:
- Informasi waktu respons
- Konsumsi listrik
- Suara
- Radiasi elektromagnet
Sebagai ilustrasi coba bayangkan, bagaimana caranya mengetahui apakah Pentagon sedang merencanakan suatu operasi besar ?
Mungkin ada yang menjawab, kita harus menyelundupkan mata-mata ke sana. Cara itu memang bisa dilakukan, tapi mengingat Pentagon penjagaannya super ketat, cara itu bisa dibilang mission impossible, sangat sulit, mahal dan beresiko tinggi. Cara lain yang bisa dilakukan dengan mudah dan murah adalah dengan Pizza!
Lho kok bisa, apa hubungannya Pentagon dan Pizza ? Ternyata penjualan pizza Domino berhubungan dengan aktivitas yang dilakukan pegawai Pentagon. Ketika Pentagon sedang merencanakan atau melakukan sesuatu yang besar, maka akan terjadi aktivitas tinggi. Ketika aktivitas tinggi, banyak pegawai yang memesan Pizza sehingga penjualan pizza Domino akan melonjak.
Jadi ternyata informasi yang tampaknya sepele, penjualan pizza, bisa menjadi indikator yang cukup akurat untuk mengetahui apakah Pentagon sedang merencakan operasi besar. Mengenai indikator pizza ini pernah ditulis di washingtonpost.com tahun 1998 lalu.
Lie to Me
Saya termasuk penggemar serial TV “Lie to Me” yang menceritakan tentang seorang bernama Dr. Lightman yang memiliki kemampuan khusus untuk mendekteksi perasaan seseorang hanya dengan mengamati body language seseorang ketika menjawab suatu pertanyaan. Salah satu keahliannya adalah dia bisa menjadi “human lie detector” artinya dia bisa mengetahui apakah seseorang berbohong atau jujur.
Ekspresi di wajah menunjukkan isi hati seseorang, apakah dia sedang sedih, gembira, marah atau berbohong. Ekspresi ini akan muncul secara alami jadi sulit untuk ditutup-tutupi atau dibuat-buat, kecuali mungkin orang yang sudah sangat terlatih atau mungkin seorang psikopat.
Bisa dikatakan ekspresi di wajah ini adalah bentuk kebocoran informasi yang bila dibaca oleh orang yang ahli bisa membocorkan informasi isi hati seseorang, jadi serangan dengan membaca ekspresi wajah ini juga salah satu bentuk side channel attack.
Timing Attack
Kalau kita cari-cari di internet, banyak sumber yang menyebutkan indikator yang bisa dipakai sebagai lie indicator.
seorang yang berbohong membutuhkan waktu processing lebih lama dari pada kalau dia sedang jujur
Ketika seseorang berbohong dia akan cenderung mengulur-ngulur waktu atau menunda waktu karena dia butuh waktu lebih banyak untuk berpikir. Kata-kata atau gerak gerik yang mengindikasikan bahwa dia sedang mengulur waktu karena butuh waktu processing lebih lama antara lain (sumber) :
- repeat the question
- adjust their clothing
- start by speaking slowly, until confident
- start with ‘well’, ‘actually’ and other words that delay
Cara mendeteksi kebohongan dengan melihat waktu respons yang dibutuhkan untuk menjawab pertanyaan adalah salah satu bentuk side channel attack atau lebih khusus lagi timing attack.
Timing attack ini adalah serangan yang sulit untuk dicegah karena setiap operasi di komputer membutuhkan waktu untuk mengekesekusinya. Secepat apapun operasi komputer dilakukan tetap saja ada waktu yang terpakai walaupun hanya sekian nanosecond. Waktu eksekusi suatu program bisa berbeda bila input yang diberikan berbeda. Dengan pengukuran yang akurat dari waktu untuk mengerjakan suatu operasi, seorang penyerang bisa membaca dan menebak informasi rahasia
String Matching
Programmer ketika membuat program umumnya menggunakan algoritma yang seefisien dan secepat mungkin waktu eksekusinya, ini sudah menjadi insting dasar seorang programmer. Namun yang jadi masalah adalah insting dasar untuk mempersingkat waktu dalam tempo sesingkat-singkatnya ini justru menjadi kelemahan yang bisa dieksploitasi attacker.
Pseudo code untuk mengetahui apakah dua string sama atau tidak biasanya seperti ini:
Perhatikan pseudo-code di atas yang pertama dilakukan adalah memeriksa apakah panjang string A dan B sama? Bila berbeda, fungsi langsung berhenti di situ dengan nilai false. Hal ini terlihat sangat logis, bila panjangnya saja sudah berbeda, untuk apa lagi harus memeriksa isinya.
Bila panjang A dan B sama, maka dilakukan pengecekan apakah byte pertama isinya sama? Bila byte pertama sama, fungsi akan berlanjut untuk memeriksa byte kedua, ketiga, keempat dan seterusnya. Namun bila byte pertama isinya berbeda, fungsi juga berhenti disini dengan nilai false. Ini juga sangat sesuai dengan insting programmer, bila byte pertama saja sudah berbeda, untuk apa memeriksa byte kedua, ketiga dan seterusnya.
Lalu dimana sebenarnya masalahnya pseudo-code di atas? Bukankah ini sangat logis dan sesuai dengan insting dasar programmer, menyelesaikan masalah tanpa masalah dan dalam tempo yang sesingkat-singkatnya?
Kebocoran Informasi Waktu
Diagram di bawah ini menunjukkan aktivitas yang dilakukan server untuk memeriksa apakah password yang dikirim client sama dengan password yang tersimpan di server. Setiap aktivitas yang dilakukan server tentu akan memakan waktu yang dalam gambar di bawah ini dilambangkan dengan t0, t1, t2, t3 dan seterusnya.
Perhatikan pada t0, attacker mengirimkan password. Server akan memeriksa apakah panjang password yang dikirim client sama dengan panjang password yang tersimpan.
- Bila panjang tidak sama, server akan memberi respons pada waktu t1
- Bila panjang sama, tapi byte pertama tidak sama, server akan memberi respons pada waktu t2
- Bila panjang dan byte pertama sama, tapi byte kedua tidak sama, server akan memberi respons pada waktu t3
Dari alur aktivitas tersebut terjadi kebocoran informasi yang fatal, dengan mengamati waktu respons, apakah t1, t2, t3, t4 dan seterusnya, informasi yang bisa didapatkan attacker adalah:
- Panjang password di server
- Posisi byte yang salah
Dua informasi tersebut sudah cukup untuk mendapatkan password yang dirahasiakan di server.
Sebenarnya timing attack ada banyak bentuk dan variasinya, tidak hanya string matching saja. Pada dasarnya timing attack bisa dilakukan pada aplikasi yang membocorkan informasi pada clientnya dalam bentuk perbedaan waktu respons.
Sebagai contoh, potongan pseudo-code di bawah ini menunjukkan logika bahwa bila secret key adalah bilangan ganjil maka program akan memanggil fungsi doA() yang diketahui menghabiskan waktu 10 ms, sedangkan bila secret key adalah bilangan genap, maka program akan memanggil fungsi doB() yang lebih lama dibandingkan doA().
Dengan cara mengirimkan informasi ke server dan mengamati waktu responsnya, apakah 10 ms atau 15 ms, seorang attacker bisa mengetahui bahwa secretkey yang dipakai adalah bilangan ganjil atau genap.
Contoh lain adalah potongan pseudo-code di bawah ini. Ceritanya ini adalah potongan kode yang menangani proses transfer ke suatu rekening tujuan. Bila potongan kodenya seperti ini, maka seseorang yang mengirimkan uang ke rekening tujuan bisa mengetahui saldo rekening tujuan dengan cara mengamati waktu transfer.
Bila ketika transfer ke rekening XXX waktu yang dibutuhkan adalah 1 ms, maka isi rekening XXX diyakini di bawah 100 ribu. Bila ketika transfer ke rekening XXX waktu yang dibutuhkan adalah 5 ms, maka isi rekening XXX diyakini antara 100 ribu sampai 1 juta rupiah. Namun bila waktu yang dibutuhkan untuk transfer adalah 20 ms, maka isi rekening tersebut diyakini berisi lebih dari satu juta.
Itu adalah beberapa contoh bentuk-bentuk timing attack. Ada masih banyak lagi bentuk yang lain, tapi dalam tulisan ini saya akan fokuskan pembahasan pada timing attack pada string matching untuk mendapatkan secret key.
Ada yang bisa memberi contoh lain timing attack atau side channel attack di dunia nyata ? Mungkin waktu yang dibutuhkan KPK untuk menetapkan seseorang menjadi tersangka bisa dijadikan suatu indikator, lonjakan jumlah nasi box yang dikirim ke gedung KPK mungkin menandakan akan ada tersangka baru atau akan ada operasi tangkap tangan baru.
Contoh Kasus
Sebagai ilustrasi saya akan memberi contoh kasus yang bisa menunjukkan bagaimana timing attack bisa dilakukan untuk mencuri kunci rahasia. Berikut adalah contoh source code aplikasi (kita sebut sebagai guessme) yang vulnerable terhadap timing attack.
Aplikasi guessme tersebut membaca file secretkey.txt yang berisi kunci rahasia, kemudian membandingkan dengan input dari user (argv). Bila input argument dari user sama dengan isi kunci dalam file secretkey.txt, maka program akan menampilkan ‘CORRECT’, namun bila salah program akan langsung keluar tanpa pesan apapun. Program di atas vulnerable karena ketika melakukan perbandingan dua string, program akan berhenti ketika panjang tidak sama atau ketika karakter pada posisi tertentu tidak sama.
Karena aplikasi tersebut membutuhkan file secretkey.txt, kita harus membuat file secretkey.txt dulu. Saya membuat script bash kecil untuk men-generate teks random dengan panjang 4-9. Script bash makerandom.sh ini digunakan untuk men-generate kunci rahasia secara random. Dalam skenario ini, sebagai proof of concept, saya sendiri tidak membaca isi file secretkey.txt dan kita harus mengetahui isinya dengan timing attack.
Setelah program dicompile, berikut adalah apa yang terjadi ketika kita menjalankan program tersebut tapi tidak tahu kunci rahasianya. Setiap kali kita memasukkan kunci yang salah, program akan langsung keluar tanpa berkomentar apa-apa.
Mengukur Waktu Eksekusi
Cara untuk mengukur waktu eksekusi adalah dengan mencatat waktu sebelum dan sesudah eksekusi kemudian menghitung perbedaan dua waktu tersebut. Agar pengukurannya akurat, kita membutuhkan fungsi yang bisa mendapatkan waktu dengan akurasi sampai nanosecond. Saya menggunakan fungsi clock_gettime() di Linux untuk mendapatkan waktu dengan akurasi sampai nanosecond.
Berikut adalah contoh program yang melakukan pengukuran waktu eksekusi. Perhatikan apa yang dilakukan program ini:
- Mengambil waktu sebelum eksekusi dengan clock_gettime
- Mengeksekusi program yang akan diukur waktu (dalam contoh ini: guessme) di child process
- Parent process menunggu dengan wait() sampai child process selesai menjalankan guessme
- Setelah child selesai mengeksekusi guessme, parent mengambil waktu sekarang dengan clock_gettime
- Menghitung selisih waktu dalam nanosecond antara sesudah dan sebelum eksekusi
Bila source di atas dicompile (jangan lupa tambahkan -lrt di gcc) dan dijalankan, maka hasilnya seperti gambar di bawah ini. Output dari program ini adalah input string dan waktu eksekusi dalam nanosecond.
Ternyata setelah dijalankan waktu eksekusi guessme berbeda-beda dengan rentang yang lebar, terkadang rendah terkadang tinggi atau bahkan tinggi sekali. Mari kita coba jalankan program timingattack ini sebanyak 5.000 kali lalu kita plot hasilnya pada chart.
Wow hasilnya ternyata cukup berantakan, ada banyak noise dengan nilai yang sangat tinggi atau sangat rendah. Sepintas kalau dilihat logika timing attack itu sederhana, kita hanya mengirim input ke server kemudian mengamati apakah waktu respons dari server adalah t1, t2 atau t3 dan seterusnya. Namun sebenarnya mengukur waktu respons server tidak sesederhana itu, waktu dari respons tidak pasti dan berubah-ubah, tergantung dari banyak faktor, antara lain load CPU, bandwidth jaringan dan faktor lain yang kita sebut sebagai noise/jitter.
Karena adanya noise/jitter itu maka kita tidak bisa mengukur hanya satu kali, kita harus melakukan banyak pengukuran dan mengambil rata-ratanya. Sebelum mengambil rata-ratanya akan lebih baik lagi kalau kita menyaring data agar data dengan nilai yang sangat tinggi atau sangat rendah dihilangkan sehingga lebih mencerminkan waktu eksekusi yang sebenarnya.
Saya menggunakan pendekatan sederhana untuk memfilter noise, semua data hasil sekian banyak pengukuran diurutkan dulu secara ascending, kemudian saya membuang 15% data tertinggi dan 15% data terendah sehingga hanya menyisakan 70% data di tengah yang tidak terlalu tinggi dan tidak terlalu rendah. Data yang telah difilter inilah yang kemudian akan diambil reratanya.
Berikut adalah source code program yang melakukan pengukuran waktu eksekusi sebanyak 10.000 kali, memfilter datanya kemudian mengeluarkan rata-rata waktu eksekusi.
Source code di atas mirip dengan yang sebelumnya hanya saja ada penambahan kode di bawahnya untuk melakukan sorting dengan QuickSort, kemudian 15% data tertinggi dan terendah dibuang kemudian dihitung rata-ratanya.
Mencari Panjang Kunci dengan Timing Attack
Pertama yang harus kita lakukan adalah mencari tahu panjang kunci dari waktu respons server. Bila waktu response dari server adalah t1, maka kemungkinan besar panjang password yang kita kirim salah, dan kita harus mencoba lagi dengan password yang berbeda panjangnya, sampai akhirnya kita mendapatkan waktu respons t2 yang berarti panjang password benar, tapi byte pertama salah.
Jadi cara mencari panjang kunci adalah dengan brute force (trial/error), dimulai dengan password yang panjangnya satu, bila salah, coba dengan password yang panjangnya dua, tiga, empat dan seterusnya.
Berikut adalah script bash yang digunakan untuk mencoba password dengan panjang 4-9.
Dan berikut adalah hasil eksekusi script bash di atas.
Bila data di atas kita plot dalam chart maka akan terlihat jelas ada perbedaan waktu ketika kita mengirim guess dengan panjang 7 karakter. Ketika menerima input yang panjangnya 7, waktu responsnya sedikit lebih lama dibandingkan kalau panjang input bukan 7. Berdasarkan hasil pengukuran ini, kita cukup yakin bahwa panjang kunci adalah 7 karakter.
Mencari Karakter ke-1
Setelah mengetahui bahwa panjang kunci adalah 7 karakter, selanjutnya kita harus mulai mencari isinya dimulai dari byte pertama. Cara mencari tahu isi byte pertama adalah dengan mengirimkan input sepanjang 7 karakter “a######”, “b######”, “c######” sampai dengan “z######” dan mengamati waktu respons dari setiap input tersebut. Dari semua input string tersebut, input string yang membuat waktu respons relatif lebih lama dibanding yang lain adalah tersangka utama isi byte pertama.
Kita membutuhkan satu script lagi untuk melakukan brute force dari a sampai z. Script brutetime.sh di atas membutuhkan argument berupa prefix (kecuali byte pertama tidak perlu) yang akan diconcat dengan byte yang dicoba dari a-z dan diakhiri dengan postfix berupa deretan karakter ‘#’. Berikut adalah output dari script brutetime.sh di atas.
Data di atas bila diplot dalam chart akan terlihat seperti gambar di bawah ini.
Dari grafik di atas terlihat bahwa ketika kita mencoba guess dengan string ‘z######’ waktu responsenya lebih tinggi daripada yang lainnya sehingga kita bisa yakin bahwa karakter pertama adalah ‘z’.
Mencari karakter ke-2
Setelah kita yakin bahwa karakter pertama adalah ‘z’ selanjutnya kita harus mencari karakter ke-2. Caranya adalah dengan mengirimkan input string sepanjang 7 karakter: ‘za#####’, ‘zb#####’, ‘zc#####’ sampai ‘zz#####’ kemudia mengamati waktu respons dari setiap input tersebut. Input string yang membuat waktu responsnya relatif lebih lama dibanding yang lain diduga adalah isi karakter ke-2.
Chart di bawah ini menunjukkan bahwa waktu respons dari input string ‘zf#####’ relatif lebih tinggi dibanding yang lain, sehingga kita bisa menduga dengan keyakinan tinggi bahwa huruf kedua adalah ‘f’.
Mencari karakter ke-3
Kita lanjutkan dengan cara yang sama untuk mencari karakter sesudah ‘zf’.
Dari hasil chart di bawah ini terlihat bahwa input string ‘zfa####’ mendapatkan waktu respons yang relatif lebih lama dibanding yang lain sehingga kita yakin bahwa karakter ke-3 adalah huruf ‘a’.
Mencari karakter ke-4
Mari kita mencari tahu karakter ke-4 sesudah ‘zfa’. Gambar di bawah ini adalah output dari script brutetime.sh dengan argument zfa (3 karater yang sudah diketahui).
Pada chart di bawah ini ada satu titik data outlier yang terpencil, berbeda sendiri dari kelompoknya, data ini bisa diabaikan dan dianggap sebagai noise. Waktu respons untuk input string ‘zfam###’ terlihat konsisten lebih tinggi dibanding yang lain sehingga kita bisa meyakini bahwa karakter ke-4 adalah huruf ‘m’.
Mencari karakter ke-5
Ayo tinggal 3 lagi byte lagi. Gambar di bawah ini adalah output dari script brutetime.sh dengan argument zfam (4 byte yang sudah diketahui).
Berikut adalah chart dari output data di atas.
Kali ini hasilnya tidak sebagus sebelumnya. Ada tiga kandidat yang diduga sebagai karakter ke-5, yaitu i, o atau x yang nilainya tidak berbeda banyak. Kalau ada kasus begini kita bisa uji sekali lagi untuk tiga huruf tersebut. Berikut adalah hasil pengujiannya.
Ternyata hasilnya kandidat zfami## hasilnya konsisten lebih tinggi dari 741 ribu, sedangkan zfamo## dan zfamx## hasilnya jauh di bawah zfami dan setara dengan huruf lainnya. Input string ‘zfamo’ dan ‘zfamx’ ketika ditest terlihat lebih tinggi dari seharusnya mungkin karena CPU load kebetulan sedang tinggi.
Mencari karakter ke-6
Satu lagi karakter yang harus kita cari dengan timing attack adalah karakter ke-6. Dengan cara yang sama dengan yang sebelumnya, berikut adalah output dari script brutetime.
Hasil di atas ketika diplot sebagai chart memperlihatkan bahwa input string ‘zfamip#’ mendapatkan waktu respons lebih tinggi di banding yang lain sehingga kita yakin bahwa 6 karakter pertama adalah zfamip.
Mencari karakter terakhir
Mencari karakter terakhir tidak perlu dengan timing attack karena input string yang benar akan meresponse dengan ‘CORRECT’. Kita butuh script untuk melakukan brute force karakter terakhir mulai dari ‘a’ sampai ‘z’. Script di bawah ini adalah script untuk melakukan brute force karakter terakhir.
Bila script di atas dijalankan kita bisa mendapatkan konfirmasi positif bahwa kunci rahasia yang panjangnya 7 karakter adalah ‘zfamipd’.
If you enjoyed this article, please consider sharing it!
Category
Komentar