def _detect_token_reentrant(contract: Contract) -> Dict[Function, List[Node]]: ret: Dict[Function, List[Node]] = defaultdict(list) for function in contract.functions_entry_points: if function.full_name in [ "transfer(address,uint256)", "transferFrom(address,address,uint256)", ]: for ir in function.all_slithir_operations(): if isinstance(ir, (LowLevelCall, HighLevelCall)): if not function.parameters: continue if any( ( is_dependent(ir.destination, parameter, function) for parameter in function.parameters ) ): ret[function].append(ir.node) if is_dependent( ir.destination, SolidityVariableComposed("msg.sender"), function ): ret[function].append(ir.node) if is_dependent( ir.destination, SolidityVariableComposed("tx.origin"), function ): ret[function].append(ir.node) return ret
def _call_a_parameter(slither: SlitherCore) -> Dict[str, List[Dict]]: """ Detect the functions with external calls :param slither: :return: """ # contract -> [ (function, idx, interface_called) ] ret: Dict[str, List[Dict]] = defaultdict(list) for contract in slither.contracts: # pylint: disable=too-many-nested-blocks for function in contract.functions_entry_points: for ir in function.all_slithir_operations(): if isinstance(ir, HighLevelCall): for idx, parameter in enumerate(function.parameters): if is_dependent(ir.destination, parameter, function): ret[contract.name].append( { "function": _get_name(function), "parameter_idx": idx, "signature": _get_name(ir.function), } ) if isinstance(ir, LowLevelCall): for idx, parameter in enumerate(function.parameters): if is_dependent(ir.destination, parameter, function): ret[contract.name].append( { "function": _get_name(function), "parameter_idx": idx, "signature": None, } ) return ret
def arbitrary_send(self, func): """ """ if func.is_protected(): return [] ret = [] for node in func.nodes: for ir in node.irs: if isinstance(ir, SolidityCall): if ir.function == SolidityFunction('ecrecover(bytes32,uint8,bytes32,bytes32)'): return False if isinstance(ir, Index): if ir.variable_right == SolidityVariableComposed('msg.sender'): return False if is_dependent(ir.variable_right, SolidityVariableComposed('msg.sender'), func.contract): return False if isinstance(ir, (HighLevelCall, LowLevelCall, Transfer, Send)): if isinstance(ir, (HighLevelCall)): if isinstance(ir.function, Function): if ir.function.full_name == 'transferFrom(address,address,uint256)': return False if ir.call_value is None: continue if ir.call_value == SolidityVariableComposed('msg.value'): continue if is_dependent(ir.call_value, SolidityVariableComposed('msg.value'), func.contract): continue if is_tainted(ir.destination, func.contract, self.slither): ret.append(node) return ret
def _arbitrary_from(nodes: List[Node], results: List[Node]): """Finds instances of (safe)transferFrom that do not use msg.sender or address(this) as from parameter.""" for node in nodes: for ir in node.irs: if (isinstance(ir, HighLevelCall) and isinstance(ir.function, Function) and ir.function.solidity_signature == "transferFrom(address,address,uint256)" and not (is_dependent( ir.arguments[0], SolidityVariableComposed("msg.sender"), node.function.contract, ) or is_dependent( ir.arguments[0], SolidityVariable("this"), node.function.contract, ))): results.append(ir.node) elif (isinstance(ir, LibraryCall) and ir.function.solidity_signature == "safeTransferFrom(address,address,address,uint256)" and not (is_dependent( ir.arguments[1], SolidityVariableComposed("msg.sender"), node.function.contract, ) or is_dependent( ir.arguments[1], SolidityVariable("this"), node.function.contract, ))): results.append(ir.node)
def timestamp(self, func): """ """ ret = set() for node in func.nodes: if node.contains_require_or_assert(): for var in node.variables_read: if is_dependent(var, SolidityVariableComposed('block.timestamp'), func.contract): ret.add(node) for ir in node.irs: if isinstance(ir, Binary) and BinaryType.return_bool(ir.type): for var in ir.read: if is_dependent(var, SolidityVariableComposed('block.timestamp'), func.contract): ret.add(node) return list(ret)
def advancedUpdateEth_2(self, function): from slither.analyses.data_dependency.data_dependency import is_dependent allNodes = function.nodes for ethNode in function.ethNodes: entryPointToethNode = [] entryPointToethNode.append(function.entry_point) pilotProcessNodes = list( set(allNodes) - set([function.entry_point, ethNode])) entryPointToethNode.extend(pilotProcessNodes) entryPointToethNode.append(ethNode) adjMatrix = getadjMatrix(entryPointToethNode) mydeepGraph = MyDeepGraph(len(entryPointToethNode)) mydeepGraph.setadjMetrix(adjMatrix) allPaths = mydeepGraph.getPathofTwoNode( 0, len(entryPointToethNode) - 1) allPaths_Node = allPaths_intToNode(allPaths, entryPointToethNode) for path in allPaths_Node: for ir in path[-1].irs: if isinstance( ir, (HighLevelCall, LowLevelCall, Transfer, Send)): if ir.call_value: for node in path[0:len(path) - 1]: for stateVariableWritten in node.state_variables_written: if is_dependent(ir.call_value, stateVariableWritten, function.contract): return True # elif is_dependent(stateVariableWritten, ir.call_value, function.contract): # return True return False
def _timestamp(func: Function) -> List[Node]: ret = set() for node in func.nodes: if node.contains_require_or_assert(): for var in node.variables_read: if is_dependent(var, SolidityVariableComposed("block.timestamp"), func.contract): ret.add(node) if is_dependent(var, SolidityVariable("now"), func.contract): ret.add(node) for ir in node.irs: if isinstance(ir, Binary) and BinaryType.return_bool(ir.type): for var in ir.read: if is_dependent( var, SolidityVariableComposed("block.timestamp"), func.contract ): ret.add(node) if is_dependent(var, SolidityVariable("now"), func.contract): ret.add(node) return sorted(list(ret), key=lambda x: x.node_id)
def inspect_index_ir(self, ir, index_usage: Dict[Variable, Dict[int, Set[StateVariableSolc]]]): params = self.slither_function.parameters + self.slither_function.solidity_variables_read for param in params: if is_dependent(ir.variable_right, param, self.parent_contract.slither_contract): level = 0 temp = ir.variable_left while isinstance(temp, ReferenceVariable): temp = temp.points_to level += 1 if isinstance(temp, StateVariableSolc): index_usage[param][level].add(temp)
def arbitrary_send(func: Function): if func.is_protected(): return [] ret: List[Node] = [] for node in func.nodes: for ir in node.irs: if isinstance(ir, SolidityCall): if ir.function == SolidityFunction("ecrecover(bytes32,uint8,bytes32,bytes32)"): return False if isinstance(ir, Index): if ir.variable_right == SolidityVariableComposed("msg.sender"): return False if is_dependent( ir.variable_right, SolidityVariableComposed("msg.sender"), func.contract, ): return False if isinstance(ir, (HighLevelCall, LowLevelCall, Transfer, Send)): if isinstance(ir, (HighLevelCall)): if isinstance(ir.function, Function): if ir.function.full_name == "transferFrom(address,address,uint256)": return False if ir.call_value is None: continue if ir.call_value == SolidityVariableComposed("msg.value"): continue if is_dependent( ir.call_value, SolidityVariableComposed("msg.value"), func.contract, ): continue if is_tainted(ir.destination, func.contract): ret.append(node) return ret
def call_in_loop(f, node, in_loop, visited, ret, loopsum): if node in visited: return # shared visited visited.append(node) if node.type == NodeType.STARTLOOP: loopsum.append('hasloop') # print('>>>>>>>>>>>>>begin loop') in_loop = True # is_tainted_by_arg, is_tainted_by_statevar, is_tained_by_local, has_transaction, has_lib_call, has_nested_loop = MultipleCallsInLoop.collect_summary(node, f) # print('Loop Summary----', 'has_nested_loop:', has_nested_loop, 'has_lib_call:', has_lib_call, 'has_transaction:', has_transaction, # 'is_tained_by_local:', is_tained_by_local, 'is_tainted_by_arg:', is_tainted_by_arg, 'is_tainted_by_statevar:', is_tainted_by_statevar ) elif node.type == NodeType.ENDLOOP: # print('<<<<<<<<<<<<<exit loop') in_loop = False if in_loop: has_nested_loop = any( (son.type == NodeType.STARTLOOP) for son in node.sons) if has_nested_loop: loopsum.append('nested_loop') for ir in node.irs: if isinstance(ir, (LowLevelCall, HighLevelCall, Send, Transfer)): if isinstance(ir, LibraryCall): has_lib_call = True loopsum.append('lib_call') else: has_transaction = True loopsum.append('transaction') if isinstance(ir, Condition): is_tainted_by_arg = is_tainted(ir.value, f) is_tainted_by_statevar = any( is_dependent(ir.value, t, f) for t in f.contract.state_variables) is_tained_by_local = not (is_tainted_by_arg or is_tainted_by_statevar) # print(is_tainted_by_arg, is_tainted_by_statevar, is_tained_by_local, node, type(node)) if is_tainted_by_arg: loopsum.append('tainted_by_arg') if is_tainted_by_statevar: loopsum.append('tainted_by_statevar') if is_tained_by_local: loopsum.append('tained_by_local') for son in node.sons: MultipleCallsInLoop.call_in_loop(f, son, in_loop, visited, ret, loopsum)
from slither import Slither from slither.analyses.data_dependency.data_dependency import is_dependent, is_tainted, pprint_dependency from slither.core.declarations.solidity_variables import SolidityVariableComposed slither = Slither('data_dependency.sol') contract = slither.get_contract_from_name('Simple') destination = contract.get_state_variable_from_name('destination') source = contract.get_state_variable_from_name('source') print('{} is dependent of {}: {}'.format( source, destination, is_dependent(source, destination, contract))) assert not is_dependent(source, destination, contract) print('{} is dependent of {}: {}'.format( destination, source, is_dependent(destination, source, contract))) assert is_dependent(destination, source, contract) print('{} is tainted {}'.format(source, is_tainted(source, contract, slither))) assert not is_tainted(source, contract, slither) print('{} is tainted {}'.format(destination, is_tainted(destination, contract, slither))) assert is_tainted(destination, contract, slither) contract = slither.get_contract_from_name('Reference') destination = contract.get_state_variable_from_name('destination') source = contract.get_state_variable_from_name('source') print('Reference contract') print('{} is dependent of {}: {}'.format( source, destination, is_dependent(source, destination, contract)))
def advancedUpdateEth(self, function): from slither.analyses.data_dependency.data_dependency import is_dependent allNodes = function.nodes for ethNode in function.ethNodes: entryPointToethNode = [] entryPointToethNode.append(function.entry_point) pilotProcessNodes = list( set(allNodes) - set([function.entry_point, ethNode])) entryPointToethNode.extend(pilotProcessNodes) entryPointToethNode.append(ethNode) adjMatrix = getadjMatrix(entryPointToethNode) mydeepGraph = MyDeepGraph(len(entryPointToethNode)) mydeepGraph.setadjMetrix(adjMatrix) allPaths = mydeepGraph.getPathofTwoNode( 0, len(entryPointToethNode) - 1) allPaths_Node = allPaths_intToNode(allPaths, entryPointToethNode) for path in allPaths_Node[:]: careifNodeStack = [] care_if_StateVariablesRead = set() care_RequireOrAssert_StateVariableRead = set() state_variables_written = set() for node in path: # [start, end] # 直接转帐函数cfg上的路径节点 if node.contains_require_or_assert(): care_RequireOrAssert_StateVariableRead |= set( node.state_variables_read) state_variables_written |= set( node.state_variables_written) if node.type == NodeType.IF: for son in node.sons: if son.type == NodeType.THROW or son.type == NodeType.RETURN: careifNodeStack.append(node) if node.type == NodeType.IF: careifNodeStack.append(node) if node.type == NodeType.ENDIF: if careifNodeStack: careifNodeStack.pop() if careifNodeStack: # eth被包裹在if中 for careifNode in careifNodeStack: care_if_StateVariablesRead |= set( careifNode.state_variables_read) for stateVariableWritten in state_variables_written: for careStateVariableRead in care_if_StateVariablesRead | care_RequireOrAssert_StateVariableRead: result = is_dependent(stateVariableWritten, careStateVariableRead, function.contract) if result == True: return True # allPaths_Node.remove(path) else: # 如果 转账语句不在if block中 for stateVariableWritten in state_variables_written: for careStateVariableRead in care_RequireOrAssert_StateVariableRead: result = is_dependent(stateVariableWritten, careStateVariableRead, function.contract) if result == True: return True #allPaths_Node.remove(path) #return False # if allPaths_Node: # return False return False
from slither.core.declarations.solidity_variables import SolidityVariableComposed if len(sys.argv) != 2: print("Usage: python data_dependency.py file.sol") sys.exit(-1) slither = Slither(sys.argv[1]) contracts = slither.get_contract_from_name("Simple") assert len(contracts) == 1 contract = contracts[0] destination = contract.get_state_variable_from_name("destination") source = contract.get_state_variable_from_name("source") print(f"{source} is dependent of {destination}: {is_dependent(source, destination, contract)}") assert not is_dependent(source, destination, contract) print(f"{destination} is dependent of {source}: {is_dependent(destination, source, contract)}") assert is_dependent(destination, source, contract) print(f"{source} is tainted {is_tainted(source, contract)}") assert not is_tainted(source, contract) print(f"{destination} is tainted {is_tainted(destination, contract)}") assert is_tainted(destination, contract) contracts = slither.get_contract_from_name("Reference") assert len(contracts) == 1 contract = contracts[0] destination = contract.get_state_variable_from_name("destination") assert destination source = contract.get_state_variable_from_name("source") assert source
def advancedUpdateEth(self, function): # PPT,检查程序执行锁 from slither.analyses.data_dependency.data_dependency import is_dependent allNodes = function.nodes path_between_sender_and_if = [] for ethNode in function.ethNodes: entryPointToethNode = [] entryPointToethNode.append(function.entry_point) pilotProcessNodes = list( set(allNodes) - set([function.entry_point, ethNode])) entryPointToethNode.extend(pilotProcessNodes) entryPointToethNode.append(ethNode) adjMatrix = getadjMatrix(entryPointToethNode) mydeepGraph = MyDeepGraph(len(entryPointToethNode)) mydeepGraph.setadjMetrix(adjMatrix) allPaths = mydeepGraph.getPathofTwoNode( 0, len(entryPointToethNode) - 1) allPaths_Node = allPaths_intToNode(allPaths, entryPointToethNode) for path in allPaths_Node[:]: careifNodeStack = [] care_if_StateVariablesRead = set() care_RequireOrAssert_StateVariableRead = set() state_variables_written = set() for node in path: # [start, end] # 直接转帐函数cfg上的路径节点 if node.contains_require_or_assert(): care_RequireOrAssert_StateVariableRead |= set( node.state_variables_read) state_variables_written |= set( node.state_variables_written) if node.type == NodeType.IF: for son in node.sons: if son.type == NodeType.THROW or son.type == NodeType.RETURN: careifNodeStack.append(node) if node.type == NodeType.IF: careifNodeStack.append(node) path_between_sender_and_if.append(node) if node.type == NodeType.ENDIF: if careifNodeStack: careifNodeStack.pop() path_between_sender_and_if = [] else: path_between_sender_and_if.append(node) if careifNodeStack: # 被包裹在if语句中的Node for careifNode in careifNodeStack: care_if_StateVariablesRead |= set( careifNode.state_variables_read) for stateVariableWritten in state_variables_written: if len(care_if_StateVariablesRead | care_RequireOrAssert_StateVariableRead) > 1: return True if len(care_if_StateVariablesRead | care_RequireOrAssert_StateVariableRead) == 0: return True careStateVariableRead = list( care_if_StateVariablesRead | care_RequireOrAssert_StateVariableRead)[0] for suspicious_node in path_between_sender_and_if: ir_list = suspicious_node.irs_ssa for ir in ir_list: if isinstance(ir, Assignment): if hasattr(ir.lvalue, 'pure_name'): if ir.lvalue.pure_name == careStateVariableRead.name: r_v = ir.rvalue else: if ir.lvalue.name == careStateVariableRead.name: r_v = ir.rvalue else: r_v = None continue var_list_length = len( care_if_StateVariablesRead | care_RequireOrAssert_StateVariableRead) for careifNode in careifNodeStack: symbol_result = solve_expression( careifNode.irs_ssa, r_v) if symbol_result == False: return True else: result = is_dependent(stateVariableWritten, careStateVariableRead, function.contract) if result == True: return True # TODO: 为什么这个位置是True # allPaths_Node.remove(path) else: # 如果 转账语句不在if block中 for stateVariableWritten in state_variables_written: for careStateVariableRead in care_RequireOrAssert_StateVariableRead: result = is_dependent(stateVariableWritten, careStateVariableRead, function.contract) if result == True: return True #allPaths_Node.remove(path) #return False # if allPaths_Node: # return False return False