Introdução
Este artigo visa demonstrar o quão poderosa e flexível é a
Engine de script do Nmap. O exemplo utilizado neste artigo é inteiramente
didático, apesar de explorar uma falha publicamente conhecida. Nem a Conviso®
nem o autor se responsabilizam pelo mau uso do material aqui apresentado.
O principal objetivo desta engine é automatizar uma série de
tarefas de rede, através
do uso de uma linguagem de domínio especifico, que facilita a elaboração de
scripts que realizam atividades relacionadas a teste de segurança em redes.
A base do NSE ( Nmap Scripting Engine )[1] é um
interpretador LUA embutido na ferramenta. LUA[2] é uma linguagem interpretada, multiparadigma, fortemente tipada e que tem como foco legibilidade, foi projetada para expandir aplicações em geral. LUA foi desenvolvida por um time de desenvolvedores da PUC-RIO, a principio apenas para um projeto específico e devido a sua eficiência passou a ser usada em diversos ramos da programação. O Adobe Photoshop
Lightroom, o jogo Angry Birds, o nmap entre outros, já usam LUA como uma
extensão dos seus aplicativos[3].
Tanto o manual do NSE[9] quanto o livro Nmap Exploration and Security auditing Cookbook[10] são ótimas referências para desenvolver os scripts. O próprio NMAP possui um script protótipo[12] que pode ser usado como exemplo para desenvolvimento dos scripts.
Tanto o manual do NSE[9] quanto o livro Nmap Exploration and Security auditing Cookbook[10] são ótimas referências para desenvolver os scripts. O próprio NMAP possui um script protótipo[12] que pode ser usado como exemplo para desenvolvimento dos scripts.
ShellCode
Para demonstrar a flexibilidade do NSE sem criar um manual de
how-to, foi utilizado o artigo[4] do pesquisador Maycon Vitali onde fez uma
excelente análise da falha publicada no CVE-2012-5905[5]. No experimento descrito no artigo, Maycon demonstra a execução de código
remoto em uma falha que descrevia apenas a possibilidade de negação de serviço.
Na análise, Maycon executou um código remoto como demonstração e
provou que muitas vezes as falhas em softwares publicadas não representam o
real problema existente na aplicação. Neste artigo você verá este real
problema, pois o código executado remoto é um bind shell.
Adaptação do exploit
O exploit original[6] foi escrito em python e explora o serviço KnFTPD[7] no WinXP SP3 – English, e em minha
estrutura utilizei WinXP SP3 – pt-BR, para
isso foi necessário adaptar o exploit. Foi necessário apenas alterar o endereço que contém a instrução JMP ESP do WinXP pt-BR.
O Ollydbg[8] foi utilizado para localizar o endereço de alguma instrução "JMP ESP" em alguma biblioteca que já estivesse carregada em memória. Achamos o código procurado e foi encontrado dentro da kernel32.dll no endereço 0x7C86467B".
![]() |
| Ollydbg - JMP ESP |
No exploit foi alterado o endereço utilizado no método struct.pack, que codifica o endereço de
hexadecimal para binário, ordenado no padrão (little-endian),
que armazena o dado do último byte para o primeiro.
![]() |
Endereço JMP ESP alterado no exploit
|
Assim o exploit original, que abre a calc.exe passa a
funcionar na minha estrutura.
O próximo passo foi sair da prova de conceito e provar o quão
perigosa é este tipo de falha, ganhando a shell da máquina.
Foi utilizado o shellcode bindshell [9] que possui 214 bytes e coube nos 284 bytes que tínhamos disponível de acordo com a vulnerabilidade explorada. A Imagem abaixo mostra o shellcode mencionado.
![]() |
| Shellcode |
Podemos notar de acordo com a imagem abaixo que a vulnerabilidade foi explorada abrindo a
porta 28876.
![]() |
| Porta 28876 aberta no host alvo, exploit executado com sucesso |
Ao estabelecermos conexão com o host na porta 28876, que foi
aberta pelo exploit no host alvo, bingo!
![]() |
| Shell do host alvo |
Automatizando com NSE
A ideia é mostrar o quanto a Engine de
Script do Nmap é flexível e eficaz para os mesmos propósitos descritos na sessão anterior, para isso foi criado um script NSE, que ao
encontrar um KnFTPD em execução ele executa os seguintes passos: (I) monta e envia o payload, (II) executa o Egg-hunter[19], (III) checa se o exploit foi executado com sucesso e se a máquina foi realmente explorada,
mostrando o IP e Porta que foi aberta caso a máquina tenha sido explorada. A
porta fica em listen enquanto o serviço estiver aberto apenas aguardando a
conexão, ao se conectar bingo! está com a shell da máquina exatamente como foi
mostrado com o exploit em pyhton, só que automatizado pelo Nmap.
Script
NSE
Segue abaixo o cabeçalho do script, que contém a descrição e a referência, logo depois as tags @usage e @output que descreve como devemos utilizar este script e o exemplo da saída do script. Também o autor a licença e a categoria, conforme pede a documentação do NSE. É importante definir corretamente em qual categoria seu script se enquadra, pois faz parte da usabilidade do nmap, ao executar um scan com script é possível escolher rodar todos os scripts de uma determinada categoria. As categorias e suas descrições encontram-se na referência [13].
Segue abaixo o cabeçalho do script, que contém a descrição e a referência, logo depois as tags @usage e @output que descreve como devemos utilizar este script e o exemplo da saída do script. Também o autor a licença e a categoria, conforme pede a documentação do NSE. É importante definir corretamente em qual categoria seu script se enquadra, pois faz parte da usabilidade do nmap, ao executar um scan com script é possível escolher rodar todos os scripts de uma determinada categoria. As categorias e suas descrições encontram-se na referência [13].
![]() |
| Inicio do script knftpd-exploit.nse |
LUA, como a maioria das linguagens, permite a criação de
bibliotecas com um grupo de funções comuns. Para este script foi utilizado as
bibliotecas abaixo. As bibliotecas existentes podem ser consultadas a partir da
referência [14].
![]() |
| Bibliotecas |
Para um script NSE ser executado é necessário definirmos uma regra e a condição dessa regra retorne verdadeiro. A regra é uma função LUA que possui condições que retornam verdadeiro ou falso e pode ser definida como: prerule, hostrule, portrule e postrule.
Neste script foi utilizado a regra
portrule, que tem como condição o IP,
porta e/ou o estado da porta como open,
filtered ou unfiltered. O script
é executado quando a condição definida na regra for verdadeira. Para funções mais comuns como um serviço em execução ou uma porta aberta, geralmente utilizamos a
biblioteca shortport[16] como foi usada neste artigo. Mais detalhes
sobre as rules, você encontra na
referência[15].
![]() |
| Rule Portrule declarada |
Em seguida foi
definido a função action, que é o coração
do NSE pois contém todas as instruções que serão executadas, a action só é
executada quando o critério definido na rule
for verdadeiro, no nosso caso usamos a rule portrule, e o nosso critério é encontrar um serviço FTP rodando no
host alvo.
![]() |
| Função Action declarada |
Foi definido que a ação do script tem como
parâmetro, o host e a porta. A seguir veremos o desenvolvimento da ação do
script.
A variável shellcode foi declarada em hexadecimal, isto é necessário para montagem do payload.
![]() |
| Shellcode |
Declarando a variável payload, esta parte
do script foi a mais importante, destaco duas bibliotecas, a stdnse[17] com a função tohex, está função codifica uma string ou um número em hexadecimal e a biblioteca bin[18] com a função pack, que codifica o dado para binário,
no nosso caso o dado está em hexadacimal e será codificado para binário. Ambas são cruciais para o exploit funcionar.
Detalhes do exploit está na pesquisa[4],
para não prolongar muito o artigo não vou entrar na questão da construção do
exploit, vou explicar as funções que foram utilizadas para escrever o script em
LUA.
O formato utilizado segue o mesmo padrão do
que foi utilizado no exploit do Maycon[6], [nops]
+ [shellcode] + [return address] + [padding] + [tag Egg-hunter
(w00tw00t)]. Apenas tive que fazer algumas conversões para hexadecimal e binário, utilizando as bibliotecas stdnse e bin.
![]() |
| Montagem do Payload |
E para finalizar o payload, foi declarado o
endereço de retorno e o Egg-hunter.
![]() |
| Endereço de retorno e o Egg Hunter |
Foi criado um socket tcp, conectando no
host e porta que foi escaneado e verificamos se o serviço ftp é o KnFTPD, se
não for o script não é executado, se for o script continua e envia o exploit para
a máquina alvo.
![]() |
| Abrindo o socket e enviando o exploit |
Após a execução do exploit, foi verificado se a
máquina foi realmente explorada, conectando no host alvo na porta 28876, o
script tenta durante 10 segundos se conectar ao host, se não conectar, não foi
aberto o socket e o host não foi explorado.
![]() |
| Validando se o host foi explorado |
Sendo assim o usuário receberá uma mensagem
dizendo, “Command shell hasn't been
opened!”
![]() |
| Mensagem no script para o host não explorado |
![]() |
| Saída do payload enviado e host não explorado |
E finalmente, se o socket na porta 28876
estiver aberto o usuário receberá a mensagem
“Command shell has been opened. (<host>:28876).
![]() |
| No script saída de host explorado |
![]() |
| Saída do payload enviado e host explorado |
Conforme o exemplo, basta se conectar no IP
192.168.208.138 na porta 28876 para ganhar a shell da máquina.
![]() |
| Shell do host |
O script completo pode ser baixado na
referência[18].
Conclusão
Lua é uma linguagem simples de programar,
leve e muito flexível, junto com o Nmap as possibilidades de automação são
infinitas. O Nmap está na versão 6.25 e possui 433 scripts, caso precise de
algum script customizado para alguma demanda específica, como vocês viram, é simples criar scripts que atendam
necessidades pontuais.
Gostaria de agradecer ao Maycon Vitali pelo
apoio no shellcode e ao Ulisses Castro pela ajuda durante a pesquisa e
desenvolvimento deste artigo.



















Nenhum comentário:
Postar um comentário