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 的 BIOEVP_PKEY 结构体)。
    • 利用连接关闭产生的“孔洞”精确定位恶意 SM2 密文的分配位置,使得 out 缓冲区紧邻目标敏感结构。
  2. 劫持 BIO 结构体控制流
    • BIO 结构体包含一个指向 BIO_METHOD 的指针,而 BIO_METHOD 内部包含 breadbwrite 等函数指针。
    • 通过溢出覆盖相邻 BIOmethod 指针,使其指向攻击者在堆中控制的伪造 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.11.1.1k
    • 安全版本:1.1.1l 及以上,或 3.0.0 及以上。
  • 应用检查:确认业务系统是否开启了国密套件支持,或是否调用了 SM2 加解密相关接口。

2. 日志痕迹分析

  • 系统日志:查看内核日志(dmesg / /var/log/syslog),寻找包含 segfaultlibcrypto.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 参考资料