def are_variants( url_a ,  url_b ):
    '''
    This function analyzes if two URLs are variants. Two requests are variants if:
        - They have the same URL
        - They have the same method
        - They have the same parameters
        - The values for each parameter have the same type (int / string)
    
    @parameter url_a: The URL we want to analyze
    @parameter url_b: The other URL we want to analyze
    @return: True if the URLs are variants.
    '''
    qs_a = urlParser.getQueryString( url_a )
    qsr_a = httpQsRequest.httpQsRequest()
    qsr_a.setURL( urlParser.uri2url(url_a) )
    qsr_a.setDc( qs_a )

    qs_b = urlParser.getQueryString( url_b )
    qsr_b = httpQsRequest.httpQsRequest()
    qsr_b.setURL( urlParser.uri2url(url_b) )
    qsr_b.setDc( qs_b )
    return qsr_a.is_variant_of( qsr_b )
Пример #2
0
    def _analyze_urls(self, references):
        '''
        Analyze what references are cached by archive.org
        
        @return: A list of query string objects for the URLs that are in the cache AND are in the
                    target web site.
        '''
        # Init some internal variables
        res = []
    
        # Translate archive.org URL's to normal URL's
        real_URLs = []
        for url in references:
            try:
                url = url.url_string[url.url_string.url.index('http', 1):]
            except Exception:
                pass
            else:
                real_URLs.append( url )
        real_URLs = list(set(real_URLs))
        
        if len( real_URLs ):
            om.out.debug('Archive.org cached the following pages:')
            for i in real_URLs:
                om.out.debug('- ' + i )
        else:
            om.out.debug('Archive.org did not find any pages.')
        
        # Verify if they exist in the target site and add them to the result if they do.
        for real_url in real_URLs:
            if self._exists_in_target( real_url ):
                QSObject = real_url.getQueryString()
                qsr = httpQsRequest()
                qsr.setURI( real_url )
                qsr.setDc( QSObject )
                res.append( qsr )

        if len( res ):
            msg = 'The following pages are in Archive.org cache and also in'
            msg += ' the target site:'
            om.out.debug(msg)
            for i in res:
                om.out.debug('- ' + i.getURI() )
        else:
            om.out.debug('All pages found in archive.org cache are missing in the target site.')
            
        return res
Пример #3
0
    def fastExploit(self):
        """
        Exploits a web app with [blind] sql injections vulns.
        The options are configured using the plugin options and setOptions() method.
        """
        om.out.debug("Starting sqlmap fastExploit.")
        om.out.console(SQLMAPCREATORS)

        if self._url is None or self._method is None or self._data is None or self._injvar is None:
            raise w3afException("You have to configure the plugin parameters")
        else:

            freq = None
            if self._method == "POST":
                freq = httpPostDataRequest.httpPostDataRequest()
            elif self._method == "GET":
                freq = httpQsRequest.httpQsRequest()
            else:
                raise w3afException("Method not supported.")

            freq.setURL(self._url)
            freq.setDc(urlParser.getQueryString("http://a/a.txt?" + self._data))
            freq.setHeaders({})

            bsql = blind_sqli_response_diff()
            bsql.setUrlOpener(self._urlOpener)
            bsql.setEqualLimit(self._equalLimit)
            bsql.setEquAlgorithm(self._equAlgorithm)

            vuln_obj = bsql.is_injectable(freq, self._injvar)
            if not vuln_obj:
                raise w3afException("Could not verify SQL injection " + str(vuln))
            else:
                om.out.console("SQL injection could be verified, trying to create the DB driver.")

                # Try to get a shell using all vuln
                msg = "Trying to exploit using vulnerability with id: " + str(vuln_obj.getId())
                msg += ". Please wait..."
                om.out.console(msg)
                shell_obj = self._generateShell(vuln_obj)
                if shell_obj is not None:
                    kb.kb.append(self, "shell", shell_obj)
                    return [shell_obj]

                raise w3afException("No exploitable vulnerabilities found.")
Пример #4
0
 def fastExploit( self ):
     '''
     Exploits a web app with [blind] sql injections vulns.
     The options are configured using the plugin options and setOptions() method.
     '''
     om.out.debug( 'Starting sqlmap fastExploit.' )
     om.out.console( SQLMAPCREATORS )
     
     if self._url is None or self._method is None or self._data is None or self._injvar is None:
         raise w3afException('You have to configure the plugin parameters')
     else:
         
         freq = None
         if self._method == 'POST':
             freq = httpPostDataRequest.httpPostDataRequest()
         elif self._method == 'GET':
             freq = httpQsRequest.httpQsRequest()
         else:
             raise w3afException('Method not supported.')
         
         freq.setURL( self._url )
         freq.setDc( parse_qs( self._data ) )
         freq.setHeaders( {} )
         
         bsql = blind_sqli_response_diff()
         bsql.setUrlOpener( self._urlOpener )
         bsql.setEqualLimit( self._equalLimit )
         bsql.setEquAlgorithm( self._equAlgorithm )
         
         vuln_obj = bsql.is_injectable( freq, self._injvar )
         if not vuln_obj:
             raise w3afException('Could not verify SQL injection ' + str(vuln) )
         else:
             om.out.console('SQL injection could be verified, trying to create the DB driver.')
             
             # Try to get a shell using all vuln
             msg = 'Trying to exploit using vulnerability with id: ' + str( vuln_obj.getId() )
             msg += '. Please wait...'
             om.out.console( msg )
             shell_obj = self._generateShell( vuln_obj )
             if shell_obj is not None:
                 kb.kb.append( self, 'shell', shell_obj )
                 return [shell_obj, ]
                 
             raise w3afException('No exploitable vulnerabilities found.')
def isExchangable( self, fuzzableRequest ):
    '''
    @parameter mutant: The mutant you want to test if sending using querystring or postdata is the same.
    @return: [True|False]
    '''
    if not ( isinstance( fuzzableRequest, httpQsRequest ) or isinstance( fuzzableRequest, httpPostDataRequest ) ) :
        return False
        
    # I get the mutant as it is
    response = self._sendMutant( fuzzableRequest, analyze=False )
    if fuzzableRequest.getMethod() == 'GET':
        # I have to create a httpPostDataRequest and set all the parameters to it.
        pdr = httpPostDataRequest()
        pdr.setURL( fuzzableRequest.getURL() )
        pdr.setDc( fuzzableRequest.getDc() )
        pdr.setHeaders( fuzzableRequest.getHeaders() )
        pdr.setCookie( fuzzableRequest.getCookie() )
        response2 = self._sendMutant( pdr, analyze=False )
        
        if response2.getBody() == response.getBody():
            return True
    
    elif fuzzableRequest.getMethod() == 'POST':
        # I have to create a httpQsRequest and set all the parameters to it.
        qsr = httpQsRequest()
        qsr.setURL( fuzzableRequest.getURL() )
        qsr.setDc( fuzzableRequest.getDc() )
        qsr.setHeaders( fuzzableRequest.getHeaders() )
        qsr.setCookie( fuzzableRequest.getCookie() )
        response2 = self._sendMutant( qsr, analyze=False )
        
        if response2.getBody() == response.getBody():
            return True 
    
    else:
        return False
Пример #6
0
def createFuzzableRequests( httpResponse, request=None, add_self=True ):
    '''
    Generates the fuzzable requests based on an http response instance.
    
    @parameter httpResponse: An httpResponse instance.
    @parameter request: The HTTP request that generated the httpResponse
    @parameter add_self: If I should add the current HTTP request (@parameter request) to the result
    on not.
    
    @return: A list of fuzzable requests.
    '''
    res = []
    
    # query string
    url = httpResponse.getURL()
    QSObject = httpResponse.getURI().getQueryString()
    
    # Headers for all fuzzable requests created here:
    # And add the fuzzable headers to the dict
    headers = {}
    for header_name in cf.cf.getData('fuzzableHeaders' ):
        if header_name not in headers:
            headers[ header_name ] = ''
    
    # Get the cookie!
    cookieObj = _createCookie( httpResponse )
    
    #
    # create the fuzzable request that represents the request object passed as parameter
    #
    if add_self:
        self_headers = {}
        if request:
            self_headers = request.getHeaders()
        for header_name in cf.cf.getData('fuzzableHeaders' ):
            if header_name not in headers:
                self_headers[ header_name ] = ''

        qsr = httpQsRequest.httpQsRequest()
        qsr.setURL( url )
        qsr.setDc( QSObject )
        qsr.setHeaders( self_headers )
        qsr.setCookie( cookieObj )
        res.append( qsr )
    
    # Try to find forms in the document
    form_list = []
    try:
        dp = dpCache.dpc.getDocumentParserFor( httpResponse )
    except w3afException:
        # Failed to find a suitable parser for the document
        pass
    else:
        form_list = dp.getForms()
    
    if not form_list:
        
        # Check if its a wsdl file
        wsdlp = wsdlParser.wsdlParser()
        try:
            wsdlp.setWsdl( httpResponse.getBody() )
        except w3afException:
            pass
        else:
            webServiceList = wsdlp.getMethods()
            if len( webServiceList ) != 0:
                for remoteMethod in webServiceList:
                    wspdr = wsPostDataRequest.wsPostDataRequest()
                    wspdr.setURL( remoteMethod.getLocation() )
                    wspdr.setAction( remoteMethod.getAction() )
                    wspdr.setParameters( remoteMethod.getParameters() )
                    wspdr.setNS( remoteMethod.getNamespace() )
                    wspdr.setMethodName( remoteMethod.getMethodName() )
                    wspdr.setHeaders( headers )
                    res.append( wspdr )     
        
    else:
        # create one httpPostDataRequest for each form variant
        mode = cf.cf.getData('fuzzFormComboValues')
        for form in form_list:
            for variant in form.getVariants(mode):
                if form.getMethod().upper() == 'POST':
                    r = httpPostDataRequest.httpPostDataRequest()
                    r.setMethod(variant.getMethod())
                    r.setFileVariables(form.getFileVariables())
                else:
                    # The default is a GET request
                    r = httpQsRequest.httpQsRequest()
                r.setURL(variant.getAction())
                r.setDc(variant)
                r.setHeaders(headers)
                r.setCookie(cookieObj)
                res.append(r)
    return res
Пример #7
0
def createFuzzableRequestRaw(method, url, postData, headers):
    '''
    Creates a fuzzable request based on a query sent FROM the browser. This is used in
    plugins like spiderMan.
    
    @parameter method: A string that represents the method ('GET', 'POST', etc)
    @parameter url: An url_object that represents the URL
    @parameter postData: A string that represents the postdata, if its a GET request, set to None.
    @parameter headers: A dict that holds the headers
    '''
    if not isinstance(url, url_object):
        msg = 'The "url" parameter of createFuzzableRequestRaw @ frFactory'
        msg += ' must be of urlParser.url_object type.'
        raise ValueError( msg )

    
    #
    # Just a query string request ! no postdata
    #
    if not postData:
        qsr = httpQsRequest.httpQsRequest()
        qsr.setURL(url)
        qsr.setMethod(method)
        qsr.setHeaders(headers)
        dc = url.getQueryString()
        qsr.setDc(dc)
        return qsr
    #
    # Seems to be something that has post data
    #
    pdr = httpPostDataRequest.httpPostDataRequest()
    pdr.setURL(url)
    pdr.setMethod(method)
    for header_name in headers.keys():
        if header_name.lower() == 'content-length':
            del headers[header_name]
    pdr.setHeaders(headers)
    #
    #   Parse the content
    #   Case #1, multipart form data
    #
    conttype = headers.get('content-type', '')
    if conttype and conttype.startswith('multipart/form-data'):
        tmp, pdict = cgi.parse_header(conttype)
        try:
            dc = cgi.parse_multipart(StringIO(postData), pdict)
        except:
            om.out.debug('Multipart form data is invalid, the browser sent something weird.')
        else:
            resultDc = queryString()
            for i in dc.keys():
                resultDc[i] = dc[i]
            # We process multipart requests as x-www-form-urlencoded
            # TODO We need native support of multipart requests!
            headers['content-type'] = 'application/x-www-form-urlencoded'
            pdr.setDc(resultDc)
            pdr.setHeaders(headers)
            return pdr
    #
    #   Case #2, JSON request
    #
    try:
        dc = json.loads(postData)
    except:
        pass
    else:
        # It's json! welcome to the party dude!
        pdr = jsonPostDataRequest.jsonPostDataRequest()
        pdr.setURL(url)
        pdr.setMethod(method)
        pdr.setHeaders(headers)
        pdr.setDc(dc)
        return pdr
    #
    #   Case #3, XMLRPC request
    #
    postDataLower = postData.lower()
    stopWords = [
            '<methodcall>',
            '<methodname>',
            '<params>',
            '</methodcall>',
            '</methodname>',
            '</params>'
            ]
    allStopWords = True
    for word in stopWords:
        if word not in postDataLower:
            allStopWords = False
    if allStopWords:
        xmlrpc_request = xmlrpcRequest.xmlrpcRequest(postData)
        xmlrpc_request.setURL( url )
        xmlrpc_request.setMethod( method )
        xmlrpc_request.setHeaders( headers )
        return xmlrpc_request
    #
    #   Case #4, the "default".
    #
    # NOT a JSON or XMLRPC request!, let's try the simple url encoded post data...
    #
    try:
        dc = parse_qs(postData)
        pdr.setDc( dc )
    except:
        om.out.debug('Failed to create a data container that can store this data: "' + postData + '".')
    else:
        return pdr
Пример #8
0
def are_variants( url_a ,  url_b ):
    '''
    This function analyzes if two URLs are variants. Two requests are variants if:
        - They have the same URL
        - They have the same method
        - They have the same parameters
        - The values for each parameter have the same type (int / string)
    
    @parameter url_a: The URL we want to analyze
    @parameter url_b: The other URL we want to analyze
    @return: True if the URLs are variants.

    >>> from core.data.parsers.urlParser import url_object
    >>> a = url_object('http://www.w3af.com/foo.php')
    >>> b = url_object('http://www.w3af.com/foo.php')
    >>> are_variants( a, b )
    True

    >>> a = url_object('http://www.w3af.com/foo.php?id=1')
    >>> b = url_object('http://www.w3af.com/foo.php?foo=1')
    >>> are_variants( a, b )
    False

    >>> a = url_object('http://www.w3af.com/bar.php?id=1')
    >>> b = url_object('http://www.w3af.com/foo.php?foo=1')
    >>> are_variants( a, b )
    False

    >>> a = url_object('http://www.w3af.com/foo.php?id=1')
    >>> b = url_object('http://www.rapid7.com/foo.php?id=1')
    >>> are_variants( a, b )
    False

    >>> a = url_object('http://www.w3af.com/foo.php?id=1&foo=bar')
    >>> b = url_object('http://www.rapid7.com/foo.php?id=1')
    >>> are_variants( a, b )
    False

    >>> a = 'http://www.w3af.com/foo.php?id=1'
    >>> b = 'http://www.rapid7.com/foo.php?id=1'
    >>> are_variants( a, b )
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
    ValueError: The "url_a" parameter in "are_variants"  must be of urlParser.url_object type.
    '''
    if not isinstance(url_a, url_object):
        msg = 'The "url_a" parameter in "are_variants" '
        msg += ' must be of urlParser.url_object type.'
        raise ValueError( msg )

    if not isinstance(url_b, url_object):
        msg = 'The "url_b" parameter in "are_variants" '
        msg += ' must be of urlParser.url_object type.'
        raise ValueError( msg )
    
    qs_a = url_a.getQueryString()
    qsr_a = httpQsRequest.httpQsRequest()
    qsr_a.setURL( url_a.uri2url() )
    qsr_a.setDc( qs_a )

    qs_b = url_b.getQueryString()
    qsr_b = httpQsRequest.httpQsRequest()
    qsr_b.setURL( url_b.uri2url() )
    qsr_b.setDc( qs_b )
    return qsr_a.is_variant_of( qsr_b )
Пример #9
0
def createFuzzableRequestRaw(method, url, postData, headers):
    """
    Creates a fuzzable request based on a query sent FROM the browser. This is used in
    plugins like spiderMan.
    
    @parameter method: A string that represents the method ('GET', 'POST', etc)
    @parameter url: A string that represents the URL
    @parameter postData: A string that represents the postdata, if its a GET request, set to None.
    @parameter headers: A dict that holds the headers
    """
    #
    # Just a query string request ! no postdata
    #
    if not postData:
        qsr = httpQsRequest.httpQsRequest()
        qsr.setURL(url)
        qsr.setMethod(method)
        qsr.setHeaders(headers)
        dc = urlParser.getQueryString(url)
        qsr.setDc(dc)
        return qsr
    #
    # Seems to be something that has post data
    #
    pdr = httpPostDataRequest.httpPostDataRequest()
    pdr.setURL(url)
    pdr.setMethod(method)
    for header_name in headers.keys():
        if header_name.lower() == "content-length":
            del headers[header_name]
    pdr.setHeaders(headers)
    #
    #   Parse the content
    #   Case #1, multipart form data
    #
    if "content-type" in headers.keys() and headers["content-type"].startswith("multipart/form-data"):
        tmp, pdict = cgi.parse_header(headers["content-type"])
        try:
            dc = cgi.parse_multipart(StringIO(postData), pdict)
        except:
            om.out.debug("Multipart form data is invalid, the browser sent something wierd.")
        else:
            resultDc = queryString()
            for i in dc.keys():
                resultDc[i] = dc[i]
            # We process multipart requests as x-www-form-urlencoded
            # TODO We need native support of multipart requests!
            headers["content-type"] = "application/x-www-form-urlencoded"
            pdr.setDc(resultDc)
            pdr.setHeaders(headers)
            return pdr
    #
    #   Case #2, JSON request
    #
    try:
        dc = json.loads(postData)
    except:
        pass
    else:
        # It's json! welcome to the party dude!
        pdr = jsonPostDataRequest.jsonPostDataRequest()
        pdr.setURL(url)
        pdr.setMethod(method)
        pdr.setHeaders(headers)
        pdr.setDc(dc)
        return pdr
    #
    #   Case #3, XMLRPC request
    #
    postDataLower = postData.lower()
    stopWords = ["<methodcall>", "<methodname>", "<params>", "</methodcall>", "</methodname>", "</params>"]
    allStopWords = True
    for word in stopWords:
        if word not in postDataLower:
            allStopWords = False
    if allStopWords:
        xmlrpc_request = xmlrpcRequest.xmlrpcRequest(postData)
        xmlrpc_request.setURL(url)
        xmlrpc_request.setMethod(method)
        xmlrpc_request.setHeaders(headers)
        return xmlrpc_request
    #
    #   Case #4, the "default".
    #
    # NOT a JSON or XMLRPC request!, let's try the simple url encoded post data...
    #
    try:
        dc = urlParser.getQueryString("http://w3af/?" + postData)
        pdr.setDc(dc)
    except:
        om.out.debug('Failed to create a data container that can store this data: "' + postData + '".')
    else:
        return pdr