
CakePHP 5.4.2 - 높음 - 원격 - 역직렬화 - 캐시 엔진이 클래스 허용 목록 없이 객체를 역직렬화함
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · cakephp-cache-unserialize
분석 문서: https://abraxaslabs.tech/research/cakephp-cache-unserialize
분류: 객체 주입(Object injection) 도달 범위: 원격(Redis/Memcached 쓰기) / 로컬(FileEngine)
CakePHP 5.4.2 (887b641) - Cake Software Foundation
5.3.7은 이러한 이유로 Redis allowedClasses를 추가했지만, 하위 호환성을 위해 기본값을 true(모두 허용)로 남겨두었습니다. RedisEngine은 해당 기본값이 유지되는 한 여전히 순수한 unserialize()를 호출합니다. FileEngine에는 허용 목록이 전혀 없습니다. MemcachedEngine은 여전히 serialize의 기본값을 php로 둡니다.
Redis에서 cake_ 키를 SET할 수 있거나 캐시 파일을 작성할 수 있는 사람은 직렬화된 객체를 심을 수 있습니다. 다음 Cache::read(또는 CacheSession 로드)가 PHP 워커에서 이를 실행합니다.
| ID | 아직 CVE 없음 |
| 분류 | 객체 주입(Object injection) |
| 도달 범위 | 공격자가 Redis 또는 Memcached에 쓸 수 있을 때 원격. tmp/cache의 FileEngine의 경우 로컬. |
| CWE | CWE-502 |
| CVSS | 높음: 8.8 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H (캐시 저장소에 대한 쓰기 필요). FileEngine은 AV:L. |
| 제품 | CakePHP |
| 영향받는 버전 | 5.4.2 (887b641de9f7aba06071f98f17edcbc573cbcf63) |
| 인증 | 캐시 저장소에 대한 쓰기(Redis SET, Memcached set 또는 캐시 파일). 잠긴 localhost Redis에 대한 비인증 HTTP는 아님. |
| 라이선스 | GNU Affero GPL v3.0 |
| 랩 | 127.0.0.1 전용 |
앱 캐시에 직렬화된 객체를 심습니다. 다음 읽기가 워커에서 PHP를 실행합니다. 이 랩은 증거 파일에서 멈춥니다. 가젯 체인이나 셸을 시연하지 않습니다.
랩에서 입증됨(무결성)
cake_<key> 후 Cache::read. 기본 접두사는 cake_입니다. RedisEngine의 unserialize()는 allowedClasses가 기본값 true일 때 순수한 unserialize($value)를 사용합니다. LabMarker로 인스턴스화된 심어진 LabMarker 객체와 __wakeup이 PHP UID로 증거 파일을 작성했습니다.{expiry}\n{serialize($obj)}를 심습니다. FileEngine::get()은 여전히 순수한 unserialize($data)를 호출합니다. 동일한 마커, 동일한 증거. 파일명은 prefix에 키를 더한 것입니다(cake_labfile).allowedClasses => false는 객체를 거부합니다. 동일한 Redis 페이로드가 __PHP_Incomplete_Class로 반환되었습니다. __wakeup이 실행되지 않았습니다. 증거 파일이 없었습니다.추론됨(여기서 실행되지 않음)
defaults => cache일 때 CacheSession::read는 동일한 싱크입니다. 모든 세션 로드가 공격자가 제어하는 캐시 바이트의 unserialize가 됩니다.serialize => php**는 동일한 종류의 버그입니다. 이 랩은 Memcached를 시작하지 않았습니다.종료됨 / 이 잔여 문제가 아님
cakephp/app에 대한 비인증 HTTP.allowedClasses => false(또는 엄격한 목록)는 운영자가 설정하면 이미 객체를 차단합니다. 기본값은 아닙니다.동일하게 고정된 잔여 항목: window SQLi, collate SQLi, attachment CRLF.
2026년 FunctionsBuilder / jsonValue / Smtp CRLF / View element 물결 이후 cakephp/cakephp 5.4.2를 고정했습니다. RedisEngine은 해당 옵션을 문서화하면서도 여전히 기본값을 열린 상태로 둡니다:
* - `allowedClasses` ... Defaults to `true` (allow all) for backwards compatibility.
...
'allowedClasses' => true,
경로 읽기:
protected function unserialize(string $value): mixed
{
if (preg_match('/^[-]?\d+$/', $value)) {
return (int)$value;
}
$allowedClasses = $this->getConfig('allowedClasses');
if ($allowedClasses !== true) {
return unserialize($value, ['allowed_classes' => $allowedClasses]);
}
return unserialize($value);
}
FileEngine에는 이에 상응하는 옵션이 없습니다:
if ($data !== '' && !empty($this->_config['serialize'])) {
$data = unserialize($data);
잘못된 방향으로 이미 기록된 것들: 잠긴 로컬호스트 Redis를 인증 없는 HTTP RCE로 취급한 것; 가젯 체인을 배포한 것; FileEngine이 원격이라고 주장한 것; 리버스 셸. 전부 쇼에 불과하다. 오라클은 플래그 파일을 작성하는 마커 __wakeup이다.
python3 cakephp-cache-unserialize-Abraxas-Labs.py
또는
cd lab
./run.sh
오직 127.0.0.1:19470만 대상으로 합니다. Docker 내부에서 태그 5.4.2의 라이브 CakePHP 5.4.2를 사용합니다. 호스트가 SET할 수 있도록 protected-mode가 꺼진 Redis 7을 사용합니다. ext-redis가 포함된 PHP 8.3을 사용합니다. /tmp/CAKEPHP-CACHE-UNSERIALIZE-WITNESS에 쓰는 __wakeup을 가진 마커 클래스 LabMarker를 사용합니다. 셸은 없습니다.
SUCCESS cakephp-cache-unserialize redis-default-wakeup=yes redis-denied-wakeup=no file-wakeup=yes pin=5.4.2 sha=887b641de9f7aba06071f98f17edcbc573cbcf63 how=live CAKEPHP-CACHE-UNSERIALIZE-WITNESS
Redis allowedClasses의 기본값을 false로 설정하거나, 애플리케이션이 실제로 저장하는 클래스의 엄격한 목록으로 설정합니다. FileEngine에도 동일한 옵션을 추가하고 get()에서 이를 준수하도록 합니다. Memcached serialize의 기본값을 json으로 설정합니다. CacheSession이 캐시 엔진의 unserialize 정책을 상속한다는 점을 문서화합니다.
887b641de9f7aba06071f98f17edcbc573cbcf63)RedisEngine.php · FileEngine.phpGNU Affero GPL v3.0. LICENSE를 참조하세요. 루프백 실습 환경 전용입니다. 보증은 제공되지 않습니다.