OWASP kategorisi: MASVS-CODE: Kod Kalitesi
Genel Bakış
Büyük miktarda Java nesne verisi depolarken veya aktarırken önce verileri serileştirmek genellikle daha verimlidir. Veriler daha sonra, verileri işleyen alıcı uygulama, etkinlik veya sağlayıcı tarafından seri durumdan çıkarma işlemine tabi tutulur. Normal şartlar altında veriler, kullanıcı müdahalesi olmadan serileştirilir ve ardından seri durumdan çıkarılır. Ancak, seri durumdan çıkarma işlemi ile amaçlanan nesnesi arasındaki güven ilişkisi, kötü niyetli bir aktör tarafından kötüye kullanılabilir. Bu aktör, örneğin, seri hale getirilmiş nesneleri yakalayıp değiştirebilir. Bu durum, kötü amaçlı aktörün hizmet reddi (DoS), ayrıcalık artırma ve uzaktan kod yürütme (RCE) gibi saldırılar gerçekleştirmesine olanak tanır.
Serializable sınıfı, serileştirme işlemini yönetmek için yaygın olarak kullanılan bir yöntem olsa da Android'in serileştirme işlemini yönetmek için Parcel adlı kendi sınıfı vardır. Parcel sınıfı kullanılarak nesne verileri, bayt akışı verilerine serileştirilebilir ve Parcelable arayüzü kullanılarak Parcel içine paketlenebilir.
Bu sayede Parcel daha verimli bir şekilde taşınabilir veya depolanabilir.
Bununla birlikte, yüksek verimli bir IPC aktarım mekanizması olması amaçlandığından Parcel
sınıfı kullanılırken dikkatli olunmalıdır. Bu sınıf, yerel kalıcı depolama alanında serileştirilmiş nesneleri depolamak için kullanılmamalıdır. Aksi takdirde veri uyumluluğu sorunları veya veri kaybı yaşanabilir. Verilerin okunması gerektiğinde Parcelable arayüzü, Parcel öğesini seri durumundan çıkarmak ve tekrar nesne verilerine dönüştürmek için kullanılabilir.
Android'de seri durumdan çıkarma işleminden yararlanmak için üç temel vektör vardır:
- Geliştiricinin, özel sınıf türünden gelen nesnelerin seri durumdan çıkarılmasının güvenli olduğu yönündeki yanlış varsayımından yararlanma. Gerçekte, herhangi bir sınıf tarafından sağlanan tüm nesneler, en kötü senaryoda aynı veya diğer uygulamaların sınıf yükleyicileriyle etkileşime girebilecek kötü amaçlı içeriklerle değiştirilebilir. Bu müdahale, sınıfın amacına göre örneğin veri sızdırma veya hesap ele geçirme gibi sonuçlara yol açabilecek tehlikeli değerlerin yerleştirilmesi şeklinde gerçekleşir.
- Tasarım açısından güvenli olmadığı düşünülen seri durumdan çıkarma yöntemlerinden yararlanma (ör. CVE-2023-35669, derin bağlantı seri durumdan çıkarma vektörü aracılığıyla rastgele JavaScript kodu yerleştirmeye izin veren yerel ayrıcalık artırma hatası)
- Uygulama mantığındaki kusurlardan yararlanma (ör. CVE-2023-20963, bir uygulamanın Android'in WorkSource paket mantığındaki bir kusur aracılığıyla ayrıcalıklı bir ortamda kod indirmesine ve yürütmesine olanak tanıyan yerel bir ayrıcalık artırma kusuru).
Etki
Güvenilmeyen veya kötü amaçlı olarak serileştirilmiş verileri seri durumdan çıkarma işlemi yapan tüm uygulamalar, uzaktan kod yürütme veya hizmet reddi saldırılarına karşı savunmasız olabilir.
Risk: Güvenilmeyen girişin seri durumundan çıkarma işlemi
Saldırganlar, uygulamadaki paket doğrulama eksikliğinden yararlanarak rastgele nesneler ekleyebilir. Bu nesneler seri durumdan çıkarıldıktan sonra uygulamayı hizmet reddine (DoS), ayrıcalık artırmaya ve uzaktan kod yürütmeye (RCE) neden olabilecek kötü amaçlı kodlar yürütmeye zorlayabilir.
Bu tür saldırılar fark edilmesi zor olabilir. Örneğin, bir uygulama yalnızca bir parametre bekleyen bir amaç içerebilir. Bu parametre, doğrulandıktan sonra seri durumundan çıkarılır. Bir saldırgan, beklenen parametreyle birlikte ikinci bir beklenmedik kötü amaçlı ek parametre gönderirse bu durum, amaç ekstraları Bundle olarak değerlendirdiğinden eklenen tüm veri nesnelerinin seri durumdan çıkarılmasına neden olur. Kötü niyetli bir kullanıcı, bu davranıştan yararlanarak nesne verileri ekleyebilir. Bu veriler seri durumdan çıkarıldığında RCE, veri ihlali veya kaybına yol açabilir.
Çözümler
En iyi uygulama olarak, tüm serileştirilmiş verilerin güvenilmediğini ve kötü amaçlı olabileceğini varsayın. Serileştirilmiş verilerin bütünlüğünü sağlamak için veriler üzerinde doğrulama kontrolleri yaparak uygulamanın beklediği doğru sınıf ve biçimde olduğundan emin olun.
Uygun bir çözüm, java.io.ObjectInputStream kitaplığı için ileriye bakma modelini uygulamak olabilir. Serileştirmeden kaldırma işleminden sorumlu kodu değiştirerek, niyet içinde yalnızca açıkça belirtilen bir sınıf kümesinin serileştirmeden kaldırıldığından emin olabilirsiniz.
Android 13 (API düzeyi 33) itibarıyla, paketlerin işlenmesi için kullanılan eski ve artık kullanımdan kaldırılmış yöntemlere kıyasla daha güvenli alternatifler olarak kabul edilen Intent sınıfındaki çeşitli yöntemler güncellendi. getParcelableExtra(java.lang.String, java.lang.Class) ve getParcelableArrayListExtra(java.lang.String, java.lang.Class) gibi bu yeni tür güvenli yöntemler, uygulamaların kilitlenmesine neden olabilecek ve ayrıcalık artırma saldırıları (ör. CVE-2021-0928) gerçekleştirmek için kullanılabilecek tür uyuşmazlığı zayıflıklarını yakalamak üzere veri türü kontrolleri yapar.
Aşağıdaki örnekte, Parcel sınıfının güvenli bir sürümünün nasıl uygulanabileceği gösterilmektedir:
UserParcelable sınıfının Parcelable uyguladığını ve ardından Parcel'ye yazılan bir kullanıcı verileri örneği oluşturduğunu varsayalım. Daha sonra, serileştirilmiş paketi okumak için aşağıdaki tür açısından daha güvenli readParcelable yöntemi kullanılabilir:
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);
Yukarıdaki Java örneğinde, yöntemde UserParcelable.CREATOR kullanımına dikkat edin. Bu zorunlu parametre, readParcelable yöntemine hangi türü bekleyeceğini söyler ve readParcelable yönteminin artık kullanımdan kaldırılan sürümünden daha iyi performans gösterir.
Belirli Riskler
Bu bölümde, standart dışı azaltma stratejileri gerektiren veya belirli bir SDK düzeyinde azaltılmış olan ve eksiksiz olması için buraya eklenen riskler yer almaktadır.
Risk: İstenmeyen Nesne Seri Durumundan Çıkarma
Bir sınıfta Serializable arayüzünün uygulanması, söz konusu sınıfın tüm alt türlerinin arayüzü otomatik olarak uygulamasına neden olur. Bu senaryoda, bazı nesneler yukarıda belirtilen arayüzü devralabilir. Bu da seri durumdan çıkarma işlemi yapılmaması gereken belirli nesnelerin yine de işleneceği anlamına gelir.
Bu durum, saldırı yüzeyini istemeden artırabilir.
Çözümler
Bir sınıf, OWASP yönergelerine göre Serializable arayüzünü devralıyorsa sınıftaki bir dizi nesnenin seri durumdan çıkarılmasını önlemek için readObject yöntemi aşağıdaki gibi uygulanmalıdır:
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");
}
Kaynaklar
- Parcelable'lar
- Parsel
- Serializable
- Amaç
- Android Deserialization Vulnerabilities: A Brief history
- Android Parcels: The Bad, the Good and the Better (video) [Android Paketleri: Kötü, İyi ve Daha İyi (video)]
- Android Parcels: The Bad, the Good and the Better (presentation slides)
- CVE-2014-7911: Android <5.0'da ObjectInputStream kullanılarak ayrıcalık artırma
- CVE-CVE-2017-0412
- CVE-2021-0928: Paket Serileştirme/Serileştirmeyi Kaldırma Uyuşmazlığı
- OWASP rehberi