
Linux ELF x32/x64 ASLR DEP/NX bypass exploit avec stack-spraying
Exploit Linux ELF x32/x64 contournant ASLR et DEP/NX avec stack-spraying

Propriétés :
Dépendances :
Limites :
Vous avez peut-être entendu parler de l'attaque Heap Spraying ? Eh bien, le Stack Spraying est similaire, mais il était considéré comme peu pratique dans la plupart des cas, en particulier avec ASLR sur x86-64.
Mes travaux prouveront le contraire.
Pour le 32 bits, il y a 2^32 (4 294 967 296) adresses théoriques, néanmoins, le noyau ne permettra de contrôler qu'environ la moitié des bits (2^(32/2) = 65 536) pour une exécution en mémoire virtualisée, ce qui signifie que si nous contrôlons plus de 50 000 caractères dans la pile, nous sommes presque certains de pointer vers notre shellcode, quelle que soit l'adresse, grâce à la redirection et à la retraduction du noyau. Selon mes tests, même 100 ou 10 caractères suffisent si la fonction appelée ne crée pas d'autres variables, ce qui permettra une attaque de style ROP.
Cela peut être réalisé à l'aide de variables shell, qui ne sont pas vraiment limitées à une longueur spécifique, mais la limite pratique est d'environ cent mille, sinon cela sature le TTY.
Donc, pour exploiter avec succès n'importe quel shellcode, nous devons placer un NOP sled suivi du shellcode dans une variable shell, puis simplement exploiter le binaire avec une adresse aléatoire. Notez que le NOP sled n'est pas nécessaire, c'est juste pour universaliser l'exploit.
Dans un système 64 bits, la situation est différente, mais pas tant que ça après ma découverte.
Bien sûr, vous n'auriez pas à couvrir toutes les 2^64 possibilités, en fait, le noyau n'en permet que 48 bits, plus une partie d'entre eux sont prévisibles et statiques, ce qui nous laisse environ 2^(4x8+5) (137 438 953 472) possibilités.
J'ai mentionné la limite de taille des variables shell, mais il y a aussi une limite de nombre, qui semble être d'environ 10, nous permettant ainsi de stocker un shellcode d'un million de caractères, ne nous laissant que quelques dizaines de milliers de possibilités qui peuvent être testées rapidement et automatiquement. Cette fois cependant, vous devrez bruteforcer et utiliser des NOP-sleds pour accélérer les choses.
Cela dit, l'ASLR sur 32 et 64 bits peut être facilement contourné en quelques minutes et avec quelques lignes de shell...
Le DEP/NX, quant à lui, peut être contourné sur x32 en utilisant la technique return-to-libc couplée à des études statistiques de différents OS, plus précisément leurs limitations et implémentations d'ASLR, ce qui peut mener à une exploitation réussie pour 2 raisons. La première est que l'ASLR n'est pas si aléatoire dans son choix et possède des constantes et une faible entropie (adresse de libC facile à deviner et chaque OS a ses propres constantes). La seconde est de pulvériser l'argument shell pour libC dans l'environnement (facile à trouver et à passer à libC).
Pour conclure, DEP/NX sur 32 bits est affaibli à cause de l'ASLR.
Une description plus détaillée se trouve dans le numéro Hakin9-12-14 issue.
Si vous avez déjà exploité au moins un buffer overflow dans votre vie, vous pouvez sauter, mais au cas où :
apt install gcc libc6-dev-i386 || kill -9 $$
chmod u+x ASLRay.sh
sudo gcc -z execstack test.c -o test
sudo gcc -m32 -z execstack test.c -o test32
sudo chmod +s test test32
source ASLRay.sh test32 1024
source ASLRay.sh test 1024
source ASLRay.sh test 1024 \x31\x80...your_shellcode_here
sudo gcc -m32 test.c -o test32x
sudo chmod +s test test32
source ASLRay.sh test32x 1024
Pour prouver que le NOP-sled n'est pas nécessaire pour Debian x32 :
!!! ATTENTION !!! cela modifiera votre /etc/passwd et changera les permissions de /etc/shadow, exécution dans une VM conseillée
chmod u+x PoC.sh
source PoC.sh
grep ALI /etc/passwd
Si cela ne fonctionne toujours pas, ajoutez quelques NOP (\x90) au début.
Pour prouver que même la variable d'environnement n'est pas nécessaire pour Debian x32 :
chmod u+x PoC2.sh
source PoC2.sh
Ainsi, vous pouvez simplement placer votre shellcode dans une variable et donner des adresses aléatoires aux registres pour un shell avec ASLR, car le contexte spécifique où la fonction n'a qu'une seule variable qui sera réécrite, donc la pile sera dépilée vers EIP juste avec notre shellcode, ce qui ressemble plus à une attaque ROP.
Pour Arch/Ubuntu vous devrez également désactiver la protection contre le stack smashing et le brute-force peut prendre beaucoup plus de temps (délai d'exécution, probablement dû à l'appel système brk(NULL/0) ou/et au canary) :
sudo gcc -z execstack -fno-stack-protector test.c -o test
sudo gcc -m32 -z execstack -fno-stack-protector test.c -o test32
sudo gcc -m32 -fno-stack-protector test.c -o test32x
Sous Debian 10, ce problème a été partiellement corrigé, notamment grâce à AppArmor.
Fiez-vous toujours à plusieurs protections, pas à une seule.
Nous avons besoin de nouveaux mécanismes de sécurité système.
« De là où nous sommes, la pluie semble aléatoire. Si nous étions ailleurs, nous verrions l'ordre en elle. »
Tony Hillerman, Coyote Waits