def execute(statespace): """ Executes analysis module for delegate call analysis module :param statespace: Statespace to analyse :return: Found issues """ issues = [] for call in statespace.calls: if call.type is not "DELEGATECALL": continue if call.node.function_name is not "fallback": continue state = call.state address = state.get_current_instruction()['address'] meminstart = get_variable(state.mstate.stack[-3]) if meminstart.type == VarType.CONCRETE: issues += _concrete_call(call, state, address, meminstart) if call.to.type == VarType.SYMBOLIC: issues += _symbolic_call(call, state, address, statespace) return issues
def _analyze_states(state: GlobalState) -> List[Issue]: """ :param state: the current state :return: returns the issues for that corresponding state """ call = get_call_from_state(state) if call is None: return [] issues = [] # type: List[Issue] if call.type is not "DELEGATECALL": return [] if call.node.function_name is not "fallback": return [] state = call.state address = state.get_current_instruction()["address"] meminstart = get_variable(state.mstate.stack[-3]) if meminstart.type == VarType.CONCRETE: issues += _concrete_call(call, state, address, meminstart) return issues
def get_call_from_state(state: GlobalState) -> Union[Call, None]: """ :param state: :return: """ instruction = state.get_current_instruction() op = instruction["opcode"] stack = state.mstate.stack if op in ("CALL", "CALLCODE", "STATICCALL"): gas, to, value, meminstart, meminsz, memoutstart, memoutsz = ( get_variable(stack[-1]), get_variable(stack[-2]), get_variable(stack[-3]), get_variable(stack[-4]), get_variable(stack[-5]), get_variable(stack[-6]), get_variable(stack[-7]), ) if to.type == VarType.CONCRETE and 0 < to.val < 5: return None if meminstart.type == VarType.CONCRETE and meminsz.type == VarType.CONCRETE: return Call( state.node, state, None, op, to, gas, value, state.mstate.memory[meminstart.val : meminsz.val * 4], ) else: return Call(state.node, state, None, op, to, gas, value) else: gas, to, meminstart, meminsz, memoutstart, memoutsz = ( get_variable(stack[-1]), get_variable(stack[-2]), get_variable(stack[-3]), get_variable(stack[-4]), get_variable(stack[-5]), get_variable(stack[-6]), ) return Call(state.node, state, None, op, to, gas)
def execute(statespace): issues = [] for call in statespace.calls: if (call.type == "DELEGATECALL"): state = call.state address = state.get_current_instruction()['address'] if (call.node.function_name == "fallback"): stack = state.mstate.stack meminstart = get_variable(stack[-3]) if meminstart.type == VarType.CONCRETE: if (re.search(r'calldata.*_0', str(state.mstate.memory[meminstart.val]))): issue = Issue( call.node.contract_name, call.node.function_name, address, "Call data forwarded with delegatecall()", "Informational") issue.description = \ "This contract forwards its call data via DELEGATECALL in its fallback function. " \ "This means that any function in the called contract can be executed. Note that the callee contract will have access to the storage of the calling contract.\n" if (call.to.type == VarType.CONCRETE): issue.description += ("DELEGATECALL target: " + hex(call.to.val)) else: issue.description += "DELEGATECALL target: " + str( call.to) issues.append(issue) if (call.to.type == VarType.SYMBOLIC): issue = Issue(call.node.contract_name, call.node.function_name, address, call.type + " to a user-supplied address") if ("calldata" in str(call.to)): issue.description = \ "This contract delegates execution to a contract address obtained from calldata. " else: m = re.search(r'storage_([a-z0-9_&^]+)', str(call.to)) if (m): idx = m.group(1) func = statespace.find_storage_write(idx) if (func): issue.description = "This contract delegates execution to a contract address in storage slot " + str( idx ) + ". This storage slot can be written to by calling the function '" + func + "'. " else: logging.debug( "[DELEGATECALL] No storage writes to index " + str(idx)) issue.description += "Be aware that the called contract gets unrestricted access to this contract's state." issues.append(issue) return issues