编辑推荐: |
本文来自于jianshu,
本文通过介绍在python开发中经常出现的常规web漏洞,然后通过静态和动态两种方式对python代码进行自动化审计挖掘漏洞,并且展示自动化系统在自动化审计python应用代码的成果。 |
|
从python常规漏洞来看都有一个共同点,那就是危险函数中使用了可控参数,
如system函数中使用到的(‘mv %s’% filename),
如execute函数中使用到的username参数,
如HttpResponse中使用到的nickname参数,
这些参数直接从第一层入口函数中传进来,或者经过简单的编码,截断等处理直接进入危险函数,导致了以上危险行为。
静态分析的核心是什么?
注入判断的核心就在于找到危险函数,并且判断其参数是可控的,找到危险函数这个只需要维护一个危险函数列表即可。
当在语法树中发现了函数调用并且其名称在危险列表中就可以标记出该行代码,接下来的难点就在于跟踪该函数的参数,默认认为该危险函数的外层函数的参数是可控的,那就只需要分析这个外层函数参数的传递过程即可
在python中,参数的处理过程大概总结如下这些情况:
直接赋值:GET参数直接赋值
属性赋值:request.POST.get(‘name’)赋值,排除META中的内容
字符串拼接:字符串拼接
列表解析式:
元组、列表、字典数据处理:元素相加,赋值value等
Subscript分片取值:通过下标索引取值
函数调用后赋值:字符串操作的系统函数str,strip,split,encode等,未过滤的自定义函数,危险函数
With操作:
For循环:
If判断:
排除特殊情况:
判断是否合法:os.path.exitst,isdir等
锁定范围:Type in [xxx,xxx]
如果存在此文件中导入了其他非系统模块,继续递归解析此模块文件
如果存在此文件中导入了其他非系统模块,继续递归解析此模块文件
如果存在类的话,继续递归类里面方法的内容
Body的内容是嵌套的,一个body里面可能还有很多个body
循环body体中的元素,然后取出body中的body,orelse,test,handlers元素,继续递归查找可控参数
以行为单位解析出来的结构和内容
Name为被赋值的变量名
然后value里面就是具体的内容
从右往左一次嵌套,所以request在最里层的value
以Python文件为入口,解析成语法树,格式化为json格式
取出语法树中的函数体内容
然后遍历函数体中的代码行:
如果有危险函数调用,并且有可控参数进入此危险函数,则报出漏洞
所以这里的核心就是:
1、递归全部代码查找可控参数,生成可控参数列表
2、维护危险函数列表
最早的版本已经开源,大家可以借鉴,可以阅读代码了解python的语法树
静态分析的缺陷:
漏报误报高
可控参数分析覆盖不够全
外部导入函数对可控参数判断的影响
python 是一种动态类型语言,python 中一切皆对象
所以换句话说每个对象可以在程序里任何地方改变它
这就意味着我们可以劫持我们认为危险的函数
拦截进入函数的参数,判断是否有恶意参数进入,从而判断是否存在漏洞
Python的广泛使用,很大部分是因为开发效率高,模块使用方便
所以就劫持就针对:
1、模块的直接方法
2、模块的类,已经类方法进行了
举例:
模块的方法可以直接被劫持
首先通过imp导入os模块,然后在覆盖到其中的system方法
在调用system方法时,就是这里的__call__方法了
判断进入system方法的参数是否有恶意内容,从而可以判断是否真正触发了漏洞
元类:
元类就是用来创建类的类,函数type实际上是一个元类
元类的主要目的就是为了当创建类时能够自动地改变类。
__metaclass__:
你可以在写一个类的时候为其添加__metaclass__属性, Python就会用它来创建类
__metaclass__可以接受任何可调用的对象,你可以在__metaclass__中放置可以创建一个类的东西
__new__:是用来创建类并返回这个类的实例
__call__:任何类,只需要定义一个__call__()方法,就可以直接对实例进行调用,用callable来判断是否可被调用
__getattribute__:定义了你的属性被访问时的行为
你首先写下class Foo(object),但是类对象Foo还没有在内存中创建。
Python会在类的定义中寻找__metaclass__属性,如果找到了,Python就会用它来创建类Foo,如果没有找到,就会用内建的type来创建这个类
定义test类,使用metaclass来创建tesk类
这时在metaclass中就可以动态修改这个类
这里使用upperattr,在创建test类时,将属性名称全部大写
在test类实例化的时候就会执行上述操作,达到动态修改类的效果
举例:
模块的类的劫持
在当前pythonpath路径下创建socket.py文件
然后劫持_fileobject类,使用_installclshook动态修改此类
变量_fileobject的属性方法时,返回_hook_writelin 和 _hook_readline
写好的劫持脚本,放到当前的工作根目录下即可
然后正常启动项目,劫持脚本就会自动生效,劫持特定的方法
但是内建函数方法,built-in method无法直接覆盖劫持
这时也可以通过monkey path来实现:
Monkey patch就是在运行时修改代码,实现hot patch的一种手段
将patch脚本import到应用里面,在功能函数入口通过装饰器的方式应用patch即可
动态审计的优点:
准确性高
可以平台化
但是使用和扩展需要了解具体模块的结构,pyhton的魔术方法等基础知识
因为需要部署到目标系统代码中,所以动态修改后的类和方法会对系统造成未知的影响,(不过目前测试来看还没出现)
这里这个开源的项目是使用动态hook来制作python后门的例子,可以参考
动态检测和静态检测相结合,相辅相成,相互补助,才能达到更好的效果,最后才能自动化检测
对于,git和svn这种版本控制的,可以不用每次都扫描全部代码,可以根据版本号扫描范围之间的代码,节省资源,速度快
下载agent安装包后,根据右边的部署说明,部署agent到需要检测的服务器上即可
成功部署agent后,会在平台上显示主机是否在线
并且agent会自动hook功能代码入口:
比如django开发的系统,根据url整理views中的方法,然后自动劫持这些方法即可,不用全部劫持,尽量减少对系统代码的改动
用户设置代理,正常访问系统
代理替换参数内容为payload,到系统后,漏洞检测系统自动检测漏洞然后显示信息到控制台
|