0x00 Python安全检查引擎
Xcheck的Python分析引擎,能够自动分析Python写的Web应用,检测诸如命令注入、SQL注入、URL跳转、SSRF、XXE等常见的Web安全漏洞。
Python语言的Web框架十分丰富,对于主流的Web框架如Django、Flask、Tornado、Webpy、Bottle等,Xcheck已经内建支持;对于其他Web框架,用户可以基于Xcheck的扩展框架编写自定义规则,简单快速地完成适配。
0x01 Python作者谈Python静态分析
Python语言的作者吉多·范罗苏姆曾经在第九届 Laser Summer School(https://www.laser-foundation.org/) 上分享Python语言设计,其中一个独立的章节是关于他对Python静态分析的想法。原文在这里:http://laser.inf.ethz.ch/2012/slides/vanRossum/laser-stc.pdf
。
为什么Python静态分析这么难?吉多的答案是:
- Python解释器的原因
- Python没有类型标注(3.5版本之后支持,但不是强制)
- Python的动态语言特性
- Python用户偏好写一些奇技淫巧的代码(crazy hacks)
本文重点谈Xcheck静态分析如何处理程序的动态特性。
0x02 一般程序的动态性
工具在静态分析时遇到的最大挑战,即程序的动态性。
所谓动态性,是指程序的行为受运行时外部输入数据的影响。
以下面这个代码片段为例:
这里name
和now
都是运行时才确定的数据,程序实际执行哪个分支是运行时才确定的。
类似这样的“动态性”在程序中无处不在:
- 走哪条分支
- 循环执行多少次
- 取数组哪个下标的数据
- 取Map里哪个key的数据
- 等等
0x03 Python程序的动态性
Python写的程序除了一般程序都有的“动态性”之外,还有语言特性带来的“动态性”,因而给静态分析带来了更大的挑战。
比如(具体的代码示例可以在吉多的材料里找到):
- 模块以怎样的顺序导入,
sys.path.insert(0, ??)
- 存取对象的哪个属性?
setattr(A, ??, x)
- 任意修改某个局部、全局变量?
locals()[??] = 12
- 任意修改内建模块的内容和行为,
__builtins__.len = xxx
- 任意魔改操作符的行为,
def __add__(xx)...
- 等等
以第二条为例简要说明。
当你这么写代码的时候,你要操作对象的哪个属性是静态确定的(名字为foo
的属性):
但是,Python允许开发者这样写代码:
???
是一个变量,是运行时才确定的。
0x04 Xcheck的设计
像Python这样的动态语言特性,为Python开发者提供了遍历,但同时增加了静态分析的难度。
在实践中,静态分析工具往往无法准确理解这类动态特性的代码,尤其是实现动态调用相关功能的时候。
我们在设计Xcheck时就十分理性地考虑到静态分析工具在实践中的局限性。工具是死的,但人是活的。Xcheck更加关注:怎样将人的知识准确简单地“传授”给工具?
因此,我们为Xcheck设计了一套扩展框架,将用户基于Xcheck接口编写的“经验”通过扩展规则传入分析引擎,发挥工具极致的静态分析能力。
0x05 SaltStack漏洞案例
SaltStack是Python语言写的一个分布式运维系统。
SaltStack官方在2020年11月3日发布安全补丁修复了三个漏洞,其中包括一个在未授权的情况下通过salt-api接口执行任意命令的严重漏洞。
经过人工分析,这个漏洞的关键入口在salt/netapi/__init__.py:NetapiClient.run()
方法,其中low
变量的内容是用户可控的(称之为污点)。
注意到,第83行到第85行,是典型的利用Python动态特性编写的代码。
解释器执行这条语句时,根据用户上传数据的client
字段,获取当前NetapiClient
实例的某个方法。静态分析工具在这里无法预测运行时用户上传的数据,因而无法理解l_fun
这个变量所表示的是哪个函数方法,进而导致污点分析中断。
不得不承认,在类似这样的动态特性之下,工具能做的的确不多,因而需要人工经验的帮助。
人工分析得出的经验是什么呢?就是这里low['client']
的取值是有确定可枚举的范围的,即local
、local_async
、 local_batch
、 local_subset
、runner
、 runner_async
、 ssh
、wheel
和 wheel_async
。
通过自定义规则将这个经验”告诉”工具,然后看下会发生什么。
这是Xcheck的自定义规则,通过封装好的接口,十分简洁地“告诉”工具这个经验:
- 如上所述,
salt.netapi.NetapiClient.run
方法中引入了静态分析工具无法理解的动态特性代码,这里X.override
的意思是告诉工具重载这个方法,而这个方法的行为定义在mock_run
函数里 mock_run
方法首先拿到self
变量所引用的对象,即一个NetapiClient
类实例- 定义合法的
client
字段取值 - 取每个合法的
client
值,取self
的属性,即attr = self.get_attr(name)
- 属性应该是个方法,将其kwargs参数设置为污点,然后触发调用,
attr.call()
加上这个规则之后,工具的分析结果如下:
其中就有上面提到的这次SaltStack的任意命令执行漏洞。
这里Xcheck分析出了另外3个命令执行风险,笔者未验证其是否为误报,其sink语句在thin.py
文件,也同样是类似shell.py
中拼接命令的不安全写法,在新版本SaltStack中已经被删除了。
0x06 总结
静态分析工具无法凭借现有的理论和技术手段准确理解动态特性的代码,这是使用静态分析技术导致的必然局限性。Xcheck内建了扩展能力,支持用户以自定义规则的形式“传授”经验和知识给分析引擎,赋能工具,让工具发挥更大的价值。
专注于代码安全 | 公众号:腾讯代码安全检查Xcheck
来源:freebuf.com 2021-05-14 18:02:29 by: Xcheck
请登录后发表评论
注册