Como prevenir o Buffer Overflow

O grande problema de segurança em softwares, tem sido falhas de Buffer Overflow. E como prova disso, existe vários exploits que exploram essa falha. A falha acontece quando uma string armazenada em uma variável tem tamanho maior do que foi reservado para a variável.

[ Hits: 12.975 ]

Por: Perfil removido em 06/08/2014


Introdução



Como funciona o Buffer Overflow?

Ao copiar uma quantidade grande de bytes, esses bytes sobrepõem outros valores na memória, tais como o armazenado no registador EBP e EIP.

Como é realizado um ataque contra esse tipo de falha?

O atacante gera um buffer contendo uma string qualquer (geralmente usam NOP) mais um endereço de retorno que, no caso, aponta para onde a execução do programa deve saltar e, por fim, o shellcode (códigos de máquina. Chama-se shellcode, pois na maioria das vezes, é executado um código que retorna um shell ao atacante).

Quando o valor de EIP é sobreposto, o programa desvia sua execução saltando para o código do shellcode e então o código malicioso é executado.

Nesse artigo, irei mostrar formas de prevenir essa falha e alguns métodos conhecidos como cookie, que também ajudam a evitar o Buffer Overflow.

Prevenindo o buffer overflow (métodos tradicionais)

Como já foi explicado anteriormente, a exploração da falha ocorre ao passar uma string com quantidade maior do que o esperado pelo programa. Então, já temos em mente que para evitar a falha, basta que verifiquemos a quantidade de bytes que será copiado, e caso seja maior, copiaremos apenas a quantidade suportada pela variável.

Exemplo example1.c:

#include <stdio.h>
#include <string.h>

int main(int argc, char** argv)
{
    char buffer[128];

    if (argc > 1)
strcpy(buffer, argv[1]);

    return 0;
}

Temos acima, um programa vulnerável que não está verificando o tamanho da string que será copiada para a variável buffer. Como a verificação não é feita, este programa pode ser explorado facilmente.

Como podemos evitar que ocorra um estouro de buffer nesse programa?

A resolução do problema é simples! Basta que utilizemos uma outra função que faz a copia por tamanho definido por nós. Veja:

#include <stdio.h>
#include <string.h>

int main(int argc, char** argv)
{
    char buffer[128];

    if (argc > 1)
    memcpy(buffer, argv[1], 127);

    return 0;
}

Este é o método mais simples de proteção contra Buffer Overflow e é 100% garantido que só será copiado para a variável buffer uma string de tamanho até 127 bytes.

Agora, vamos ver um método que resolve o problema de forma diferente ao anterior.

Iremos copiar toda a string informada pelo usuário, mesmo que a quantidade de bytes seja grande. Precisaremos utilizar alocação dinâmica de memória para que o tamanho da memória reservada para a variável seja do mesmo tamanho da string. Pra trabalhar com alocação dinâmica, iremos fazer uso de ponteiros, o canivete suíço da linguagem C.

Exemplo example2.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char** argv)
{
    char *buffer;
    long long int len;

    if (argc > 1)
    {
    len = strlen(argv[1]) + 1;
    buffer = (char*) malloc(sizeof(char) * len--);
    memcpy(buffer, argv[1], len);
    buffer[len] =  '\0';

    printf("%d bytes copiados\n", len);
    }

    return 0;
}

A diferença desse código para o anterior é praticamente de 99%, 1% fica para a linha aonde fizemos a cópia da string. O que fizemos foi obter o tamanho da string que será copiada para buffer, alocamos memória com a quantidade obtida, copiamos a string e, por fim, finalizamos a string (buffer[len] = '\0';).

Este código é tão seguro quanto o anterior, mas existe um problema com esse último exemplo. Quem está decidindo a quantidade de memória a reservar é o usuário e não o programador. Isso é um grande problema.

Para resolvermos isso, basta definirmos um tamanho máximo de bytes que podem ser copiados. Veja:

Exemplo example3.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_BUFFER 1025

int main(int argc, char** argv)
{
    char *buffer;
    long long int len;

    if (argc > 1)
    {
    len = strlen(argv[1]) + 1;
    if (len > MAX_BUFFER)
    {
        fprintf(stderr, "String muito longa\n.");
        exit(-1);
    }

    buffer = (char*) malloc(sizeof(char) * len--);
    memcpy(buffer, argv[1], len);
    buffer[len] =  '\0';

    printf("%d bytes copiados\n", len);
    }

    return 0;
}

Prevenindo o buffer pverflow (cookies)

Cookies como são conhecidos, servem para armazenar informações que serão utilizadas em um futuro pouco distante, seja para validação ou para lembrar algo feito anteriormente pelo usuário.

Vamos aplicar este método em nosso programa para verificarmos se o valor do cookie não foi sobreposto. Se o valor for outro, significa que um Buffer Overflow está acontecendo.

Exemplo example4.c:

#include <stdio.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>

#define MAX_BUFFER 10
#define MAX_COOKIE sizeof(int)

int main(int argc, char** argv)
{
    char buffer[MAX_BUFFER + MAX_COOKIE];
    static int cookie;
    int bkp_cookie;

    if (argc > 1)
    {
    srand(time(NULL));

    //Gera um cookie
    cookie = rand() % INT_MAX;

    //Copia o cookie para o final da string
    memcpy(&buffer[MAX_BUFFER], &cookie, MAX_COOKIE);

    //Copia a string (Tamanho 125)
    strcpy(buffer, argv[1]);

    memcpy(&bkp_cookie, &buffer[MAX_BUFFER], MAX_COOKIE);

    if (bkp_cookie != cookie)
    {
    printf("Buffer overflow!!!\n");
    printf("Cookie: %d Backup Cookie: %d\n", cookie, bkp_cookie);
    exit(-1);
    }
    else
    {
    buffer[MAX_BUFFER] = '\0';
    printf("String informada: %s\n", buffer);
    }

    }

    return 0;
}

Obs.: isso é só um exemplo! Não estou dizendo aqui que você deve utilizar isto ou que seja a melhor forma.

A melhor forma de evitar falhas de Buffer Overflow, é seguindo os exemplos da página anterior.

   

Páginas do artigo
   1. Introdução
Outros artigos deste autor

Exportando e importando confs do Putty em Windows

Como instalar as extensões Dash To Dock e Hide Top Bar no Gnome 45/46

Configurando o monitor no SuSE 10.1

Asterisk com PostgreSQL e unixodbc

expr - Definição e uso do comando

Leitura recomendada

Programação Segura

Biometria digital - Sistemas AFIS em Gnu/Linux

Brute force de senhas no Linux com loncrack

Gerencie suas contas financeiras pessoais com Terminal Finances

Conio.h para Linux

  
Comentários
[1] Comentário enviado por removido em 11/08/2014 - 21:00h

Obs.:

Este exemplo que utiliza cookie ainda pode ser explorado devido a não verificação do tamanho da string copiada.
Um explorador pode muito bem obter o valor do cookie e adiciona-lo no local exato fazendo com que o programa pense que está tudo ok.
Mas tem métodos com cookies que são eficazes o que no caso não é o desse exemplo.


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts