Puock WordPress 主题 v2.10.2 安全审计报告
- 审计对象:
wordpress-theme-puock-2.10.2(WordPress 主题源码,本地授权审计) - 审计日期: 2026-08-12
- 审计范围: 主题自有 PHP 代码(121 个文件,含
timthumb.php、vendor/yurunsoft/OAuth 库,不含其他第三方 WP 插件) - 威胁模型: 未认证前台访客 / 已认证低权限用户(订阅者/作者)/ 已登录管理员
- 目标: 反序列化、命令执行/RCE、SQL 注入、未授权访问、硬编码凭据、XSS、SSRF、越权(IDOR)
一、执行摘要
主题整体安全性中等偏弱。未发现可被未认证访客直接利用的 RCE / 反序列化 / 命令执行 漏洞;OAuth 状态校验、评论 SQL 预处理、IP 溯源等关键防御点实现正确。但存在 1 个高危未认证 SQL 注入 与 多处未认证/作者级 XSS,可导致数据库拖库(含 wp_users 密码哈希)、管理员会话窃取、整站配置被篡改等后果。
最优先处置:短代码 SQL 注入(Critical,未认证直接拖库)。
| 编号 | 严重性 | 漏洞 | 位置 | 攻击者 | 默认可利用 |
|---|---|---|---|---|---|
| S-01 | 🔴 Critical | 未认证 SQL 注入(短代码) | inc/fun/short-code.php:200-210 |
未认证 | ✅ 是 |
| S-02 | 🟠 High | 反射型 XSS(base64 参数)+ 开放重定向 | inc/go.php |
未认证 | ✅ 是 |
| S-03 | 🟠 High | 反射型 XSS(url 参数原样输出) |
inc/favicon.php:98 |
未认证 | ✅ 是 |
| S-04 | 🟠 High | 存储型 XSS(评论者昵称/网址属性注入,读者墙/最新评论全站组件) | pages/template-reads.php:32/35/36、inc/fun/widget.php:472/544 |
未认证评论者 | ✅ 是 |
| S-05 | 🟡 Medium | 存储型 XSS(文章 SEO 元数据原样输出 <head>) |
inc/seo.php:6-9,22-25 |
作者 | ✅ 是 |
| S-06 | 🟡 Medium | 存储型 XSS(短代码参数:DPlayer JS 注入等) | inc/fun/short-code.php:143-144,163,178-181,296-298,307 |
作者 | ✅ 是 |
| S-07 | 🟡 Medium | 存储型 XSS(文章标题属性注入;转载出处 meta) | inc/ajax/page-poster.php:31/104、inc/fun/widget.php:163-196、single.php:122/124 |
作者 | ✅ 是 |
| S-08 | 🟡 Medium | 存储型 XSS(用户资料 description/display_name) | inc/seo.php:52、author.php:16-17、functions.php:456,543 |
注册用户 | ✅ 是 |
| S-09 | 🟡 Medium | 未授权 IDOR(草稿/私有文章内容泄露)+ 反射 XSS | inc/ajax/page-poster.php:8-40 |
未认证 | ⚠️ 需开启 post_poster_open(默认关) |
| S-10 | 🟡 Medium | 主题配置 AJAX CSRF(无 nonce) | inc/fun/ajax.php:46-112 |
已登录管理员 | ⚠️ 受 SameSite=Lax 部分缓解 |
| S-11 | 🟡 Medium | SSRF(重定向跟随绕过白名单) | timthumb.php:263-279,1331-1371 |
未认证 | ⚠️ 需配置 thumbnail_allows(默认空) |
| S-12 | 🟡 Medium | SSRF(重定向跟随 + DNS rebinding) | inc/favicon.php:15-34 |
未认证 | ⚠️ 需友链表命中 |
| S-13 | 🟢 Low | timthumb 错误信息泄露内部路径/QUERY_STRING | timthumb.php:1077,1086,470-472 |
未认证 | ✅ 是 |
| S-14 | 🟢 Low | 邮箱枚举 | inc/ajax/page-front-login.php:145 |
未认证 | ✅ 是 |
| S-15 | 🟢 Low | OAuth 解绑 GET CSRF(无 nonce) | inc/oauth/oauth.php:196-209 |
已登录用户 | ✅ 是 |
| S-16 | 🟢 Low | 个人资料更新 CSRF | inc/classes/PuockUserCenter.php:45-72 |
已登录用户 | ✅ 是 |
| S-17 | 🟢 Low | error.php 会话信息未转义输出 |
error.php:24 |
— | 纵深缺口 |
| S-18 | 🟢 Low | AI 对话无频率限制 | inc/ajax/ai.php |
未认证 | ✅ 是 |
| S-19 | 🟢 Low | 特权评论者评论内容 img 白名单放行事件属性 |
inc/fun/widget.php:547 |
编辑/管理员 | ⚠️ 需 unfiltered_html |
| S-20 | ⚪ Info | 选项写 .tas.php 代码注入(管理员级) |
inc/fun/core.php:1137-1148 |
管理员 | 非提权 |
二、漏洞详情
🔴 S-01 [Critical] 短代码未认证 SQL 注入
位置: inc/fun/short-code.php:200-210(注册于 :216 add_shortcode('reply', 'pk_reply_read'))
$email = null;
$user_id = (int)wp_get_current_user()->ID;
...
} else {
if (isset($_COOKIE['comment_author_email_' . COOKIEHASH])) {
$email = $_COOKIE['comment_author_email_' . COOKIEHASH]; // ← 攻击者可控
}
}
...
$post_id = get_the_ID();
$query = "SELECT count(comment_ID) as c FROM {$wpdb->comments} WHERE comment_post_ID={$post_id}
and comment_approved='1' and comment_author_email='{$email}' LIMIT 1"; // ← 直接拼接
if ($wpdb->get_row($query)->c > 0) { ... }
成因: 未认证访客的评论邮箱 Cookie(comment_author_email_<hash>)被原样拼接进 SQL,全程无 $wpdb->prepare()。任何含 短代码的文章页面都会渲染并执行该查询,get_the_ID() 无需真实文章 ID(可在任意含短代码的页面触发)。
攻击利用:
- 时间盲注拖库(未认证):
Cookie: comment_author_email_<hash>=' AND SLEEP(5) AND '1'='1→ 可逐字符抽取整个数据库。由于查询走count(),可利用comment_author_email='...' OR (IF(BIT, SLEEP(5), 0)) #型盲注按位提取。最终可拖出wp_users.user_pass(PHPass 密码哈希)与全站内容/配置。 - 内容绕过("回复可见"失效):
Cookie: comment_author_email_<hash>' OR 1=1 #→c > 0恒真,隐藏内容直接可见。
修复: 使用 $wpdb->prepare():
$query = $wpdb->prepare(
"SELECT count(comment_ID) as c FROM {$wpdb->comments} WHERE comment_post_ID=%d and comment_approved='1' and comment_author_email=%s LIMIT 1",
$post_id, $email
);
🟠 S-02 [High] inc/go.php 反射型 XSS + 开放重定向(未认证)
位置: inc/go.php:5-8,26,40
$url = $_GET['to'] ?? '';
$name = $_GET['name'] ?? '';
if (!empty($name)) { $name = base64_decode(str_replace(' ','+',$name)); }
...
<?php echo empty($name) ? $url : $name; ?> <!-- :26/:40 原样输出 -->
成因: 跳转页 inc/go.php 直接 require wp-blog-header.php 渲染完整页面。name 参数经 base64 解码后原样 echo;url 经 htmlentities 处理故属性注入被阻断,但 name 无任何处理。
攻击:
/inc/go.php?name=PHNjcmlwdD5hbGVydChkb2N1bWVudC5jb29raWUpPC9zY3JpcHQ+
(即 base64('<script>alert(document.cookie)</script>'))。管理员等任意用户点击即可窃取会话 Cookie。同一页面 to 参数允许任意 http(s) 跳转,构成开放重定向(钓鱼跳转)。
修复: echo esc_html($name);对 to 使用 wp_safe_redirect。
🟠 S-03 [High] inc/favicon.php:98 反射型 XSS(未认证)
位置: inc/favicon.php:89-99
$url = @$_GET['url'];
...
$exists = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(1) FROM $wpdb->links WHERE link_url LIKE %s", '%' . $wpdb->esc_like( $url ) . '%') );
if(!$exists){
die('invalid url: '.$url); // ← 原样输出,PHP 默认 text/html
}
攻击: /wp-content/themes/puock/inc/favicon.php?url="><script>alert(document.cookie)</script>(URL 未命中友链表时直接执行)。
修复: die(esc_html('invalid url: '.$url))。
🟠 S-04 [High] 存储型 XSS(评论者昵称/网址,全站读者墙与最新评论组件)
位置: pages/template-reads.php:32/35/36、inc/fun/widget.php:472,544
// template-reads.php 读者墙
href="<?php echo $use_theme_link_forward ? pk_go_link($read->url) : $read->url; ?>"
title="<?php echo $read->name?>" alt="<?php echo $read->name?>"
<span class="t-sm">…<?php echo $read->name?></span>
// widget.php:472 读者墙 / :544 最新评论
<img … alt="<?php echo $author->name?>">
<img … alt="<?php echo $comment->comment_author ?>">
成因: comment_author(评论者昵称)经 WP wp_filter_kses 只剥标签但保留双引号;comment_author_url 保存时不做 URL 过滤。数据源为未认证评论者,输出组件为全站通用(首页/正文/侧边栏),危害面大。
攻击 1(属性注入): 昵称填 x" onmouseover="alert(document.cookie) → alt="x" onmouseover="alert(document.cookie)",任意访客悬停头像即触发。
攻击 2(javascript: URL): 当后台关闭"评论者链接跳转页"时,评论网址填 javascript:alert(document.cookie),点击昵称链接即执行。
修复: esc_attr($read->name) / esc_attr($author->name) / esc_url($read->url)。
🟡 S-05 [Medium] 存储型 XSS(文章 SEO 元数据,作者级)
位置: inc/seo.php:6-9,22-25(配合 inc/classes/meta/PuockAbsMeta.php:61-79 baseSaveData 仅校验 nonce、对 $_POST 不做任何过滤直接 update_post_meta)
<meta name="keywords" content="<?php echo trim($single_seo_keywords); ?>"/>
<meta name="description" content="<?php echo trim($single_seo_desc); ?>"/>
攻击: 作者在文章"SEO 设置"填 "><script>alert(document.cookie)</script> → 文章页 <head> 中直接执行,所有访客(含管理员)中招。此元框对 Authors 开放。
修复: esc_attr(trim($single_seo_keywords));PuockAbsMeta::baseSaveData 增加 sanitize。
🟡 S-06 [Medium] 存储型 XSS(短代码参数,作者级)
位置: inc/fun/short-code.php
:143-144pk_sc_videoDPlayer 分支把$url/$type拼入<script>:url: '{$url}',。直接 JS 注入(视频警告:播放链接不能为空dplayer选项开启时)。:151非 DPlayer 分支<video src="$url">属性逃逸。:163pk_musicsrc="'.trim($content).'"。:178-181pk_download的$filename/$size/$content原样。:59,67sc_tips的$icon(class 属性)/$content原样。:296-298pk_sc_collapse的$title/$content原样。:307pk_sc_githubdata-repo="'. $content .'"属性逃逸。
成因: 短代码属性在 the_content 渲染时不会经过 kses 过滤(作者输入直接入库),任意访客打开含恶意短代码的文章页即触发。短代码参数本身无 < 时还可绕过编辑器过滤。
修复: 统一 esc_attr/esc_html 输出;pk_sc_video 的 JS 串改用 json_encode 嵌入。
🟡 S-07 [Medium] 存储型 XSS(文章标题/转载出处,作者级)
位置: inc/ajax/page-poster.php:28,31,104、inc/fun/widget.php:163-196(comment_post_output)、single.php:122/124
// page-poster.php:31 <img class="qrcode" src="…" alt="<?php echo $title ?>">
// page-poster.php:104 $root.html("<img … alt='<?php echo $title ?>'>"); // JS 单引号串
// single.php:122 href="<?php echo get_post_meta(get_the_ID(), 'origin_url', true) ?>"
// single.php:124 echo $origin_author
成因: WP 保存文章标题仅 wp_strip_all_tags(去标签保留引号)。作者可建标题 x" onmouseover="alert(document.cookie)(或 x' onerror='… 命中 :104 的 JS 单引号串)触发海报生成/侧栏文章组件属性注入。origin_url/origin_author 转载出处 meta 同样作者可控、原样输出(origin_url 可填 javascript:)。
修复: 属性上下文 esc_attr($title);page-poster.php:104 JS 串改用 esc_js + 引号转义;esc_url/esc_html 处理转载出处。
🟡 S-08 [Medium] 存储型 XSS(用户资料字段,注册用户级)
位置: inc/seo.php:52、author.php:16-17、functions.php:456,543
<meta name="description" content="<?php echo the_author_meta('description') ?>"/>
<?php the_author_meta('display_name') ?> ...
… >' . get_the_author_meta('nickname') . '</li>'; // 面包屑
$pk_title .= sprintf(__('作者:%s', PUOCK), get_the_author()) …; // <title>
成因: WP 用户资料 description/display_name/nickname 保存时不过滤 HTML。任一注册用户可设 "><script>…,其作者归档页(<meta>、正文、面包屑、<title>)直接执行(需该用户有至少 1 篇已发布文章)。
修复: esc_attr/esc_html 输出;<title> 内做 </title> 防护 + esc_html。
🟡 S-09 [Medium] 海报端点未授权 IDOR + 反射 XSS(未认证,默认关闭)
位置: inc/ajax/page-poster.php:3-40
if (pk_is_checked('post_poster_open')) { pk_ajax_register('pk_poster', 'pk_poster_page_callback', true); } // true = nopriv
function pk_poster_page_callback() {
$id = $_REQUEST['id'];
...
$post = get_post($id); // ← 不校验 post_status
if (empty($post)) { wp_die(sprintf(__('无效的文章ID: %s', PUOCK), $id)); } // ← 反射 XSS
setup_postdata($post);
$title = get_the_title($post); // ← 草稿/私有/未来文章标题/摘要/首图/链接泄露
...
IDOR: get_post($id) 不按 post_status 过滤,未认证者可 admin-ajax.php?action=pk_poster&id=<草稿/私有文章ID> 读取其标题、摘要、首图、正文链接。
反射 XSS: $id 为非空恶意值时(如 <script>)get_post 返回 null → wp_die 按 text/html 原样回显 $id。
默认
post_poster_open=false,需管理员开启后才暴露。另注意dialog-post-share.php:6-8的同类写法用$_REQUEST['id'] ?? 0+empty()前置判断,恶意输入不回显,不构成 XSS(已核实排除)。
修复: get_post($id) 后校验 $post->post_status === 'publish' 且 current_user_can('read_post', ...);wp_die(sprintf(..., esc_html($id)))。
🟡 S-10 [Medium] 主题配置 AJAX CSRF(无 nonce)
位置: inc/fun/ajax.php:46-112
function pk_ajax_update_theme_options() {
if (current_user_can('edit_theme_options')) {
$body = pk_ajax_get_req_body();
update_option(PUOCK_OPT, $body);
do_action('pk_option_updated', $body); // ← 触发 .tas.php 等联动
flush_rewrite_rules();
wp_send_json_success();
update_theme_options / reset_theme_options / get_theme_options 三个端点只校验权限、无 check_ajax_referer。攻击者可诱导已登录管理员访问恶意页面,以管理员身份发送 POST,清空/篡改整份主题配置(SMTP、OAuth、AI、百度推送等密钥被覆盖为攻击者值),并联动 pk_option_updated 触发缩略图白名单文件重写(见 S-20)。
缓解: 现代浏览器 SameSite=Lax 会阻止跨站 POST 携带认证 Cookie,实际利用受限;但缺少 nonce 属于明确的纵深缺口,且其他同站 XSS(S-02/S-03)可被用来在此处放大为配置篡改。
修复: 三个端点均加 check_ajax_referer('pk_theme_options', ...)。
🟡 S-11 [Medium] timthumb.php SSRF(重定向跟随绕过白名单,配置依赖)
位置: timthumb.php:263-279(白名单校验)、:1063-1095(serveExternalImage)、:1331-1371(getURL)
// 白名单仅校验初始 URL 的主机(parse_url 字符串比较)
foreach ($ALLOWED_SITES as $site) {
if ((strtolower(substr($this->url['host'], -strlen($site) - 1)) === strtolower(".$site")) || …) { … }
}
// 抓取时跟随重定向到任意主机,不再校验
@curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
@curl_setopt($curl, CURLOPT_MAXREDIRS, 10);
curl_exec($curl);
成因: 主机白名单在构造函数里对初始 URL 只做一次校验;随后 curl 以 FOLLOWLOCATION=true 抓取,重定向的每一跳不再校验主机/IP。CURLOPT_SSL_VERIFYPEER=false、无 CURLOPT_PROTOCOLS 限制。白名单匹配为后缀匹配(endswith ".$site"),a.evil-blog.example.com 可命中 example.com 白名单。
攻击: 未认证访客访问 timthumb.php?src=http://<白名单域名>/<开放重定向路径>。thumbnail_allows 常见填入 github.io/jsdelivr/CDN/图床等域名——其中不少是攻击者可托管并制造 302 的域名。令白名单域名 302 到 http://169.254.169.254/latest/meta-data/、http://127.0.0.1:<端口> 或内网服务:返回 image/* 的响应会经 GD 处理后落入缓存并回显,非 image 响应形成盲 SSRF(可探测内网端口)。
前置条件: 默认 thumbnail_allows=''(OptionGlobal.php:254-257),外部抓取被完全拦截 → 默认不可利用,配置后可用。
修复: 禁 CURLOPT_FOLLOWLOCATION,手动循环跟随并对每一跳重新做主机/IP 校验;追加 IP 层拦截(回环/私网/链路本地/保留段/云元数据网段),拒绝 DNS rebinding;限制 CURLOPT_PROTOCOLS 仅 http/https。
🟡 S-12 [Medium] favicon.php SSRF(重定向跟随 + DNS rebinding)
位置: inc/favicon.php:15-34
$resolved_ip = gethostbyname($host); // 只解析一次(仅 IPv4)
if ($resolved_ip === $host || filter_var($resolved_ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | …) === false) { … }
$ch = curl_init($url . '/' . $basename); // curl 再次独立解析
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
成因: 内网防护只对初始 host 做一次 gethostbyname:
- 重定向绕过:
FOLLOWLOCATION=true,Location可指向169.254.169.254/127.0.0.1/内网,重定向目标不校验。 - DNS rebinding:
gethostbyname与curl两次独立解析,攻击者可在检查时返回公网 IP、在 curl 解析时返回内网 IP。
前置条件: $_GET['url'] 必须是 wp_links 表某 link_url 的子串——利用友链表中任一存在开放重定向的域名,或攻击者自己的友链域名(DNS 可控)。内网返回 image/* 时内容会写入公开可访问的 cache/icon-<md5(url)>.ico(pk_favicon_get_ico_contents 直接 301 到该缓存),否则盲 SSRF。
修复: 手动跟随重定向并对每一跳重新做解析+私网/回环校验;统一解析一次并绑定连接(防 rebinding);对 CURLINFO_CONTENT_TYPE 与文件头二次校验后再落盘/回显。
🟢 S-13 [Low] timthumb 错误信息泄露
位置: timthumb.php:1077,1086,470-472
$this->error("The remote file is not a valid image. Mimetype = '" . $mimeType . "'" . $tempfile); // 拼接临时文件绝对路径
echo '<br />Query String : ' . htmlentities($_SERVER['QUERY_STRING'], ENT_QUOTES);
DISPLAY_ERROR_MESSAGES 默认 true,未认证访客可触发:错误页泄露 curl 错误、远端响应 MIME、cache/thumbnail/ 内 tempnam() 生成的临时文件绝对路径及完整 QUERY_STRING,辅助内网指纹识别。修复:生产环境置 DISPLAY_ERROR_MESSAGES=false。
🟢 S-14 [Low] 登录接口邮箱枚举
inc/ajax/page-front-login.php:145 对不存在的邮箱返回 "不存在该邮箱的用户"(区别于"密码错误"),未认证可遍历枚举注册邮箱。修复:统一错误文案。
🟢 S-15 [Low] OAuth 解绑 GET CSRF
inc/oauth/oauth.php:196-209 pk_oauth_clear_bind 为 GET 端点、无 nonce,未认证可诱导已登录用户访问以解除其 OAuth 绑定(配合 pk_oauth_clear_bind2 才有 nonce)。修复:改为 POST + nonce。
🟢 S-16 [Low] 个人资料更新 CSRF
inc/classes/PuockUserCenter.php:45-72 update_profile 无 nonce 校验(有 esc_html 过滤、ID 强制为当前用户,故仅数据篡改无提权)。修复:加 check_ajax_referer。
🟢 S-17 [Low] error.php 会话信息未转义
error.php:24 $_SESSION['error_info'] 原样 echo。当前赋值方均为静态/主题文案,暂无直接可控输入,属纵深缺口。修复:esc_html。
🟢 S-18 [Low] AI 对话无频率限制
inc/ajax/ai.php AI 聊天接口未做速率限制,未认证访客可批量消耗上游 API 配额/费用。修复:限流 + 登录要求。
🟢 S-19 [Low] 特权评论内容 img 白名单放行事件属性
inc/fun/widget.php:547 最新评论组件 strip_tags(convert_smilies($comment->comment_content), ['img']) 保留整张 <img> 及其事件属性。普通评论被 wp_filter_kses 剥掉 <img>,但拥有 unfiltered_html 的编辑/管理员发表 <img src=x onerror=alert(1)> 会在全站最新评论组件执行。修复:改用 wp_kses 属性白名单。
⚪ S-20 [Info] 选项写入 .tas.php 的代码注入(管理员级,非提权)
位置: inc/fun/core.php:1137-1148
$template = "<?php \$ALLOWED_SITES = [\n";
foreach ($sites as $site) { $template .= "\t\"$site\",\n"; } // $site 原样拼入
file_put_contents(pk_get_thumbnail_allow_sites_filepath(), $template);
thumbnail_allows 若含 "; phpinfo(); // 会使生成的 .tas.php(timthumb 启动时 require)执行注入代码。该文件仅由 edit_theme_options 权限写入,管理员本可编辑主题文件获得同等能力 → 不构成提权;但结合 S-10(无 nonce CSRF)在无 SameSite 保护的浏览器上可被外部触发。建议:对 $site 做白名单字符校验(preg_match('/^[a-zA-Z0-9\.\-]+$/'))。
三、已排查并确认安全/修复正确的点(重要)
以下为本次审计中重点排查后确认无误的项,避免误报:
| 检查项 | 结论 |
|---|---|
| 反序列化 / 对象注入 | 主题自有代码无 unserialize()/__destruct gadget,vendor/yurunsoft OAuth 库同样无。不存在反序列化利用面。 |
| 命令执行 / RCE | 主题代码无 system/exec/passthru;timthumb serveWebshot 的反引号执行被 WEBSHOT_ENABLED(默认 false)严格门控。未发现 RCE 链。 |
| OAuth 登录 CSRF / 账号接管 | vendor/yurunsoft/yurun-oauth-login/src/Base.php:168-190,212-220 与 inc/oauth/RainbowOAuth.php:63-69 的 checkState 均对 $_GET['state'] 与 session 存储值做严格 === 比较,state 注入/登录劫持被阻断。回调统一 wp_safe_redirect,无开放重定向。 |
| 评论写入 SQL | 评论相关查询均用 $wpdb->prepare('%d/%s') 预处理。 |
| IP 溯源 | inc/fun/opt.php:567-570 pk_get_client_ip() 仅用 $_SERVER['REMOTE_ADDR'],不可伪造 → 登录限流有效。 |
| timthumb 缓存投毒 / RCE 链 | 缓存文件名 = md5(不可预测salt + 排序QUERY_STRING + version);写入内容带 <?php die('Execution denied!'); // 前缀;processImageAndWriteToCache 强制 getimagesize MIME ∈ {gif/jpg/jpeg/png/webp/avif}。CVE-2011-4106/4107 链不成立。 |
| timthumb 任意文件读取 | getLocalImagePath(:921-988)自定义 realpath() + stripos($real,$docRoot)===0 双重约束阻断 ../ 越出文档根;file:// 协议被 ^https?:// 判定拒绝。 |
| 硬编码凭据 | 全主题多轮 grep(password/secret/api_key/appkey/client_secret/sk-/Bearer/高熵字面量)无命中;SMTP/Turnstile/极验/OpenAI/OAuth 密钥均读取自后台选项 pk_get_option()。 |
| favicon 友链 SQL | favicon.php:95 用 $wpdb->prepare + esc_like,无注入。 |
| 搜索词反射 | functions.php:453,533 面包屑/SEO 标题均已 esc_html。 |
| 核心模板输出 | header/footer/search/category/tag/404/page 及文章标题/摘要/正文/评论均使用 WP 转义函数(the_title/the_excerpt/the_content/comment_text)。 |
| UA 输出 | comment.php:84-85 浏览器/系统输出经 parse_user_agent 正则约束为 [0-9A-Za-z.\-],不可注入。 |
| dialog-post-share 反射 XSS | 已核实 $_REQUEST['id'] ?? 0 + empty() 前置,恶意输入不回显(仅回显 0/空),排除。 |
| 分页/二维码/邮箱通知/更新检查 | page-load-more 的 paged 经 intval;二维码文件名 md5(url) 无路径穿越;邮件通知收件人为库内已验证邮箱;更新元数据 URL 硬编码 GitHub/licoy.cn 非用户可控。 |
四、修复优先级建议
P0(立即,1 天内)
S-01短代码 SQL 注入 →$wpdb->prepare()。(只需 1 处修改即可封死未认证拖库)
P1(1 周内)
2. S-02 go.php 反射 XSS → esc_html($name);S-03 favicon.php → esc_html($url)。
3. S-04 评论者昵称/网址输出 → esc_attr/esc_url(读者墙 + 最新评论组件)。
4. S-10 主题配置端点补 nonce。
P2(1 个月内)
5. S-05/06/07/08 各作者级存储 XSS → 补齐 esc_attr/esc_html/esc_url/esc_js 输出转义;PuockAbsMeta::baseSaveData 增加 sanitize。
6. S-11/12 timthumb/favicon SSRF → 重写重定向处理 + IP 层拦截。
7. S-09 海报端点补 post_status 校验(即使默认关闭也应修复)。
P3(纵深加固)
8. S-13~S-19 错误信息、枚举、CSRF、限流、img 白名单等按列表逐项处理。
本报告基于静态代码审计 + PHP CLI 行为验证,全部为只读分析,未对文件做任何修改。