Continuando nossos estudos com sockets, vamos a um exemplo diferente de cliente e servidor. Vou mostrar um Fuzzer. Para quem não sabe fuzzing está sendo usado para ajudar no descobrimento de falha em geral, ele faz testes em determinado programa, seja por entradas stdin, forms http, argv, packets ou strings SQL etc.
No nosso caso ele faz teste em programas remotos.
/*
by m0nad
versão do fuzzer do Cooler_ só que melhorado
greetz
Thanks _mlk_ , Cooler_,IAK,Fox,edenc,D3lf0,zepplin and f0kerdebug.
__ ____
/ /. .\
|--| 0 0 |
| | . . |
\ \____/
_----\___/---- _
/___\ /___\
| | | |0| | | |
| | | | |0| | | rick taylor from
| | |0|0|0| | | The Game SplatterHouse 2 at 1992
| | | / art and code by Cooler_
=================================
*/
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "netdb.h"
#include "unistd.h"
#include "arpa/inet.h"
void
erro (char *msg)
{
perror(msg);
exit (1);
}
void *ec_malloc(unsigned int tam)
{
void *ptr;
ptr = malloc(tam);
if ( ptr == NULL )
erro("erro malloc");
return ptr;
}
void
inicia_alvo (struct sockaddr_in *nome, unsigned int port, char *host)
{
// memset((char *) nome,0, sizeof(*nome)); // zera a estrutura
nome->sin_family = AF_INET;
nome->sin_port = htons (port);
nome->sin_addr.s_addr = inet_addr(host);
}
int
inicia_socket (char *host, unsigned int porta)
{
int sockfd, conex;
struct sockaddr_in alvo;
sockfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
if ( sockfd < 0 )
erro("[-] SOCKET");
inicia_alvo (&alvo, porta, host);
conex = connect (sockfd, (struct sockaddr *)&alvo, sizeof alvo);
if ( conex < 0 )
erro("[-] CONNECT");
return sockfd;
}
int
main(int argc, char **argv)
{
int sockfd, porta, bit, cont, qtd;
char *ip, *buffer;
if (argc < 5) {
printf ("./fuzz_cooler <qtd chars(=> 4)> <incremento> <porta> <ip>\n./fuzz_cooler 2000 4 6666 192.168.0.172\n");
exit(1);
}
bit = atoi (argv[1]);
qtd = atoi (argv[2]);
porta = atoi (argv[3]);
ip = argv[4];
if((porta > 65535)||(porta <= 0)||(bit < 4) || qtd <=0) {
fprintf(stderr, "ERRO veja se digitou dados validos\n");
return 0;
}
buffer = (char *)ec_malloc (bit * sizeof (char));
for (cont = 4; cont < bit; cont +=qtd) {
memset(buffer, 'A', cont);
buffer[cont] = 0;
//printf ("buffer %s\n", buffer);
sockfd = inicia_socket (ip, porta);
send(sockfd, buffer, strlen (buffer), 0);
printf ("[%d] letras enviadas para %s porta %d\n", cont, ip, porta);
close(sockfd);
}
return 0;
}
Não tem nada de mais no fuzzer, tudo que vimos neste paper, funções e tal. Agora vamos passar um exemplo simples de uso, você tem um servidor vulnerável sabendo que ele dá crash com mais de mil caracteres de envio, então temos o ambiente:
./server 4000 <---- iniciamos server vulnerável em outro term, ele fica na escuta "listening"
No terminal do teste faça:
./fuzz
quantos caracters ?
2000
qual numero da porta a testar ?
4000
digite o ip
127.0.0.1
Depois de uns minutos testando o serviço funcionando na porta 4000...
+++ no terminal do servidor
outras tentativas blá blá
conexão a partir de 127.0.0.1...
Descritores dos sockets: Servidor: 65, Conexão: 4
Mensagem recebida: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...até 1026
Não foi possível aceitar conexão.
deu crash
+++ no terminal do teste
...blá blá blá
[1017] letras enviadas para 127.0.0.1 porta 4000
[1018] letras enviadas para 127.0.0.1 porta 4000
[1019] letras enviadas para 127.0.0.1 porta 4000
[1020] letras enviadas para 127.0.0.1 porta 4000
[1021] letras enviadas para 127.0.0.1 porta 4000
[1022] letras enviadas para 127.0.0.1 porta 4000
[1023] letras enviadas para 127.0.0.1 porta 4000
[1024] letras enviadas para 127.0.0.1 porta 4000
[1025] letras enviadas para 127.0.0.1 porta 4000
Porta [4000] ip: 127.0.0.1 conexão não ativa ao envio de 1025 strings
BINGO! No envio de 1025 caracteres "A" o buffer estoura e o servidor cai.
Bom, agora explorar é com você, o tutorial aqui é apenas de sockets. ;)
Obs.: O código do servidor vulnerável está no fim deste paper.