* Travaillez-vous dans une **entreprise de cybersécurité** ? Voulez-vous voir votre **entreprise annoncée dans HackTricks** ? Ou voulez-vous avoir accès à la **dernière version de PEASS ou télécharger HackTricks en PDF** ? Consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop) !
* Découvrez [**The PEASS Family**](https://opensea.io/collection/the-peass-family), notre collection exclusive de [**NFTs**](https://opensea.io/collection/the-peass-family)
* Obtenez le [**swag officiel PEASS & HackTricks**](https://peass.creator-spring.com)
* **Rejoignez le** [**💬**](https://emojipedia.org/speech-balloon/) [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe Telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
* **Partagez vos astuces de piratage en soumettant des PR au** [**repo hacktricks**](https://github.com/carlospolop/hacktricks) **et au** [**repo hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
J'ai découvert que l'utilisation de `--break-on 'java.lang.String.indexOf'` rend l'exploit plus **stable**. Et si vous avez la possibilité de télécharger une porte dérobée sur l'hôte et de l'exécuter au lieu d'exécuter une commande, l'exploit sera encore plus stable.
Normalement, ce débogueur s'exécute sur le port 8000 et si vous établissez une connexion TCP avec le port et envoyez "**JDWP-Handshake**", le serveur devrait vous répondre avec la même chaîne.\
Vous pouvez également vérifier cette chaîne dans le réseau pour trouver d'éventuels services JDWP.
En listant les **processus**, si vous trouvez la chaîne "**jdwk**" à l'intérieur d'un **processus Java**, il est probable qu'il ait activé le \*\*Java Debug Wired Protocol \*\*et vous pourrez peut-être vous déplacer latéralement ou même **escalader les privilèges** (si exécuté en tant que root).
**Java Platform Debug Architecture (JPDA)**: JDWP est l'un des composants du système de débogage Java global, appelé Java Platform Debug Architecture (JPDA)\[2]. Voici un diagramme de l'architecture globale :
Le Debuggee est constitué d'une JVM multi-thread exécutant notre application cible. Pour pouvoir être débogué à distance, l'instance JVM doit être explicitement démarrée avec l'option -Xdebug passée en ligne de commande, ainsi que l'option -Xrunjdwp (ou -agentlib). Par exemple, démarrer un serveur Tomcat avec le débogage à distance activé ressemblerait à ceci :
Comme le montre le diagramme d'architecture, le protocole Java Debug Wire est le lien central entre le Débogueur et l'instance JVM. Les observations sur le protocole incluent :
* C'est un protocole binaire réseau basé sur des paquets.
* Il est principalement synchrone. Le débogueur envoie une commande via JDWP et s'attend à recevoir une réponse. Cependant, certaines commandes, comme les événements, n'attendent pas de réponse synchrone. Elles enverront une réponse lorsque des conditions spécifiques seront remplies. Par exemple, un point d'arrêt est un événement.
Toutes ces observations ont du sens puisqu'il s'agit d'un protocole de débogage. Cependant, lorsque ce service est exposé à un réseau hostile ou accessible depuis Internet, les choses peuvent mal tourner.\
**Handshake**: JDWP stipule\[9] que la communication doit être initiée par une simple poignée de main. Après une connexion TCP réussie, le Débogueur (client) envoie la chaîne ASCII de 14 caractères "JDWP-Handshake". Le Debuggee (serveur) répond à ce message en renvoyant exactement la même chaîne. La trace scapy\[3] suivante montre la poignée de main initiale à deux voies :
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
0007 15:49:30.407636 Ether / IP / TCP 192.168.2.2:59079 > 192.168.2.9:8000 A
Un auditeur de sécurité expérimenté aurait déjà réalisé qu'une telle poignée de main simple offre un moyen de découvrir facilement des services JDWP actifs sur Internet. Il suffit d'envoyer une simple sonde et de vérifier la réponse spécifique. Plus intéressant encore, un comportement a été observé sur le kit de développement Java IBM lors de l'analyse avec ShodanHQ\[4] avec le serveur "parlant" d'abord avec la même bannière mentionnée. Par conséquent, il existe un moyen totalement passif de découvrir un service JDWP actif (cela sera abordé plus tard dans cet article avec l'aide du (tristement célèbre) Shodan).\
\
**Communication**: JDWP définit les messages\[10] impliqués dans les communications entre le Débogueur et le Debuggee. Les messages suivent une structure simple, définie comme suit: 
Les champs Longueur et Id sont assez explicites. Le champ Flag est utilisé uniquement pour distinguer les paquets de demande des réponses, une valeur de 0x80 indiquant un paquet de réponse. Le champ CommandSet définit la catégorie de la Commande, comme indiqué dans le tableau suivant.\
| 0x40 | Action à prendre par la JVM (par exemple, définir un point d'arrêt) |
| 0x40–0x7F | Fournir des informations d'événement au débogueur (par exemple, la JVM a atteint un point d'arrêt et attend d'autres actions) |
| 0x80 | Extensions tierces |
En gardant à l'esprit que nous voulons exécuter du code arbitraire, les commandes suivantes sont les plus intéressantes pour nos besoins.
* VirtualMachine/IDSizes définit la taille des structures de données gérées par la JVM. C'est l'une des raisons pour lesquelles le script nmap jdwp-exec.nse\[11] ne fonctionne pas, car le script utilise des tailles codées en dur.
* ClassType/InvokeMethod vous permet d'appeler une fonction statique.
* ObjectReference/InvokeMethod vous permet d'appeler une fonction à partir d'un objet instancié dans la JVM.
* StackFrame/(Get|Set)Values fournit des capacités de poussée/pop à partir de la pile des threads.
* Event/Composite force la JVM à réagir à des comportements spécifiques déclarés par cette commande. Cette commande est une clé majeure à des fins de débogage car elle permet, entre autres choses, de définir des points d'arrêt, de parcourir pas à pas les threads pendant l'exécution et d'être notifié lors de l'accès/modification de valeurs de la même manière que GDB ou WinDBG.
Non seulement JDWP vous permet d'accéder et d'invoquer des objets déjà présents en mémoire, mais il vous permet également de créer ou de remplacer des données.
* VirtualMachine/CreateString vous permet de transformer une chaîne de caractères en un java.lang.String vivant dans l'exécution JVM.
* VirtualMachine/RedefineClasses vous permet d'installer de nouvelles définitions de classes.
**"Tous vos JDWP nous appartiennent"**
Comme nous l'avons vu, JDWP fournit des commandes intégrées pour charger des classes arbitraires dans la mémoire JVM et invoquer du bytecode déjà existant et/ou nouvellement chargé. La section suivante couvrira les étapes de création d'un code d'exploitation en Python, qui se comporte comme une implémentation partielle d'une interface JDI afin d'être aussi fiable que possible. La principale raison de ce script d'exploitation autonome est que, en tant que pentester, j'aime les exploits "head-shot". C'est-à-dire, lorsque je sais avec certitude qu'un environnement/application/protocole est vulnérable, je veux avoir mon outil prêt à l'exploiter immédiatement (c'est-à-dire sans PoC, qui est essentiellement la seule chose qui existait jusqu'à présent). Maintenant que nous avons couvert la théorie, passons à la mise en œuvre pratique. Lorsqu'un service JDWP ouvert est rencontré, l'exécution de commandes arbitraires n'est qu'à cinq étapes (ou avec cette exploitation, à seulement une ligne de commande) de distance. Voici comment cela se passerait : 1. Obtenir la référence de l'exécution JavaLa JVM manipule les objets via leurs références. Pour cette raison, notre exploitation doit d'abord obtenir la référence de la classe java.lang.Runtime. À partir de cette classe, nous avons besoin de la référence de la méthode getRuntime(). Cela est réalisé en récupérant toutes les classes (paquet AllClasses) et toutes les méthodes de la classe que nous recherchons (paquet ReferenceType/Methods). 2. Configurer un point d'arrêt et attendre une notification (appels asynchrones)C'est la clé de notre exploitation. Pour invoquer du code arbitraire, nous devons être dans un contexte d'exécution de thread. Pour ce faire, une astuce consiste à configurer un point d'arrêt sur une méthode qui est connue pour être appelée à l'exécution. Comme nous l'avons vu précédemment, un point d'arrêt dans JDI est un événement asynchrone dont le type est défini sur BREAKPOINT(0x02). Lorsqu'il est atteint, la JVM envoie un paquet EventData à notre débogueur, contenant notre ID de point d'arrêt, et plus important encore, la référence au thread qui l'a atteint.\
Il est donc judicieux de le configurer sur une méthode fréquemment appelée, telle que java.net.ServerSocket.accept(), qui est très susceptible d'être appelée chaque fois que le serveur reçoit une nouvelle connexion réseau. Cependant, il faut garder à l'esprit que cela pourrait être n'importe quelle méthode existant à l'exécution. 3. Allouer un objet Java String dans l'exécution pour effectuer la charge utileNous exécuterons du code dans l'exécution JVM, donc toutes nos données manipulées (comme les chaînes de caractères) doivent exister dans l'exécution JVM (c'est-à-dire posséder une référence d'exécution). Cela est assez facilement réalisé en envoyant une commande CreateString.
4\. Obtenir l'objet Runtime à partir du contexte du point d'arrêtÀ ce stade, nous avons presque tous les éléments nécessaires pour une exploitation réussie et fiable. Ce qui nous manque, c'est une référence d'objet Runtime. Il est facile de l'obtenir, et nous pouvons simplement exécuter dans l'exécution JVM la méthode statique java.lang.Runtime.getRuntime()\[8] en envoyant un paquet ClassType/InvokeMethod et en fournissant la classe Runtime et les références de thread. 5. Rechercher et invoquer la méthode exec() dans l'instance RuntimeLa dernière étape consiste simplement à rechercher la méthode exec() dans l'objet Runtime statique obtenu à l'étape précédente et à l'invoquer (en envoyant un paquet ObjectReference/InvokeMethod) avec l'objet String que nous avons créé à l'étape trois. 
L'exploit final utilise ces techniques, ajoute quelques vérifications et envoie des signaux de suspension/reprise pour causer le moins de perturbations possible (il est toujours préférable de ne pas casser l'application sur laquelle vous travaillez, n'est-ce pas ?). Il fonctionne en deux modes :
* Le mode "par défaut" est totalement non intrusif et exécute simplement du code Java pour obtenir des informations système locales (parfait pour une preuve de concept à un client).
* En passant l'option "cmd", une commande système est exécutée sur l'hôte distant et est donc plus intrusive. La commande est exécutée avec les privilèges avec lesquels la JVM fonctionne.
Comme Java est conçu pour être indépendant de la plate-forme, des commandes peuvent être exécutées sur n'importe quel système d'exploitation pris en charge par Java. Eh bien, c'est en fait une bonne nouvelle pour nous, les pentesteurs : **le service JDWP ouvert signifie une RCE fiable**. Jusqu'à présent, tout va bien.
En réalité, JDWP est assez souvent utilisé dans le monde des applications Java. Cependant, les pentesteurs ne le voient peut-être pas souvent lorsqu'ils effectuent des évaluations à distance, car les pare-feu bloquent généralement (et devraient bloquer) le port sur lequel il s'exécute. Mais cela ne signifie pas que JDWP ne peut pas être trouvé dans la nature :
* Au moment de la rédaction de cet article, une recherche rapide sur ShodanHQ\[4] révèle immédiatement environ 40 serveurs envoyant la poignée de main JDWP :
* En effectuant un scan masscan sur Internet à la recherche de ports spécifiques (tcp/8000, tcp/8080, tcp/8787, tcp/5005), de nombreux hôtes (qui ne peuvent pas être signalés ici) ont répondu à la poignée de main initiale.
* Des applications "entreprise" ont été trouvées dans la nature exécutant un service JDWP \*par défaut\* (la recherche du numéro de port réel est laissée en exercice au lecteur curieux).
Ce ne sont que quelques façons de découvrir des services JDWP ouverts sur Internet. Cela nous rappelle que les applications devraient régulièrement faire l'objet d'examens de sécurité approfondis, que les environnements de production devraient désactiver toute fonctionnalité de débogage, et que les pare-feu devraient être configurés pour limiter l'accès aux services nécessaires au fonctionnement normal. Permettre à n'importe qui de se connecter à un service JDWP revient exactement à autoriser une connexion à un service gdbserver (de manière peut-être plus stable). J'espère que vous avez apprécié la lecture de cet article autant que j'ai apprécié jouer avec JDWP. À vous, les puissants pirates, joyeux JDWP pwning !!
* Travaillez-vous dans une **entreprise de cybersécurité** ? Voulez-vous voir votre **entreprise annoncée dans HackTricks** ? ou voulez-vous avoir accès à la **dernière version de PEASS ou télécharger HackTricks en PDF** ? Consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop) !
* Obtenez le [**swag officiel PEASS & HackTricks**](https://peass.creator-spring.com)
* **Rejoignez le** [**💬**](https://emojipedia.org/speech-balloon/) [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe Telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
* **Partagez vos astuces de piratage en soumettant des PR au** [**repo hacktricks**](https://github.com/carlospolop/hacktricks) **et au** [**repo hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).