安全与隐私审计报告 —— 某大wp主题 9.1 改版
审计对象:
zib91mod(846 个 PHP 文件 + 前端资源)
方法:静态扫描(域名/密钥/危险函数/AJAX 校验矩阵)+ 运行时验证(带管理员会话的 HTTP 实测)
结论:PHP 侧无厂商数据回传;发现 2 个真实漏洞已修复,1 类系统性风险已统一缓解
一、结论速览
| # | 发现 | 等级 | 状态 |
|---|---|---|---|
| 1 | 17 个后台 AJAX 处理器有权限校验但无 nonce → CSRF | 中危 | 已缓解(同源守卫,实测 403) |
| 2 | 微信回调 echostr 未转义直接输出 → 反射型 XSS |
中危 | 已修复(esc_html) |
| 3 | 短信测试端点可被 CSRF 诱导发短信(花钱) | 中低危 | 含在 #1,已缓解 |
| 4 | 厂商域名 186+14+2 处,PHP 侧 0 处外发 | 无 | 已验证,改版已切断回传 |
| 5 | 硬编码密钥 3 处(均在 vendor/SDK 样本内) | 低危 | 需确认线上是否启用 |
| 6 | 前端 JS 有 4 处外发(翻译/地理编码/占位图) | 低危(隐私) | 建议按需关闭 |
| 7 | 变量 include 8 处,均在框架内部 | 低危 | 无需处理 |
| 8 | eval( 1 处,实为字符串检测非执行 |
无 | 无需处理 |
二、详细发现
1. CSRF:17 个后台 AJAX 无 nonce(中危,已缓解)
证据:inc/options/action.php 全部 17 个处理器
zib_weixin_gzh_create_menu cap=Y nonce=N
zib_admin_ajax_weixin_gzh_get_menu cap=Y nonce=N
zib_admin_ajax_weixin_freepublish_batchget cap=Y nonce=N
zib_audit_test cap=Y nonce=N
zib_test_send_mail cap=Y nonce=N
zib_test_send_sms cap=Y nonce=N ← 可导致短信费用
zib_ajax_reset_user_medal cap=Y nonce=N
zib_ajax_options_import cap=Y nonce=N ← 可导入恶意配置
zib_ajax_options_backup cap=Y nonce=N
zib_ajax_options_backup_delete cap=Y nonce=N
zib_ajax_options_backup_restore cap=Y nonce=N ← 可回滚配置
zib_ajax_test_wechat_template_test cap=Y nonce=N
zib_test_ip_addr_sdk cap=Y nonce=N
zib_test_express_query cap=Y nonce=N
zib_ajax_search_ms_rebuild cap=Y nonce=N
zib_ajax_search_ms_stats cap=Y nonce=N
zib_ajax_search_ms_sync_synonyms cap=Y nonce=N
风险:管理员(super admin)访问恶意页面时,攻击者可用跨站表单提交这些 action,
在管理员已登录的浏览器里执行:发短信(花钱)、导入/恢复配置(站点接管)、重建索引。
缓解措施:新增 inc/z5-csrf-guard.php,在 admin-ajax.php 入口统一校验:
放行条件(任一):
① 带 X-Requested-With: XMLHttpRequest(跨站表单无法设置自定义头)
② Origin / Referer 与本站同源
③ 提供有效 nonce
否则 → 403
实测:
| 场景 | 结果 |
|---|---|
正常后台 AJAX(带 X-Requested-With) |
200,返回正确 JSON |
| 跨站伪造(无头、无 Origin/Referer) | 403 Request blocked |
伪造 Referer: https://evil.example/ |
403 |
2. 反射型 XSS:微信回调 echostr(中危,已修复)
证据:oauth/weixingzh/callback.php 第 20、36 行(修复前)
php
if (!empty($_REQUEST['echostr']) && !empty($_REQUEST['signature'])) {
if (_pz('oauth_weixingzh_option', 0, 'token_nocheck')) {
echo $_REQUEST['echostr']; // ← 无任何校验直接输出
exit();
}
…
if ($tmpStr == $signature) {
echo $_REQUEST['echostr']; // ← 校验后仍直接输出
exit();
}
利用条件:
– token_nocheck 开启时:无需任何凭据即可构造 ?echostr=<script>...&signature=x
– token_nocheck 关闭时:需知道微信 token 才能算对 sha1
修复:两处均改为
php
echo esc_html(wp_unslash($_REQUEST['echostr']));
微信回调的 echostr 是纯数字串,转义不影响正常校验流程。
3. 隐私:厂商域名 202 处,PHP 侧零外发(已确认安全)
证据:全量扫描(排除 vendor/)
| 性质 | 数量 |
|---|---|
链接 / 文案(href、帮助文档) |
199 |
| 静态资源引用(JS/CSS 内的 URL 常量) | 376 |
真正的网络请求(wp_remote_*/curl/fetch) |
0 |
即:改版后的 PHP 代码不会再向 zibll.com 发送任何数据。原有授权校验/更新检查已由
明文实现替换为「不联网」版本(curl_update() 返回 false、get_download_url() 返回空)。
4. 硬编码密钥 3 处(低危)
vendor/qcloudsms/qcloudsms_php/demo/composer/app.php:21 appkey = 9ff91d87c2cd…
vendor/qcloudsms/qcloudsms_php/demo/simple/app.php:21 appkey = 9ff91d87c2cd…
zibpay/sdk/xunhupay/notify.php:31 appsecret = 160130736b1a…
前两处是腾讯云短信 SDK 的 demo 示例文件,不参与运行;
第三处是虎皮椒支付 SDK 内的样本值,需确认线上是否真的使用该值(若使用,应更换为你自己的密钥)。
5. 前端 JS 的 4 处外发(低危,隐私相关)
| 位置 | 目标 | 说明 | 建议 |
|---|---|---|---|
js/libs/translate.js |
translate.zvo.cn / api.zvo.cn |
网页翻译:会把页面文本发到第三方 | 不用翻译就禁用该脚本 |
inc/codestar-framework/assets/js/main.js |
nominatim.openstreetmap.org |
地址地理编码(后台) | 仅后台触发 |
js/slidercaptcha.min.js |
picsum.photos |
验证码背景占位图 | 无敏感数据 |
zibpay/assets/js/jquery.form.js |
groups.google.com |
注释里的文档链接 | 无实际请求 |
6. 其余扫描项(无风险)
| 项 | 数量 | 结论 |
|---|---|---|
变量 include/require |
8 | 全在 CSF 框架 / composer / zib_require() 内部,参数非用户可控 |
eval( |
1 | go.php:18 是对 REQUEST_URI 做 strpos 检测(WAF 式防护),非执行 |
unserialize( |
0 | — |
| SQL 字符串插值 | 0 | 全部走 $wpdb->prepare() 参数绑定 |
转义调用 esc_* |
1,630 | — |
能力校验 current_user_can |
259 | — |
nonce 校验 |
43 | 集中在非表单类端点 |
三、本次改动的文件
新增 inc/z5-csrf-guard.php CSRF 同源守卫
修改 functions.php 挂载守卫
修改 oauth/weixingzh/callback.php echostr 转义(2 处)
四、建议(未实施,需你决定)
1. 翻译脚本:若不需要网页自动翻译,从主题里移除 js/libs/translate.js 的引入,
可彻底避免页面文本外发
2. 虎皮椒 appsecret:确认 zibpay/sdk/xunhupay/notify.php:31 是否是线上真实密钥,
若是则立即更换
3. 给 17 个处理器补 nonce:本次用同源守卫统一缓解(零侵入);若希望更严格,
可逐个加 check_ajax_referer,但需同步修改后台 JS 的请求参数
4. 短信端点:建议加频率限制(如同一管理员每分钟 ≤1 次)
*审计完成时间:2026-10-22*