Example #1
0
    def visit(self, node, state):
        currscope = self.locate_scope(node, state)
        varnode = node.node
        var_name = varnode.name

        # Store object properties (vars, class variables) as $this->property
        # otherwise $a->var and $b->var overwrite each other (both stored as $var).
        if type(node.node) is phpast.ObjectProperty:
            var_name = node.node.node.name + "->" + varnode.name

        # Create var
        newobj = VariableDef(var_name, varnode.lineno, currscope, ast_node=node.expr)
        node._obj = newobj

        currscope.add_var(newobj)

        # New object property? Also add var to parent scope (if not exist)
        if type(node.node) is phpast.ObjectProperty:
            root_scope = currscope.get_root_scope()._parent_scope
            if not root_scope.get_var(var_name):
                # create object var
                property = VariableDef(var_name, varnode.lineno, currscope, ast_node=node.expr)
                property.parents = [newobj]
                root_scope.add_var(property)

        # Overwrite object property
        if type(node.node) is phpast.ObjectProperty:
            # link this var to object property
            root_scope = currscope.get_root_scope()
            if type(root_scope._ast_node) is phpast.Method:
                # link this var to property
                root_scope._parent_scope.get_var(var_name).parents = [newobj]

        # Object creation
        if type(node.expr) is phpast.New and node.expr.name in state.classes:
            # Start ast travel class Node
            class_node = state.classes[node.expr.name]
            class_node._object = True
            class_node._object_var = newobj  # pass this var to object
            class_node.accept(self._main_visitor_method)

        return newobj, False
Example #2
0
    def visit(self, node, state):
        stoponthis = False
        newobj = None
        
        # global parent scope
        parentscope = self.locate_scope(node, state)
        
        if not getattr(node, '_object', False):
            # Start traveling node when instance is created
            node._parent_scope = parentscope
            state.classes[node.name] = node
            stoponthis = True
        else:
            # new instance has been created
            # Create new Scope and push it onto the stack
            newscope = Scope(node, parent_scope=parentscope, is_root=True)
            
            # add builtins to scope
            newscope._builtins = dict(
                    ((uv, VariableDef(uv, -1, newscope)) for uv in VariableDef.USER_VARS))
                            
            state.scopes.append(newscope)
            
            newobj = Obj(node.name, node.lineno, newscope, node._object_var, ast_node=node)
            
            # create $this var for internal method calling
            this_var = VariableDef('$this', node.lineno, newscope)
            this_var._obj_def = newobj
            newscope.add_var(this_var)
            
            # add ObjDef to VarDef, this way we can trace method call back to the correct instance
            node._object_var._obj_def = newobj            
            
            node._scope = newscope
            state.objects[node._object_var.name] = node._object_var

        return newobj, stoponthis

        
Example #3
0
    def _parse_me(self, node, scope):
        '''
        TODO: add method call
        
        Traverse this AST subtree until either a Variable or FunctionCall node
        is found...
        '''
        for node in NodeRep.parse(node):
            
            if type(node) is phpast.BinaryOp:
                # only parse direct nodes
                for item in NodeRep.parse(node, 0, 0, 1): 
                    self._parse_me(item, scope)
                break
            
            if type(node) is phpast.Variable:
                # object properties are stored as $this->property
                varname = node.name
                if type(node._parent_node) is phpast.ObjectProperty:
                    varname = node._parent_node.node.name + '->' + node._parent_node.name 
                 
                vardef = VariableDef(varname + '__$temp_anon_var$_', node.lineno, scope)
                vardef.var_nodes = [node]
                # anon var is not stored in scope
                vardef._anon_var = True
                # get and set parent
                scopevar = scope.get_var(varname)
                vardef.add_parent(scopevar)
                # add Param to VarDef
                # TODO: not really necessary?
                vardef._parent_obj = self
                # add var to current scope
                scope.add_var(vardef)
                self.vars.append(vardef)
                break
            
            elif type(node) is phpast.FunctionCall:
                
                # TEST call functioncal visitor
                from core.visitors.base_visitor import BaseVisitor
                from core.visitors.function_call_visitor import FunctionCallVisitor
                
                visitor = FunctionCallVisitor(BaseVisitor);
                fc, stoponthis = visitor.visit(node, scope.get_state())
                
                vardef = VariableDef(node.name + '_funvar', node.lineno, scope)
                
#                 from core.nodes.function_call import FuncCall
#                 from core.nodes.function_call import FuncCall
#                 fc = FuncCall(node.name, node.lineno, node, scope, self)
                
                #TODO: Can we do this in a more extensible way? Why different ways for handling FILE_DISC / XSS?
                # Add vulntrace
                vulntype = fc.is_vulnerable_for()
                if vulntype and 'FILE_DISCLOSURE' in vulntype and \
                self._parent_obj.name in SENSITIVE_FUNCTIONS['XSS']: 
                    # Add vulntrace to parent call with pending trace
                    fc.add_vulntrace(vulntype)
                    self._parent_obj._pending_trace = fc.get_vulntraces()[-1]
                    vardef._safe_for.append('XSS')
                    vardef.set_clean()
                 
#                 elif vulntype:
#                     fc.add_vulntrace(vulntype)
#                     # Keep track of thin funccal
#                     self.get_root_obj()._functions.append(fc)
#                     vardef.set_clean()
                
                # return values (custom function)?
                called_obj = fc.get_called_obj();
                if called_obj:
                    # Set function scope as active code
                    called_obj._scope._dead_code = False
                    for var in called_obj._return_vars:
                        vardef.add_parent(var)
#                  
                else:
                    for param in fc.params:
                        for var in param.vars:
                            vardef.add_parent(var)
                   
                # Securing function?
                vulnty = get_vulnty_for_sec(fc.name)
                if vulnty:
                    vardef._safe_for.append(vulnty)
                
                self.vars.append(vardef)
                break