ARTICLE / 安全

CVE-2021-3711: OpenSSL SM2 解密缓冲区溢出漏洞分析

0x00 漏洞背景与详情

  • 漏洞名称:OpenSSL SM2 解密缓冲区溢出漏洞
  • CVE 编号:CVE-2021-3711
  • 影响组件:OpenSSL
  • 影响版本:OpenSSL 1.1.1 - 1.1.1k
  • 漏洞等级:高危 (CVSS 3.1 评分: 8.8)
  • 核心风险:远程代码执行 (RCE)、拒绝服务 (DoS)

该漏洞源于 OpenSSL 在实现 SM2 (中国国家商用密码算法) 解密逻辑时,对输出缓冲区大小的计算存在缺陷。攻击者可通过发送特制的畸形 SM2 密文,导致堆缓冲区溢出,进而造成服务崩溃或潜在的远程代码执行。

0x01 漏洞原理分析

在 SM2 解密过程中,应用程序通常会调用两次 EVP_PKEY_decrypt 函数:

  1. 第一次调用:传入 NULL 作为输出缓冲区,函数返回解密后明文所需的字节数(outlen)。
  2. 第二次调用:应用程序根据 outlen 分配堆内存,并再次调用函数进行实际的解密操作。

漏洞根源: 位于 crypto/sm2/sm2_pmeth.c 中的 pkey_sm2_decrypt 函数在预估“所需长度”时,使用了错误的逻辑。当攻击者构造畸形的 ASN.1 编码密文时,该函数返回的长度会小于实际解密后写入的数据长度。在第二次调用实际解密并写入数据时,就会向过小的缓冲区中写入超出其容量的数据,从而触发堆缓冲区溢出。

0x02 漏洞 POC 与高级利用姿势

POC 逻辑示意

触发该漏洞的关键在于构造一个“长度声明与实际内容不符”的恶意 SM2 密文。

构造步骤:

  1. 获取一个有效的 SM2 公钥。
  2. 生成一个标准的 SM2 密文,并将其封装为 ASN.1 格式。
  3. 篡改 ASN.1 结构中的长度字段,使其在 OpenSSL 进行长度预估时返回一个较小值(如 10 字节),但实际密文解密后会产生更多字节(如 100 字节)。
  4. 调用 EVP_PKEY_decrypt 触发溢出。

原理示意 (C语言):

// 1. 初始化上下文并加载恶意密文 'malicious_ciphertext'
EVP_PKEY_decrypt_init(ctx);

// 2. 漏洞导致 outlen 返回的值比实际需要的少
EVP_PKEY_decrypt(ctx, NULL, &outlen, malicious_ciphertext, ciphertext_len); 

// 3. 应用程序分配了不足够的内存 (L_small)
unsigned char *out = malloc(outlen); 

// 4. 执行解密,向 out 写入过量数据 (L_large),发生堆溢出
EVP_PKEY_decrypt(ctx, out, &outlen, malicious_ciphertext, ciphertext_len); 

堆内存布局与 RCE 利用思路

由于 OpenSSL 广泛应用于高性能服务端,直接通过堆溢出实现 RCE 具有挑战性,但理论上可通过以下高级思路达成:

  1. 堆风水 (Heap Feng Shui):
    • 攻击者通过发送大量 TLS 扩展数据或证书,在堆上“喷射”(Spray)目标对象(如 OpenSSL 的 BIO 或 EVP_PKEY 结构体)。
    • 利用连接关闭产生的“孔洞”精确定位恶意 SM2 密文的分配位置,使得 out 缓冲区紧邻目标敏感结构。
  2. 劫持 BIO 结构体控制流:
    • BIO 结构体包含一个指向 BIO_METHOD 的指针,而 BIO_METHOD 内部包含 bread、bwrite 等函数指针。
    • 通过溢出覆盖相邻 BIO 的 method 指针,使其指向攻击者在堆中控制的伪造 BIO_METHOD 结构。
    • 当服务端尝试对该 BIO 进行读写操作时,程序便会跳转到伪造结构中定义的恶意地址,结合 ROP(返回导向编程)绕过 DEP/ASLR,最终执行 Shellcode。

实战场景与崩溃分析 (Crash Analysis)

  • 国密 SSL/TLS 握手拒绝服务 (DoS):
    • 在支持国密 TLS(如基于 OpenSSL 1.1.1 的定制版)的 Web 服务器中,攻击者在握手阶段发送畸形的 ClientKeyExchange 数据包即可触发堆溢出。
    • 崩溃现象:由于覆盖了相邻堆块的元数据(如 size 字段),往往会在随后调用 free() 时触发 glibc 的完整性检查,报错 double free or corruption 并导致服务崩溃(SIGABRT)。
  • 加密机/安全网关横向移动:
    • 许多硬件安全模块 (HSM) 提供 SM2 加解密接口。若后端处理逻辑未及时修补 OpenSSL,内部网络中的攻击者可通过批量构造畸形 API 请求,尝试稳定内存布局,最终实现内网横向控制。

0x03 应急排查与日志痕迹分析建议

1. 漏洞环境排查

  • 版本检测:执行 openssl version。
    • 风险版本:1.1.1 至 1.1.1k。
    • 安全版本:1.1.1l 及以上,或 3.0.0 及以上。
  • 应用检查:确认业务系统是否开启了国密套件支持,或是否调用了 SM2 加解密相关接口。

2. 日志痕迹分析

  • 系统日志:查看内核日志(dmesg / /var/log/syslog),寻找包含 segfault、libcrypto.so.1.1 相关的内存段错误记录。
  • Core Dump 分析:如果服务崩溃,提取 Core Dump 文件通过 gdb 查看崩溃时的调用栈。如果崩溃点位于 sm2_decrypt 或相关的 SM2 解析函数中,基本可确认遭到攻击。
  • 网络流量监测:关注 TLS 握手包中异常大的 ClientKeyExchange 数据包,或不符合规范的 ASN.1 编码密文。

0x04 修复与缓解建议

  1. 升级版本(最有效):将 OpenSSL 升级到官方发布的修复版本 1.1.1l 或更新版本。
  2. 禁用 SM2/国密算法:如果在业务场景中并非强制要求使用国密算法,可以通过配置 TLS 密码套件暂时禁用 SM2。

0x05 参考资料