代码审计工具 Cobra 源码分析(二)
0x00 前言
几天前发过一篇笔记:代码审计工具 Cobra 源码分析(一),通过pdb动态调试对代码审计工具 Cobra 的执行流程做了一个简要的分析。
在之后的文章中将记录下我对该工具部分代码的分析,可能是一个文件、也可能是一个类或者方法,看到哪里写到哪里吧,纯粹是为了记录。
0x01 分析工具及环境
Pycharm 2017.3.2(Professional Edition)
Notepad++ v7.5.2
Python 2.7.12
0x02 漏扫函数 scan_parser() 分析
scan_parser()是漏洞扫描函数,其主要的功能是对文件中的相应代码做安全审计,原理主要有两点:
1、判断代码中是否存在敏感函数
2、通过回溯传入敏感函数的参数,参数可控,则漏洞存在,反之漏洞不存在
scan_parser() 定义位置:\cobra\parser.py 第667-689行
def scan_parser(code_content, sensitive_func, vul_lineno, repair):
"""
开始检测函数
:param code_content: 要检测的文件内容
:param sensitive_func: 要检测的敏感函数,传入的为函数列表
:param vul_lineno: 漏洞函数所在行号
:param repair: 对应漏洞的修复函数列表
:return:
"""
try:
global repairs
global scan_results
repairs = repair
scan_results = []
parser = make_parser()
all_nodes = parser.parse(code_content, debug=False, lexer=lexer.clone(), tracking=with_line)
for func in sensitive_func: # 循环判断代码中是否存在敏感函数,若存在,递归判断参数是否可控;对文件内容循环判断多次
back_node = []
analysis(all_nodes, func, back_node, int(vul_lineno), function_params=None)
except SyntaxError as e:
logger.warning('[AST] [ERROR]:{e}'.format(e=e))
return scan_results
scan_parser() 漏洞扫描函数回溯调用链:
0、\cobra\parser.py 第667-689行定义scan_parser()函数
1、\cobra\engine.py 第634行 Core类中scan()方法调用scan_parser()函数
2、\cobra\engine.py 第345行 SingleRule类中process()方法调用Core类中scan()方法
3、\cobra\engine.py 第144行 scan_single()函数调用SingleRule类中process()方法
4、\cobra\engine.py 第194行 scan()函数已多进程的方式对scan_single()函数进行调用,并将相应的漏扫结果存储于回调函数store()中(第163-169行定义,其为scan()函数的内置函数)
5、\cobra\cli.py 第91行 start()函数调用scan()函数
6、\cobra\__init__.py 第82行 main()函数调用start()函数
7、\cobra.py 第22行 调用main()函数【此处即为程序入口】
好,既然已经理清楚了函数调用链,现在就可以重点分析scan_parser()函数了。
scan_parser()函数一共有4个参数,结合注释以及我的实际测试,各个参数的内容为:
def scan_parser(code_content, sensitive_func, vul_lineno, repair):
1、code_content 参数:即需要进行漏洞扫描的文件内容,通常为程序启动后遍历目标项目中的每一个文件(在分析时将仅传入一个文件便于理解),参数类型为【字符串类型】
2、sensitive_func 参数:即可能引起漏洞的敏感函数列表,参数类型为【列表类型】
3、vul_lineno 参数:即存在漏洞代码的对应行号,其实叫代码行号会更贴切一些,因为并不是每一行都存在漏洞,参数类型为【unicode字符串】
4、repair 参数:即判断存在漏洞后,给出相应的漏洞修复函数,参数类型为【列表类型】
第681-682行是是该程序的精髓所在,通过【make_parser() 语法分析】、【lexer.clone() 词法分析】对文件中的代码做处理(此处要打个标签,有机会系统的学习下编译原理的知识)。
第685行 调用analysis()函数,跟进,其在610-664行定义。而后该函数又调用了anlysis_function()、analysis_eval()、analysis_echo_print()、analysis_file_inclusion()、analysis_if_else(),对文件内容一行一行处理(在判断语句、循环语句、赋值语句、函数调用、文件包含语句中执行不同的分析函数)。
这里拿其中一个函数的实现方式举例:anlysis_function()函数,在其在340-367行定义。
第352行,判断当前代码是否为敏感函数,若是敏感函数则继续向下跟进,根据参数的不同类型做进一步分析
拿php.Variable节点来说,会进入到该函数,对其是否可可控做进一步分析。
last处理完毕后,将其结果存储在\cobra\engine.py 第634行 Core类中的scan方法内的result变量中。
再继续后续的分析和处理,不是本小结的重点,由于时间关系,有点累了,回家睡觉。之后再继续分析记录。
0x03 后记
Cobra中好多函数、类中的方法同名,不同文件中还有不通功能的同名方法,翻起来实在是有点累~
当然,由于本人对《编译原理》相关的知识掌握的并不牢靠,笔记中有错误再说难免,权当提供一个思路吧。如有谬误,还请不吝赐教。