O livro “Hacking: The Art of Exploit. 2ª ed. ”

imagem Todo programador é essencialmente um hacker. Afinal, inicialmente o hacking foi chamado de busca de uma solução hábil e não óbvia. Compreender a programação ajuda a encontrar vulnerabilidades, e as habilidades de detecção de vulnerabilidades ajudam a criar programas; muitos hackers fazem as duas coisas ao mesmo tempo. Existem movimentos não padronizados interessantes, tanto nas técnicas para escrever programas elegantes quanto nas técnicas para encontrar pontos fracos.

Por onde começar? Para sobrescrever a memória usando estouros de buffer, acessar um servidor remoto e interceptar conexões, é necessário programar em C e assembler, usar registros de código e processador de shell, familiarizar-se com interações e criptografia de rede e muito mais.

Não importa o quanto desejemos acreditar em milagres, o software e as redes de computadores das quais nossas vidas diárias dependem têm vulnerabilidades.

Um mundo sem hackers é um mundo sem curiosidade e soluções inovadoras. (John Erickson)

Contramedidas


Existe um sapo desses - um terrível listolaz (Phyllobates terribilis). As glândulas da pele dela contêm o veneno mais forte. Basta tocar para obter um envenenamento fatal. Um remédio tão poderoso é explicado pelo fato de que esses sapos se alimentam de certos tipos de cobras que desenvolveram imunidade ao veneno. Gradualmente, o veneno de sapos tornou-se cada vez mais forte. Como resultado dessa evolução conjunta, os terríveis escaladores de folhas não têm mais nenhum inimigo natural. Algo semelhante está acontecendo com os hackers. As técnicas que eles inventaram são conhecidas há muito tempo, portanto o surgimento de contramedidas é bastante natural. Em resposta, os hackers estão procurando maneiras de burlar e destruir os mecanismos de defesa, o que leva à criação de novas técnicas defensivas.

Esse ciclo de busca de medidas e contramedidas é muito útil. Vírus e worms se tornam a causa de numerosos problemas e trazem grandes prejuízos aos negócios, mas ao mesmo tempo forçam os desenvolvedores a tomar medidas retaliatórias para resolver os problemas que surgiram. Os worms se replicam usando vulnerabilidades de software de baixa qualidade. Os erros costumam passar despercebidos ao longo dos anos e worms relativamente inofensivos, como CodeRed ou Sasser, forçam os desenvolvedores a corrigi-los. Esse processo pode ser comparado à varicela, que é melhor para adoecer na infância e não na idade adulta, quando pode levar a conseqüências desastrosas. Se os worms da Internet não tivessem atraído atenção universal para as falhas de segurança, elas permaneceriam abertas para ataques com propósitos muito mais maliciosos do que a simples auto-reprodução. Dessa maneira, worms e vírus contribuem para a segurança a longo prazo. Mas existem métodos mais ativos: técnicas que tentam anular os resultados de um ataque ou torná-lo completamente impossível. O conceito de "contramedidas" é bastante vago. Essas palavras podem significar meios técnicos de segurança, um conjunto de regras, um programa ou apenas um administrador de sistema atento. As contramedidas são condicionalmente divididas em dois grupos: tentando detectar um ataque e tentando proteger a vulnerabilidade.

Ferramenta de detecção de ataque 0x610


As contramedidas do primeiro grupo se resumem a tentativas de perceber a invasão no tempo e de alguma forma reagir a ela. O processo de reconhecimento pode ser implementado de qualquer maneira - desde o administrador lendo os logs do sistema até os programas que analisam o tráfego da rede. Às vezes, a reação a uma invasão se resume à desconexão automática da conexão ou ao fechamento do processo, e às vezes o administrador precisa estudar cuidadosamente todo o conteúdo do console.

Os métodos conhecidos de exploração de vulnerabilidades não são tão perigosos para o administrador do sistema quanto aqueles que ele ainda não conhece. Quanto mais cedo uma invasão for detectada, mais cedo o trabalho começará e mais provável será localizada. A intrusão que foi ignorada por meses é um sério motivo de preocupação.

Para reconhecer a invasão, você precisa prever o que o invasor fará. Isso fornece informações sobre o que exatamente precisa ser monitorado. Os detectores procuram padrões familiares de ataque em logs, pacotes de rede e até na memória do programa. Quando uma invasão é detectada, você pode privar o hacker de acesso à máquina, restaurar o sistema de arquivos danificado usando um backup e identificar e corrigir a falha de segurança. Com os recursos de backup e recuperação disponíveis hoje, as contramedidas que se reduzem à detecção de ataques são bastante eficazes.

Para um invasor, detecção significa combater tudo o que ele faz. Obviamente, nem sempre é possível perceber imediatamente um ataque; portanto, existem vários cenários de "captura e execução" nos quais o fato da detecção não é importante, mas mesmo nesses casos é melhor não deixar rastros. O sigilo é uma das qualidades mais valiosas dos hackers. Obter acesso ao shell de comando com direitos de administrador, explorando vulnerabilidades, torna possível fazer qualquer coisa no sistema e, se você conseguir evitar a detecção, ninguém saberá sobre sua presença. É a combinação de permissividade com invisibilidade que torna os hackers perigosos. Eles podem facilmente interceptar senhas e dados na rede, adicionar marcadores aos programas para acesso não autorizado subseqüente e atacar outros nós da rede. Para permanecer na sombra, o hacker deve entender quais métodos de reconhecimento são usados ​​em um caso específico. Se você souber exatamente o que eles estão procurando, poderá evitar certos padrões de exploração da vulnerabilidade ou disfarçar suas ações como válidas. O fator determinante para o ciclo de evolução conjunta de ferramentas e técnicas de detecção que permitem passar despercebido são as idéias que ainda não ocorreram para o outro lado.

0x620 Daemons do sistema


No entanto, é melhor discutir as contramedidas contra hackers e suas soluções alternativas usando um exemplo prático. Agora, consideraremos um ataque a um programa de servidor que aceite conexões de entrada. Em sistemas operacionais do tipo UNIX, os daemons do sistema são adequados para esses critérios. Um daemon é um programa em execução em segundo plano e de certa maneira separado do terminal de controle. O termo foi cunhado na década de 1960 por hackers do Massachusetts Institute of Technology. O protótipo era uma criatura mítica que separava moléculas de um experimento mental do físico James Maxwell. O demônio Maxwell possuía uma capacidade sobrenatural de executar facilmente tarefas complexas, violando a segunda lei da termodinâmica. Da mesma forma, os daemons do sistema Linux executam incansavelmente tarefas como conceder acesso ao SSH e manter logs do sistema. Os nomes de demônios geralmente terminam com d, que enfatiza sua natureza: por exemplo, sshd ou syslogd.

Uma pequena edição transformará tinyweb.c da seção 0x427 em uma semelhança realista com um daemon do sistema. A nova versão do código contém a função daemon (), que gera um novo processo em segundo plano. É usado por muitos processos de daemon do sistema Linux. Aqui está a página dedicada a ela no diretório:

DAEMON (3) Referência do Programador Linux DAEMON (3)

NAME
daemon - executado em segundo plano
Sintaxe

#include <unistd.h> int daemon(int nochdir, int noclose); 

DESCRIÇÃO

A função daemon () desconecta o programa do terminal de controle e inicia
ela em segundo plano como um daemon do sistema.
Com um argumento diferente de zero, nochdir, a função daemon () altera o diretório de trabalho atual.
na raiz ("/").
Com nullose, a função daemon () redireciona threads
entrada padrão, saída padrão e erros em / dev / null.
VALOR DE DEVOLUÇÃO

(Essa função gera uma cópia do processo e se fork () for bem-sucedido
o pai executa _exit (0) para que outros erros sejam visíveis apenas
processo filho.) Se for bem-sucedido, retorna zero. Em caso de erro, a função
daemon () retorna -1 e atribui o número do erro à variável global errno
da biblioteca de funções fork (2) e setsid (2).

Os daemons do sistema não possuem um terminal de controle; portanto, o código para o novo daemon tinywebd será exibido no diário de bordo. Demônios são geralmente controlados por sinais. A nova versão do tinyweb deve poder receber um sinal de conclusão para sair corretamente.

Visão geral do sinal 0x621


Os sinais fornecem comunicação entre processos no UNIX. Depois que um sinal é recebido por um processo, o sistema operacional interrompe sua execução para chamar o manipulador de sinal. Cada sinal tem seu próprio número e seu próprio manipulador. Por exemplo, quando você pressiona a combinação de teclas Ctrl + C, um sinal de interrupção é enviado, cujo manipulador finaliza o programa aberto no terminal de controle, mesmo que ele tenha entrado em um loop infinito.

Você pode criar seus próprios manipuladores de sinal e registrá-los usando a função signal (). Vejamos um código no qual vários manipuladores são registrados para alguns sinais, e na parte principal há um loop infinito.

 signal_example.c #include <stdio.h> #include <stdlib.h> #include <signal.h> /*    signal.h * #define SIGHUP 1  * #define SIGINT 2  (Ctrl+C) * #define SIGQUIT 3  (Ctrl+\) * #define SIGILL 4   * #define SIGTRAP 5   * #define SIGABRT 6  * #define SIGBUS 7   * #define SIGFPE 8     * #define SIGKILL 9   * #define SIGUSR1 10   1 * #define SIGSEGV 11   * #define SIGUSR2 12   2 * #define SIGPIPE 13    ,    * #define SIGALRM 14   ,  alarm() * #define SIGTERM 15  (  kill) * #define SIGCHLD 17    * #define SIGCONT 18 ,    * #define SIGSTOP 19  (  ) * #define SIGTSTP 20   [] (Ctrl+Z) * #define SIGTTIN 21       * #define SIGTTOU 22       */ /*   */ void signal_handler(int signal) { printf("  %d\t", signal); if (signal == SIGTSTP) printf("SIGTSTP (Ctrl-Z)"); else if (signal == SIGQUIT) printf("SIGQUIT (Ctrl-\\)"); else if (signal == SIGUSR1) printf("SIGUSR1"); else if (signal == SIGUSR2) printf("SIGUSR2"); printf("\n"); } void sigint_handler(int x) { printf(" Ctrl-C (SIGINT)   \nExiting.\n"); exit(0); } int main() { /* Registering signal handlers */ signal(SIGQUIT, signal_handler); //  signal_handler() signal(SIGTSTP, signal_handler); //    signal(SIGUSR1, signal_handler); signal(SIGUSR2, signal_handler); signal(SIGINT, sigint_handler); //  sigint_handler()  SIGINT while(1) {} //   } 

Quando um programa compilado é executado, os manipuladores de sinais são registrados e, em seguida, o programa entra em um loop sem fim. Mas, apesar disso, os sinais recebidos interromperão sua execução e passarão a manipuladores registrados. A seguir, são apresentados exemplos da aplicação de sinais que podem ser ativados a partir do terminal de controle. Depois que a função signal_handler () é concluída, o controle retorna ao loop interrompido, enquanto a função sigint_handler () finaliza o programa.

 reader@hacking:~/booksrc $ gcc -o signal_example signal_example.c reader@hacking:~/booksrc $ ./signal_example   20 SIGTSTP (Ctrl-Z)   3 SIGQUIT (Ctrl-\)  Ctrl-C (SIGINT)    Exiting. reader@hacking:~/booksrc $ 

O comando kill permite enviar todo um conjunto de sinais para um processo. Por padrão, ele envia um sinal de conclusão (SIGTERM). A adição da opção -l exibe uma lista de todos os sinais possíveis. Vamos ver como o programa signal_example em execução em outro terminal envia os sinais SIGUSR1 e SIGUSR2.

 reader@hacking:~/booksrc $ kill -l 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL 5) SIGTRAP      6) SIGABRT      7) SIGBUS       8) SIGFPE 9) SIGKILL     10) SIGUSR1     11) SIGSEGV     12) SIGUSR2 13) SIGPIPE     14) SIGALRM     15) SIGTERM     16) SIGSTKFLT 17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP 21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU 25) SIGXFSZ     26) SIGVTALRM   27) SIGPROF     28) SIGWINCH 29) SIGIO       30) SIGPWR      31) SIGSYS      34) SIGRTMIN 35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3  38) SIGRTMIN+4 39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8 43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7  58) SIGRTMAX-6 59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2 63) SIGRTMAX-1  64) SIGRTMAX reader@hacking:~/booksrc $ ps a | grep signal_example 24491 pts/3    R+     0:17 ./signal_example 24512 pts/1    S+     0:00 grep signal_example reader@hacking:~/booksrc $ kill -10 24491 reader@hacking:~/booksrc $ kill -12 24491 reader@hacking:~/booksrc $ kill -9 24491 reader@hacking:~/booksrc $ 

No final, o comando kill -9 envia um sinal SIGKILL. O manipulador de sinal não pode ser alterado, portanto, o comando kill -9 é sempre usado para matar processos. O programa signal_example lançado em outro terminal mostra que os sinais foram interceptados e o processo foi destruído.

 reader@hacking:~/booksrc $ ./signal_example   10       SIGUSR1   12       SIGUSR2 Killed reader@hacking:~/booksrc $ 

Os sinais em si são muito simples, mas a interação entre processos pode rapidamente se transformar em uma complexa rede de dependências. Felizmente, em nosso daemon tinyweb, os sinais são usados ​​apenas para o desligamento correto e tudo é implementado de maneira muito simples.

0x622 Tinyweb Daemon


A nova versão do tinywebd é um daemon de sistema lançado em segundo plano sem um terminal de controle. Os dados de saída são gravados no diário de bordo com registro de data e hora e o próprio programa aguarda o sinal do SIGTERM para concluir o trabalho corretamente.

As alterações feitas no original não são muito significativas, mas permitem um estudo mais realista do processo de exploração da vulnerabilidade. Novos fragmentos de código estão em negrito.

 tinywebd.c #include <sys/stat.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <time.h> #include <signal.h> #include "hacking.h" #include "hacking-network.h" #define PORT 80 // ,     #define WEBROOT "./webroot" //   - #define LOGFILE "/var/log/tinywebd.log" //    int logfd, sockfd; //       void handle_connection(int, struct sockaddr_in *, int); int get_file_size(int); //         //  void timestamp(int); //        //       void handle_shutdown(int signal) { timestamp(logfd); write(logfd, " .\n", 16); close(logfd); close(sockfd); exit(0); } int main(void) { int new_sockfd, yes=1; struct sockaddr_in host_addr, client_addr; //    socklen_t sin_size; logfd = open(LOGFILE, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR); if(logfd == -1) fatal("  ");  if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)        fatal(" "); if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) fatal("   SO_REUSEADDR"); printf("  tiny web.\n"); if(daemon(1, 0) == -1) //    fatal("   "); signal(SIGTERM, handle_shutdown);   //    handle_shutdown signal(SIGINT, handle_shutdown);   //    handle_shutdown timestamp(logfd); write(logfd, ".\n", 15); host_addr.sin_family = AF_INET;       //    host_addr.sin_port = htons(PORT);     //  ,    host_addr.sin_addr.s_addr = INADDR_ANY; //    IP memset(&(host_addr.sin_zero), '\0', 8); //    if (bind(sockfd, (struct sockaddr *)&host_addr, sizeof(struct sockaddr)) == -1) fatal("  "); if (listen(sockfd, 20) == -1) fatal("   "); while(1) { //   accept sin_size = sizeof(struct sockaddr_in); new_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size); if(new_sockfd == -1) fatal(" "); handle_connection(new_sockfd, &client_addr, logfd); } return 0; } /*         *         FD. *    -,    *   .     . */ void handle_connection(int sockfd, struct sockaddr_in *client_addr_ptr, int logfd) { unsigned char *ptr, request[500], resource[500], log_buffer[500]; int fd, length; length = recv_line(sockfd, request); sprintf(log_buffer, " %s:%d \"%s\"\t", inet_ntoa(client_addr_ptr->sin_addr), ntohs(client_addr_ptr->sin_port), request); ptr = strstr(request, " HTTP/"); //    if(ptr == NULL) { //    HTTP  strcat(log_buffer, "  HTTP!\n"); } else { *ptr = 0; //      URL ptr = NULL; //  ptr  NULL (           //  ) if(strncmp(request, "GET ", 4) == 0) //  GET ptr = request+4; // ptr -  URL if(strncmp(request, "HEAD ", 5) == 0) //  HEAD ptr = request+5; // ptr -  URL if(ptr == NULL) { //     strcat(log_buffer, "  !\n"); } else { //    ptr,     if (ptr[strlen(ptr) - 1] == '/')   //  ,                                        //  '/', strcat(ptr, "index.html");   //    'index.html' strcpy(resource, WEBROOT);   //  resource                                            //  strcat(resource, ptr);   //      fd = open(resource, O_RDONLY, 0);  //    if(fd == -1) { //     strcat(log_buffer, " 404 Not Found\n");           send_string(sockfd, "HTTP/1.0 404 NOT FOUND\r\n");                send_string(sockfd, "Server: Tiny webserver\r\n\r\n");                send_string(sockfd, "<html><head><title>404 Not Found</title>                                     </head>");            send_string(sockfd, "<body><h1>URL not found</h1></body></html>                                     \r\n"); } else {       //      strcat(log_buffer, " 200 OK\n");             send_string(sockfd, "HTTP/1.0 200 OK\r\n");           send_string(sockfd, "Server: Tiny webserver\r\n\r\n");            if(ptr == request + 4) { //    GET     if( (length = get_file_size(fd)) == -1)          fatal("     ");     if( (ptr = (unsigned char *) malloc(length)) == NULL)          fatal("      ");          read(fd, ptr, length);  //              send(sockfd, ptr, length, 0);  //              free(ptr);  //      } close(fd); //   } //   if  /        } //   if     } //   if    HTTP timestamp(logfd); length = strlen(log_buffer); write(logfd, log_buffer, length); //    shutdown(sockfd, SHUT_RDWR); //    } /*         *    .    -1. */ int get_file_size(int fd) { struct stat stat_struct; if(fstat(fd, &stat_struct) == -1) return -1; return (int) stat_struct.st_size; } /*          *   . */ void timestamp(fd) { time_t now; struct tm *time_struct; int length; char time_buffer[40]; time(&now); //       time_struct = localtime((const time_t *)&now); //    tm length = strftime(time_buffer, 40, "%m/%d/%Y %H:%M:%S> ", time_struct); write(fd, time_buffer, length); //       } 

Este programa cria um processo duplicado que é executado em segundo plano, grava no arquivo de log junto com os carimbos de data e hora e termina corretamente após receber o sinal correspondente. O descritor do arquivo de log e o soquete que aceitam a conexão são declarados como variáveis ​​globais, para que a função handle_shutdown () possa concluir seu trabalho corretamente. É definido como um manipulador de retorno de chamada para sinais de conclusão e interrupção, o que garante que o programa seja finalizado pelo comando kill.

Aqui está o resultado da compilação, execução e conclusão do programa. Preste atenção nos registros de data e hora no log e na mensagem de conclusão exibida após o programa receber o sinal correspondente e chamar a função handle_shutdown ().

 reader@hacking:~/booksrc $ gcc -o tinywebd tinywebd.c reader@hacking:~/booksrc $ sudo chown root ./tinywebd reader@hacking:~/booksrc $ sudo chmod u+s ./tinywebd reader@hacking:~/booksrc $ ./tinywebd   tiny web. reader@hacking:~/booksrc $ ./webserver_id 127.0.0.1 The web server for 127.0.0.1 is Tiny webserver reader@hacking:~/booksrc $ ps ax | grep tinywebd 25058 ? Ss 0:00 ./tinywebd 25075 pts/3 R+ 0:00 grep tinywebd reader@hacking:~/booksrc $ kill 25058 reader@hacking:~/booksrc $ ps ax | grep tinywebd 25121 pts/3 R+ 0:00 grep tinywebd reader@hacking:~/booksrc $ cat /var/log/tinywebd.log cat: /var/log/tinywebd.log: Permission denied reader@hacking:~/booksrc $ sudo cat /var/log/tinywebd.log 07/22/2007 17:55:45> . 07/22/2007 17:57:00>  127.0.0.1:38127 "HEAD / HTTP/1.0" 200 OK 07/22/2007 17:57:21>  . reader@hacking:~/booksrc $ 

O novo programa tinywebd processa o conteúdo HTTP, como o tinyweb original, mas se comporta como um daemon do sistema porque não possui um terminal de controle e a saída é para um arquivo de log. Ambos os programas são vulneráveis ​​ao mesmo estouro de buffer - mas este é apenas o começo dessa vulnerabilidade. Agora que escolhemos o tinywebd como alvo do ataque, mostrarei como evitar a detecção depois de entrar em outra máquina.

»Mais informações sobre o livro podem ser encontradas no site do editor
» Conteúdo
» Trecho

Desconto de 20% no cupom para Habrozhitel - Hacking

Source: https://habr.com/ru/post/pt413989/


All Articles