OWASP kategorisi: MASVS-CODE: Kod Kalitesi
Genel Bakış
Büyük miktarda Java nesne verisi depolarken veya aktarırken genellikle verileri önce serileştirmek daha verimlidir. Daha sonra veriler; alıcı uygulama, etkinlik veya sağlayıcı tarafından seri durumdan çıkarılarak işlenir. Normal şartlar altında veriler, serileştirilir ve ardından herhangi bir kullanıcı müdahalesi olmadan seri dışı bırakılır. Ancak serileştirmeden çıkarma işlemi ile amaçlanan nesnesi arasındaki güven ilişkisi, kötü amaçlı bir kişi tarafından kötüye kullanılabilir. Bu kişi, örneğin serileştirilmiş nesneleri durdurup değiştirebilir. Bu durum, kötü amaçlı kullanıcının hizmet reddi (DoS), ayrıcalık yükseltme ve uzaktan kod yürütme (RCE) gibi saldırılar gerçekleştirmesine olanak tanır.
Serializable
sınıfı, serileştirmeyi yönetmek için yaygın olarak kullanılan bir yöntem olsa da Android'in serileştirmeyi işlemek 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 bir Parcel
içine paketlenebilir.
Bu sayede Parcel
daha verimli bir şekilde taşınabilir veya depolanabilir.
Bununla birlikte, yüksek verimli bir IPC taşıma mekanizması olması amaçlandığından, ancak veri uyumluluğu sorunlarına veya kaybına yol açabileceğinden, serileştirilmiş nesneleri yerel kalıcı depolama alanında depolamak için kullanılmamalıdır. Parcel
sınıfını kullanırken dikkatli olunmalıdır. Verilerin okunması gerektiğinde, Parcel
öğesini seri dışına çıkarmak ve nesne verilerine dönüştürmek için Parcelable
arayüzü kullanılabilir.
Android'de seri dışılaştırmadan yararlanmak için üç temel vektör vardır:
- Geliştiricinin, özel sınıf türünden gelen nesnelerin seri dışına çı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 kaynak olarak kullanılan herhangi bir nesne, kötü amaçlı içerikle değiştirilebilir. Bu içerik, en kötü senaryoda aynı veya diğer uygulamaların sınıf yükleyicilerini etkileyebilir. Bu müdahale, sınıf amacına göre örneğin veri sızıntısına veya hesap ele geçirilmesine yol açabilecek tehlikeli değerlerin eklenmesi şeklinde gerçekleşir.
- Tasarım gereği güvenli olmayan olarak kabul edilen seri dışılaştırma yöntemlerinin kötüye kullanılması (ör. derin bağlantı seri dışılaştırma vektörü aracılığıyla keyfi JavaScript kodu eklemeye izin veren yerel ayrıcalık yükseltme hatası olan CVE-2023-35669)
- Uygulama mantığındaki açıklardan yararlanma (örneğin, CVE-2023-20963; bir uygulamanın Android'in WorkSource paket mantığındaki bir kusur aracılığıyla ayrıcalıklı bir ortamda kod indirip yürütmesine olanak tanıyan bir yerel ayrıcalık yükseltme hatası).
Etki
Güvenilmeyen veya kötü amaçlı serileştirilmiş verileri seri dışı bırakan 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 dışı bırakılması
Saldırganlar, uygulama mantığındaki paket doğrulamasının eksikliğinden yararlanarak rastgele nesneler enjekte edebilir. Bu nesneler, seri dışı hale getirildikten sonra uygulamayı hizmet reddi (DoS), ayrıcalık yükseltme ve uzaktan kod yürütme (RCE) ile sonuçlanabilecek kötü amaçlı kod yürütmeye zorlayabilir.
Bu tür saldırılar fark edilmeyebilir. Örneğin, bir uygulama, doğrulandıktan sonra seri durumdan çıkarılacak yalnızca bir parametrenin yapılmasını bekleyen bir amaç içerebilir. Bir saldırgan, beklenenle birlikte beklenmedik ikinci bir kötü amaçlı ek parametre gönderirse intent, ekleri Bundle
olarak ele aldığından, enjekte edilen tüm veri nesnelerinin seri dışına çıkarılmasına neden olur. Kötü amaçlı kullanıcılar, bu davranışı kullanarak seriden çıkarıldıktan sonra RCE, veri güvenliği ihlali veya kayba neden olabilecek nesne verilerini yerleştirebilir.
Çö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 verilerde doğru sınıf ve biçimin kullanıldığını doğrulamak amacıyla doğrulama kontrolleri yapın.
java.io.ObjectInputStream
Kitaplığı için ileriye dönük kalıbı uygulamak uygun bir çözüm olabilir. Nesneden dizeye dönüştürme işleminden sorumlu kodu değiştirerek intent içinde yalnızca açıkça belirtilen bir sınıf grubunun serileştirildiğinden emin olabilirsiniz.
Android 13 (API düzeyi 33) itibarıyla, Intent
sınıfında paketleri işlemeyle ilgili eski ve artık desteği sonlandırılmış yöntemlerin daha güvenli alternatifleri olarak kabul edilen çeşitli yöntemler güncellendi. getParcelableExtra(java.lang.String, java.lang.Class)
ve getParcelableArrayListExtra(java.lang.String, java.lang.Class)
gibi tür daha güvenli bu yeni yöntemler, uygulamaların çökmesine ve CVE-2021-0928 gibi ayrıcalık artırma saldırıları gerçekleştirirken kötüye kullanılma olasılığı bulunan uyumsuzluk zayıflarını yakalamak için veri türü denetimleri gerçekleştirir.
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 kullanıcı verilerinin, daha sonra Parcel
öğesine yazılan bir örneğini oluşturduğunu varsayalım. Daha sonra, serileştirilmiş paketi okumak için aşağıdaki readParcelable
türüne daha güvenli yöntem 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öntem içinde UserParcelable.CREATOR
kullanıldığına dikkat edin. Bu zorunlu parametre, readParcelable
yöntemine ne tür olması gerektiğini bildirir ve readParcelable
yönteminin kullanımdan kaldırılmış olan sürümüne göre daha iyi performans gösterir.
Belirli Riskler
Bu bölümde, standart olmayan azaltma stratejileri gerektiren veya belirli bir SDK düzeyinde azaltılan riskler toplanmıştır. Bu riskler, eksiksiz bir liste sunmak için burada yer almaktadır.
Risk: İstenmeyen Nesne Seri Dışı Dönüştürme
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, seri dışına çıkarı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 Serializable
arayüzünü devralır ve OWASP yönergelerine uygunsa sınıftaki bir nesne grubunun seri dışı hale getirilmesini önlemek için readObject
yöntemi aşağıdaki şekilde 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
- Paketlenebilirler
- Parsel
- Yayınlanabilir
- Intent
- Android Nesne Dizi Oluşturma Açıkları: Kısa bir geçmiş
- Android Paketleri: Kötü, İyi ve Daha İyi (video)
- Android paketleri: Kötü, İyi ve Daha İyi (sunum slaytları)
- CVE-2014-7911: Android <5.0 ObjectInputStream kullanarak ayrıcalık artırma
- CVE-CVE-2017-0412
- CVE-2021-0928: Paket Serileştirme/Seri Çözme Eşleşmemesi
- OWASP kılavuzu