Kategori OWASP: MASVS-CODE: Kualitas Kode
Ringkasan
Saat menyimpan atau mentransfer data objek Java dalam jumlah besar, sering kali lebih efisien untuk melakukan serialisasi data terlebih dahulu. Data kemudian akan menjalani proses deserialisasi oleh aplikasi, aktivitas, atau penyedia penerima yang akhirnya menangani data tersebut. Dalam keadaan normal, data diserialisasi dan kemudian dideserialisasi tanpa intervensi pengguna. Namun, hubungan tepercaya antara proses deserialisasi dan objek yang dimaksud dapat disalahgunakan oleh aktor berbahaya yang dapat, misalnya, mencegat dan mengubah objek yang diserialisasi. Hal ini akan memungkinkan pihak tidak bertanggung jawab melakukan serangan seperti penolakan layanan (DoS), eskalasi hak istimewa, dan eksekusi kode jarak jauh (RCE).
Meskipun class Serializable adalah metode umum untuk mengelola serialisasi, Android memiliki class sendiri untuk menangani serialisasi yang disebut Parcel. Dengan menggunakan class Parcel, data objek dapat diserialisasi menjadi data aliran byte dan dikemas ke dalam Parcel menggunakan antarmuka Parcelable.
Hal ini memungkinkan Parcel diangkut atau disimpan dengan lebih efisien.
Namun demikian, pertimbangan yang cermat harus diberikan saat menggunakan class Parcel, karena class ini dimaksudkan sebagai mekanisme transportasi IPC berefisiensi tinggi, tetapi tidak boleh digunakan untuk menyimpan objek yang diserialisasi dalam penyimpanan persisten lokal karena dapat menyebabkan masalah atau kehilangan kompatibilitas data. Saat data
perlu dibaca, antarmuka Parcelable dapat digunakan untuk mendeserialisasi
Parcel dan mengubahnya kembali menjadi data objek.
Ada tiga vektor utama untuk mengeksploitasi deserialisasi di Android:
- Memanfaatkan asumsi salah developer bahwa deserialisasi objek yang berasal dari jenis class kustom aman. Pada kenyataannya, setiap objek yang bersumber dari class apa pun berpotensi diganti dengan konten berbahaya yang, dalam skenario terburuk, dapat mengganggu pemuat class aplikasi yang sama atau aplikasi lainnya. Interferensi ini berbentuk penyisipan nilai berbahaya yang, menurut tujuan class, dapat menyebabkan, misalnya, eksfiltrasi data atau pengambilalihan akun.
- Mengeksploitasi metode deserialisasi yang dianggap tidak aman berdasarkan desain (misalnya, CVE-2023-35669, yaitu kerentanan eskalasi hak istimewa lokal yang memungkinkan injeksi kode JavaScript arbitrer melalui vektor deserialisasi deep link)
- Mengeksploitasi kelemahan dalam logika aplikasi (misalnya CVE-2023-20963, kelemahan eskalasi hak istimewa lokal yang memungkinkan aplikasi mendownload dan mengeksekusi kode dalam lingkungan yang memiliki hak istimewa melalui kelemahan dalam logika paket WorkSource Android).
Dampak
Aplikasi apa pun yang melakukan deserialisasi data berserial yang tidak tepercaya atau berbahaya dapat rentan terhadap eksekusi kode jarak jauh atau serangan penolakan layanan.
Risiko: Deserialisasi input yang tidak tepercaya
Penyerang dapat mengeksploitasi kurangnya verifikasi paket dalam logika aplikasi untuk menyuntikkan objek arbitrer yang, setelah dideserialisasi, dapat memaksa aplikasi untuk mengeksekusi kode berbahaya yang dapat menyebabkan penolakan layanan (DoS), eskalasi hak istimewa, dan eksekusi kode jarak jauh (RCE).
Jenis serangan ini mungkin tidak terlihat. Misalnya, aplikasi dapat berisi maksud yang hanya mengharapkan satu parameter yang, setelah divalidasi, akan dideserialisasi. Jika penyerang mengirim parameter tambahan berbahaya kedua yang tidak terduga bersama dengan parameter yang diharapkan, hal ini akan menyebabkan semua objek data yang disusupi dideserialisasi karena intent memperlakukan parameter tambahan sebagai Bundle. Pengguna berbahaya dapat memanfaatkan perilaku ini untuk menyuntikkan data objek yang, setelah dideserialisasi, dapat menyebabkan RCE, penyusupan, atau kehilangan data.
Mitigasi
Sebagai praktik terbaik, asumsikan bahwa semua data berserial tidak tepercaya dan berpotensi berbahaya. Untuk memastikan integritas data berseri, lakukan pemeriksaan verifikasi pada data untuk memastikan data tersebut adalah class dan format yang benar yang diharapkan oleh aplikasi.
Solusi yang memungkinkan adalah menerapkan pola lihat ke depan untuk
java.io.ObjectInputStream library. Dengan mengubah kode yang bertanggung jawab untuk
deserialisasi, Anda dapat memastikan bahwa hanya sekumpulan
class yang ditentukan secara eksplisit yang dideserialisasi dalam intent.
Mulai Android 13 (level API 33), beberapa metode telah diupdate dalam class
Intent yang dianggap sebagai alternatif yang lebih aman untuk metode yang lebih lama dan
kini tidak digunakan lagi untuk menangani paket. Metode baru yang lebih aman untuk mengetik ini, seperti
getParcelableExtra(java.lang.String, java.lang.Class) dan
getParcelableArrayListExtra(java.lang.String, java.lang.Class), melakukan
pemeriksaan jenis data untuk mendeteksi kelemahan ketidakcocokan yang dapat menyebabkan aplikasi
error dan berpotensi dieksploitasi untuk melakukan serangan eskalasi hak istimewa, seperti
CVE-2021-0928.
Contoh berikut menunjukkan cara menerapkan versi aman class Parcel:
Misalkan class UserParcelable mengimplementasikan Parcelable dan membuat instance data pengguna yang kemudian ditulis ke Parcel. Metode readParcelable yang lebih aman
berikutnya dapat digunakan untuk membaca
parcel yang diserialisasi:
Kotlin
val parcel = Parcel.obtain()
val userParcelable = parcel.readParcelable(UserParcelable::class.java.classLoader)
Java
Parcel parcel = Parcel.obtain();
UserParcelable userParcelable = parcel.readParcelable(UserParcelable.class, UserParcelable.CREATOR);
Perhatikan dalam contoh Java di atas penggunaan UserParcelable.CREATOR dalam
metode. Parameter wajib ini memberi tahu metode readParcelable jenis apa yang diharapkan dan memiliki performa yang lebih baik daripada metode readParcelable versi yang kini tidak digunakan lagi.
Risiko Khusus
Bagian ini mengumpulkan risiko yang memerlukan strategi mitigasi non-standar atau dimitigasi di tingkat SDK tertentu dan dilakukan untuk menyelesaikan.
Risiko: Deserialisasi Objek yang Tidak Diinginkan
Menerapkan antarmuka Serializable dalam class akan otomatis
menyebabkan semua subjenis class tertentu menerapkan antarmuka. Dalam
skenario ini, beberapa objek dapat mewarisi antarmuka yang disebutkan di atas, yang berarti
objek tertentu yang tidak dimaksudkan untuk dideserialisasi akan tetap diproses.
Hal ini dapat meningkatkan permukaan serangan secara tidak sengaja.
Mitigasi
Jika class mewarisi antarmuka Serializable, sesuai dengan panduan OWASP, metode readObject harus diimplementasikan sebagai berikut untuk
menghindari sekumpulan objek dalam class dapat dideserialisasi:
Kotlin
@Throws(IOException::class)
private final fun readObject(in: ObjectInputStream) {
throw IOException("Cannot be deserialized")
}
Java
private final void readObject(ObjectInputStream in) throws java.io.IOException {
throw new java.io.IOException("Cannot be deserialized");
}
Resource
- Parcelable
- Parcel
- Serializable
- Intent
- Kerentanan Deserialisasi Android: Sejarah Singkat
- Android Parcels: The Bad, the Good and the Better (video)
- Android Parcels: The Bad, the Good and the Better (slide presentasi)
- CVE-2014-7911: Eskalasi Akses Android <5.0 menggunakan ObjectInputStream
- CVE-CVE-2017-0412
- CVE-2021-0928: Ketidakcocokan Serialisasi/Deserialisasi Parcel
- Panduan OWASP