in Cryptography

Advanced Padding Oracle Attack

Tulisan ini adalah lanjutan dari tulisan sebelumnya yang membahas tentang padding oracle attack. Dalam tulisan sebelumnya saya sudah menjelaskan bagaimana melakukan dekripsi dengan mengirimkan ‘specially crafted’ ciphertext dan menginterogasi ‘the oracle’ apakah hasil dekripsinya menghasilkan padding yang valid atau tidak.

Kali ini saya akan lanjutkan pembahasan padding oracle attack untuk mengenkripsi pesan baru, bukan hanya mendekrip pesan seperti yang sudah dibahas di tulisan sebelumnya. Saya juga akan memberikan contoh aplikasi yang vulnerable dan bagaimana membuat script untuk eksploitasinya.

Bagi yang belum mengerti apa itu padding oracle attack sangat dianjurkan membaca tulisan sebelumnya karena disini tidak dibahas lagi apa yang sudah dibahas di sana.

Padding Oracle Encryption

Dalam tulisan sebelumnya sudah dibahas bagaimana padding oracle attack bisa digunakan untuk mendekrip suatu cipherteks. Namun ternyata tidak hanya itu yang bisa dilakukan dengan padding oracle attack, padding oracle juga bisa digunakan untuk mengenkrip plainteks.

Mari kita sedikit mereview cara kita mendekrip ciphertext dengan padding oracle attack. Dalam contoh pada tulisan sebelumnya kita diberikan ciphertext ‘2D7850F447A90B87123B36A038A8682F’ untuk didekrip. Cipherteks tersebut bisa dipecah menjadi 2 blok berukuran 8 byte:

  • C1 = 2D-78-50-F4-47-A9-0B-87
  • C2 = 12-3B-36-A0-38-A8-68-2F

Dalam tulisan sebelumnya pertama kita mendekrip blok dari C2 dulu. Gambar di bawah ini memperlihatkan apa yang terjadi di server ketika mendekrip blok C2 menjadi P2.

Screen Shot 2013-03-17 at 2.38.45 PM

Perlu diperhatikan bahwa P2 adalah hasil XOR antara Decrypt(C2) dengan C1.

  • P2 = Decrypt(C2) XOR C1

Lalu apa artinya? Artinya adalah P2 sangat tergantung dengan blok ciphertext sebelumnya (C1). Jadi bila kita mengirim 2 blok ciphertext, hasil dekripsi blok ciphertext kedua dipengaruhi atau tergantung dari blok ciphertext pertama.

Ingat, ketika melakukan serangan padding oracle attack, kita juga mengirimkan 2 blok ciphertext, blok pertama berubah-ubah ketika melakukan brute force (sedangkan blok kedua tetap) untuk memaksa byte terakhir P2 bernilai seperti yang kita inginkan (01, 02-02, 03-03-03, 04-04-04-04 dan seterusnya). Saya posting lagi gambar di tulisan sebelumnya.

Screen Shot 2013-03-13 at 2.20.57 PM

Dalam gambar di atas kita mengirimkan 2 blok ciphertext, dengan blok pertama nilainya dirancang khusus agar P2 bernilai 08-08-08-08-08-08-08-08.

Kalau kita bisa memaksa P2 bernilai tertentu, artinya kita bisa membuat P2 bernilai apapun yang kita mau, bagaimana caranya? Caranya mudah, yaitu dengan mengirimkan C1 tertentu yang membuat hasil XOR antara Decrypt(C2) dan C1 menjadi yang kita mau.

Dari padding oracle attack kita bisa tahu isi Decrypt(C2), sedangkan C1 adalah nilai yang bisa bebas dikirim oleh client (under attacker’s control), jadi tidak ada kesulitan untuk membuat P2 menjadi bernilai apapun yang diinginkan.

Sebagai contoh, kita ambil kasus dari tulisan sebelumnya. Dari padding oracle attack di tulisan sebelumnya kita sudah mengetahui Decrypt(C2):

  • Decrypt(12-3B-36-A0-38-A8-68-2F) = 64-32-1B-B8-0A-AA-08-86

Berapakah C1 agar P2 menjadi 4b-49-4c-4c-20-49-54-01 (‘KILL IT’ + 1 byte padding).

Screen Shot 2013-03-17 at 3.32.09 PM

C1 (warna hijau pada gambar di atas) bisa dihitung dengan mudah, dengan mengXORkan antara Decrypt(C2) (warna kuning pada gambar di atas) dengan P2 yang diinginkan (warna orange pada gambar di atas).

  • 86 XOR 01 = 87
  • 08 XOR 54 = 5C
  • AA XOR 49 = E3
  • 0A XOR 20 = 2A
  • B8 XOR 4C = F4
  • 1B XOR 4C = 57
  • 32 XOR 49 = 7B
  • 64 XOR 4B = 2F

Bila kita kirimkan C1, 2F-7B-57-F4-2A-E3-5C-87 dan C2, 12-3B-36-A0-38-A8-68-2F seperti gambar di bawah ini, maka bisa dipastikan P2 akan bernilai ‘KILL IT’+01 byte padding, artinya kita berhasil mengenkrip teks baru ‘KILL IT’+01 hanya dengan operasi XOR sederhana walaupun kita tidak mengetahui kunci enkripsinya.

Screen Shot 2013-03-17 at 3.38.07 PM

Jadi secara umum bila kita akan mengenkrip n blok plainteks, maka cara untuk mengenkripnya adalah:

  1. Generate blok Cn dengan isi bebas (random atau null byte)
  2. Dengan padding oracle attack, cari Decrypt(Cn)
  3. Hitung Cn-1 = Decrypt(Cn) XOR Pn
  4. Dengan padding oracle attack, cari Decrypt(Cn-1)
  5. Hitung Cn-2 = Decrypt(Cn-1) XOR Pn-1
  6. Dengan padding oracle attack, cari Decrypt(Cn-2)
  7. Hitung Cn-3 = Decrypt(Cn-2) XOR Pn-2
  8. dan seterusnya

Kenapa kita mulai dengan Cn berisi nilai random ? Karena sebenarnya isi Cn tidaklah penting, apapun isinya nanti hasil enkripsinya akan dipaksa menjadi plainteks yang diinginkan dengan bantuan Cn-1 di sebelah kirinya. Jadi terserah Cn isinya apa, yang penting Cn-1 dikirinya dihitung khusus untuk memaksa hasil dekripsinya menjadi yang diharapkan.

Dalam bahasa sederhana, agar dekripsi Ci menjadi Pi yang diinginkan, harus ditaruh Ci-1 yang sudah dihitung khusus di sebelah kirinya sebagai faktor yang mengoreksi atau memperbaiki hasil enkripsi Ci.

Begitu pula Ci-1 juga akan dikoreksi dengan Ci-2 yang juga sudah dihitung khusus dengan cara yang sama disebelah kirinya agar Ci-1 ketika didekrip menjadi Pi-1 yang diinginkan. Khusus untuk C1, pengoreksinya adalah C0 atau IV.

Contoh Enkripsi

Dalam skenario ini kita diberikan suatu server yang berperilaku sebagai ‘the oracle’, dia akan menjawab dengan padding valid/invalid setiap menerima kiriman ciphertext dari client.

Plainteks yang akan dienkrip: BESOK PAGI SERANGAN UMUM IWO JIMA.

Langkah pertama adalah memecah plainteks menjadi blok berukuran 8 byte termasuk paddingnya:

  1. P1 = ‘BESOK PA’
  2. P2 = ‘GI SERAN’
  3. P3 = ‘GAN UMUM’
  4. P4 = ‘ IWO JIM’
  5. P5 = ‘A’+07+07+07+07+07+07+07

Challengenya adalah kita harus mengenkrip plainteks di atas hanya dengan memanfaatkan ‘the oracle’ tanpa mengetahui kunci enkripsinya.

Kita akan menghitung mulai dari blok plainteks terakhir, P5 kemudian beranjak maju sampai P1. Proses mencari ciphertext adalah:

  1. C5 dipilih bebas secara random
  2. C4 = Decrypt(C5) XOR P5
  3. C3 = Decrypt(C4) XOR P4
  4. C2 = Decrypt(C3) XOR P3
  5. C1 = Decrypt(C2) XOR P2
  6. IV = Decrypt(C1) XOR P1

Decrypt(Ci) bisa dicari dengan padding oracle attack. Saya tidak akan menjelaskan bagaimana caranya, bila anda masih belum mengerti, silakan baca lagi tulisan saya sebelum ini.

Dengan prosedur sederhana ini kini kita sudah punya lengkap IV+C1+C2+C3+C4+C5 yang bila dikirim ke server akan didekrip menjadi plainteks yang kita inginkan ‘BESOK PAGI SERANGAN UMUM IWO JIMA’ walaupun kita tidak tahu kuncinya.

Tools Dekripsi dengan Padding Oracle Attack

Sebelum masuk ke enkripsi dengan padding oracle, kita mulai dulu dengan dekripsi padding oracle. Sebagai studi kasus, saya membuat script php yang vulnerable terhadap padding oracle attack, berikut adalah source codenya.

Screen Shot 2013-03-17 at 8.01.10 PM

Script tersebut menerima input dari parameter GET ‘crypted’ yang berisi IV+ciphertext dalam hex encoded string. Script mengambil 8 byte paling depan sebagai IV, dan sisanya sebagai ciphertext yang akan didekrip.

Ketika dikirimkan ciphertext melalui parameter crypted, script akan mendekripnya dan memeriksa padding hasil dekripsinya. Bila paddingnya valid maka script akan memberi response ‘PADDING OK’, bila padding invalid script akan memberi HTTP response status ‘500 Internal Server Error’.

Kita diberikan URL dibawah ini berisi IV+ciphertext dan diminta untuk mendekrip isinya dengan menggunakan padding oracle attack.

http://localhost:8888/kripto/thematrixoracle.php?crypted=0102030405060708C10E6DCBB8CF910B324F2E498BFCFF207832DB0455ADFBD576577FF983EDE9454BCFDFB1F4678929

Script ‘thematrixoracle.php’ tersebut tidak memberikan banyak informasi, bila URL tersebut direquest, maka response yang didapat hanya teks ‘PADDING OK’. Namun bila parameter crypted tersebut diubah sedikit byte terakhirnya dari 29 menjadi 20, maka responsenya tidak ada, hanya status code 500. Gambar di bawah ini adalah ketika script tersebut direquest.

Screen Shot 2013-03-18 at 2.08.19 PM

Hanya dengan mengirimkan ‘specially crafted’ ciphertext dan menginterogasi ‘the oracle’ apakah ciphertext tersebut ketika didekrip menghasilkan plainteks dengan padding yang valid atau tidak, kita bisa mendekrip suatu cipherteks.

Source code dibawah ini adalah tools yang saya buat dengan python untuk melakukan padding oracle attack ke URL di atas.

Screen Shot 2013-03-18 at 12.49.33 PM

Screen Shot 2013-03-18 at 1.36.19 PM

Di bawah ini adalah rekaman screen recording ketika tools diatas dijalankan untuk mendekrip ciphertext yang diminta. Tools tersebut berhasil mendekrip ciphertext yang diminta menjadi ‘Serangan Umum 1 Maret jam 6 pagi’ walaupun tanpa mengetahui kuncinya sama sekali.

Tools di atas terlihat mendekrip ciphertext satu byte per satu byte sampai akhirnya semua ciphertext berhasil didekrip.

Tools Enkripsi dengan Padding Oracle Attack

Oke saya sudah menunjukkan sebuah contoh padding oracle dan tools untuk mengeksploitasinya yang digunakan untuk mendekrip suatu ciphertext. Ingat padding oracle tidak hanya bisa dipakai untuk mendekrip ciphertext, tapi kita bisa mengenkrip plainteks apa saja yang kita inginkan walaupun tanpa mengetahui kuncinya.

Di bawah ini adalah source code yang saya buat juga dengan python untuk mengenkrip suatu teks menggunakan padding oracle attack, tanpa mengetahui kuncinya.

Screen Shot 2013-03-19 at 6.22.37 AM

Screen Shot 2013-03-18 at 1.38.06 PM

Kalau dilihat source code padfinder.py sebelumnya, yang dipakai untuk mendekrip, dengan tools padenkrip.py untuk mengenkrip di atas tidak banyak bedanya. Baik enkrip maupun dekrip keduanya memang sama-sama mengirimkan ‘specially crafted’ ciphertext dan menginterogasi ‘the oracle’. Namun ada sedikit perbedaan di antara keduanya.

Bedanya hanya ketika melakukan dekripsi, hasil Decrypt di-XOR dengan ciphertext blok sebelumnya, sedangkan ketika melakukan enkripsi, hasil Decrypt di-XOR dengan plaintext yang diinginkan (ditarget).

Berikut adalah rekaman screen recording ketika tools di atas dijalankan untuk mengenkrip teks ‘BESOK PAGI SERANGAN UMUM IWO JIMA’. Setelah berhasil mengenkrip, untuk menguji apakah ciphertextnya benar atau salah. Cciphertext tersebut coba didekrip dengan padding oracle attack yang sama menggunakan tools padfinder.py yang sudah ditunjukkan dalam rekaman screen recording di atas.

Solving CTF Challenge

Saya menemukan sebuah challenge CTF yang mengeksploitasi padding oracle attack. Peserta diberikan URL berikut:

http://y-shahinzadeh.ir/padding-oracle/index.php?Str=51afc6b478d9031efdffca538c68dd4cfb7dbaba9b28d756

Bila URL tersebut dibuka di browser maka akan terlihat aturan dan goal dari challenge ini beserta plainteks hasil dekripsi cipherteks yang dikirim melalui parameter GET ‘Str’ bila padding plainteksnya valid.

Screen Shot 2013-03-19 at 5.59.04 AM
Screen Shot 2013-03-19 at 5.55.19 AM

Namun bila cipherteks yang dikirim plainteksnya tidak mengandung padding yang valid, akan terlihat pesan ‘Wrong padding’.

Screen Shot 2013-03-19 at 5.57.46 AM

Goalnya adalah kita harus mengenkrip teks ‘haroldabelson’ dan mengirimkan cipherteksnya ke URL tersebut. Goal berhasil tercapai bila URL tersebut memperlihatkan bahwa cipherteks yang kita kirim berhasil didekrip menjadi teks ‘haroldabelson’ yang diminta.

CTF ini mirip dengan PoC yang kita buat, jadi tools untuk eksploitasinya juga tidak banyak perubahan. Saya hanya perlu mengubah URL target dari localhost ke url CTF ini dan mengubah kondisi valid paddingnya. Kondisi valid paddingnya bukan lagi status ‘200 OK’ tapi padding disebut valid bila HTML responsnya tidak mengandung kata ‘Wrong’.

Screen Shot 2013-03-19 at 6.17.40 AM

Karena iseng saya tidak akan mengenkrip teks ‘haroldabelson’ seperti yang diminta, saya akan mengenkrip tag HTML untuk melihat apakah hasil dekripsinya langsung di-dump ke client tanpa validasi atau ada validasi XSS dulu.

Screen Shot 2013-03-19 at 6.07.30 AM

Hasilnya ternyata memang tidak ada validasi XSS, cipherteks yang saya kirim langsung didekrip dan di-dump ke browser client tanpa dilakukan filtering atau validasi.

Screen Shot 2013-03-19 at 6.11.08 AM

Padding Oracle dan Authenticated Encryption

Padding oracle bisa dipakai untuk mendekrip pesan itu memang berbahaya karena mengancam confidentiality data. Namun sebenarnya enkripsi dengan padding oracle tidak kalah bahayanya dari dekripsi.

Bayangkan dalam situasi perang bila orang lain bisa membuat encrypted message palsu yang menyesatkan dengan kunci yang benar tanpa harus tahu kunci enkripsinya. Pihak yang menerima pesan palsu tadi akan mengira pesan tersebut ‘legitimate’ karena bisa didekrip dengan sempurna dan hasil dekripsinya pun menghasilkan pesan yang bisa dimengerti.

Don’t use encryption without message authentication

Ingat enkripsi hanya memberikan jaminan confidentiality, enkripsi tidak menjamin integrity dan authenticity. Kesalahan yang umum dilakukan adalah menggunakan enkripsi tanpa adanya message authentication. Padding oracle attack terjadi karena server langsung mendekrip ciphertext yang diterima, tanpa sebelumnya memeriksa apakah ciphertext tersebut terjamin integrity dan authenticitynya.

Seharusnya selain enkripsi, dibarengi juga dengan MAC untuk menjamin integrity dan authenticity dari pesan. Server tidak boleh mendekrip ciphertext sebelum yakin bahwa ciphertext tersebut integritasnya terjamin dengan cara memverifikasi MAC.

Write a Comment

Comment