
WordPress용으로 고정된 Docker 공식 이미지 하나에 대한 CVE-2026-111497 RCE PoC
이 소스 전용 PoC는 고정된 Docker Official Image for WordPress 하나를 대상으로 인증 없는 명령 실행을 재현합니다.
pingback.ping 요청 하나로 WordPress가 동일한 PHP 요청 중에 공격자 URL을 두 번 가져오게 됩니다. 첫 번째 응답은 Brotli를 통해 PHP 핸들러를 손상시킵니다. 재시도 헤더가 Bash를 시작하고 랩 플래그를 반환합니다.
이 프로필은 대상에 특화되어 있습니다. 현재 WordPress 이미지, 다른 다이제스트, 또는 WordPress Core의 메모리 오류에 대해서는 어떠한 주장도 하지 않습니다.
경고: 이 PoC는 소유한 시스템의 포함된 랩에서만 실행하십시오. 작동하는 RCE 페이로드가 포함되어 있습니다.
/flag.txt를 읽고, 플래그가 XML-RPC 응답으로 반환됩니다.sh에서 bash로, 다시 sleep으로 이어지는 프로세스 체인을 기록합니다.| 항목 | 값 |
|---|---|
| 대상 | docker.io/library/wordpress@sha256:806680ba62232c4c300fb9dcc9f89d08e9e8c2bfc59837a1f58716f8648306d5 |
| 이미지 ID | c64dd89c00079939f18d70489e7c3e30cb071e8581824ab2de688f9f4d70d076 |
| 플랫폼 | Linux amd64, Debian 13.7 |
| 애플리케이션 | WordPress 7.1.3, Apache 2.4.69 prefork |
| 런타임 | PHP 8.3.36 NTS |
| 디코더 | libbrotli1:amd64 1.1.0-2+b7 |
이 Linux/amd64 매니페스트는 게시 당시 wordpress:latest에 의해 선택되었습니다. 현재 latest 태그는 더 이상 이를 선택하지 않습니다.
랩은 이 수정되지 않은 Docker Official Image를 rootless Podman으로 실행합니다. Brotli 라이브러리를 주입하지 않습니다.
CVE-2026-111497은 디코더 손상을 제공합니다. WordPress는 pingback.ping을 통해 인증 없는 가져오기 경로를 제공합니다.
잘못된 형식의 스트림은 라이브 system 핸들러 포인터에서 strtolower 핸들러로 6바이트를 복사합니다. 두 포인터 모두 동일한 ASLR 로드된 libphp.so 베이스를 사용합니다. 따라서 프로필은 절대 주소 누출이 필요하지 않습니다.
프로필은 여전히 정확한 Brotli, PHP, glibc, cURL, Requests, Apache, 할당자 및 요청 이력에 의존합니다. 첫 번째 응답은 161바이트 헤더와 23,069,816바이트 본문을 사용합니다. 오리진은 23,069,752바이트를 보내고, 1초 대기한 후 최종 64바이트를 보냅니다.
디코더는 손상 후 오류를 반환합니다. Requests는 CURLE_BAD_CONTENT_ENCODING 후 콘텐츠 디코딩 없이 재시도합니다. 첫 번째 헤더 이름이 수정된 핸들러에 도달하여 고정된 Bash 명령을 시작합니다.
애플리케이션 경로에는 다음 조건이 필요합니다:
/xmlrpc.php에 접근 가능하고 pingback.ping이 활성화되어 있어야 합니다.랩은 플러그인이나 피해자 측 계측 없이 이러한 조건을 생성합니다.
generate_payloads.py가 권위 있는 페이로드 소스입니다. 저장소는 미리 빌드된 페이로드 바이너리를 추적하지 않습니다.
생성기는 Python 표준 라이브러리만 사용합니다. 오프라인으로 작동하며 트래픽을 보내거나 명령을 실행하지 않습니다. RFC 7932의 프로필 상수와 직렬화 단계를 정의합니다.
verify.sh는 모든 프래그먼트를 재생성합니다. 크기, 해시, 중간 비트 오프셋 및 1비트 선택자 관계를 검증합니다.
테스트된 호스트는 amd64의 WSL2에서 Ubuntu 24.04.4를 사용했습니다. rootless Podman 4.9.3, Bash 5.2.21, Python 3.12.3을 사용했습니다.
최소 요구 사항은 Linux amd64, rootless Podman, Bash, Python 3.8 이상, ASLR 모드 2 및 표준 GNU 사용자 도구입니다. 포트 18170과 서브넷 93.184.218.0/24를 비워 두거나 대안을 선택하십시오. SELinux가 강제 적용되는 호스트는 바인드 마운트를 거부할 수 있습니다.
랩을 실행하기 전에 불변 이미지를 가져오십시오:
podman pull docker.io/library/wordpress@sha256:806680ba62232c4c300fb9dcc9f89d08e9e8c2bfc59837a1f58716f8648306d5
podman pull docker.io/library/wordpress@sha256:65d5f185a6f539803a177ea9cdd5ad632ae24427bea114447e67a6fcd5d8bfe8
podman pull docker.io/library/mariadb@sha256:33a6653ab666774f48818120045f9367a81cd4c54c027412fe294a7d1274e2dc
스크립트를 실행 가능하게 만든 다음, 소스 패키지를 검증합니다:
chmod +x generate_payloads.py verify.sh run.sh
./verify.sh
각 모드를 새 태그로 실행합니다:
| 모드 | 명령 | 요구 결과 |
|---|---|---|
| Positive | ./run.sh standard | 플래그를 반환하고 PoC positive:를 출력함 |
| Observable | ./run.sh observable | 또한 보이는 bash 및 sleep 프로세스를 기록함 |
| Selector | ./run.sh selector | 재시도하지만 응답에서 플래그를 제외함 |
selector는 바이트 오프셋 1066에서 한 비트를 변경합니다. 이는 동일 이미지 인과적 제어이며, 고정 디코더 제어가 아닙니다.
선택적 인수는 모드, 태그, 호스트 포트, 세 번째 네트워크 옥텟입니다:
./run.sh standard trial2 18171 219
러너는 증거를 runs/<tag>/에 기록합니다. 주요 파일은 다음과 같습니다:
VERDICT.txt: 결과 및 요청 횟수client-request.raw 및 client-response.raw: 인바운드 와이어 데이터origin-evidence/origin-events.json: 아웃바운드 요청과 재시도 헤더 모두oracle-match.txt: 응답에서 일치한 플래그payloads/identity.json: 생성된 프로필 메타데이터MANIFEST.sha256: 모든 증거 파일의 해시러너는 내부 Podman 네트워크를 사용하며 WordPress를 127.0.0.1에서만 게시합니다. 클라이언트는 대상 주소를 받지 않습니다. 오리진은 명령 입력을 받지 않습니다. 고정된 명령은 합성 플래그만 읽습니다.
러너는 Apache가 시작되기 전에 Apache 환경에서 플래그 값을 제거합니다. 또한 새로운 자격 증명을 생성하고 현재 실행의 리소스만 제거합니다.
응답 분할과 프로세스 기록은 익스플로잇 입력입니다. 실행이 실패하면 변경되지 않은 프로필을 새 태그로 반복하십시오. 실패한 실행 후에는 주소나 페이로드 바이트를 조정하지 마십시오.
이 패키지는 이미지 다이제스트, PHP 빌드, 아키텍처, 할당자 또는 응답 스케줄 전반에 걸친 이식성을 확립하지 않습니다. 다른 대상은 실행을 중단시키거나 충돌만 일으킬 수 있습니다.
업스트림은 유지 관리되는 Brotli 브랜치를 1.0.10, 1.1.1, 1.2.1에서 수정했습니다. 배포 벤더는 수정 사항을 백포트할 수 있습니다. 표시된 버전만이 아니라 벤더 권고 및 패키지 변경 로그를 사용하십시오.