예제 #1
0
 def modifyRequest(self, request ):
     '''
     Mangles the request
     
     @parameter request: urllib2.Request instance that is going to be modified by the evasion plugin
     '''
     # First we mangle the URL        
     path = urlParser.getPathQs( request.get_full_url() )
     path = self._mutate( path )
     
     # Now we mangle the postdata
     data = request.get_data()
     if data:
         # Only mangle the postdata if it is a url encoded string
         try:
             urlParser.getQueryString('http://w3af/?' + data )
         except:
             pass
         else:
             data = self._mutate( data )            
     
     # Finally, we set all the mutants to the request in order to return it
     url = urlParser.getProtocol( request.get_full_url() )
     url += '://' + urlParser.getNetLocation( request.get_full_url() ) + path
     
     new_req = urllib2.Request( url , data, request.headers, request.get_origin_req_host() )
     
     return new_req
예제 #2
0
 def modifyRequest(self, request ):
     '''
     Mangles the request
     
     @parameter request: urllib2.Request instance that is going to be modified by the evasion plugin
     '''
     # This is a test URL
     # http://172.16.1.132/index.asp?q=%uFF1Cscript%3Ealert(%22Hello%22)%3C/script%3E
     # This is the content of index.asp :
     # <%=Request.QueryString("q")%>
     
     # First we mangle the URL        
     path = urlParser.getPathQs( request.get_full_url() )
     path = self._mutate( path )
     
     # Now we mangle the postdata
     data = request.get_data()
     if data:
         # Only mangle the postdata if it is a url encoded string
         try:
             urlParser.getQueryString('http://w3af/?' + data )
         except:
             pass
         else:
             data = self._mutate( data )            
     
     # Finally, we set all the mutants to the request in order to return it
     url = urlParser.getProtocol( request.get_full_url() )
     url += '://' + urlParser.getNetLocation( request.get_full_url() ) + path
     
     new_req = urllib2.Request( url , data, request.headers, request.get_origin_req_host() )
     
     return new_req
예제 #3
0
    def GET(self, uri, data='', headers={}, useCache=False, grepResult=True):
        '''
        Gets a uri using a proxy, user agents, and other settings that where set previously.
        
        @param uri: This is the url to GET
        @param data: Only used if the uri parameter is really a URL.
        @return: An httpResponse object.
        '''
        self._init()

        if self._isBlacklisted(uri):
            return self._new_no_content_resp(uri, log_it=True)

        
        qs = urlParser.getQueryString( uri )
        if qs:
            req = HTTPRequest( uri )
        else:
            if data:
                req = HTTPRequest( uri + '?' + data )
            else:
                # It's really an url...
                req = HTTPRequest( uri )
            
        req = self._addHeaders( req, headers )
        return self._send( req , useCache=useCache, grepResult=grepResult)
예제 #4
0
 def _return_without_eval( self, parameters, uri ):
     if urlParser.getDomainPath( uri ) == uri:
         return False
     
     (server, query , expected_response, method , desc) = parameters
     function_reference = getattr( self._urlOpener , method )
     
     url = urlParser.uri2url( uri )
     url += createRandAlNum( 7 )
     if urlParser.getQueryString( query ):
         url = url + '?' + str( urlParser.getQueryString( query ) )
         
     try:
         response = function_reference( url )
     except KeyboardInterrupt,e:
         raise e
 def getPage(self, url):
     """
     Connect to the target url or proxy and return the target
     url page.
     """
     m = self._vuln.getMutant()
     m.setDc( urlParser.getQueryString( url ) )
     m.setURL( urlParser.uri2url( url ) )
     response = self._sendMutant( m , analyze=False )
     if response.getCode() in range( 500, 599 ):
         raise w3afException('getPage request returned an HTTP error 500.')
     return response.getBody()
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 )
예제 #7
0
 def setOptions(self, optionsMap):
     """
     This method sets all the options that are configured using the user interface 
     generated by the framework using the result of getOptions().
     
     @parameter OptionList: A dictionary with the options for the plugin.
     @return: No value is returned.
     """
     self._url = optionsMap["url"].getValue()
     self._method = optionsMap["method"].getValue()
     self._data = urlParser.getQueryString(optionsMap["data"].getValue())
     self._fileVars = optionsMap["fileVars"].getValue()
     self._fileDest = optionsMap["fileDest"].getValue()
예제 #8
0
 def setOptions( self, optionsMap ):
     '''
     This method sets all the options that are configured using the user interface 
     generated by the framework using the result of getOptions().
     
     @parameter optionsMap: A dict with the options for the plugin.
     @return: No value is returned.
     ''' 
     self._changeToPost = optionsMap['changeToPost'].getValue()
     self._url = optionsMap['url'].getValue()
     self._method = optionsMap['method'].getValue()
     self._data = urlParser.getQueryString( optionsMap['data'].getValue() )
     self._inj_var = optionsMap['injvar'].getValue()
     self._generateOnlyOne = optionsMap['generateOnlyOne'].getValue()
예제 #9
0
 def modifyRequest(self, request ):
     '''
     Mangles the request
     
     @parameter request: urllib2.Request instance that is going to be modified by the evasion plugin
     '''
     # Mangle the postdata
     data = request.get_data()
     if data:
         # Only mangle the postdata if it is a url encoded string
         try:
             urlParser.getQueryString('http://w3af/?' + data )
         except:
             pass
         else:
             data = '\x00' + data 
             headers_copy = copy.deepcopy(request.headers)
             headers_copy['content-length'] = str(len(data))
             
             request = urllib2.Request( request.get_full_url() , data, 
                                                 headers_copy, request.get_origin_req_host() )
             
     return request
예제 #10
0
    def _generate_qs( self, fuzzableRequest ):
        '''
        Check the URL query string.
        @return: A list of mutants.
        '''     
        # The result
        result = []

        query_string = urlParser.getQueryString( fuzzableRequest.getURI() )
        for parameter_name in query_string:
            # this for loop was added to address the repeated parameter name issue
            for element_index in xrange(len(query_string[parameter_name])):
                wordnet_result = self._search_wn( query_string[parameter_name][element_index] )
                result.extend( self._generate_URL_from_result( parameter_name, element_index, wordnet_result, fuzzableRequest ) )
        return result
예제 #11
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.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 = urlParser.getQueryString( real_url )
                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
예제 #12
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.")
예제 #13
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 sql_webshell fastExploit.' )
     
     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.')
예제 #14
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
예제 #15
0
 def setURI( self, uri ):
     self._dc = urlParser.getQueryString(uri)
     self._uri = uri.replace(' ', '%20')
     self._url = urlParser.uri2url( uri )
예제 #16
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 = urlParser.getQueryString(httpResponse.getURI())

    # 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
예제 #17
0
            postData = self._getPostData()

            try:
                httpCommandMethod = getattr( self._urlOpener, self.command )
                res = httpCommandMethod( path, data=postData, headers=self.headers )
            except w3afException, w:
                om.out.error('The proxy request failed, error: ' + str(w) )
            except Exception, e:
                raise e
            else:
                return res
            
        else:
            # most likely a GET request
            url = uri2url( path )
            qs = getQueryString( self.path )
            try:
                httpCommandMethod = getattr( self._urlOpener, self.command )
                res = httpCommandMethod( url, data=str(qs), headers=self.headers,  grepResult=grep )
            except w3afException, w:
                traceback.print_exc()
                om.out.error('The proxy request failed, error: ' + str(w) )
                raise w
            except Exception, e:
                traceback.print_exc()
                raise e
            else:
                return res
    
    def _sendError( self, exceptionObj, trace=None ):
        '''
예제 #18
0
    def grep(self, request, response):
        '''
        Plugin entry point.
        
        @parameter request: The HTTP request object.
        @parameter response: The HTTP response object
        @return: None, all results are saved in the kb.
        '''
        try:
            dp = dpCache.dpc.getDocumentParserFor( response )
        except w3afException:
            pass
        else:
            # Note:
            # - With parsed_references I'm 100% that it's really something in the HTML
            # that the developer intended to add.
            #
            # - The re_references are the result of regular expressions, which in some cases
            # are just false positives.
            parsed_references, re_references = dp.getReferences()
            
            for ref in parsed_references:
                
                qs = urlParser.getQueryString( ref )
                
                for param_name in qs:
                    # This for loop is to address the repeated parameter name issue
                    for element_index in xrange(len(qs[param_name])):
                        if self._is_strange( request, param_name, qs[param_name][element_index] )\
                        and ref not in self._already_reported:
                            # Don't repeat findings
                            self._already_reported.add(ref)

                            i = info.info()
                            i.setPluginName(self.getName())
                            i.setName('Strange parameter')
                            i.setURI( ref )
                            i.setId( response.id )
                            msg = 'The URI: "' +  i.getURI() + '" has a parameter named: "' + param_name
                            msg += '" with value: "' + qs[param_name][element_index] + '", which is quite odd.'
                            i.setDesc( msg )
                            i.setVar( param_name )
                            i['parameterValue'] = qs[param_name][element_index]
                            i.addToHighlight(qs[param_name][element_index])

                            kb.kb.append( self , 'strangeParameters' , i )
                            
                        # To find this kind of vulns
                        # http://thedailywtf.com/Articles/Oklahoma-
                        # Leaks-Tens-of-Thousands-of-Social-Security-Numbers,-Other-
                        # Sensitive-Data.aspx
                        if self._is_SQL( request, param_name, qs[param_name][element_index] )\
                        and ref not in self._already_reported:
                            
                            # Don't repeat findings
                            self._already_reported.add(ref)
                            
                            v = vuln.vuln()
                            v.setPluginName(self.getName())
                            v.setName('Parameter has SQL sentence')
                            v.setURI( ref )
                            v.setId( response.id )
                            msg = 'The URI: "' +  v.getURI() + '" has a parameter named: "' + param_name
                            msg +='" with value: "' + qs[param_name][element_index] + '", which is a SQL sentence.'
                            v.setDesc( msg )
                            v.setVar( param_name )
                            v['parameterValue'] = qs[param_name][element_index]
                            i.addToHighlight(qs[param_name][element_index])
                            kb.kb.append( self , 'strangeParameters' , v )