
Linux ELF x32/x64 ASLR DEP/NX bypass exploit com stack-spraying
Exploit de bypass de ASLR e DEP/NX para Linux ELF x32/x64 com stack-spraying

Propriedades:
Dependências:
Limitações:
Você deve ter ouvido falar do ataque de Heap Spraying? Bem, Stack Spraying é semelhante, no entanto, foi considerado impraticável para a maioria dos casos, especialmente ASLR em x86-64.
Meu trabalho provará o contrário.
Para 32 bits, existem 2^32 (4 294 967 296) endereços teóricos, no entanto, o kernel permite controlar apenas cerca de metade dos bits (2^(32/2) = 65 536) para uma execução em memória virtualizada, o que significa que se controlarmos mais de 50 000 caracteres na pilha, temos quase certeza de apontar para nosso shellcode, independentemente do endereço, graças ao redirecionamento e retranslação do kernel. De acordo com meus testes, até 100 ou 10 caracteres são suficientes se a função chamada não contiver outras criações de variáveis, o que permitirá um ataque do tipo ROP.
Isso pode ser alcançado usando variáveis de shell, que não são realmente limitadas a um comprimento específico, mas o limite prático é de cerca de cem mil, caso contrário, saturará o TTY.
Então, para explorar com sucesso com qualquer shellcode, precisamos colocar um NOP sled seguindo o shellcode em uma variável de shell e apenas explorar o binário com um endereço aleatório. Observe que o NOP sled não é necessário, isso é apenas para universalizar o exploit.
Em sistemas de 64 bits, a situação é diferente, mas não tanto quanto da minha descoberta.
Claro, você não teria que cobrir todas as 2^64 possibilidades, na verdade, o kernel permite apenas 48 bits, além de que uma parte deles é previsível e estática, o que nos deixa com cerca de 2^(4x8+5) (137 438 953 472) possibilidades.
Eu mencionei o limite de tamanho das variáveis de shell, mas também há um limite de contagem, que parece ser de cerca de 10, permitindo-nos armazenar um shellcode de 1 000 000 caracteres, deixando-nos com apenas algumas dezenas de milhares de possibilidades que podem ser testadas rapidamente e automaticamente. Desta vez, no entanto, você precisará usar força bruta e usar NOP-sleds para tornar as coisas mais rápidas.
Dito isso, o ASLR tanto em 32 quanto em 64 bits pode ser facilmente contornado em poucos minutos e com poucas linhas de shell...
O DEP/NX, por outro lado, pode ser contornado em x32 usando a técnica return-to-libc ao combiná-la com estudos estatísticos de diferentes sistemas operacionais, mais especificamente, suas limitações e implementações de ASLR, o que pode levar a uma exploração bem-sucedida por 2 motivos. O primeiro é o ASLR não ser tão aleatório em sua escolha e ter algumas constantes e baixa entropia (fácil de adivinhar o endereço da libC e cada SO tem suas próprias constantes). O segundo é pulverizar o argumento shell para a libC no ambiente (fácil de encontrar e passá-lo para a libC).
Para concluir, o DEP/NX em 32 bits é enfraquecido por causa do ASLR.
Uma descrição mais detalhada pode ser encontrada na edição do Hakin9-12-14.
Se você já explorou pelo menos um buffer overflow na sua vida, pode pular, mas apenas por precauçã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
Para provar que o NOP-sled não é necessário para Debian x32:
!!! AVISO !!! isso modificará seu /etc/passwd e alterará as permissões do /etc/shadow, execução em VM recomendada
chmod u+x PoC.sh
source PoC.sh
grep ALI /etc/passwd
Caso ainda não funcione, basta adicionar alguns NOPs (\x90) no início.
Para provar que nem mesmo a variável de ambiente é necessária para Debian x32:
chmod u+x PoC2.sh
source PoC2.sh
Assim, você pode simplesmente colocar seu shellcode em uma variável e fornecer endereços aleatórios para registradores para um shell com ASLR, isso porque o contexto específico onde a função tem apenas uma variável que será reescrita, então a pilha será desempilhada para EIP apenas com nosso shellcode, que é mais como um ataque ROP.
Para Arch/Ubuntu você também precisará desabilitar a proteção contra stack smashing e a força bruta pode demorar muito mais (atraso na execução, provavelmente devido à syscall brk(NULL/0) e/ou canário):
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
No Debian 10, esse problema foi parcialmente corrigido, notadamente devido ao AppArmor.
Sempre confie em múltiplas proteções e não em uma única.
Precisamos de novos mecanismos de segurança do sistema.
"De onde estamos, a chuva parece aleatória. Se pudéssemos estar em outro lugar, veríamos a ordem nela. "
Tony Hillerman, Coyote Waits