From 9048f79f620195a8b7cab40468b2bbd8193d78f2 Mon Sep 17 00:00:00 2001 From: LoRexxar Date: Mon, 22 Apr 2019 18:10:50 +0800 Subject: [PATCH 1/6] add parent_node to confirm nodes location --- cobra/export.py | 2 +- cobra/parser.py | 107 +++++++++++++++++++++++++++++------------------- 2 files changed, 65 insertions(+), 44 deletions(-) diff --git a/cobra/export.py b/cobra/export.py index 278a2c62..d5e004c4 100644 --- a/cobra/export.py +++ b/cobra/export.py @@ -92,7 +92,7 @@ def dict_to_csv(vul_list, filename): if not os.path.exists(filename): with open(filename, 'w+', encoding='utf-8', errors='ignore') as f: # 防止在 Excel 中中文显示乱码 - f.write(BOM_UTF8) + # f.write(BOM_UTF8) csv_writer = csv.DictWriter(f, header) csv_writer.writeheader() csv_writer.writerows(vul_list) diff --git a/cobra/parser.py b/cobra/parser.py index 499afb39..c2564a91 100644 --- a/cobra/parser.py +++ b/cobra/parser.py @@ -24,7 +24,7 @@ with_line = True scan_results = [] # 结果存放列表初始化 is_repair_functions = [] # 修复函数初始化 -scan_chain = [] # 回溯链变量 +scan_chain = [] # 回溯链变量 def export(items): @@ -362,7 +362,7 @@ def is_controllable(expr, flag=None): # 获取表达式中的变量,看是否 # return is_co, cp, expr_lineno -def function_back(param, nodes, function_params, vul_function=None, file_path=None, isback=None): # 回溯函数定义位置 +def function_back(param, nodes, function_params, vul_function=None, file_path=None, isback=None, parent_node=None): # 回溯函数定义位置 """ 递归回溯函数定义位置,传入param类型不同 :param isback: @@ -391,7 +391,7 @@ def function_back(param, nodes, function_params, vul_function=None, file_path=No return_param = return_node.node is_co, cp, expr_lineno = parameters_back(return_param, function_nodes, function_params, vul_function=vul_function, file_path=file_path, - isback=isback) + isback=isback, parent_node=parent_node) return is_co, cp, expr_lineno @@ -429,12 +429,13 @@ def array_back(param, nodes, vul_function=None, file_path=None, isback=None): # if is_co != 1: is_co, cp, expr_lineno = array_back(param, nodes, file_path=file_path, - isback=isback) + isback=isback) else: n_node = php.Variable(p_node.value) - is_co, cp, expr_lineno = parameters_back(n_node, nodes, vul_function=vul_function, file_path=file_path, - isback=isback) + is_co, cp, expr_lineno = parameters_back(n_node, nodes, vul_function=vul_function, + file_path=file_path, + isback=isback) if param == param_node: # 处理数组一次性赋值,左值为数组 if isinstance(param_node_expr, php.ArrayOffset): # 如果赋值值仍然是数组,先经过判断在进入递归 @@ -442,21 +443,23 @@ def array_back(param, nodes, vul_function=None, file_path=None, isback=None): # if is_co != 1: is_co, cp, expr_lineno = array_back(param, nodes, file_path=file_path, - isback=isback) + isback=isback) else: is_co, cp = is_controllable(param_node_expr) if is_co != 1 and is_co != -1: n_node = php.Variable(param_node_expr.node.value) - is_co, cp, expr_lineno = parameters_back(n_node, nodes, vul_function=vul_function, file_path=file_path, - isback=isback) + is_co, cp, expr_lineno = parameters_back(n_node, nodes, vul_function=vul_function, + file_path=file_path, + isback=isback) return is_co, cp, expr_lineno -def class_back(param, node, lineno, vul_function=None, file_path=None, isback=None): +def class_back(param, node, lineno, vul_function=None, file_path=None, isback=None, parent_node=None): """ 回溯类中变量 + :param parent_node: :param isback: :param file_path: :param vul_function: @@ -473,8 +476,9 @@ def class_back(param, node, lineno, vul_function=None, file_path=None, isback=No if class_node.lineno < int(lineno): vul_nodes.append(class_node) - is_co, cp, expr_lineno = parameters_back(param, vul_nodes, lineno=lineno, vul_function=vul_function, file_path=file_path, - isback=isback) + is_co, cp, expr_lineno = parameters_back(param, vul_nodes, lineno=lineno, function_flag=1, + vul_function=vul_function, file_path=file_path, + isback=isback, parent_node=parent_node) if is_co == 1 or is_co == -1: # 可控或者不可控,直接返回 return is_co, cp, expr_lineno @@ -486,8 +490,8 @@ def class_back(param, node, lineno, vul_function=None, file_path=None, isback=No # 递归析构函数 is_co, cp, expr_lineno = parameters_back(param, constructs_nodes, function_params=class_node_params, - lineno=lineno, vul_function=vul_function, file_path=file_path, - isback=isback) + lineno=lineno, function_flag=1, vul_function=vul_function, file_path=file_path, + isback=isback) if is_co == 3: # 回溯输入参数 @@ -536,7 +540,7 @@ def new_class_back(param, nodes, vul_function=None, file_path=None, isback=None) return_param = tostring_node.node is_co, cp, expr_lineno = parameters_back(return_param, tostring_nodes, vul_function=vul_function, file_path=file_path, - isback=isback) + isback=isback) return is_co, cp, expr_lineno else: @@ -547,9 +551,11 @@ def new_class_back(param, nodes, vul_function=None, file_path=None, isback=None) def parameters_back(param, nodes, function_params=None, lineno=0, - function_flag=0, vul_function=None, file_path=None, isback=None): # 用来得到回溯过程中的被赋值的变量是否与敏感函数变量相等,param是当前需要跟踪的污点 + function_flag=0, vul_function=None, file_path=None, + isback=None, parent_node=None): # 用来得到回溯过程中的被赋值的变量是否与敏感函数变量相等,param是当前需要跟踪的污点 """ 递归回溯敏感函数的赋值流程,param为跟踪的污点,当找到param来源时-->分析复制表达式-->获取新污点;否则递归下一个节点 + :param parent_node: 父节点 ,为了处理无法确定当前节点位置的问题 :param file_path: :param vul_function: :param param: @@ -572,10 +578,11 @@ def parameters_back(param, nodes, function_params=None, lineno=0, is_co, cp, expr_lineno = array_back(param, nodes, file_path=file_path, isback=isback) return is_co, cp, expr_lineno - if isinstance(param, php.New) or (hasattr(param, "name") and isinstance(param.name, php.New)): # 当污点为新建类事,进入类中tostring函数分析 + if isinstance(param, php.New) or ( + hasattr(param, "name") and isinstance(param.name, php.New)): # 当污点为新建类事,进入类中tostring函数分析 logger.debug("[AST] AST analysis for New Class {} in line {}".format(param.name, param.lineno)) is_co, cp, expr_lineno = new_class_back(param, nodes, file_path=file_path, - isback=isback) + isback=isback) return is_co, cp, expr_lineno expr_lineno = 0 # source所在行号 @@ -649,8 +656,10 @@ def parameters_back(param, nodes, function_params=None, lineno=0, return_param = return_node.node is_co, cp, expr_lineno = parameters_back(return_param, function_nodes, function_params, lineno, function_flag=1, - vul_function=vul_function, file_path=file_path, - isback=isback) + vul_function=vul_function, + file_path=file_path, + isback=isback, + parent_node=node) if param_name == param_node and isinstance(param_expr, list): logger.debug( @@ -671,14 +680,15 @@ def parameters_back(param, nodes, function_params=None, lineno=0, param = php.Variable(param) _is_co, _cp, expr_lineno = parameters_back(param, nodes[:-1], function_params, lineno, - function_flag=1, vul_function=vul_function, file_path=file_path, + function_flag=1, vul_function=vul_function, + file_path=file_path, isback=isback) if _is_co != -1: # 当参数可控时,值赋给is_co 和 cp,有一个参数可控,则认定这个函数可能可控 is_co = _is_co cp = _cp - elif isinstance(node, php.Function) or isinstance(node, php.Method) and function_flag == 0: + elif isinstance(node, php.Function) or isinstance(node, php.Method): function_nodes = node.nodes function_lineno = node.lineno function_params = node.params @@ -686,11 +696,12 @@ def parameters_back(param, nodes, function_params=None, lineno=0, # 如果仅仅是函数定义,如果上一次赋值语句不在函数内,那么不应进去函数里分析,应该直接跳过这部分 # test1 尝试使用行数叠加的方式 - if len(function_nodes) + function_lineno < int(lineno): + # 目前测试结果中,这里会出现严重的bug + if function_flag == 0 and parent_node is None: is_co, cp, expr_lineno = parameters_back(param, nodes[:-1], function_params, lineno, function_flag=0, vul_function=vul_function, file_path=file_path, - isback=isback) + isback=isback, parent_node=node) return is_co, cp, expr_lineno logger.debug( @@ -709,8 +720,9 @@ def parameters_back(param, nodes, function_params=None, lineno=0, if len(vul_nodes) > 0: is_co, cp, expr_lineno = parameters_back(param, function_nodes, function_params, function_lineno, - function_flag=1, vul_function=vul_function, file_path=file_path, - isback=isback) + function_flag=1, vul_function=vul_function, + file_path=file_path, + isback=isback, parent_node=None) if is_co == 3: # 出现新的敏感函数,重新生成新的漏洞结构,进入新的遍历结构 for node_param in node.params: @@ -740,7 +752,8 @@ def parameters_back(param, nodes, function_params=None, lineno=0, return is_co, cp, 0 elif isinstance(node, php.Class): - is_co, cp, expr_lineno = class_back(param, node, lineno, vul_function=vul_function, file_path=file_path, isback=isback) + is_co, cp, expr_lineno = class_back(param, node, lineno, vul_function=vul_function, file_path=file_path, + isback=isback, parent_node=node) return is_co, cp, expr_lineno elif isinstance(node, php.If): @@ -760,12 +773,12 @@ def parameters_back(param, nodes, function_params=None, lineno=0, # 进入分析if内的代码块,如果返回参数不同于进入参数,那么在不同的代码块中,变量值不同,不能统一处理,需要递归进入不同的部分 is_co, cp, expr_lineno = parameters_back(param, if_nodes, function_params, if_node_lineno, function_flag=1, vul_function=vul_function, - file_path=file_path, isback=isback) + file_path=file_path, isback=isback, parent_node=node) if is_co == 3 and cp != param: # 理由如上 is_co, cp, expr_lineno = parameters_back(param, nodes[:-1], function_params, lineno, function_flag=1, vul_function=vul_function, - file_path=file_path, isback=isback) # 找到可控的输入时,停止递归 + file_path=file_path, isback=isback, parent_node=node) # 找到可控的输入时,停止递归 return is_co, cp, expr_lineno if is_co is not 1 and node.elseifs != []: # elseif可能有多个,所以需要列表 @@ -782,13 +795,15 @@ def parameters_back(param, nodes, function_params=None, lineno=0, elif_node_lineno = 0 is_co, cp, expr_lineno = parameters_back(param, elif_nodes, function_params, elif_node_lineno, - function_flag=1, vul_function=vul_function, file_path=file_path, - isback=isback) + function_flag=1, vul_function=vul_function, + file_path=file_path, + isback=isback, parent_node=node) if is_co == 3 and cp != param: # 理由如上 is_co, cp, expr_lineno = parameters_back(param, nodes[:-1], function_params, lineno, - function_flag=1, vul_function=vul_function, file_path=file_path, - isback=isback) # 找到可控的输入时,停止递归 + function_flag=1, vul_function=vul_function, + file_path=file_path, + isback=isback, parent_node=node) # 找到可控的输入时,停止递归 return is_co, cp, expr_lineno else: break @@ -806,12 +821,13 @@ def parameters_back(param, nodes, function_params=None, lineno=0, is_co, cp, expr_lineno = parameters_back(param, else_nodes, function_params, else_node_lineno, function_flag=1, vul_function=vul_function, - file_path=file_path, isback=isback) + file_path=file_path, isback=isback, parent_node=node) if is_co == 3 and cp != param: # 理由如上 is_co, cp, expr_lineno = parameters_back(param, nodes[:-1], function_params, lineno, - function_flag=1, vul_function=vul_function, file_path=file_path, - isback=isback) # 找到可控的输入时,停止递归 + function_flag=1, vul_function=vul_function, + file_path=file_path, + isback=isback, parent_node=node) # 找到可控的输入时,停止递归 return is_co, cp, expr_lineno elif isinstance(node, php.For): @@ -823,12 +839,12 @@ def parameters_back(param, nodes, function_params=None, lineno=0, is_co, cp, expr_lineno = parameters_back(param, for_nodes, function_params, for_node_lineno, function_flag=1, vul_function=vul_function, file_path=file_path, - isback=isback) + isback=isback, parent_node=node) if is_co == 3 or int(lineno) == node.lineno: # 当is_co为True时找到可控,停止递归 is_co, cp, expr_lineno = parameters_back(param, nodes[:-1], function_params, lineno, function_flag=1, vul_function=vul_function, file_path=file_path, - isback=isback) # 找到可控的输入时,停止递归 + isback=isback, parent_node=node) # 找到可控的输入时,停止递归 elif len(nodes) == 0 and function_params is not None: # 当敏感函数在函数中时,function_params不为空,这时应进入自定义敏感函数逻辑 for function_param in function_params: @@ -841,7 +857,8 @@ def parameters_back(param, nodes, function_params=None, lineno=0, return is_co, cp, expr_lineno -def deep_parameters_back(param, back_node, function_params, count, file_path, lineno=0, vul_function=None, isback=False): +def deep_parameters_back(param, back_node, function_params, count, file_path, lineno=0, vul_function=None, + isback=False): """ 深度递归遍历 :param isback: 是否返回 @@ -856,7 +873,8 @@ def deep_parameters_back(param, back_node, function_params, count, file_path, li count += 1 padding = {} - is_co, cp, expr_lineno = parameters_back(param, back_node, function_params, lineno, vul_function=vul_function, file_path=file_path, isback=isback) + is_co, cp, expr_lineno = parameters_back(param, back_node, function_params, lineno, vul_function=vul_function, + file_path=file_path, isback=isback) if count > 20: logger.warning("[Deep AST] depth too big, auto exit...") @@ -877,14 +895,17 @@ def deep_parameters_back(param, back_node, function_params, count, file_path, li for param in params: # 主要解决两个问题,一个是全局define,一个是变量 if isinstance(param, php.Variable): - logger.debug("[AST][INCLUDE] The include file name has an unknown parameter {}.".format(param)) + logger.debug( + "[AST][INCLUDE] The include file name has an unknown parameter {}.".format(param)) file_path = os.path.normpath(file_path) code = "find {} in Include path".format(param, file_path) scan_chain.append(('IncludePath', code, file_path, node.lineno)) - is_co, ccp, expr_lineno = deep_parameters_back(param, back_node[:back_node.index(node)], function_params, count, - file_path, lineno, vul_function=vul_function, isback=True) + is_co, ccp, expr_lineno = deep_parameters_back(param, back_node[:back_node.index(node)], + function_params, count, + file_path, lineno, vul_function=vul_function, + isback=True) if is_co == -1: padding[param.name] = ccp From 6ca6873e1195bfa043e1e33c9ac5d5111e553200 Mon Sep 17 00:00:00 2001 From: LoRexxar Date: Tue, 23 Apr 2019 14:06:22 +0800 Subject: [PATCH 2/6] Fix deep recursion problems --- cobra/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cobra/engine.py b/cobra/engine.py index d4f14051..8c2f68db 100644 --- a/cobra/engine.py +++ b/cobra/engine.py @@ -995,7 +995,7 @@ def NewCore(old_single_rule, target_directory, new_rules, files, count=0, secret else: if reason == 'New Core': # 新的规则 logger.debug('[CVI-{cvi}] [NEW-VUL] New Rules init') - new_rule_vulnerabilities = NewCore(sr, target_directory, data, files, 0, secret_name=secret_name) + new_rule_vulnerabilities = NewCore(sr, target_directory, data, files, count, secret_name=secret_name) if not new_rule_vulnerabilities: return rule_vulnerabilities From e22ef66157388c5eb3a6fc6eea45b752243dc831 Mon Sep 17 00:00:00 2001 From: LoRexxar Date: Tue, 23 Apr 2019 15:26:17 +0800 Subject: [PATCH 3/6] set function_flag to set true flag --- cobra/parser.py | 16 ++++++++++++---- cobra/pretreatment.py | 1 + 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/cobra/parser.py b/cobra/parser.py index c2564a91..e01fa8e3 100644 --- a/cobra/parser.py +++ b/cobra/parser.py @@ -247,6 +247,8 @@ def get_filename(node, file_path): # 获取filename constant_node = filenames[i] constant_node_name = constant_node.name + # 尝试做一些处理针对右值非常量的问题 + filenames[i] = ast_object.get_define(constant_node_name) return filenames @@ -723,6 +725,7 @@ def parameters_back(param, nodes, function_params=None, lineno=0, function_flag=1, vul_function=vul_function, file_path=file_path, isback=isback, parent_node=None) + function_flag = 0 if is_co == 3: # 出现新的敏感函数,重新生成新的漏洞结构,进入新的遍历结构 for node_param in node.params: @@ -754,6 +757,7 @@ def parameters_back(param, nodes, function_params=None, lineno=0, elif isinstance(node, php.Class): is_co, cp, expr_lineno = class_back(param, node, lineno, vul_function=vul_function, file_path=file_path, isback=isback, parent_node=node) + function_flag = 0 return is_co, cp, expr_lineno elif isinstance(node, php.If): @@ -774,10 +778,11 @@ def parameters_back(param, nodes, function_params=None, lineno=0, is_co, cp, expr_lineno = parameters_back(param, if_nodes, function_params, if_node_lineno, function_flag=1, vul_function=vul_function, file_path=file_path, isback=isback, parent_node=node) + function_flag = 0 if is_co == 3 and cp != param: # 理由如上 is_co, cp, expr_lineno = parameters_back(param, nodes[:-1], function_params, lineno, - function_flag=1, vul_function=vul_function, + function_flag=function_flag, vul_function=vul_function, file_path=file_path, isback=isback, parent_node=node) # 找到可控的输入时,停止递归 return is_co, cp, expr_lineno @@ -798,10 +803,11 @@ def parameters_back(param, nodes, function_params=None, lineno=0, function_flag=1, vul_function=vul_function, file_path=file_path, isback=isback, parent_node=node) + function_flag = 0 if is_co == 3 and cp != param: # 理由如上 is_co, cp, expr_lineno = parameters_back(param, nodes[:-1], function_params, lineno, - function_flag=1, vul_function=vul_function, + function_flag=function_flag, vul_function=vul_function, file_path=file_path, isback=isback, parent_node=node) # 找到可控的输入时,停止递归 return is_co, cp, expr_lineno @@ -822,10 +828,11 @@ def parameters_back(param, nodes, function_params=None, lineno=0, is_co, cp, expr_lineno = parameters_back(param, else_nodes, function_params, else_node_lineno, function_flag=1, vul_function=vul_function, file_path=file_path, isback=isback, parent_node=node) + function_flag = 0 if is_co == 3 and cp != param: # 理由如上 is_co, cp, expr_lineno = parameters_back(param, nodes[:-1], function_params, lineno, - function_flag=1, vul_function=vul_function, + function_flag=function_flag, vul_function=vul_function, file_path=file_path, isback=isback, parent_node=node) # 找到可控的输入时,停止递归 return is_co, cp, expr_lineno @@ -840,10 +847,11 @@ def parameters_back(param, nodes, function_params=None, lineno=0, is_co, cp, expr_lineno = parameters_back(param, for_nodes, function_params, for_node_lineno, function_flag=1, vul_function=vul_function, file_path=file_path, isback=isback, parent_node=node) + function_flag = 0 if is_co == 3 or int(lineno) == node.lineno: # 当is_co为True时找到可控,停止递归 is_co, cp, expr_lineno = parameters_back(param, nodes[:-1], function_params, lineno, - function_flag=1, vul_function=vul_function, file_path=file_path, + function_flag=function_flag, vul_function=vul_function, file_path=file_path, isback=isback, parent_node=node) # 找到可控的输入时,停止递归 elif len(nodes) == 0 and function_params is not None: # 当敏感函数在函数中时,function_params不为空,这时应进入自定义敏感函数逻辑 diff --git a/cobra/pretreatment.py b/cobra/pretreatment.py index 541a608f..35100bdd 100644 --- a/cobra/pretreatment.py +++ b/cobra/pretreatment.py @@ -66,6 +66,7 @@ def pre_ast(self): if isinstance(node, php.FunctionCall) and node.name == "define": define_params = node.params logger.debug("[AST][Pretreatment] new define {}={}".format(define_params[0].node, define_params[1].node)) + self.define_dict[define_params[0].node] = define_params[1].node def get_nodes(self, filepath): From 9087d380e5e6fd0b9db46b189f564326f439f69e Mon Sep 17 00:00:00 2001 From: LoRexxar Date: Tue, 23 Apr 2019 15:48:18 +0800 Subject: [PATCH 4/6] fix right param is empty list error to check --- cobra/parser.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cobra/parser.py b/cobra/parser.py index e01fa8e3..7505732c 100644 --- a/cobra/parser.py +++ b/cobra/parser.py @@ -673,6 +673,11 @@ def parameters_back(param, nodes, function_params=None, lineno=0, code = "{}={}".format(param_name, param_expr) scan_chain.append(('ListAssignment', code, file_path, node.lineno)) + if param_expr is []: + _is_co = -1 + cp = param + return is_co, cp, 0 + for expr in param_expr: param = expr is_co, cp = is_controllable(expr) From 932b8a22e6e0ed080b73b4e11d56def090f28c0a Mon Sep 17 00:00:00 2001 From: LoRexxar Date: Tue, 23 Apr 2019 18:15:08 +0800 Subject: [PATCH 5/6] add controlled_list for tamper --- cobra/cast.py | 6 ++++-- cobra/engine.py | 15 +++++++++++++-- cobra/parser.py | 33 ++++++++++++++++++++++++--------- rules/secret/demo.py | 4 ++++ 4 files changed, 45 insertions(+), 13 deletions(-) diff --git a/cobra/cast.py b/cobra/cast.py index 2b76985b..0d3570d6 100644 --- a/cobra/cast.py +++ b/cobra/cast.py @@ -27,7 +27,7 @@ class CAST(object): languages = ['php', 'java', 'sol'] - def __init__(self, rule, target_directory, file_path, line, code, files=None, rule_class=None, repair_functions=[]): + def __init__(self, rule, target_directory, file_path, line, code, files=None, rule_class=None, repair_functions=[], controlled_params=[]): self.target_directory = target_directory self.data = [] self.rule = rule @@ -40,6 +40,8 @@ def __init__(self, rule, target_directory, file_path, line, code, files=None, ru self.language = None self.sr = rule_class self.repair_functions = repair_functions + self.controlled_list = controlled_params + for language in self.languages: if self.file_path[-len(language):].lower() == language: self.language = language @@ -241,7 +243,7 @@ def is_controllable_param(self): logger.debug("[Deep AST] Start AST for param {param_name}".format(param_name=param_name)) - _is_co, _cp, expr_lineno, chain = anlysis_params(param_name, self.file_path, self.line, self.sr.vul_function, self.repair_functions, isexternal=True) + _is_co, _cp, expr_lineno, chain = anlysis_params(param_name, self.file_path, self.line, self.sr.vul_function, self.repair_functions, self.controlled_list, isexternal=True) if _is_co == 1: logger.debug("[AST] Is assign string: `Yes`") diff --git a/cobra/engine.py b/cobra/engine.py index 8c2f68db..c6294580 100644 --- a/cobra/engine.py +++ b/cobra/engine.py @@ -497,6 +497,7 @@ def __init__(self, target_directory, vulnerability_result, single_rule, project_ self.data = [] self.repair_dict = {} self.repair_functions = [] + self.controlled_list = {} self.target_directory = target_directory @@ -634,12 +635,22 @@ def init_php_repair(self): a = __import__('rules.secret.demo', fromlist=['IS_REPAIR_DEFAULT']) self.repair_dict = getattr(a, 'IS_REPAIR_DEFAULT') + b = __import__('rules.secret.demo', fromlist=['IS_CONTROLLED_DEFAULT']) + self.controlled_list = getattr(b, 'IS_CONTROLLED_DEFAULT') + if self.secret_name is not None: try: + # 首先加载修复函数指定 a = __import__('rules.secret.' + self.secret_name, fromlist=[self.secret_name]) a = getattr(a, self.secret_name) self.repair_dict = self.repair_dict.copy() self.repair_dict.update(a.items()) + + # 然后加载输入函数 + b = __import__('rules.secret.' + self.secret_name, fromlist=[self.secret_name]) + b = getattr(b, self.secret_name + "_controlled") + self.controlled_list += b + except ImportError: logger.warning('[AST][INIT] Secret_name init error... No nodule named {}'.format(self.secret_name)) @@ -694,7 +705,7 @@ def scan(self): try: self.init_php_repair() ast = CAST(self.rule_match, self.target_directory, self.file_path, self.line_number, - self.code_content, files=self.files, rule_class=self.single_rule, repair_functions=self.repair_functions) + self.code_content, files=self.files, rule_class=self.single_rule, repair_functions=self.repair_functions, controlled_params=self.controlled_list) # only match if self.rule_match_mode == const.mm_regex_only_match: @@ -713,7 +724,7 @@ def scan(self): # with open(self.file_path, 'r') as fi: # fi = codecs.open(self.file_path, "r", encoding='utf-8', errors='ignore') # code_contents = fi.read() - result = scan_parser(rule_match, self.line_number, self.file_path, repair_functions=self.repair_functions) + result = scan_parser(rule_match, self.line_number, self.file_path, repair_functions=self.repair_functions, controlled_params=self.controlled_list) logger.debug('[AST] [RET] {c}'.format(c=result)) if len(result) > 0: if result[0]['code'] == 1: # 函数参数可控 diff --git a/cobra/parser.py b/cobra/parser.py index 7505732c..33a4e5c2 100644 --- a/cobra/parser.py +++ b/cobra/parser.py @@ -24,6 +24,7 @@ with_line = True scan_results = [] # 结果存放列表初始化 is_repair_functions = [] # 修复函数初始化 +is_controlled_params = [] scan_chain = [] # 回溯链变量 @@ -306,6 +307,10 @@ def is_controllable(expr, flag=None): # 获取表达式中的变量,看是否 '$HTTP_RAW_POST_DATA', '$HTTP_GET_VARS' ] + + # 传入合并 + controlled_params += is_controlled_params + if isinstance(expr, php.ObjectProperty): return 3, php.Variable(expr) @@ -364,7 +369,8 @@ def is_controllable(expr, flag=None): # 获取表达式中的变量,看是否 # return is_co, cp, expr_lineno -def function_back(param, nodes, function_params, vul_function=None, file_path=None, isback=None, parent_node=None): # 回溯函数定义位置 +def function_back(param, nodes, function_params, vul_function=None, file_path=None, isback=None, + parent_node=None): # 回溯函数定义位置 """ 递归回溯函数定义位置,传入param类型不同 :param isback: @@ -492,7 +498,8 @@ def class_back(param, node, lineno, vul_function=None, file_path=None, isback=No # 递归析构函数 is_co, cp, expr_lineno = parameters_back(param, constructs_nodes, function_params=class_node_params, - lineno=lineno, function_flag=1, vul_function=vul_function, file_path=file_path, + lineno=lineno, function_flag=1, vul_function=vul_function, + file_path=file_path, isback=isback) if is_co == 3: @@ -581,7 +588,7 @@ def parameters_back(param, nodes, function_params=None, lineno=0, return is_co, cp, expr_lineno if isinstance(param, php.New) or ( - hasattr(param, "name") and isinstance(param.name, php.New)): # 当污点为新建类事,进入类中tostring函数分析 + hasattr(param, "name") and isinstance(param.name, php.New)): # 当污点为新建类事,进入类中tostring函数分析 logger.debug("[AST] AST analysis for New Class {} in line {}".format(param.name, param.lineno)) is_co, cp, expr_lineno = new_class_back(param, nodes, file_path=file_path, isback=isback) @@ -788,7 +795,8 @@ def parameters_back(param, nodes, function_params=None, lineno=0, if is_co == 3 and cp != param: # 理由如上 is_co, cp, expr_lineno = parameters_back(param, nodes[:-1], function_params, lineno, function_flag=function_flag, vul_function=vul_function, - file_path=file_path, isback=isback, parent_node=node) # 找到可控的输入时,停止递归 + file_path=file_path, isback=isback, + parent_node=node) # 找到可控的输入时,停止递归 return is_co, cp, expr_lineno if is_co is not 1 and node.elseifs != []: # elseif可能有多个,所以需要列表 @@ -856,7 +864,8 @@ def parameters_back(param, nodes, function_params=None, lineno=0, if is_co == 3 or int(lineno) == node.lineno: # 当is_co为True时找到可控,停止递归 is_co, cp, expr_lineno = parameters_back(param, nodes[:-1], function_params, lineno, - function_flag=function_flag, vul_function=vul_function, file_path=file_path, + function_flag=function_flag, vul_function=vul_function, + file_path=file_path, isback=isback, parent_node=node) # 找到可控的输入时,停止递归 elif len(nodes) == 0 and function_params is not None: # 当敏感函数在函数中时,function_params不为空,这时应进入自定义敏感函数逻辑 @@ -998,7 +1007,8 @@ def get_function_params(nodes): return params -def anlysis_params(param, file_path, lineno, vul_function=None, repair_functions=None, isexternal=False): +def anlysis_params(param, file_path, lineno, vul_function=None, repair_functions=None, controlled_params=None, + isexternal=False): """ 在cast调用时做中转数据预处理 :param repair_functions: @@ -1009,12 +1019,15 @@ def anlysis_params(param, file_path, lineno, vul_function=None, repair_functions :param file_path: :return: """ - global is_repair_functions, scan_chain + global is_repair_functions, is_controlled_params, scan_chain count = 0 function_params = None if repair_functions is not None: is_repair_functions = repair_functions + if controlled_params is not None: + is_controlled_params = controlled_params + if type(param) is str and "->" in param: param_left = php.Variable(param.split("->")[0]) param_right = param.split("->")[1] @@ -1551,9 +1564,10 @@ def analysis(nodes, vul_function, back_node, vul_lineo, file_path=None, function back_node.append(node) -def scan_parser(sensitive_func, vul_lineno, file_path, repair_functions=[]): +def scan_parser(sensitive_func, vul_lineno, file_path, repair_functions=[], controlled_params=[]): """ 开始检测函数 + :param controlled_params: :param repair_functions: :param sensitive_func: 要检测的敏感函数,传入的为函数列表 :param vul_lineno: 漏洞函数所在行号 @@ -1561,11 +1575,12 @@ def scan_parser(sensitive_func, vul_lineno, file_path, repair_functions=[]): :return: """ try: - global scan_results, is_repair_functions, scan_chain + global scan_results, is_repair_functions, is_controlled_params, scan_chain scan_chain = ['start'] scan_results = [] is_repair_functions = repair_functions + is_controlled_params = controlled_params all_nodes = ast_object.get_nodes(file_path) for func in sensitive_func: # 循环判断代码中是否存在敏感函数,若存在,递归判断参数是否可控;对文件内容循环判断多次 diff --git a/rules/secret/demo.py b/rules/secret/demo.py index 9ea83b22..4a9e68ea 100644 --- a/rules/secret/demo.py +++ b/rules/secret/demo.py @@ -23,3 +23,7 @@ "escapeshellcmd": [1009, 1011], "escapeshellarg": [1009, 1011], } + +IS_CONTROLLED_DEFAULT = [ + "$_GET", +] From 367b98664a00d2204babb89ceeb673421cd51051 Mon Sep 17 00:00:00 2001 From: LoRexxar Date: Tue, 23 Apr 2019 18:19:00 +0800 Subject: [PATCH 6/6] update 1.4.0 --- cobra/__version__.py | 2 +- docs/changelog.md | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/cobra/__version__.py b/cobra/__version__.py index 6ebeb431..3651b0e2 100644 --- a/cobra/__version__.py +++ b/cobra/__version__.py @@ -7,7 +7,7 @@ __issue_page__ = 'https://github.com/LoRexxar/Cobra-W/issues/new' __python_version__ = sys.version.split()[0] __platform__ = platform.platform() -__version__ = '1.3.0' +__version__ = '1.4.0' __author__ = 'LoRexxar' __author_email__ = 'LoRexxar@gmail.com' __license__ = 'MIT License' diff --git a/docs/changelog.md b/docs/changelog.md index 375e4cf7..92c14b17 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -92,4 +92,10 @@ - 修复了上版本中如果路径错误会导致获取node失败的问题 - 修复了针对function节点递归检测异常的问题 - 修复了针对function-regex模式即使匹配到敏感函数之后还会继续匹配的问题 +- 2019-04-23 + - Cobra-W 1.4.0 + - tamper中更新加入了关于输入函数的tamper部分,现在可以通过设置输入函数来定制扫描 + - 修复了对于list参数为空时仍会进入分析的bug + - 修复了关于function_flag设置的bug + - 添加了父类在递归中以解决部分无限递归的问题 \ No newline at end of file