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 tersebut kemudian akan melalui proses deserialisasi oleh aplikasi, aktivitas, atau penyedia penerima yang akhirnya menangani data. Dalam keadaan normal, data diserialisasi, lalu di-deserialisasi tanpa intervensi pengguna. Namun, hubungan kepercayaan antara proses deserialisasi dan objek yang dimaksud dapat disalahgunakan oleh pelaku berbahaya yang dapat, misalnya, mencegat dan mengubah objek yang diserialisasi. Hal ini akan memungkinkan pelaku berbahaya melakukan serangan seperti denial of service (DoS), eskalasi hak istimewa, dan eksekusi kode jarak jauh (RCE).
Meskipun class Serializable
adalah metode umum untuk mengelola
serialisasi, Android memiliki class-nya sendiri untuk menangani serialisasi yang disebut
Parcel
. Dengan menggunakan class Parcel
, data objek dapat diserialisasi menjadi data
byte stream dan dikemas ke dalam Parcel
menggunakan antarmuka Parcelable
.
Hal ini memungkinkan Parcel
diangkut atau disimpan secara lebih efisien.
Namun, pertimbangan yang cermat harus diberikan saat menggunakan class
Parcel
, karena dimaksudkan sebagai mekanisme transpor IPC yang efisien, tetapi
tidak boleh digunakan untuk menyimpan objek serialisasi dalam penyimpanan persisten
lokal karena dapat menyebabkan masalah kompatibilitas data atau kehilangan. 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 melakukan deserialisasi objek yang dimulai dari jenis class kustom adalah hal yang aman. Pada kenyataannya, objek apa pun yang bersumber dari class apa pun berpotensi diganti dengan konten berbahaya yang, dalam skenario terburuk, dapat mengganggu loader class aplikasi yang sama atau aplikasi lain. Interferensi ini berupa memasukkan nilai berbahaya yang, menurut tujuan class, dapat menyebabkan, misalnya, pemindahan data yang tidak sah atau pengambilalihan akun.
- Mengeksploitasi metode deserialisasi yang dianggap tidak aman secara desain (misalnya CVE-2023-35669, kelemahan 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 dengan hak istimewa melalui kelemahan dalam logika paket WorkSource Android).
Dampak
Aplikasi apa pun yang melakukan deserialisasi data serial yang tidak tepercaya atau berbahaya dapat rentan terhadap eksekusi kode jarak jauh atau serangan denial of service.
Risiko: Deserialisasi input yang tidak tepercaya
Penyerang dapat memanfaatkan kurangnya verifikasi paket dalam logika aplikasi untuk memasukkan objek arbitrer yang, setelah di-deserialisasi, dapat memaksa aplikasi untuk mengeksekusi kode berbahaya yang dapat menyebabkan denial of service (DoS), eskalasi akses, dan eksekusi kode jarak jauh (RCE).
Jenis serangan ini mungkin tidak terlihat jelas. Misalnya, aplikasi mungkin berisi intent 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 dimasukkan dideserialisasi karena intent memperlakukan tambahan sebagai
Bundle
. Pengguna berbahaya dapat memanfaatkan perilaku ini untuk memasukkan data
objek yang, setelah dideserialisasi, dapat menyebabkan RCE, kompromi data, atau kehilangan.
Mitigasi
Sebagai praktik terbaik, asumsikan bahwa semua data serial tidak tepercaya dan berpotensi berbahaya. Untuk memastikan integritas data serial, lakukan pemeriksaan verifikasi pada data untuk memastikan class dan format yang benar yang diharapkan oleh aplikasi.
Solusi yang dapat dilakukan adalah menerapkan pola look-ahead untuk
library java.io.ObjectInputStream
. Dengan mengubah kode yang bertanggung jawab untuk
deserialisasi, Anda dapat memastikan bahwa hanya kumpulan class
yang ditentukan secara eksplisit yang dideserialisasi dalam intent.
Mulai Android 13 (API level 33), beberapa metode telah diperbarui dalam
class Intent
yang dianggap sebagai alternatif yang lebih aman daripada metode lama dan
yang kini tidak digunakan lagi untuk menangani paket. Metode baru yang lebih aman, seperti
getParcelableExtra(java.lang.String, java.lang.Class)
dan
getParcelableArrayListExtra(java.lang.String, java.lang.Class)
, melakukan
pemeriksaan jenis data untuk menemukan kelemahan ketidakcocokan yang dapat menyebabkan
aplikasi mengalami error dan berpotensi dieksploitasi untuk melakukan serangan eskalasi akses, seperti
CVE-2021-0928.
Contoh berikut menunjukkan cara menerapkan versi class Parcel
yang aman:
Misalkan class UserParcelable
menerapkan Parcelable
dan membuat
instance data pengguna yang kemudian ditulis ke Parcel
. Metode
readParcelable
yang lebih aman jenis berikut kemudian dapat digunakan untuk membaca
paket 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 yang diperlukan ini memberi tahu metode readParcelable
jenis yang diharapkan
dan lebih berperforma tinggi daripada versi metode
readParcelable
yang sekarang 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
Mengimplementasikan antarmuka Serializable
dalam class akan otomatis
menyebabkan semua subjenis class tertentu mengimplementasikan 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 secara tidak sengaja meningkatkan permukaan serangan.
Mitigasi
Jika class mewarisi antarmuka Serializable
, sesuai dengan panduan OWASP, metode readObject
harus diimplementasikan sebagai berikut untuk
menghindari sekumpulan objek di 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");
}
Referensi
- Parcelable
- Persil
- Serializable
- Intent
- Kerentanan Deserialisasi Android: Ringkasan histori
- Paket Android: yang Buruk, yang Baik, dan yang Lebih Baik (video)
- Android Parcels: The Bad, the Good and the Better (slide presentasi)
- CVE-2014-7911: Eskalasi Hak Istimewa Android <5.0 menggunakan ObjectInputStream
- CVE-CVE-2017-0412
- CVE-2021-0928: Ketidakcocokan Serialisasi/Deserialisasi Paket
- Panduan OWASP