Stack Canaries
{{#include ../../../../banners/hacktricks-training.md}}
StackGuard ve StackShield
StackGuard, EIP (Extended Instruction Pointer)'dan önce, özellikle 0x000aff0d
(null, yeni satır, EOF, taşıma dönüşü temsil eder) olarak bilinen özel bir değeri canary olarak ekler ve bu, tampon taşmalarına karşı koruma sağlar. Ancak, recv()
, memcpy()
, read()
ve bcopy()
gibi fonksiyonlar hala savunmasızdır ve EBP (Base Pointer)'yi korumaz.
StackShield, tüm dönüş adreslerini (EIPs) saklayan bir Global Return Stack tutarak StackGuard'dan daha sofistike bir yaklaşım benimser. Bu yapı, herhangi bir taşmanın zarar vermemesini sağlar, çünkü saklanan ve gerçek dönüş adresleri arasında bir karşılaştırma yapılmasına olanak tanır. Ayrıca, StackShield, EIP'nin beklenen veri alanının dışına işaret edip etmediğini tespit etmek için dönüş adresini bir sınır değeri ile kontrol edebilir. Ancak, bu koruma, Return-to-libc, ROP (Return-Oriented Programming) veya ret2ret gibi tekniklerle aşılabilir, bu da StackShield'in yerel değişkenleri de korumadığı anlamına gelir.
Stack Smash Protector (ProPolice) -fstack-protector
:
Bu mekanizma, EBP'den önce bir canary yerleştirir ve yerel değişkenleri daha yüksek bellek adreslerinde konumlandıracak şekilde yeniden düzenler, böylece diğer değişkenleri yazmalarını engeller. Ayrıca, yerel değişkenlerin üzerinde yığılan argümanları güvenli bir şekilde kopyalar ve bu kopyaları argüman olarak kullanır. Ancak, 8'den az eleman içeren dizileri veya bir kullanıcının yapısı içindeki tamponları korumaz.
Canary, /dev/urandom
'dan türetilen rastgele bir sayıdır veya varsayılan değeri 0xff0a0000
'dir. TLS (Thread Local Storage)'de saklanır, bu da iş parçacıkları arasında paylaşılan bellek alanlarının iş parçacığına özgü küresel veya statik değişkenlere sahip olmasına olanak tanır. Bu değişkenler başlangıçta ana süreçten kopyalanır ve çocuk süreçler, ana veya kardeşleri etkilemeden verilerini değiştirebilir. Ancak, eğer bir fork()
yeni bir canary oluşturmadan kullanılırsa, tüm süreçler (ana ve çocuklar) aynı canary'yi paylaşır, bu da onu savunmasız hale getirir. i386 mimarisinde, canary gs:0x14
'te, x86_64'de ise fs:0x28
'de saklanır.
Bu yerel koruma, saldırılara karşı savunmasız tamponlara sahip fonksiyonları tanımlar ve bu fonksiyonların başına canary'yi yerleştirmek için kod enjekte eder ve sonunda bütünlüğünü doğrulamak için kod ekler.
Bir web sunucusu fork()
kullandığında, canary'yi byte byte tahmin etmek için bir kaba kuvvet saldırısını etkinleştirir. Ancak, fork()
'tan sonra execve()
kullanmak bellek alanını yazdığı için saldırıyı geçersiz kılar. vfork()
, çocuk sürecin yazma girişiminde bulunana kadar kopyalamadan çalışmasına izin verir; bu noktada bir kopya oluşturulur ve süreç oluşturma ve bellek yönetimi için farklı bir yaklaşım sunar.
Uzunluklar
x64
ikili dosyalarında, canary çerezi bir 0x8
byte qword'dur. İlk yedi byte rastgeledir ve son byte bir null byte'dır.
x86
ikili dosyalarında, canary çerezi bir 0x4
byte dword'dur. İlk üç byte rastgeledir ve son byte bir null byte'dır.
Caution
Her iki canary'nin en az anlamlı byte'ı bir null byte'dır çünkü bu, daha düşük adreslerden gelen yığında ilk olacak ve bu nedenle string okuyan fonksiyonlar onu okumadan önce duracaktır.
Bypass'ler
Canary'yi sızdırmak ve ardından kendi değeriyle (örneğin, tampon taşması) üzerine yazmak.
- Eğer canary çocuk süreçlerde fork edilirse, bir byte bir seferde brute-force yapmak mümkün olabilir:
{{#ref}} bf-forked-stack-canaries.md {{#endref}}
- İkili dosyada ilginç bir sızıntı veya keyfi okuma açığı varsa, onu sızdırmak mümkün olabilir:
{{#ref}} print-stack-canary.md {{#endref}}
- Yığın üzerinde saklanan işaretçileri üzerine yazma
Yığın, bir yığın taşmasına karşı savunmasızsa, string'lere veya işlevlere ait adresleri içerebilir ve bu adresler, canary'ye ulaşmadan açığı istismar etmek için üzerine yazılabilir. Kontrol et:
{{#ref}} ../../stack-overflow/pointer-redirecting.md {{#endref}}
- Hem ana hem de iş parçacığı canary'sini değiştirme
Canary ile korunan bir iş parçacıklı fonksiyonda bir tampon taşması, iş parçacığının ana canary'sini değiştirmek için kullanılabilir. Sonuç olarak, bu önlem işe yaramaz çünkü kontrol, aynı (değiştirilmiş) iki canary ile kullanılır.
__stack_chk_fail
GOT girişini değiştirme
Eğer ikili dosya Partial RELRO'ya sahipse, o zaman canary değiştiğinde programı engellemeyen sahte bir fonksiyon olacak şekilde __stack_chk_fail
'in GOT girişini değiştirmek için keyfi bir yazma kullanabilirsiniz.
Referanslar
- https://guyinatuxedo.github.io/7.1-mitigation_canary/index.html
- http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads
- 64 bit, no PIE, nx, iş parçacığı ve ana canary'yi değiştir.
- https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/
- 64 bit, no PIE, nx, write-what-where primitive.
__stack_chk_fail
'in GOT girişini değiştir.
{{#include ../../../../banners/hacktricks-training.md}}