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

{{#include ../../../../banners/hacktricks-training.md}}