diff --git a/README.md b/README.md index 60dc84c..65cd442 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# VulnFanatic (3.3) +# VulnFanatic (3.4) Author: **Martin Petran** diff --git a/plugin.json b/plugin.json index a6d3b2a..716f22b 100644 --- a/plugin.json +++ b/plugin.json @@ -21,7 +21,7 @@ "installers": [], "other": [] }, - "version": "3.3", + "version": "3.4", "author": "Martin Petran", "minimumbinaryninjaversion": 2263 } diff --git a/scanner/free_scanner3.py b/scanner/free_scanner3.py index 8916c2b..57c9b2d 100644 --- a/scanner/free_scanner3.py +++ b/scanner/free_scanner3.py @@ -160,10 +160,10 @@ def is_global_var(self,var,function): defs = function.get_var_definitions(v) for d in defs: try: - consts = self.extract_hlil_operation(d.instr,[HighLevelILOperation.HLIL_CONST_PTR]) + consts = self.extract_hlil_operation(d.instr,[HighLevelILOperation.HLIL_CONST_PTR,HighLevelILOperation.HLIL_CONST]) for c in consts: - if c.parent.operation == HighLevelILOperation.HLIL_DEREF: - # Likely a global variable deref + if "bss" in str(self.current_view.get_sections_at(c.constant)): + # Likely a global variable return True vs = self.extract_hlil_operation(d.instr,[HighLevelILOperation.HLIL_VAR]) for a in vs: diff --git a/scanner/rules3.json b/scanner/rules3.json index 735f7aa..d9974c5 100644 --- a/scanner/rules3.json +++ b/scanner/rules3.json @@ -275,7 +275,19 @@ {"function_name":"lstrcpyW", "trace_params":[1,0]}, {"function_name":"lstrcpynW", "trace_params":[1, 2,0]}, {"function_name":"lstrcatA", "trace_params":[1, 0]}, - {"function_name":"lstrcatW", "trace_params":[1, 0]} + {"function_name":"lstrcatW", "trace_params":[1, 0]}, + {"function_name":"execl", "trace_params":[0]}, + {"function_name":"execlp", "trace_params":[0]}, + {"function_name":"execle", "trace_params":[0]}, + {"function_name":"execv", "trace_params":[0]}, + {"function_name":"execvp", "trace_params":[0]}, + {"function_name":"execvpe", "trace_params":[0]}, + {"function_name":"_execl", "trace_params":[0]}, + {"function_name":"_execlp", "trace_params":[0]}, + {"function_name":"_execle", "trace_params":[0]}, + {"function_name":"_execv", "trace_params":[0]}, + {"function_name":"_execvp", "trace_params":[0]}, + {"function_name":"_execvpe", "trace_params":[0]} ], "test_cases":[ { @@ -389,6 +401,11 @@ "exported": true, "if_dependant": true } + }, + { + "0":{ + "global_var": true + } } ], "Info": [ @@ -686,6 +703,14 @@ "-2":{ "not_affected_by": ["toa","toi"] } + }, + { + "1":{ + "global_var": true + }, + "-2":{ + "not_affected_by": ["toa","toi"] + } } ], "Info": [ @@ -782,6 +807,11 @@ "exported": true, "if_dependant": true } + }, + { + "2":{ + "global_var": true + } } ], "Info": [ @@ -840,6 +870,11 @@ "exported": true, "if_dependant": true } + }, + { + "3":{ + "global_var": true + } } ], "Info": [ @@ -892,6 +927,11 @@ "exported": true, "if_dependant": true } + }, + { + "4":{ + "global_var": true + } } ], "Info": [ @@ -961,6 +1001,15 @@ "0":{ "not_affected_by": ["strlen"] } + }, + { + "1":{ + "global_var": true, + "not_affected_by": ["strlen","toa","toi"] + }, + "0":{ + "not_affected_by": ["strlen"] + } } ], "Info": [ @@ -1034,6 +1083,15 @@ "0":{ "not_affected_by": ["strlen"] } + }, + { + "1":{ + "global_var": true, + "not_affected_by": ["strlen","toa","toi"] + }, + "0":{ + "not_affected_by": ["strlen"] + } } ], "Info": [ @@ -1119,6 +1177,19 @@ "is_constant": false, "not_affected_by": ["strlen","alloc"] } + }, + { + "1":{ + "global_var": true, + "not_affected_by": ["strlen","toa","toi"] + }, + "0":{ + "not_affected_by": ["strlen"] + }, + "2":{ + "is_constant": false, + "not_affected_by": ["strlen","alloc"] + } } ], "Info": [ @@ -1206,6 +1277,19 @@ "is_constant": false, "not_affected_by": ["strlen","alloc"] } + }, + { + "1":{ + "global_var": true, + "not_affected_by": ["strlen","toa","toi"] + }, + "0":{ + "not_affected_by": ["strlen"] + }, + "2":{ + "is_constant": false, + "not_affected_by": ["strlen","alloc"] + } } ], "Info": [ @@ -1295,6 +1379,19 @@ "is_constant": false, "not_affected_by": ["strlen","alloc"] } + }, + { + "1":{ + "global_var": true, + "not_affected_by": ["strlen","toa","toi"] + }, + "0":{ + "not_affected_by": ["strlen"] + }, + "2":{ + "is_constant": false, + "not_affected_by": ["strlen","alloc"] + } } ], "Info": [ @@ -1384,6 +1481,19 @@ "is_constant": false, "not_affected_by": ["strlen","alloc"] } + }, + { + "1":{ + "global_var": true, + "not_affected_by": ["strlen","toa","toi"] + }, + "0":{ + "not_affected_by": ["strlen"] + }, + "2":{ + "is_constant": false, + "not_affected_by": ["strlen","alloc"] + } } ], "Info": [ @@ -1489,6 +1599,16 @@ "if_dependant": true, "not_affected_by": ["strlen","alloc"] } + }, + { + "1":{ + "global_var": true, + "not_affected_by": ["strlen","toa","toi","alloc"] + }, + "2":{ + "global_var": true, + "not_affected_by": ["strlen","alloc"] + } } ], "Info": [ @@ -1591,6 +1711,16 @@ "if_dependant": true, "not_affected_by": ["strlen","alloc"] } + }, + { + "1":{ + "global_var": true, + "not_affected_by": ["strlen","toa","toi","alloc"] + }, + "2":{ + "global_var": true, + "not_affected_by": ["strlen","alloc"] + } } ], "Info": [ @@ -1663,6 +1793,15 @@ "0":{ "exported": true + }, + "1":{ + "constant_value": ["%s"] + } + }, + { + "0":{ + "global_var": true + }, "1":{ "constant_value": ["%s"] @@ -1719,6 +1858,15 @@ "1":{ "constant_value": ["%s"] } + }, + { + "0":{ + "global_var":true, + "if_dependant": true + }, + "1":{ + "constant_value": ["%s"] + } } ] } @@ -1773,6 +1921,15 @@ "1":{ "constant_value": ["%s"] } + }, + { + "-2":{ + "global_var":true, + "not_affected_by": ["strlen","toa","toi"] + }, + "1":{ + "constant_value": ["%s"] + } } ] } @@ -1863,6 +2020,23 @@ "is_constant": false, "not_affected_by": ["strlen","alloc"] } + }, + { + "2":{ + "global_var": true, + "not_affected_by": ["strlen","toa","toi"] + }, + "0":{ + "not_affected_by": ["strlen"] + }, + "3":{ + "is_constant": false, + "not_affected_by": ["strlen","alloc"] + }, + "1":{ + "is_constant": false, + "not_affected_by": ["strlen","alloc"] + } } ], "Info": [ @@ -1972,6 +2146,23 @@ "is_constant": false, "not_affected_by": ["strlen","alloc"] } + }, + { + "2":{ + "global_var": true, + "not_affected_by": ["strlen","toa","toi"] + }, + "0":{ + "not_affected_by": ["strlen"] + }, + "3":{ + "is_constant": false, + "not_affected_by": ["strlen","alloc"] + }, + "1":{ + "is_constant": false, + "not_affected_by": ["strlen","alloc"] + } } ], "Info": [ @@ -2063,6 +2254,19 @@ "2":{ "constant_value": ["%s"] } + }, + { + "-3":{ + "global_var": true, + "not_affected_by": ["strlen","toa","toi","alloc"] + }, + "1":{ + "is_constant": false, + "not_affected_by": ["strlen","toa","toi","alloc"] + }, + "2":{ + "constant_value": ["%s"] + } } ], "Info": [ @@ -2122,6 +2326,12 @@ "if_dependant": true, "not_affected_by": ["strlen","toa","toi"] } + }, + { + "2":{ + "global_var": true, + "not_affected_by": ["strlen","toa","toi"] + } } ], "Info": [ @@ -2190,6 +2400,16 @@ "is_constant": false, "not_affected_by": ["strlen","alloc"] } + }, + { + "3":{ + "global_var": true, + "not_affected_by": ["strlen","toa","toi"] + }, + "1":{ + "is_constant": false, + "not_affected_by": ["strlen","alloc"] + } } ], "Info": [ @@ -2215,7 +2435,19 @@ "_popen", "popen", "wpopen", - "_wpopen" + "_wpopen", + "execl", + "execlp", + "execle", + "execv", + "execvp", + "execvpe", + "_execl", + "_execlp", + "_execle", + "_execv", + "_execvp", + "_execvpe" ], "checks":{ "High":[ @@ -2246,6 +2478,11 @@ "exported": true, "if_dependant": true } + }, + { + "0":{ + "global_var": true + } } ], "Info": [ diff --git a/scanner/scanner31.py b/scanner/scanner31.py index 02612eb..5d37d70 100644 --- a/scanner/scanner31.py +++ b/scanner/scanner31.py @@ -4,6 +4,7 @@ from .free_scanner3 import FreeScanner3 #import time + class Scanner31(BackgroundTaskThread): def __init__(self,bv): self.progress_banner = f"[VulnFanatic] Running the scanner ..." @@ -162,7 +163,8 @@ def trace(self,xref,params_arg): "if_dependant": False, "affected_by": {}, "affected_by_in_same_block": {}, - "if_checked": True + "if_checked": True, + "global_var": False } if p == "return": # At this point only test case for return we have is whether it is if checked @@ -175,17 +177,19 @@ def trace(self,xref,params_arg): continue if p < len(xref.params): if (xref.params[p].operation == HighLevelILOperation.HLIL_CONST or xref.params[p].operation == HighLevelILOperation.HLIL_CONST_PTR): - try: - value = self.current_view.get_string_at(xref.params[p].constant).value - except: - value = hex(xref.params[p].constant) - # handle constant here - trace_struct[str(p)]["is_constant"] = True - trace_struct[str(p)]["constant_value"].append(value) - continue + if "bss" in str(self.current_view.get_sections_at(xref.params[p].constant)): + trace_struct[str(p)]["global_var"] = True + else: + try: + value = self.current_view.get_string_at(xref.params[p].constant).value + except: + value = hex(xref.params[p].constant) + # handle constant here + trace_struct[str(p)]["is_constant"] = True + trace_struct[str(p)]["constant_value"].append(value) + continue param_vars = self.prepare_relevant_variables(xref.params[p]) # The main tracing loop - blocks = [{"block":xref.il_basic_block,"start":xref.il_basic_block.start-1,"end":xref.instr_index,"param_vars":param_vars.copy()}] previous_function = xref.il_basic_block.function.name hlil_instructions = list(xref.il_basic_block.function.hlil.instructions) @@ -198,14 +202,6 @@ def trace(self,xref,params_arg): # Previous function here always holds current function name params_to_check = current_block["param_vars"]["possible_values"] - #params_to_check = [] - #try: - # for param in current_block["param_vars"]["possible_values"]: - # if re.search(param,str(hlil_instructions[current_block["start"]:current_block["end"]+1])): - # params_to_check.append(param) - #except: - # pass - #if params_to_check: for index in range(current_block["end"],current_block["start"],-1): if index < len(hlil_instructions): instruction = hlil_instructions[index] @@ -219,13 +215,16 @@ def trace(self,xref,params_arg): # Constant check if instruction.operation == HighLevelILOperation.HLIL_ASSIGN or instruction.operation == HighLevelILOperation.HLIL_VAR_INIT: if instruction.src.operation == HighLevelILOperation.HLIL_CONST or instruction.src.operation == HighLevelILOperation.HLIL_CONST_PTR: - try: - value = self.current_view.get_string_at(instruction.src.constant).value - except: - value = hex(instruction.src.constant) - # handle constant here - trace_struct[str(p)]["is_constant"] = True - trace_struct[str(p)]["constant_value"].append(value) + if "bss" in str(self.current_view.get_sections_at(instruction.src.constant)): + trace_struct[str(p)]["global_var"] = True + else: + try: + value = self.current_view.get_string_at(instruction.src.constant).value + except: + value = hex(instruction.src.constant) + # handle constant here + trace_struct[str(p)]["is_constant"] = True + trace_struct[str(p)]["constant_value"].append(value) # Check if it is part of a call: calls = self.extract_hlil_operation(instruction,[HighLevelILOperation.HLIL_CALL]) for call in calls: @@ -236,10 +235,13 @@ def trace(self,xref,params_arg): for call_param in call.params: param_value = "" if call_param.operation == HighLevelILOperation.HLIL_CONST or call_param.operation == HighLevelILOperation.HLIL_CONST_PTR: - try: - param_value = self.current_view.get_string_at(call_param.constant).value - except: - param_value = hex(call_param.constant) + if "bss" in str(self.current_view.get_sections_at(call_param.constant)): + param_value = "DYNAMIC_VALUE" + else: + try: + param_value = self.current_view.get_string_at(call_param.constant).value + except: + param_value = hex(call_param.constant) if self.is_in_operands(param,self.expand_postfix_operands(call_param)): param_value = "TRACKED" if not param_value: @@ -264,10 +266,13 @@ def trace(self,xref,params_arg): for call_param in call.params: param_value = "" if call_param.operation == HighLevelILOperation.HLIL_CONST or call_param.operation == HighLevelILOperation.HLIL_CONST_PTR: - try: - param_value = self.current_view.get_string_at(call_param.constant).value - except: - param_value = hex(call_param.constant) + if "bss" in str(self.current_view.get_sections_at(call_param.constant)): + param_value = "DYNAMIC_VALUE" + else: + try: + param_value = self.current_view.get_string_at(call_param.constant).value + except: + param_value = hex(call_param.constant) else: param_value = "DYNAMIC_VALUE" params_dict[str(call_param_index)] = param_value @@ -396,7 +401,7 @@ def prepare_relevant_variables(self,param): op.type if not op in vars["orig_vars"][param_var]: vars["orig_vars"][param_var].append(op) - vars["vars"].append(p.var) + vars["vars"].append(op) except: if type(op) is list: operands.extend(op)