VulnHub Jigsaw:1 (Walkthrough)

Apresento hoje mais um excelente desafio no estilo boot2root CTF. A ideia é bem semelhante à outros da mesma categoria: enumeração, exploração, elevar privilégios e ler a flag final. Com um “tempero” um pouco mais pesado, esta máquina aborda conceitos de Buffer Overflow e Ataques Ret2Libc.

Desta vez, trago mais uma máquina do autor Zayotic, e para aqueles que já tem alguma prática em suas VMs, saiba que esta é mais uma de nível Hard to Insane (ノಠ ∩ಠ)ノ彡( \o°o)\

Apresento a VM Jigsaw:1 que está disponível no VulnHub para fins de exploração e práticas de pentest. Pertence a série de máquinas Jigsaw.

Para mais informações e download desta VM, acesse o link abaixo:

Level: Hard
VM Alvo: Jigsaw:1
VM Atacante: Kali Linux 2019.2

É sempre importante observar algumas dicas do autor (quando houver alguma), pois isto evitará perda de tempo em outras atividades.

Observando suas recomendações, ao invés de realizarmos uma busca padrão para enumeração de serviços, o autor indica ficar atento aos “pacotes ARP” oriundos provavelmente da VM alvo.

So… Let’s go guys!! ( ဖ‿ဖ)人(စ‿စ )

Identificando o dispositivo alvo na rede

Utilizando o método que preferir, busque e identifique os hosts da rede alvo (neste caso do laboratório é a mesma rede que você está conectado). Utilizei o arp-scan, porém fique a vontade para utilizar o nmap ou o netdiscover, por exemplo:

Reconhecimento / Enumeração

Normalmente, você poderia iniciar uma varredura de portas em busca de serviços e/ou alguma vulnerabilidade. Porém, o autor deixa uma dica sutil informando para prestar mais atenção aos pacotes ARP:

Assim, optei por iniciar uma captura de pacotes de redes com um sniffer. Nesta etapa, você poderá utilizar qualquer sniffer de sua escolha, como por exemplo o Wireshark. Eu optei por utilizar o tcpdump:

Porém, a única informação capturada é padrão deste protocolo ARP. Assim, deduzi que poderia ser uma dica falsa ou ao menos uma pegadinha e desta forma, decidi então “excluir da captura todo tráfego ARP”. Para isto, acrescentei o parâmetro: “and not arp”.

E bingo!! ( ˘ ³˘)♥

Enfim uma nova informação obtida de um tráfego vindo do protocolo UDP na porta 666, a mensagem:

Ao que tudo indica, podemos ter alguma senha em modo leet ou algo esperado com esta característica. Dessa forma, realizei um teste básico na porta 666 utilizando o Nmap, a fim de identificar algum serviço:

Infelizmente o Nmap não trouxe alguma informação útil. Além disso, ao que tudo indica, há um serviço de proteção na porta 666 filtrando o tráfego.

Sabemos que esta porta está enviando dados através de algum serviço (não identificado ainda). Assim, podemos testar a conexão com esta porta e avaliar se conseguimos capturar algum banner:

Observe que após testar algumas palavras, conseguimos um texto cifrado quando enviamos “j19s4w(leet mode). A mensagem parece ser em base64 (👁 ͜ʖ👁). Para facilitar, é possível enviar a mensagem junto com a conexão. Você pode mandar com “python” ou com “echo” ou qualquer outra forma de exibir mensagens via terminal e redirecionar esta saída para a conexão do Netcat.

Desta forma, já temos nossa mensagem cifrada em base64. Para confirmar, vamos realizar um decode desta mensagem. Aqui fique a vontade em copiar e depois decodar ou simplesmente aproveitar a saída do Netcat e redirecionar para o comando “base64 -d” do Linux.

Wow guys!! Bingo!! Temos uma nova dica!! |o|
Conseguimos a flag1 e a dica para a próxima etapa.

Seguindo para a próxima dica, será necessário realizar um procedimento conhecido como “Port Knocking”.

Port Knocking é uma técnica bastante interessante para incrementar a segurança do seu firewall. Consiste basicamente em criar um conjunto de duas ou mais portas tcp/udp que, quando acionadas na ordem correta, vão permitir a conexão ao firewall a partir daquele endereço IP que fez o “toc toc” nas portas e na ordem correta.

Desta maneira, após realizar este “toc toc” na sequência correta, o firewall deverá liberar o acesso à alguma outra porta que antes não era possível conectar-se. Para realizar este procedimento, você pode simplesmente se conectar nestas portas na sequência informada usando qualquer serviço de conexão que desejar: knockd, netcat, telnet, nmap, etc…

Para este guia, utilizei o próprio nmap, através de um script básico:

Embora a saída do Nmap não diga que houve sucesso, agora é possível simplesmente realizar uma nova varredura neste host que provavelmente encontraremos alguma porta aberta.

(̿▀̿ ̿Ĺ̯̿̿▀̿ ̿)̄ Agora é possível acessar um serviço web através da porta 80 deste host.

Nesta etapa, vou testar a página web com o Browser, mas você pode escolher o software de sua preferência (como cURL, Burpsuite, etc).

Como a página inicial só traz uma imagem (boneco “personagem” da série de filmes “jigsaw” ¯\_(⊙_ʖ⊙)_/¯). Portanto, é sempre bom também analisar o código-fonte desta página exibida.

Embora não tenha muita informação, já sabemos que ainda vem mais “testes” por aí! t(-.-’t)

A primeira tentativa foi buscar por informações no arquivo “/robots.txt”, mas retornou um “404 not found”. Também podemos tentar buscar por diretórios através de webcrawlers como Dirsearch, Gobuster, Dirb, etc.

Infelizmente este procedimento não retornou nenhum diretório conhecido através de dicionários comuns e como não há muita dica aqui, optei por tentar outras alternativas.

Em outras alternativas, é possível identificar através do código-fonte da página, um arquivo de imagem GIF.

Se levar em conta o “pensar fora da caixa” comum em desafios de CTF, ao se deparar com imagens e arquivos de dados, surge logo a ideia de “esteganografia”, dados ocultos em outros arquivos.
┬┴┬┴┤ ͜ʖ ͡°) ├┬┴┬┴

Desta forma, após o download desta imagem, o processo básico é logo buscar com textos claros (strings) vazadas na estrutura do arquivo. Com o comando “strings” do Linux, podemos fazer uma busca rápida no arquivo.

Após testar algumas informações que poderiam ser novos diretórios ou arquivos, chegamos a última linha da saída do comando “strings”. Ao que tudo indica, trata-se de um novo caminho e desta forma, podemos testar direto no navegador.

Agora que já descobrimos um novo ambiente, temos acesso a um formulário de login. Após alguns testes, sempre que inserimos algum usuário incorreto, o formulário apresenta uma mensagem de erro, conforme imagens abaixo.

Como já é de costume, podemos avaliar o código-fonte em busca de alguma informação que possa ser alguma dica ou alguma falha de desenvolvimento, como um comentário, link, path, etc.

Aqui temos uma função em XML que trata este formulário de login. E se você já é um praticante experiente de desafios CTF ou mantém-se atualizado sobre novos ataques, já deve ter percebido que provavelmente poderemos explorar este ambiente utilizando algum “Ataque XXE”.

Test #2: Ataque XML eXternal Entity (XXE)

Ao que tudo indica, este ambiente “pode” estar vulnerável a ataques do tipo XXE. Desta forma, podemos tentar alterar a requisição original e manipular estes dados a fim de obter informações sensíveis de dentro do servidor.

O Ataque XXE é um tipo específico de Server-Side Request Forgery (SSRF) e acontece quando uma requisição utilizando XML não é sanitizada (tratada corretamente), possibilitando assim a queda do serviço e/ou o acesso direto aos arquivos e informações do servidor, entre outros impactos. Isso acontece quando a informação recebida pelo servidor, contendo referência a uma entidade externa, é processada de forma insegura.

Saiba mais sobre este método de ataque através do artigo publicado no portal do OWASP.

Para testar o ambiente, você pode interceptar a requisição original e alterar estes dados inserindo seu payload. Para auxiliar nesta etapa, utilizei um payload padrão do “PayloadsAllTheThings” disponível no Github.

Utilizei o Burpsuite para interceptar uma tentativa de login e compreender melhor a requisição conforme imagem a seguir.

Basicamente, os dados enviados via método POST são:

Compreendendo este processo de requisição/resposta, podemos manipular os dados enviados via POST e submeter nosso payload.

Wow… excelente!! O sistema de fato é vulnerável a ataques XXE.
Com o teste, conseguimos ler o arquivos de senhas usuários do Linux.

Agora que já temos a prova de conceito, podemos então continuar explorando. Além disso, também já sabemos que há um usuário chamado “jigsaw”, com permissão de login para esta máquina.

Por se tratar de um acesso realizado através do recurso de proteção “Port Knocking” é ideal então ler as informações do arquivo de configuração deste serviço localizado em: /etc/knockd.conf.

O arquivo retornou algumas configurações para abrir e fechar portas específicas, utilizando “Port Knocking”. Além disso, também já temos a sequência para liberar também o acesso à porta 22 para SSH.

Acessando o SSH (porta 22)

Agora que já sabemos como liberar o SSH, vamos ao teste e exploração deste serviço. Realizamos este procedimento anteriormente utilizando um script básico para “bater” na sequência e portas corretas. Porém, o sistema Kali Linux já possui o comando “knock” para realizar este procedimento conforme exemplo abaixo.

Agora já podemos tentar acessar este serviço. Temos em mãos o usuário “jigsaw” mas não muita informação sobre a provável senha. Porém, se voltar um pouco antes, durante o procedimento de Network Sniffing, capturamos uma mensagem via protocolo UDP.

Você pode até tentar alguns métodos para misturar estas palavras, gerar anagramas e palavras e modo leet, mas já adianto que a senha é o próprio nome do usuário em modo leet.

Assim, com as credenciais em mãos, basta testar e validar o acesso.

Assim que acessamos a máquina, já temos um aviso bastante interessante:

A mensagem dá uma possível ideia para analisar os processos em execução nesta máquina. Também realizei esta varredura, mas não me retornou muita informação.

Desta forma, podemos navegar entre diretórios e buscar arquivos e pastas com permissão de escrita, leitura e execução, buscar por permissões de SUDO e também por executáveis com SUID e/ou GUID.

Após listar o conteúdo da pasta do usuário atual, já identificamos um arquivo TXT que contém a flag2.

| (•□•) | (❍ᴥ❍ʋ)
Maravilha pessoal!! Conseguimos a flag2!! ;)
Infelizmente, como nem tudo são flores ლ(ಠ_ಠლ) (já dizia um antigo professor), parece que este não é o final
.·´¯`(>▂<)´¯`·.

Agora que temos acesso ao shell, geralmente buscamos por arquivos executáveis SUID e/ou GUID e também por privilégios de SUDO.

Já a busca por executáveis SUID nos trouxe um binário bem interessante.

Este binário “/bin/game3” dá uma ideia de que estamos no caminho certo, pois se conferir os caminhos até o momento, este será o 3º desafio (3º == game3, pegou a dica?? kkkkkk).

Trata-se de um arquivo do tipo ELF 32bits, ou seja, um executável para Linux. Aqui poderíamos buscar por strings, testar as saídas entre outros métodos: tudo é válido. Porém, adiantando o processo aqui, após alguns testes (inserindo diversos dados como entrada), identifiquei um possível estouro de pilha, ou seja, provavelmente este binário é vulnerável a “Buffer Overflow”.

Criando eXploit para Buffer Overflow (BoF XPL)

Confesso a vocês que meu conhecimento em exploração de binários, como em BoF e engenharia reversa em ELF é bastante básico (ainda), mas estou trabalhando para evoluir esta habilidade. ¯\_(ツ)_/¯

Assim, recorri ao “bom e velho Google” em busca de alguma ajuda.

Vamos analisar com calma o returno do comando “file” para compreender melhor cada etapa a seguir.

O resultado da execução do comando mostra que temos um ELF 32-bit executável, dynamically linked (ligado com ‘includes’ da libc) e not-stripped (significando que contem todas as informações de depuração).

Você pode remover estas informações com a opção -g no gcc durante o processo de compilação do programa em C.

Como a máquina alvo não possui um depurador interno (como o GDB), optei por copiar o binário para minha máquina atacante e tentar explorar este binário por lá para criarmos nosso exploit. Aqui trata-se de BoF Ret2Libc (Return-to-libc).

O ataque return-to-libc é um ataque normalmente inicia com um BoF em que o endereço de retorno da função chamada na pilha é substituído pelo endereço de uma outra instrução, e uma parte da pilha é sobrescrita para fornecer argumentos para esta função. Isto permite que o atacante invoque uma função preexistente sem precisar injetar código malicioso no programa. Uma biblioteca compartilhada chamada “libc” provê o runtime C em sistemas baseados em UNIX (como o Linux). Embora o atacante pudesse fazer o código retornar para qualquer lugar, libc é o alvo mais comum, como ela está sempre ligada ao programa, e oferece chamadas úteis ao atacante (como uma chamada de sistema para executar um programa arbitrário que necessite somente um argumento). É por isso que o ataque é chamado return-to-libc mesmo quando o endereço de retorno pode apontar para um local completamente diferente. (Wikipedia)

O comando abaixo, copia o binário da máquina alvo para a máquina atacante.

Sabemos que após a inserção de determinadas quantidades de caracteres o executável retorna “falha de segmentação”, um estouro. Porém, se você for testar um caractere por vez até encontrar a quantidade correta, poderá perder bastante tempo.

Portanto, é mais rápido utilizar as funções “pattern_create” e “pattern_offset” do gdb-peda para identificar o padrão e qual a quantidade em que ocorreu o estouro.

Não vou entrar em detalhes sobre criação de exploits, nem tão pouco em técnicas para exploração de BoF ou uso da ferramenta gdb-peda. Desta forma, indico que você, caso precise, dê uma lida sobre o assunto. Abaixo segue um blog muito interessante, escrito por “Helvio Junior” que poderá lhe ajudar mais.

Após a execução do binário com o padrão criado com 200 caracteres (pattern_create 200), é retornado um estouro no endereço: 0x41344141. Observe a imagem abaixo e veja o padrão que preencheu a EIP.

EIP : ponto de instrução (instruction pointer) : mantém o ponto de memória do código da próxima instrução

Com a função “pattern_offset” vamos identificar em qual quantidade houve de fato o estouro. Basta informar para a função, o valor (padrão) que foi para a EIP.

Agora já sabemos o número de caracteres para substituir e preencher a EIP é 76. Este é o tamanho do nosso Buffer.

Portanto, iniciaremos nossa exploração. Para este exploit utilizei a linguagem python, pois tem permissão de execução na máquina alvo.

Para compreender o processo de criação de payload para explorar o ataque ret2libc, utilizei como guia o artigo publicado no blog SpZ.

A fim de testar, vamos desenvolver nosso primeiro payload e testar. Abaixo segue um exemplo básico de payload em python:

Salve este payload em algum “arquivo.py” e execute no gdp-peda.

Observe que conseguimos preencher a EIP com os dados que enviamos. Assim, perceba que o endereço de saída (Exit Address) foi manipulado.

Para sobrescrever a EIP e injetar nosso shell, precisaremos ainda pegar mais 3 endereços: Libc System Address, Libc Exit Address, Libc “/bin/sh” Address.

Assim, voltamos agora para nossa máquina alvo e iremos criar o payload diretamente neste host. Recomendo acessar algum diretório que o usuário atual tenha permissão de escrita, como por exemplo o “/tmp”.

No host, digite o comandos abaixo para coletar os respectivos endereços para Libc.

Agora temos os seguintes endereços:

Vamos ao nosso exploit. Crie um arquivo no diretório que você escolheu anteriormente com o editor de sua preferência (neste host há o VI e o Nano).

Abaixo segue um exemplo de código para nosso payload. Não adianta querer copiar e colocar o código que provavelmente os endereços serão diferentes em seu ambiente.

O exemplo do payload abaixo foi retirado do Blog SpZ, informado antes.

Após executar o payload, aguarde alguns segundos. Como não acrescentei nenhum texto de feedback para sua tela, o loop while fica tentando até conseguir injetar o payload.

Caso deseje ter algum retorno em tela durante a execução do payload, basta acrescentar algum “print” dentro do loop while:

Wow guys!! (╯°□°)╯︵ ┻━┻
Mais um sistema Owned!! ;)

Considerações finais

Escrever este artigo não foi fácil, pois ainda estou desenvolvendo minhas habilidades em PWN! huahuahua

Já peço que em sua leitura, se identificar algum erro, por favor me informe nos comentários que estarei corrigindo o mais breve possível.

Espero que este guia tenha contribuído para o seu aprendizado e conhecimentos e se possível compartilhe com a sua rede de amigos e parceiros.

Muito obrigado pela paciência em ler este passo a passo até o final!!
E ao autor Zayotic, mais uma vez, excelente desafio. Obrigado!!

Não esqueça: pense fora da caixa!! (•̀ᴗ•́)و

Cybersecurity & IT Consultant, Pentester and Writer. Loves: Computer Networking, Programming and Hacking!!

Cybersecurity & IT Consultant, Pentester and Writer. Loves: Computer Networking, Programming and Hacking!!