Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
 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)
Ejemplo n.º 3
0
 def __init__(self, result, left_variable, right_variable, index_type):
     super().__init__()
     assert is_valid_lvalue(
         left_variable) or left_variable == SolidityVariableComposed(
             "msg.data")
     assert is_valid_rvalue(right_variable)
     assert isinstance(result, ReferenceVariable)
     self._variables = [left_variable, right_variable]
     self._type = index_type
     self._lvalue = result
def msg_value_in_loop(node: Node, in_loop_counter: int, visited: List[Node],
                      results: List[Node]) -> None:
    if node in visited:
        return
    # shared visited
    visited.append(node)

    if node.type == NodeType.STARTLOOP:
        in_loop_counter += 1
    elif node.type == NodeType.ENDLOOP:
        in_loop_counter -= 1

    for ir in node.all_slithir_operations():
        if in_loop_counter > 0 and SolidityVariableComposed(
                "msg.value") in ir.read:
            results.append(ir.node)
        if isinstance(ir, (InternalCall)):
            msg_value_in_loop(ir.function.entry_point, in_loop_counter,
                              visited, results)

    for son in node.sons:
        msg_value_in_loop(son, in_loop_counter, visited, results)
Ejemplo n.º 5
0
    def _post_call_expression(self, expression):
        called = get(expression.called)
        args = [get(a) for a in expression.arguments if a]
        for arg in args:
            arg_ = Argument(arg)
            arg_.set_expression(expression)
            self._result.append(arg_)
        if isinstance(called, Function):
            # internal call

            # If tuple
            if expression.type_call.startswith('tuple(') and expression.type_call != 'tuple()':
                val = TupleVariable(self._node)
            else:
                val = TemporaryVariable(self._node)
            internal_call = InternalCall(called, len(args), val, expression.type_call)
            internal_call.set_expression(expression)
            self._result.append(internal_call)
            set_val(expression, val)
        else:
            # yul things
            if called.name == 'caller()':
                val = TemporaryVariable(self._node)
                var = Assignment(val, SolidityVariableComposed('msg.sender'), 'uint256')
                self._result.append(var)
                set_val(expression, val)
            elif called.name == 'origin()':
                val = TemporaryVariable(self._node)
                var = Assignment(val, SolidityVariableComposed('tx.origin'), 'uint256')
                self._result.append(var)
                set_val(expression, val)
            elif called.name == 'extcodesize(uint256)':
                val = ReferenceVariable(self._node)
                var = Member(args[0], Constant('codesize'), val)
                self._result.append(var)
                set_val(expression, val)
            elif called.name == 'selfbalance()':
                val = TemporaryVariable(self._node)
                var = TypeConversion(val, SolidityVariable('this'), ElementaryType('address'))
                self._result.append(var)

                val1 = ReferenceVariable(self._node)
                var1 = Member(val, Constant('balance'), val1)
                self._result.append(var1)
                set_val(expression, val1)
            elif called.name == 'address()':
                val = TemporaryVariable(self._node)
                var = TypeConversion(val, SolidityVariable('this'), ElementaryType('address'))
                self._result.append(var)
                set_val(expression, val)
            elif called.name == 'callvalue()':
                val = TemporaryVariable(self._node)
                var = Assignment(val, SolidityVariableComposed('msg.value'), 'uint256')
                self._result.append(var)
                set_val(expression, val)
            else:
                # If tuple
                if expression.type_call.startswith('tuple(') and expression.type_call != 'tuple()':
                    val = TupleVariable(self._node)
                else:
                    val = TemporaryVariable(self._node)

                message_call = TmpCall(called, len(args), val, expression.type_call)
                message_call.set_expression(expression)
                # Gas/value are only accessible here if the syntax {gas: , value: }
                # Is used over .gas().value()
                if expression.call_gas:
                    call_gas = get(expression.call_gas)
                    message_call.call_gas = call_gas
                if expression.call_value:
                    call_value = get(expression.call_value)
                    message_call.call_value = call_value
                if expression.call_salt:
                    call_salt = get(expression.call_salt)
                    message_call.call_salt = call_salt
                self._result.append(message_call)
                set_val(expression, val)
Ejemplo n.º 6
0
def run_taint(slither):
    initial_taint = get_taint_state(slither)
    initial_taint += [SolidityVariableComposed('msg.sender')]

    if KEY not in slither.context:
        _run_taint(slither, initial_taint)
Ejemplo n.º 7
0
        context (Contract|Function)
        only_unprotected (bool): True only unprotected function are considered
    Returns:
        bool
    '''
    assert isinstance(context, (Contract, Function))
    context = context.context
    if isinstance(variable, Constant):
        return False
    if variable == source:
        return True
    if only_unprotected:
        return variable in context[KEY_SSA_UNPROTECTED] and source in context[KEY_SSA_UNPROTECTED][variable]
    return variable in context[KEY_SSA] and source in context[KEY_SSA][variable]

GENERIC_TAINT = {SolidityVariableComposed('msg.sender'),
                 SolidityVariableComposed('msg.value'),
                 SolidityVariableComposed('msg.data'),
                 SolidityVariableComposed('tx.origin')}

def is_tainted(variable, context, only_unprotected=False, ignore_generic_taint=False):
    '''
        Args:
        variable
        context (Contract|Function)
        only_unprotected (bool): True only unprotected function are considered
    Returns:
        bool
    '''
    assert isinstance(context, (Contract, Function))
    assert isinstance(only_unprotected, bool)
Ejemplo n.º 8
0
        bool
    """
    assert isinstance(context, (Contract, Function))
    context = context.context
    if isinstance(variable, Constant):
        return False
    if variable == source:
        return True
    if only_unprotected:
        return (variable in context[KEY_SSA_UNPROTECTED]
                and source in context[KEY_SSA_UNPROTECTED][variable])
    return variable in context[KEY_SSA] and source in context[KEY_SSA][variable]


GENERIC_TAINT = {
    SolidityVariableComposed("msg.sender"),
    SolidityVariableComposed("msg.value"),
    SolidityVariableComposed("msg.data"),
    SolidityVariableComposed("tx.origin"),
}


def is_tainted(variable,
               context,
               only_unprotected=False,
               ignore_generic_taint=False):
    """
        Args:
        variable
        context (Contract|Function)
        only_unprotected (bool): True only unprotected function are considered
    def _post_call_expression(self, expression):  # pylint: disable=too-many-branches,too-many-statements
        called = get(expression.called)
        args = [get(a) for a in expression.arguments if a]
        for arg in args:
            arg_ = Argument(arg)
            arg_.set_expression(expression)
            self._result.append(arg_)
        if isinstance(called, Function):
            # internal call

            # If tuple
            if expression.type_call.startswith(
                    "tuple(") and expression.type_call != "tuple()":
                val = TupleVariable(self._node)
            else:
                val = TemporaryVariable(self._node)
            internal_call = InternalCall(called, len(args), val,
                                         expression.type_call)
            internal_call.set_expression(expression)
            self._result.append(internal_call)
            set_val(expression, val)
        else:
            # yul things
            if called.name == "caller()":
                val = TemporaryVariable(self._node)
                var = Assignment(val, SolidityVariableComposed("msg.sender"),
                                 "uint256")
                self._result.append(var)
                set_val(expression, val)
            elif called.name == "origin()":
                val = TemporaryVariable(self._node)
                var = Assignment(val, SolidityVariableComposed("tx.origin"),
                                 "uint256")
                self._result.append(var)
                set_val(expression, val)
            elif called.name == "extcodesize(uint256)":
                val = ReferenceVariable(self._node)
                var = Member(args[0], Constant("codesize"), val)
                self._result.append(var)
                set_val(expression, val)
            elif called.name == "selfbalance()":
                val = TemporaryVariable(self._node)
                var = TypeConversion(val, SolidityVariable("this"),
                                     ElementaryType("address"))
                self._result.append(var)

                val1 = ReferenceVariable(self._node)
                var1 = Member(val, Constant("balance"), val1)
                self._result.append(var1)
                set_val(expression, val1)
            elif called.name == "address()":
                val = TemporaryVariable(self._node)
                var = TypeConversion(val, SolidityVariable("this"),
                                     ElementaryType("address"))
                self._result.append(var)
                set_val(expression, val)
            elif called.name == "callvalue()":
                val = TemporaryVariable(self._node)
                var = Assignment(val, SolidityVariableComposed("msg.value"),
                                 "uint256")
                self._result.append(var)
                set_val(expression, val)
            else:
                # If tuple
                if expression.type_call.startswith(
                        "tuple(") and expression.type_call != "tuple()":
                    val = TupleVariable(self._node)
                else:
                    val = TemporaryVariable(self._node)

                message_call = TmpCall(called, len(args), val,
                                       expression.type_call)
                message_call.set_expression(expression)
                # Gas/value are only accessible here if the syntax {gas: , value: }
                # Is used over .gas().value()
                if expression.call_gas:
                    call_gas = get(expression.call_gas)
                    message_call.call_gas = call_gas
                if expression.call_value:
                    call_value = get(expression.call_value)
                    message_call.call_value = call_value
                if expression.call_salt:
                    call_salt = get(expression.call_salt)
                    message_call.call_salt = call_salt
                self._result.append(message_call)
                set_val(expression, val)
Ejemplo n.º 10
0
        bool
    '''
    assert isinstance(context, (Contract, Function))
    context = context.context
    if isinstance(variable, Constant):
        return False
    if variable == source:
        return True
    if only_unprotected:
        return variable in context[KEY_SSA_UNPROTECTED] and source in context[
            KEY_SSA_UNPROTECTED][variable]
    return variable in context[KEY_SSA] and source in context[KEY_SSA][variable]


GENERIC_TAINT = {
    SolidityVariableComposed('msg.sender'),
    SolidityVariableComposed('msg.value'),
    SolidityVariableComposed('msg.data'),
    SolidityVariableComposed('tx.origin')
}


def is_tainted(variable,
               context,
               only_unprotected=False,
               ignore_generic_taint=False):
    '''
        Args:
        variable
        context (Contract|Function)
        only_unprotected (bool): True only unprotected function are considered
Ejemplo n.º 11
0
class Dependency(Analysis):

    dependencies = {}
    dependencies_phis = {}

    def is_dependent(self, variable, source, context, only_unprotected=False):
        '''
        Args:
            variable (Variable)
            source (Variable)
            context (Contract|Function)
            only_unprotected (bool): True only unprotected function are considered
        Returns:
            bool
        '''
        assert isinstance(context, (Contract, Function))
        if isinstance(variable, Constant):
            return False
        if variable == source:
            return True
        context = context.context

        print(context[self.KEY_NON_SSA][variable])

        if only_unprotected:
            return variable in context[
                self.KEY_NON_SSA_UNPROTECTED] and source in context[
                    self.KEY_NON_SSA_UNPROTECTED][variable]
        return variable in context[self.KEY_NON_SSA] and source in context[
            self.KEY_NON_SSA][variable]

    def is_dependent_ssa(self,
                         variable,
                         source,
                         context,
                         only_unprotected=False):
        '''
        Args:
            variable (Variable)
            taint (Variable)
            context (Contract|Function)
            only_unprotected (bool): True only unprotected function are considered
        Returns:
            bool
        '''
        assert isinstance(context, (Contract, Function))
        context = context.context
        if isinstance(variable, Constant):
            return False
        if variable == source:
            return True
        if only_unprotected:
            return variable in context[
                self.KEY_SSA_UNPROTECTED] and source in context[
                    self.KEY_SSA_UNPROTECTED][variable]
        return variable in context[self.KEY_SSA] and source in context[
            self.KEY_SSA][variable]

    GENERIC_TAINT = {
        SolidityVariableComposed('msg.sender'),
        SolidityVariableComposed('msg.value'),
        SolidityVariableComposed('msg.data'),
        SolidityVariableComposed('tx.origin')
    }

    def is_tainted(self,
                   variable,
                   context,
                   only_unprotected=False,
                   ignore_generic_taint=False):
        '''
            Args:
            variable
            context (Contract|Function)
            only_unprotected (bool): True only unprotected function are considered
        Returns:
            bool
        '''
        assert isinstance(context, (Contract, Function))
        assert isinstance(only_unprotected, bool)
        if isinstance(variable, Constant):
            return False
        slither = context.slither
        taints = slither.context[self.KEY_INPUT]
        if not ignore_generic_taint:
            taints |= GENERIC_TAINT
        return variable in taints or any(
            is_dependent(variable, t, context, only_unprotected)
            for t in taints)

    def is_tainted_ssa(self,
                       variable,
                       context,
                       only_unprotected=False,
                       ignore_generic_taint=False):
        '''
        Args:
            variable
            context (Contract|Function)
            only_unprotected (bool): True only unprotected function are considered
        Returns:
            bool
        '''
        assert isinstance(context, (Contract, Function))
        assert isinstance(only_unprotected, bool)
        if isinstance(variable, Constant):
            return False
        slither = context.slither
        taints = slither.context[self.KEY_INPUT_SSA]
        if not ignore_generic_taint:
            taints |= GENERIC_TAINT
        return variable in taints or any(
            is_dependent_ssa(variable, t, context, only_unprotected)
            for t in taints)

    def get_dependencies(self, variable, context, only_unprotected=False):
        '''
        Args:
            variable
            context (Contract|Function)
            only_unprotected (bool): True only unprotected function are considered
        Returns:
            list(Variable)
        '''
        assert isinstance(context, (Contract, Function))
        assert isinstance(only_unprotected, bool)
        if only_unprotected:
            return context.context[self.KEY_NON_SSA].get(variable, [])
        return context.context[self.KEY_NON_SSA_UNPROTECTED].get(variable, [])

    def pprint_dependency(self, context=None):
        if context: context = context.context
        print('#### NON SSA ####')
        if context:
            items = context[self.KEY_NON_SSA].items()
        else:
            items = self.dependencies.items()
        for k, values in items:
            print('{} ({}):'.format(k, hex(id(k))))
            for v in values:
                print('\t- {} ({})'.format(v, hex(id(v))))

    def add(self, lvalue, function, ir, is_protected):
        phi = False
        if not lvalue in function.context[self.KEY_SSA]:
            function.context[self.KEY_SSA][lvalue] = set()
            if not is_protected:
                function.context[self.KEY_SSA_UNPROTECTED][lvalue] = set()
        if isinstance(ir, Index):
            lvalue_split = str(lvalue).split('_')
            lvalue_base = lvalue_split[0] if len(lvalue_split) > 0 else None
            ir_split = str(ir.variable_left).split('_')
            ir_base = ir_split[0] if len(ir_split) > 0 else None
            # AVOID SELF DEPENDENCE?
            if ir_base == lvalue_base:
                return
            # if lvalue == ir.variable_left:
            #     return
            read = [ir.variable_left, ir.variable_right]
        elif isinstance(ir, InternalCall):
            read = ir.function.return_values_ssa
        elif isinstance(ir, Phi):
            phi = True
            if lvalue not in self.dependencies_phis:
                self.dependencies_phis[lvalue] = set()
            for rv in ir.rvalues:
                if not (lvalue in function.context[self.KEY_SSA]
                        and rv in function.context[self.KEY_SSA][lvalue]):
                    # print("ADDED: {0}, {1}".format(lvalue, rv))
                    self.dependencies_phis[lvalue].add(rv)
            # read = ir.rvalues
            read = []
        else:
            read = ir.read
        if not phi and lvalue in self.dependencies_phis:
            for rv in read:
                if not isinstance(
                        rv, Constant) and rv in self.dependencies_phis[lvalue]:
                    # print("REMOVED: {0}, {1}".format(lvalue, rv))
                    self.dependencies_phis[lvalue].remove(rv)
        [
            function.context[self.KEY_SSA][lvalue].add(v) for v in read
            if not isinstance(v, Constant)
        ]
        if not is_protected:
            [
                function.context[self.KEY_SSA_UNPROTECTED][lvalue].add(v)
                for v in read if not isinstance(v, Constant)
            ]

    def compute_function(self, function):
        # if self.KEY_SSA in function.context:
        #     return

        function.context[self.KEY_SSA] = dict()
        function.context[self.KEY_SSA_UNPROTECTED] = dict()

        is_protected = function.is_protected()
        test = 0
        for node in function.nodes:
            for ir in node.irs_ssa:
                if isinstance(
                        ir,
                        OperationWithLValue) and ir.lvalue and not isinstance(
                            ir, Phi) and not isinstance(ir, Length):
                    # if isinstance(ir, OperationWithLValue) and ir.lvalue:
                    if test > -1:
                        if isinstance(
                                ir.lvalue,
                                LocalIRVariable) and ir.lvalue.is_storage:
                            test += 1
                            continue
                        if isinstance(ir.lvalue, ReferenceVariable):
                            lvalue = ir.lvalue.points_to
                            if lvalue:
                                self.add(lvalue, function, ir, is_protected)
                        self.add(ir.lvalue, function, ir, is_protected)
                    test += 1
                elif isinstance(ir, Phi):
                    self.add(ir.lvalue, function, ir, is_protected)

        function.context[self.KEY_NON_SSA] = self.convert_to_non_ssa(
            function.context[self.KEY_SSA])
        function.context[
            self.KEY_NON_SSA_UNPROTECTED] = self.convert_to_non_ssa(
                function.context[self.KEY_SSA_UNPROTECTED])
        ret = self.dependencies_phis
        self.dependencies_phis = {}
        return ret