Certificate pinning adalah suatu cara agar sebuah aplikasi bisa memastikan bahwa koneksi SSL/TLS dilakukan terhadap server yang seharusnya. Topik yang sering ditanyakan ke saya adalah bagaimana membypass SSL pinning agar dapat melakukan pentest terhadap sebuah aplikasi. Di sini saya akan membahas beberapa teknik unpinning, terutama untuk mobile OS (iOS dan Android).
Sebelum masuk ke topik pinning, saya review dulu sedikit mengenai komunikasi sebuah browser/ aplikasi ke sebuah server. Agar lebih singkat: browser dan aplikasi akan saya sebut sebagai aplikasi saja, karena browser juga adalah sebuah aplikasi.
Contents
DNS
Ketika kita mengunjungi blog.compactbyte.com, aplikasi akan bertanya: apa alamat IP untuk blog.compactbyte.com? pertanyaan ini ditujukan ke server DNS (domain name system). Dan setelah tahu alamat IP-nya aplikasi bisa melakukan koneksi ke server tersebut.
Dari proses awal ini saja sudah ada dua kemungkinan masalah: pertama adalah server DNS mana yang kita pakai?
Biasanya ketika kita melakukan koneksi via WIFI, maka server DNS yang dipakai diberikan oleh router/access point. Jika kita melakukan koneksi via mobile, maka operator yang memberikan alamat DNS. Jika seseorang punya akses ke router atau ke operator, mereka bisa mengarahkan kita ke server DNS milik orang tersebut. Ketika server DNS ini ditanya: apakah alamat IP bank X, bisa dijawab dengan alamat bank palsu.
Masalah berikutnya adalah di DNS server itu sendiri. Jadi mungkin saja kita tetap memakai server DNS yang benar, tapi servernya itu yang dihack. Jika seseorang berhasil meng-hack server DNS, maka isinya bisa diganti menjadi apa saja.
Serangan lain yang mungkin terjadi adalah di nama domain itu sendiri. Ketika kita membeli nama domain di sebuah registrar, maka kita perlu mendaftarkan nama tersebut di server DNS. Biasanya dilakukan di registrar tempat kita membeli domain tersebut.
Tentunya waktu kita membeli domain, kita diminta membuat user dan password di situs tempat membeli domain tersebut. Jika orang bisa mendapatkan account di tempat beli domain ini maka seseorang bisa mengambil alih domain tersebut, atau mengganti alamatnya. Mengambil alih account seseorang ini bisa dengan banyak cara dan tidak akan saya bahas di sini. Mungkin di artikel lain akan saya bahas.
Registrar yang kurang ternama kadang memiliki customer service yang bisa dibohongi dengan Social Engineering agar kita diberi akses ke domain orang lain. Serangan semacam ini sudah terjadi cukup sering. Dan tentunya ada kemungkinan server registrar tersebut tidak aman dan bisa dibobol
Serangan DNS lain adalah pada device (baik itu ponsel, tablet, PC, atau apapun). Di dalam device ini kita bisa membuat pemetaan lokal (misalnya dengan file /etc/hosts, /etc/private/hosts/, %windir%\system32\drivers\etc\hosts): jika koneksi ke blog.compactbyte.com, selalu pakailah alamat IP ini. Jadi sebuah malware (atau teman yang jahat atau sekedar iseng) bisa mengarahkan sebuah nama domain ke IP lain dan hanya mempengaruhi satu device itu saja.
Dari semua penjelasan di atas, intinya adalah ini: jika sebuah aplikasi ingin melakukan koneksi ke sebuah server, bisa saja ada penyerang di tengah-tengah (man in the middle/MITM) yang mengarahkan koneksi ke server lain.
Routing
Semua paket data dari device kita akan melewati banyak router. Jika koneksi ini tidak terenkripsi, maka siapapun di tengah-tengah bisa membaca pesan kita. Semua yang di tengah-tengah ini misalnya: router WIFI kita, ISP kita, pemilik server (jika satu server dipakai banyak website), dan semua router antara router rumah sampai server.
Kombinasi serangan DNS dan koneksi plaintext (tidak terenkripsi) sifatnya fatal, karena setelah bisa mengarahkan akses ke server lain, semua data yang dikirim bisa dibaca oleh penyerang. Karena masalah ini maka diciptakanlah protokol agar koneksi bisa aman meskipun ada banyak router di tengah-tengah.
TLS/SSL
Transport Layer Security (TLS) yang menggantikan Secure Socket Layer (SSL) adalah protokol untuk membuat komunikasi terenkripsi. Sebuah server akan memiliki sertifikat (berupa public key) dan memiliki private key yang ada di server.
Ketika koneksi dilakukan, maka ada proses negosiasi yang rumit untuk melakukan enkripsi. Bagian depan dari komunikasi ini penting dan cukup sederhana. Bagian berikutnya rumit karena melibatkan pertukaran key kriptografi.
Pertama, client (aplikasi) akan mengirimkan “HELLO” ke server, dan server akan membalas dengan “HELLO JUGA”. Bagian ini sekedar memastikan bahwa server memang bisa melakukan koneksi terenkripsi, bukan koneksi biasa.
Berikutnya setelah mengatakan “HELLO JUGA”, server akan mengirimkan sertifikat. Ini seperti kartu nama: “saya adalah servernya blog.compactbyte.com”. Tapi tentunya kalau ini tidak diverifikasi, semua server bisa saja mengaku jadi pemilik domain apa saja.
Bagaimana supaya ini aman? ada yang namanya validasi sertifikat yang dilakukan oleh aplikasi. Sebuah sertifikat TLS/SSL perlu ditandatangani Otoritas Sertifikat (Certificate Authority atau CA) atau ditandatangani pihak lain (reseller) yang sudah ditandatangani CA.
Di dalam sistem operasi atau di dalam browser biasanya sudah ada daftar otoritas yang dipercaya. Semua sertifikat yang ditandatangani oleh otoritas ini akan dipercaya oleh browser. Teorinya sampai titik ini sudah aman: kalau ada server mengaku memiliki sertifikat blog.compactbyte.com tapi tidak ditandatangani oleh otoritas maka akan ditolak.
Sebenarnya proses ini tidak sekedar mengecek apakah sertifikat ditandatangani oleh otoritas X langsung, tapi kadang ada pihak di tengah. Pihak tengah ini bisa menandatangani sertifikat, dan aplikasi akan memverifikasi bahwa pihak di tengah ini ditandatangi oleh pihak yang otoritasnya terdaftar di sistem.
Tiap otoritas memiliki hak untuk menandatangani sertifikat domain apapun, bisa jadi ada 2 atau lebih otoritas membuat sertifikat untuk domain yang sama. Tujuannya: saya boleh membeli sertifikat di manapun, atau bahkan berganti tempat membeli sertifikat bahkan sebelum masa berlakunya habis.
Tapi apakah sebuah otoritas bisa selalu dipercaya? bagaimana jika otoritas sertifikat ini dihack? atau bagaimana jika ada orang dalam di otoritas sertifikat ini yang bandel? Atau bagaimana jika diinfiltrasi agen intel asing?Kasus ini sudah beberapa kali terjadi, dan ketika ini terjadi, para pembuat browser dan sistem operasi akan mencabut otoritas ini dari daftar pihak terpercaya.
Tadi sudah saya sebutkan bahwa di sistem operasi atau di browser sudah ada daftar sertifikat terpercaya, dan ini ada di setiap device. Jika kita menambahkan daftar otoritas yang bisa dipercaya, maka otoritas tersebut bisa membuat sertifikat untuk domain apapun. Biasanya fitur ini dipakai di perusahaan, supaya perusahaan bisa menambahkan sendiri layanan yang bisa dipercaya oleh device milik perusahaan.
Fitur ini juga dipakai pentester. Jika saya ingin menguji aplikasi, saya bisa menginstall sertifikat sendiri di handphone saya, dan bisa memonitor komunikasi aplikasi. Ini tidak mempengaruhi device ataupun server, hanya handphone saya saja.
Tentunya bukan cuma pemilik device yang bisa menambahkan otoritas ini, tapi malware atau orang jahat yang bisa mengakses device kita bisa menambahkannya. Jadi pastikan semua device Anda memiliki software terbaru dan bebas malware.
Perhatikan bahwa dengan TLS/SSL koneksi pasti akan dienkrip siapapun otoritas yang menandatangani sertifikatnya, jadi tidak bisa dimonitor/disniff oleh router. Dalam kasus sertifikat yang bukan asli, yang jadi masalah adalah: apakah kita benar-benar melakukan koneksi ke server yang sesungguhnya?
Certificate Pinning
Pihak pemilik website dan pembuat aplikasi tahu dengan tepat isi sertifikat yang dipakai dan ditandatangani oleh otoritas yang mana. Pembuat aplikasi yang ingin agar aplikasinya hanya melakukan koneksi ke server yang benar bisa membandingkan sertifikat yang diterima dari server dengan sertifikat yang tertanam di dalam aplikasi.
Inilah yang dinamakan certificate pinning: hanya mempercayai sertifikat yang diperiksa sendiri. Jika sertifikat yang diterima tidak sesuai harapan, koneksi segera dibatalkan. Kemungkinan pengguna akan mendapatkan pesan “gagal melakukan koneksi ke server” atau pesan lain sejenis itu.
Bentuk pinning paling sederhana adalah perbandingan eksak: sertifikat yang diterima harus eksak seperti yang tertanam dalam program. Tapi ini ternyata menimbulkan masalah:
- Jika sertifikat habis masa berlakunya, aplikasi harus diupdate
- Jika kita pindah ke jasa penerbitan sertifikat SSL dari pihak lain, aplikasi harus diupdate
Jika kita percaya pada otoritas tertentu, pengecekan bisa dilakukan agar hanya mempercayai jika certificate ditandatangani oleh otoritas tersebut. Ini adalah bentuk lain dari certificate pinning.
Bentuk lainnya adalah public key pinning. Sebuah sertifikat memiliki private key (rahasia, dipegang oleh pemilik dan ada di server) dan public key yang bukan rahasia, dikirimkan ke client. Jika seseorang berusaha membuat sertifikat baru, public keynya pasti akan berbeda, jadi ini bisa dijadikan pegangan. Jika public key berubah, berarti sertifikatnya bukan asli dari yang seharusnya.
Dengan certificate pinning ini, seorang pentester tidak bisa sekedar menambahkan CA baru. Meskipun sudah menambahkan CA baru, dan sertifikatnya bisa dipercaya oleh browser ketika mengakses sebuah domain (karena browser memakai daftar otoritas dari sistem), tapi aplikasi tetap tidak mau melakukan koneksi karena pemeriksaan yang dilakukanya sendiri.
Certificate Transparency
Tahun 2011 reseller otoritas sertifikat Comodo dihack, dan dikhawatirkan banyak sertifikat palsu yang sudah ditandatangani dari hasil hack ini. Hal ini sempat membuat khawatir, dan di browser tertentu sempat diimplementasikan public key pinning, tapi ternyata ini merepotkan dan rawan error jadi fiturnya dibatalkan.
Untuk mencegah kejadian serupa muncul. Sekarang setiap otoritas yang menandatangani sertifikat harus menampilkannya secara publik, ini dinamakan Certificate Transparency (CT). Proses ini seharusnya otomatis, jadi jika ada yang menghack dan berusaha membuat sertifikat baru, maka akan otomatis terdaftar di internet.
Sebagai pengganti public key pinning, sekarang sebuah server web bisa mengembalikan header “Expect-CT”, supaya browser memeriksa log Certificate Transparency. Kalau browser melihat bahwa certificatenya ini tidak ada di daftar publik, maka ini bisa dilaporkan ke server untuk dicek lebih lanjut.
API dan Library
Mengimplementasikan public key pinning ini tidak sulit, apalagi sekarang sudah ada banyak library (Voley, okhttp, dsb) yang menyediakan fasilitas pinning ini. Intinya kita hanya perlu memberikan hash dari public key, dan library itu yang akan memeriksa.
Di OS Android mulai versi 7 (Nougat) bahkan sudah ada built in certificate pinning di Android. Ini cukup dilakukan dengan mengubah file XML tanpa menyentuh kode program.
Tentu saja pemeriksaan juga bisa dilakukan secara manual/custom. Contohnya: standar pinning public key saat ini memakai SHA256, bisa saja kita tidak memakai hash tapi langsung memeriksa nilai modulus/eksponen RSA, atau memakai hash yang berbeda (misalnya SHA512), atau bahkan menambahkan pemeriksaan ekstra. Beberapa metode bypass otomatis akan gagal dengan metode custom ini.
Perlu dicatat bahwa defaultnya sistem operasi akan memeriksa sertifikat, dan akan menolak yang jelas-jelas tidak benar. Contohnya jika kita melakukan koneksi ke tinyhack.com tapi mendapatkan sertifikat untuk blog.compactbyte.com maka akan muncul peringatan dan koneksi gagal dilakukan. Selain itu diperiksa juga apakah benar ditandatanani otoritas yang ada di device.
Seorang programmer kadang membypass pemeriksaan default ini ketika sedang dalam development. Jadi semua sertifikat diterima apa adanya, bahkan jika salah total sekalipun. Kadang kala bypass mode development ini lupa dimatikan dalam versi production, dan ini sangat berbahaya.
Unpinning/Bypass Pinning
Sebagai pentester, kita harus bisa membypass certificate Pinning ini agar bisa memonitor komunikasi dan mengubah request untuk menguji keamanan. Ada beberapa cara untuk melakukan unpinning, tergantung cara pinningnya. Hal yang paling sulit adalah jika pinning dilakukan secara custom di kode yang sudah obfuscated.
Asumsi saya adalah:
- Pentester menggunakan Burp/ZaProxy/Fiddler/mitmproxy atau intercepting proxy lain
- Pentester tahu cara mendapatkan public key hash dan certificate dari sebuah domain (misalnya dengan openssl), baik yang asli maupun yang dihasilkan oleh proxy tersebut (contohnya bisa dengan membaca ini: https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning#Extracting_the_Base64_encoded_public_key_information)
- Pentester tahu cara membongkar dan mempack lagi file APK (Android)/IPA (iOS)
Memakai SSL Kill Switch 2 (iOS)
SSL Kill Switch 2 adalah tweak yang perlu diinstall di device yang dijailbreak. Dengan ini kebanyakan kode pinning standar akan bisa dibypass.
Memakai modul XPosed (Android)
Ada beberapa modul XPosed di Android yang bisa membypass SSL Pinning, misalnya JustTrustMe dan TrustMeAlready. Modul ini bekerja di cukup banyak aplikasi, tapi jika dilakukan obfuscation akan gagal.
Inti dari modul-modul tersebut (dan juga Tweak iOS) adalah mengintercept fungsi yang melakukan pemeriksaan SSL. Tentunya programmer yang paham bisa segera membuat kode alternatif yang tidak bisa dengan mudah diintercept.
Memakai skrip Frida (Android/iOS)
Sebenarnya ini juga sama saja dengan SSL Kill Switch ataupun XPosed, tapi karena sifatnya skrip kecil dalam Javascript, maka lebih mudah dimodifikasi dibandingkan harus mengkompilasi ulang Tweak iOS ataupun Modul XPosed di Android.
Saat ini ada banyak sekali script SSL unpinning dengan Frida, jadi tidak akan saya link. Cukup search saja “ssl pinning bypass frida“. Biasanya cara dengan Frida ini cukup ampuh, dan banyak aplikasi bisa dibypas dengan ini.
Edit XML/File sertifikat
Jika pinning hanya dilakukan dengan konfigurasi XML, maka edit saja file ini dengan hash kita sendiri, atau hapus restriksinya dari XML. Jika pinning dilakukan dengan membandingkan seluruh certificate, tukar saja certificatenya dengan yang dari intercepting proxy.
Edit String Hash
Selain dalam file XML, kadang string hash ini muncul di kode program. Sering kali meski program sudah obfuscated, tapi string ini masih muncul dengan jelas. Cara mudah bypass adalah dengan mengedit string tersebut dengan yang dihasilkan intercepting proxy.
Jadi intinya adalah: coba dapatkan hash server asli, cari apakah hash tersebut muncul, baik di kode program atau file konfigurasi. Lalu dapatkan hash server melalui intercepting proxy, lalu ganti string hash asli dengan string hash ini.
Bypass Teknologi Spesifik
Salah satu tips untuk melakukan pinning adalah mencari tahu teknologi spesifik apa yang dipakai oleh aplikasi dan mencari writeup orang lain. Misalnya ketika tahu bahwa sebuah aplikasi dibuat memakai Flutter, bisa dicari cara unpinning untuk teknologi tersebut.
Dalam kasus Flutter, sudah ada yang membuat writeup untuk Flutter ini (dan ada yang lain). Tapi perlu dicatat bahwa di versi yang baru, cara bypass ini belum tentu bisa berjalan.
Jika kita beruntung, sudah ada yang membuat writeup seperti dalam kasus flutter ini, tapi jika belum beruntung kita tetap harus melakukan reverse engineering terhadap aplikasinya. Dengan mencari lebih dulu kita bisa menghemat waktu sebelum terjun lebih dalam.
Code Patching
Jika semua gagal, berikutnya yang harus dilakukan adalah patching kode. Ini bisa berarti patching kode smali (untuk Android) dan kode native (di Android atau iOS).
Beberapa aplikasi tidak memeriksa sertifikat memakai API tertentu, tapi memakai library native code (bahasa mesin, bukan Java). Contoh aplikasi yang melakukan ini adalah instagram. Jika sudah ketemu seperti ini, maka kita perlu melakukan dekompilasi dan patching kode.
Sebagai catatan, untuk aplikasi tertentu kadang sudah ada yang yang memberikan hasil modifikasi APK agar pinning dibypass (misalnya ini untuk instagram), tapi ini belum tentu bisa dipercaya, bisa saja modifikasinya jahat dan mencuri password Anda.
Pertanyaan yang sering diajukan di titik ini adalah : patchingnya di mana? jawaban singkatnya: saya tidak tahu kalau tidak melihat kodenya. Intinya adalah kita perlu melakukan reverse engineering.
Saya bukan dukun yang bisa mengerti kode tanpa melihatnya. Tapi jujur saya: saya tidak akan membantu Anda di titik ini, karena biaya reverse engineering itu mahal, dan karena sering kali saya sudah tandatangan NDA (non disclosure agreement) untuk berbagai aplikasi jadi jangan bertanya untuk aplikasi Bank, e-Money, dan aneka FinTech lain.
Tapi jangan langsung menyerah, coba dilihat dulu kodenya. Sering kali patching ini sangat sederhana, sekedar mengganti perbandingan saja supaya yang tidak valid dianggap valid, atau mengubah agar apapun hasilnya dianggap valid (sekedar “return true”).
Jika paham tentang proses pinning itu sendiri, maka proses ini biasanya relatif mudah. Kita perlu mencari di mana koneksi dilakukan, misalnya ini ditelusuri dari mulai tombol login ditekan: fungsi apa yang dipanggil sampai titik pemeriksaan sertifikat. Atau bisa juga dari arah sebaliknya: jika ada SSL error, di mana error ini dihasilkan? lalu cari mundur ke titik pemeriksaan.
Tapi tentu saja tidak selalu semudah itu, contoh yang pernah saya temui seperti ini: pemeriksaan SSL dilakukan di kode .dex (kode VM Android), tapi kode .dex-nya diload secara dinamik. Kode dex-nya didekrip, diekstrak, diload, lalu langsung dihapus lagi. Di kasus seperti ini, sekilas kode pinningya tidak terlihat di mana, tapi setelah paham, maka ini bisa diakali.
Jangan kaget atau putus asa jika kesulitan melakukan unpinning terhadap aplikasi populer (apalagi game), biasanya proteksinya cukup sulit. Andaikan ketemu writeup, sering kali proteksinya diupdate di versi berikutnya. Inilah kenapa writeup bypass SSL untuk aplikasi populer jarang ada yang up to date, karena setelah pembuat aplikasi membaca writeupnya, mereka akan mengubah lagi metodenya.
Alternatif Unpinning
Dalam kasus tertentu, saya tidak melakukan unpinning karena terlalu sulit atau aplikasinya memakai raw socket yang tidak bisa diintercept oleh MITM Proxy. Tapi bukan berarti aplikasinya tidak saya test. Saya bisa menguji caranya adalah dengan mengintercept request sebelum dikirim menggunakan Frida dan mengganti requestnya. Jadi interceptnya dilakukan sebelum proses enkripsi SSL.
Misalnya untuk test bug IDOR, saya melakukan replace(“usernamesaya”, “usernamelain”) terhadap string yang dikirimkan. Dalam kasus tersebut saya tidak mengintercept dengan intercepting proxy (burp/zaproxy), tapi dengan program custom.
Penutup
Bisa membypass SSL Pinning adalah keahlian wajib seorang pentester. Saya sendiri sudah beberapa kali menemukan aplikasi yang proses unpinningnya sulit, tapi ketika berhasil, langsung bisa menemukan banyak bug, padahal katanya sudah dipentest pihak lain dan sudah masuk Play Store/App Store. Biasanya hal ini terjadi karena pentester gagal bypass SSL Pinning sehingga bagian komunikasi aplikasinya tidak ditest sama sekali.
Semoga dengan tips di artikel ini, akan ada lebih banyak yang bisa melakukan bypass SSL pinning. Jika memang gagal membongkar SSL pinning, jangan malu untuk meminta versi debug aplikasi yang pinningnya tidak diaktifkan. Masih lebih penting untuk menguji sisi server, daripada menyembunyikan fakta bahwa SSL pinning tidak bisa dibypass di aplikasi tersebut.
Untuk pembuat aplikasi: jangan panik jika SSL pinning bisa dibypass. Tujuannya ini hanyalah agar sulit melakukan MITM terhadap user. Hal yang lebih penting adalah mengamankan sisi server: pastikan bahwa semua sudah aman.
halo om,,mkin dibrowser saya tidak perlu repot2 untuk intercept sebuah situs ataupun meloloskn data yg tidak bisa di intercept ,,tapi di aplikasi android/ios saya kesulitan untuk interceptnya,,untuk aplikasi intercept saya menggunakan squid proxy ,port default intercept poxy 3128(http),dan 3129(https)..pertanyaannya apakah saya harus membongkar satu2 aplikasi android/ios agar bisa di intercept di mesin proxy squid atau saya intercept harus menggunakan tool tambahan selain squid …sebelumnya sy bkn pentester,hanya mencoba membuat cache server yg kebetulan dijalankan mesin proxy squid…terimakasih sebelumnya…
have nice day