FlawOpen

flawopen.com/Incidents/moveit-transfer-sql-injection-may-2023

● Progress Software · CVE-2023-34362 · May 2023 · CVSS 9.8 · 严重
安全研究 · FlawOpen

MOVEit Transfer:SQL 注入与大规模数据窃取

CVE-2023-34362 是 MOVEit Transfer 中可被未认证利用的 SQL 注入漏洞。Mandiant 观察到攻击自 2023 年 5 月 27 日开始,随后出现 LEMURLOOT Web Shell 和数据窃取。[4], [3]

💡 通俗易懂的原理解析 (ELI5)

想象一个表单有“文件夹编号”字段,但工作人员把字段内容直接复制进发送给归档系统的指令。如果字段内容能改变指令,而不只是指定文件夹,填写者就可能让系统执行超出预期的操作。SQL 注入跨越的也是这条边界:不可信输入被当作 SQL 语法,而不是普通值。[5]

核心概念与专有名词

SQL 注入(CWE-89)
被拼接进数据库查询的输入改变了查询本身的行为,而不是被当作一个值来处理。[5]
托管文件传输(MFT)
机构用来与合作伙伴交换大型或敏感文件的软件。一台服务器可能存有许多机构的数据。[3]
Web Shell
攻击者植入 Web 服务器以维持访问的脚本。Mandiant 将本次使用的命名为 LEMURLOOT。[3]
参数化查询
把值与查询文本分开发送的查询方式,数据库因此永远不会把数据当作 SQL 解析。[5]
受影响与已修复版本
Progress 指出,各分支中早于 2021.0.6、2021.1.4、2022.0.4、2022.1.5 和 2023.0.1 的版本受影响;上述版本包含修复。请根据 Progress 公告确认所用分支和当前升级路径。[1]

框架映射

事件演进时间线

2023-05-27

Mandiant 报告称,其观察到的 MOVEit Transfer 最早利用迹象出现在 2023 年 5 月 27 日。[3]

2023-05-31

Progress 公开漏洞,并敦促客户在打补丁前切断 HTTP 和 HTTPS 流量。[1]

2023-06-02

CISA 将 CVE-2023-34362 列入已知被利用漏洞目录。[9]

2023-06-07

CISA 与 FBI 发布联合通报 AA23-158A,将该活动描述为 CL0P 勒索软件团伙的行动。Mandiant 后来根据多项重合线索更新归因,将 UNC4857 并入 FIN11。[2], [3]

攻击执行流程分解

步骤 1

未经认证的请求

Mandiant 观察到,在 LEMURLOOT 出现前,攻击者向 MOVEit Transfer 的 guestaccess.aspx 发送了经过构造的 POST 请求;该活动不需要正常用户登录。[3]

步骤 2

输入改变查询含义

请求到达了存在缺陷的 SQL 操作。CISA 将该漏洞描述为允许未认证访问数据库;根据所用数据库引擎,攻击者还可能推断信息或更改、删除数据。[2], [5]

步骤 3

植入 Web Shell

漏洞遭利用后,Mandiant 观察到 LEMURLOOT Web Shell。它可枚举并获取文件,也可操作特定应用用户;现有来源并未证明攻击者获得了泛化的管理员控制权。[3]

步骤 4

文件被批量窃取

Mandiant 观察到大规模文件窃取。CISA 与 FBI 将更广泛的活动描述为 CL0P 勒索软件团伙的行动;Mandiant 后续更新的归因则将其与 FIN11 联系起来。[2], [3]

源代码对比:漏洞与安全实现

这是示意性的 C# 代码,并非 MOVEit 源代码。加固后的方法先把标识符解析为该列实际存储的类型,拒绝其他输入,再以带类型的参数发送,因此该值不会成为 SQL 文本的一部分。两项控制中任意一项都能单独阻止这次注入;结合使用还会在执行查询前拒绝格式错误的标识符。[5]

存在漏洞的实现
using System.Data.SqlClient;

public static class FolderLookup
{
    public static SqlDataReader Find(SqlConnection conn, string folderId)
    {
        // 查询文本与请求数据被拼接,因此数据库
        // 无法判断开发者希望将哪一部分视为数据。
        string sql = "SELECT id, name FROM folders WHERE id = '" + folderId + "'";
        var cmd = new SqlCommand(sql, conn);
        return cmd.ExecuteReader();
    }
}
加固后的安全修复
using System;
using System.Data;
using System.Data.SqlClient;

public static class FolderLookup
{
    public static SqlDataReader Find(SqlConnection conn, string folderId)
    {
        if (!long.TryParse(folderId, out long id) || id <= 0)
            throw new ArgumentException("folderId must be a positive integer");

        // 该值作为带类型的参数单独传递,与查询文本分开。
        var cmd = new SqlCommand("SELECT id, name FROM folders WHERE id = @id", conn);
        cmd.Parameters.Add("@id", SqlDbType.BigInt).Value = id;
        return cmd.ExecuteReader();
    }
}

工程与系统安全加固清单

参考来源