Neste tutorial, vamos falar sobre estouro de buffer (Estouro de buffer), uma falha que já existia há muito tempo, ocorre quando os dados que são copiados em uma área de memória (que foi previamente reservada) não são verificados corretamente, pode ser que o aplicativo funcione corretamente se o usuário inserir dados com um tamanho adequado, mas se reservarmos memória para 15 caracteres e o usuário inserir 20, isso afetará outra área da memória, que pode ou não estar reservada.
Isso pode fazer nosso programa travar, mas também pode ser muito pior, um usuário com intenções maliciosas pode tirar vantagem desse erro e influenciar a operação do aplicativo ou executar código arbitrário em um computador (normalmente esse código abrirá um interpretador de comandos ) Além disso, se o programa for executado com privilégios elevados, temos uma falha de segurança séria. Outro ataque que pode alterar o funcionamento de um aplicativo ou injetar código é o XSS.
ObservaçãoAs execuções que você verá ao longo deste tutorial foram realizadas no sistema operacional Ubuntu 16.04 de 32 bits.
Vamos ver um Exemplo simples de código C vulnerável a este ataque, ao lançar o programa devemos passar um parâmetro, o aplicativo espere receber uma string com até 15 caracteres, se for a string esperada, o acesso será bem-sucedido; caso contrário, será "negado". O código é mostrado abaixo:
#include #include #define password "Teste" void test (char * str) {char buffer [15]; int n = 0; strcpy (buffer, str); if (strcmp (buffer, senha) == 0) {n = 1; } if (n) {printf ("Sucesso \ n"); saída (0); } else {printf ("Acesso negado \ n"); }} int main (int argc, char * argv []) {if (argc <2) {printf ("O aplicativo requer um parâmetro \ n"); saída (-1); } teste (argv [1]); }O programa tem o nome de overflow.c, e para compilar o seguinte foi usado:
gcc overflow.c -o overflow -fno-stack-protectorA última parte: -fno-stack-protector É usado para que o compilador não coloque proteção e possamos mostrar o exemplo. Se o usuário inserir dados corretos, que são uma string de no máximo 15 caracteres, o programa funciona bem, se inserirmos uma "senha" incorreta ele nos mostrará Acesso negado, e se colocarmos "Teste”Vai nos colocar Sucesso. Vamos ver uma captura executando o programa 2 vezes, uma com acesso incorreto e outra com a String correta:
Vemos que tudo funciona corretamente. Mas e se inserirmos uma corda superior, vamos ver o que acontece:
Lançamos o programa com 20 letras A, e nos mostra Sucesso. Neste aplicativo não temos nada, simplesmente saímos do aplicativo, mas acessamos uma área restrita sem saber a senha. Se substituirmos a seguinte função:
strcpy (buffer, str);Pelo seguinte:
strncpy (tampão, str, 15);Y executamos o código com 20 letras A, temos a seguinte saída:
Você também pode ver que fazemos uso de strcmp, em vez disso, devemos usar strncmp, então também controlamos o tamanho. Controlamos que apenas um máximo de 15 caracteres podem ser copiados, por isso não afeta nosso programa se eles inserirem mais. Se depois de exibir a mensagem Sucesso executamos um comando do sistema (neste caso Quem sou eu), obtemos as informações:
Acima não somos root, mas se o executarmos com sudo, obteremos o seguinte:
A única coisa que adicionamos é uma linha no código que vimos acima, abaixo da linha de código:
printf ("Sucesso \ n");Colocamos:
sistema ("whoami");Para entender um pouco o que aconteceu, irei modificar o programa para mostrar as 2 variáveis que temos (amortecedor Y n) se está correto ou não, e abaixo está a saída, a primeira inserimos uma string que será tratada como correta (“Teste”), Em seguida, um incorreto que não exceda o comprimento e, finalmente, o 20 letras A:
Vemos que na primeira execução vale a pena 1 A variável n, porque a corrente passada é a correta, na segunda vale a pena 0, porque está errado, mas no último vale a pena 1094795585, o que faz com que pule a condição que colocamos if (n), será verdadeiro desde que n seja diferente de 0. Não é uma boa condição, embora não devesse falhar se o resto do código estivesse correto. Se colocarmos 16 letras A como parâmetro, veremos que o valor da variável n isto é 65:
Se olharmos para o código ASCII, o número 65 corresponde à letra PARA, vimos que a memória da variável n foi acidentalmente tocada por nós, aquela letra extra que passamos como parâmetro foi para a variável n. Teríamos a memória da seguinte forma:
Se formos além dos caracteres, pode ser que nos envie uma mensagem de violação de segmento (se eliminarmos o saída (0) o que temos no if (n)), podemos ver na imagem a seguir:
Este aviso se deve a uma tentativa de acesso a uma área da memória que está fora dos limites daquela atribuída pelo sistema operacional ao aplicativo. Se compilamos o exemplo da seguinte maneira:
gcc overflow.c -o overflow -fstack-protectorOu apenas removendo -fno-stack-protector Da compilação que vimos da primeira vez, e executamos o código com overflow, obtemos o seguinte resultado:
Uma proteção extra que o gcc nos fornece.
ObservaçãoSe quisermos executar um código (shellcode) teríamos que sobrescrever o endereço de retorno com o de nosso shellcode, é um pouco mais complexo do que o exemplo visto no tutorial e, portanto, requer mais trabalho.
Se alguém conseguir tirar proveito dessa vulnerabilidade, isso pode causar muitos danos. Evite ter esse tipo de falha e que um usuário mal-intencionado possa tirar proveito disso é muito fácil, programe corretamente, você tem que conhecer bem a linguagem de programação que está sendo utilizada, saber quais funções utilizar e quais não utilizar, testar a aplicação bem, não só com dados corretos, também tem que funcionar corretamente quando lidamos com dados imprevistos.
Outros ataques que você pode revisar e estar ciente para não afetá-lo ou minimizar seus riscos são: DoS e Força Bruta. E não se esqueça de verificar a página CVE para vulnerabilidades.
Gostou e ajudou este tutorial?Você pode recompensar o autor pressionando este botão para dar a ele um ponto positivo