检测不良OpenSSL使用模式 - Anselm工具深度解析

本文详细介绍了Anselm工具如何通过LLVM中间代码分析来检测OpenSSL API的误用模式,包括函数调用顺序检查、上下文值匹配等关键技术实现原理。

检测不良OpenSSL使用模式

OpenSSL是最流行的密码学库之一,即便您不使用C/C++,您所用编程语言的核心库很可能也包含OpenSSL绑定。由于其底层API的设计特点,这个库极易被误用。幸运的是,许多错误都遵循可识别的模式,这为自动化检测提供了可能。

在冬季和春季的实习期间,我开发了名为Anselm的工具原型。这是一个LLVM编译中间层分析工具,能够识别开发者定义的不良行为模式。与静态分析相比,Anselm的优势在于它能处理任何可编译为LLVM字节码的语言,或任何可逆向为机器码的闭源代码。

OpenSSL的挑战

OpenSSL的设计对初学者极不友好:其库中存在不一致的命名规范,为每个加密原语提供过多选项和模式。例如同时存在高级(EVP)和低级方法来完成相同任务(如DSA签名或EC签名操作)。更糟的是,其文档也常常不一致且难以理解。

该API的危险性还体现在:不一致地返回错误码、指针(含所有权和不含所有权)以及其他意外行为。若不严格检查错误码或防范空指针,就会导致程序异常终止。

函数调用分析

Anselm的核心方法是遍历函数中所有可能的执行路径,寻找不良的API调用序列。以对称加密函数为例,EVP_EncryptUpdate(加密数据块)和EVP_EncryptFinal_ex(最终加密前填充明文)不应乱序调用:

1
2
3
EVP_EncryptFinal_ex(ctx, ciphertext + len, &len);
...
EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len);

工具使用LLVM BasicBlocks(代表一组总是顺序执行的指令)构建函数调用图,通过带限制的深度优先搜索(DFS)来发现所有可能的执行路径。为提升性能,会先剪除不含相关API调用的BasicBlock,这能显著降低图复杂度。

值匹配技术

仅检查函数调用还不够。考虑OpenSSL上下文的使用场景:通过EVP_CIPHER_CTX_new创建后,必须用算法、密钥等初始化才能使用。Anselm通过匹配LLVM Value对象来实现精确检测:

1
2
3
4
EVP_CIPHER_CTX_new ctx1;
EVP_CIPHER_CTX_new ctx2; 
EVP_EncryptInit_ex(ctx1, EVP_aes_256_cbc(), NULL, key, iv); 
// ctx2未被初始化

该技术同样可检测重复初始化向量(IV)的使用:

1
2
EVP_EncryptInit_ex(ctx1, EVP_aes_256_cbc(), NULL, key1, iv);
EVP_EncryptInit_ex(ctx2, EVP_aes_256_cbc(), NULL, key2, iv);  // 重复使用iv

模式定义语法

我开发了专门的模式定义语言,开发者可通过正则表达式风格的语法指定不良行为模式。例如禁止重复IV的规则:

1
2
EVP_EncryptInit_ex _ _ _ _ _ iv
EVP_EncryptInit_ex _ _ _ _ _ iv

还支持否定前瞻语法,例如要求上下文必须初始化后才能使用:

1
2
3
EVP_CIPHER_CTX_new ctx
! EVP_EncryptInit_ex _ ctx _ _ _ _
EVP_EncryptUpdate _ ctx _ _ _ _

总结

Anselm当前已能解析广泛的函数调用模式并在LLVM字节码中搜索它们。虽然仍是原型,但核心思路已经验证可行。感谢Trail of Bits支持这类实习项目——整个过程充满乐趣!

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计