Skip to content

Commit

Permalink
Merge pull request #7 from Martyx00/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
Martyx00 authored Jul 26, 2020
2 parents 8c3d86a + 15c4050 commit 822b64b
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 49 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# VulnFanatic (2.2)
# VulnFanatic (2.3)

Author: **Martin Petran**

Expand Down
6 changes: 5 additions & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ def scan2(bv,selection_addr):
pass

def highlight2(bv,selection_addr):
current_function = bv.get_functions_containing(selection_addr)[0]
try:
current_function = bv.get_functions_containing(selection_addr)[0]
except IndexError:
show_message_box("Highlighter Error", "Not a valid highlight!", buttons=0, icon=2)
return
function_calls_at_address = []
function_calls_at_address = extract_hlil_operations(current_function.hlil,[HighLevelILOperation.HLIL_CALL],instruction_address=selection_addr)
if len(function_calls_at_address) == 0:
Expand Down
2 changes: 1 addition & 1 deletion plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"installers": [],
"other": []
},
"version": "2.2",
"version": "2.3",
"author": "Martin Petran",
"minimumbinaryninjaversion": 2263
}
Expand Down
81 changes: 36 additions & 45 deletions scanner/free_scanner2.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
from ..utils.utils import extract_hlil_operations
import time


class FreeScanner2(BackgroundTaskThread):
def __init__(self,bv):
self.current_view = bv
self.progress_banner = f"[VulnFanatic] Running the scanner ... looking for Use-after-free issues"
BackgroundTaskThread.__init__(self, self.progress_banner, True)
self.free_list = ["free","_free","_freea","freea","free_dbg","_free_dbg","free_locale","_free_locale","g_free","operator delete"]
self.free_list = ["free","_free","_freea","freea","free_dbg","_free_dbg","free_locale","_free_locale","g_free","operator delete","operator delete[]"]
#self.free_list = ["free","_free","_freea","freea","free_dbg","_free_dbg","free_locale","_free_locale"]

def run(self):
Expand All @@ -22,12 +21,11 @@ def run(self):
counter += 1
if free_xref["param_index"] < len(free_xref["instruction"].params):
param_vars = self.prepare_relevant_variables(free_xref["instruction"].params[free_xref["param_index"]])
uaf,uaf_if,double,null_set = self.scan(free_xref["instruction"],param_vars)
uaf,uaf_if,double = self.scan(free_xref["instruction"],param_vars)
current_free_xref_obj = {
"used_after": uaf,
"without_if": uaf_if,
"double_free": double,
"is_set_to_null": null_set,
"struct_free_wrapper": free_xref["struct_free_wrapper"]
}
if current_free_xref_obj["double_free"] and current_free_xref_obj["without_if"]:
Expand All @@ -40,14 +38,18 @@ def run(self):
continue
# First process parameter variables
confidence = ""
if current_free_xref_obj["used_after"] and current_free_xref_obj["without_if"] and not current_free_xref_obj["is_set_to_null"]:
if current_free_xref_obj["used_after"] and current_free_xref_obj["without_if"]:
confidence = "Medium"
elif current_free_xref_obj["used_after"] and not current_free_xref_obj["is_set_to_null"]:
elif current_free_xref_obj["used_after"]:
confidence = "Low"
elif not current_free_xref_obj["is_set_to_null"] and current_free_xref_obj["struct_free_wrapper"]:
elif current_free_xref_obj["struct_free_wrapper"]:
confidence = "Info"
if confidence:
tag = free_xref["instruction"].function.source_function.create_tag(self.current_view.tag_types["[VulnFanatic] "+confidence], "Potential Use-afer-free Vulnerability", True)
if confidence == "Info":
desc = "Free wrapper worth to investigate."
else:
desc = "Potential Use-afer-free Vulnerability"
tag = free_xref["instruction"].function.source_function.create_tag(self.current_view.tag_types["[VulnFanatic] "+confidence], desc, True)
free_xref["instruction"].function.source_function.add_user_address_tag(free_xref["instruction"].address, tag)

#log_info(str(current_free_xref_obj))
Expand All @@ -56,31 +58,16 @@ def scan(self,instruction,param_vars):
current_hlil_instructions = list(instruction.function.instructions)
# Check if instruction is in loop so that we know how to proceed with checks further
in_loop = self.is_in_loop(instruction)
instructions = []
# Check if param set to null
is_set_to_null = self.is_set_to_null(instructions,param_vars)

# Check if param is used after the free call, if not in loop get rid of first instruction
if not in_loop["in_loop"]:
used_after, used_after_with_if,double = self.used_after2(param_vars,instruction,current_hlil_instructions,in_loop)
else:
used_after, used_after_with_if,double = self.used_after2(param_vars,instruction,current_hlil_instructions,in_loop)
return used_after, used_after_with_if, double, is_set_to_null

def is_set_to_null(self,instructions,param_vars):
for i in instructions:
if i:
for param in param_vars["possible_values"]:
if i.operation == HighLevelILOperation.HLIL_ASSIGN and re.search(param,str(i.dest)):
# one of the possible values was found in the instruction which assigns value
if (i.src.operation == HighLevelILOperation.HLIL_CONST or i.src.operation == HighLevelILOperation.HLIL_CONST_PTR) and i.src.constant == 0:
# Null assgined -> return True
return True
return False
return used_after, used_after_with_if, double

def used_after2(self,param_vars,instruction,hlil_instructions,in_loop):
loops = [HighLevelILOperation.HLIL_DO_WHILE,HighLevelILOperation.HLIL_WHILE,HighLevelILOperation.HLIL_FOR]
skip_operations = [HighLevelILOperation.HLIL_IF,HighLevelILOperation.HLIL_ASSIGN,HighLevelILOperation.HLIL_VAR_INIT]
skip_operations = [HighLevelILOperation.HLIL_IF,HighLevelILOperation.HLIL_ASSIGN,HighLevelILOperation.HLIL_VAR_INIT,HighLevelILOperation.HLIL_RET]
skip_operations.extend(loops)
uaf = False
uaf_if = False
Expand Down Expand Up @@ -117,6 +104,9 @@ def used_after2(self,param_vars,instruction,hlil_instructions,in_loop):
if self.not_if_dependent(instruction,param_vars):
uaf_if = True
uaf = True
if i.function.source_function.name == "plugins_free":
log_info(f"[*] Use detected at {i.function.source_function.name} in instruction {str(i)}")
log_info(str(param_vars["possible_values"]))
return uaf, uaf_if, double
# Add following blocks only if current block have not initialized the variable
if not initialized:
Expand Down Expand Up @@ -156,7 +146,7 @@ def get_xrefs_with_wrappers(self):
})
append = False
return free_xrefs

def prepare_relevant_variables(self,param):
param_vars_hlil = extract_hlil_operations(param.function,[HighLevelILOperation.HLIL_VAR],specific_instruction=param)
param_vars = []
Expand All @@ -178,11 +168,10 @@ def prepare_relevant_variables(self,param):
for d in definitions:
if (d.operation == HighLevelILOperation.HLIL_VAR_INIT or d.operation == HighLevelILOperation.HLIL_ASSIGN)and type(d.src.postfix_operands[0]) == Variable and d.src.postfix_operands[0] not in vars["vars"]:
val = str(param).replace(str(var),str(d.src.postfix_operands[0]))
tmp_possible.append(val)
#tmp_possible.append(val)
tmp_possible.append(str(d.src))
vars["vars"].append(d.src.postfix_operands[0])
param_vars.append(d.src.postfix_operands[0])
for v in vars["vars"]:
val.replace(str(v),str(v)+"\\:?\\d*\\.?\\w*")
for val in tmp_possible:
tmp_val = val
positions = [(m.start(0), m.end(0)) for m in re.finditer(r':\d+\.\w+', val)]
Expand Down Expand Up @@ -217,6 +206,12 @@ def not_if_dependent(self,instruction,param_vars):
return if_dep

def get_xrefs_to_call(self,function_names):
altered_names = []
for f in function_names:
if f[:4] == "sub_":
altered_names.append(f"0x{f[4:]}")
else:
altered_names.append(f)
checked_functions = []
xrefs = []
for symbol_name in function_names:
Expand All @@ -233,28 +228,24 @@ def get_xrefs_to_call(self,function_names):
symbol_item.extend(self.current_view.symbols[symbol_name+"@PLT"]) if type(self.current_view.symbols[symbol_name+"@PLT"]) is list else symbol_item.append(self.current_view.symbols[symbol_name+"@PLT"])
except KeyError:
pass
# Operator Delete refs -> TODO this takes long time -> REWORK for sure
if symbol_name == "operator delete":
if len(self.current_view.functions) < len(self.current_view.symbols):
symbol_list = self.current_view.functions
name = True
else:
symbol_list = self.current_view.symbols
name = False
for symbol in symbol_list:
if name:
sym = symbol.name
symbols_mag = [list(self.current_view.symbols.items())]
while symbols_mag:
current_symbols = symbols_mag.pop()
if len(current_symbols) != 1:
l = round(len(current_symbols)/2)
if "operator delete" in str(current_symbols[l:]):
symbols_mag.append(current_symbols[l:])
if "operator delete" in str(current_symbols[:l]):
symbols_mag.append(current_symbols[:l])
else:
sym = symbol
try:
sym = current_symbols[0][0]
if type(self.current_view.symbols[sym]) is list:
for item in self.current_view.symbols[sym]:
if "operator delete" in item.full_name and item not in symbol_item:
symbol_item.append(item)
elif "operator delete" in self.current_view.symbols[sym].full_name and self.current_view.symbols[sym] not in symbol_item:
symbol_item.append(self.current_view.symbols[sym])
except:
pass
symbol_item.append(self.current_view.symbols[sym])
for symbol in symbol_item if type(symbol_item) is list else [symbol_item]:
for ref in self.current_view.get_code_refs(symbol.address):
# Get exact instruction index
Expand All @@ -269,6 +260,6 @@ def get_xrefs_to_call(self,function_names):
# Extract the call here
calls = extract_hlil_operations(instruction.function,[HighLevelILOperation.HLIL_CALL],specific_instruction=instruction)
for call in calls:
if str(call.dest) in function_names and call not in xrefs:
if str(call.dest) in altered_names and call not in xrefs:
xrefs.append(call)
return xrefs
2 changes: 1 addition & 1 deletion trackers/function_tracer2.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ def get_var_function_calls(self,variable,current_function,current_hlil_instructi
else:
variable_appearances = current_function.ssa_form.get_ssa_var_uses(variable["variable"])
for use in variable_appearances:
if use.instr_index < 500000 and time.time():
if use.instr_index < 500000:
try:
dest = use.dest
except:
Expand Down

0 comments on commit 822b64b

Please sign in to comment.