Arbitrary read primitive¶
Bir "read-where": programın dereference edip açığa çıkardığı bir pointer'ı etkile; böylece bir read'i, attacker'ın seçtiği herhangi bir adresten okumaya çevir.
Mechanism¶
Note
Bir read primitive'i, hem dereference edilen bir adres'in hem de
dereference edilen değerin output'unun attacker tarafından erişilebilir
olduğu her yerde mevcuttur. Kanonik vektör bir format string'dir: variadic
printf-ailesi fonksiyonlar argümanları pozisyonel olarak tüketir, ama
printf kaç gerçek argümanın geçildiğini bilemez; bu yüzden fazla
specifier'lar komşu memory'yi okur. %s argümanını bir pointer olarak
ele alır ve o adresteki string'i yazdırır. Attacker stack üzerinde bir değeri
de (kendi input buffer'ı) kontrol ediyorsa, oraya bir target adres yerleştirir
ve %N$s'i ona nişanlar — map'lenmiş herhangi bir adresi okuyarak.
Invariant şu: dereference ettiği adres attacker-controlled olduğunda ve sonuç gözlemlenebilir olduğunda bir read arbitrary hale gelir. Diğer biçimler: bir struct içinde sonradan dereference edilen kontrollü bir index/pointer field'ı; bir out-of-bounds read; ya da basitçe resolve edilmiş bir libc symbol'ünü leak etmek için bir GOT entry'sini okumak (bir address leak).
Walkthrough¶
# Leak raw stack slots (direct param access at offset 6):
input: %6$p
output: 0x7ffd1234abcd # a stack/canary/libc pointer
# Arbitrary read: put target in our buffer, deref it with %s
# layout: ["%7$s" + padding][ p64(0x404018) ] (0x404018 = a GOT entry)
input: %7$s<pad>\x18\x40\x40\x00\x00\x00\x00\x00
output: <8 bytes at 0x404018> # resolved libc address of that function
Beklenen davranış: %N$p N'inci slot'u açığa çıkarır (canary/libc/PIE leak);
%N$s kontrollü pointer'ı takip eder ve attacker'ın seçtiği bir adresteki
memory'yi dump eder.
Warning
printf bir NULL byte'ta durur; bu yüzden payload'da format directive'lerini
önce, ham target adresini sona yerleştir ve adres byte'larının getirdiği
offset kaymasını hesaba kat.
Mitigation¶
- Attacker input'unu asla format string olarak geçirme (
printf("%s", buf)). -Wformat -Wformat-security,printf(user)'ı compile time'da işaretler; FORTIFY_SOURCE bazı%ndurumlarını kısıtlar ama read'leri değil.- Primitive bir disclosure yoluna bağlıdır — output'u kısıtlamak ve index'leri bounds-check etmek onu ortadan kaldırır.