def test_add_httpPostDataRequest(self): ds = disk_set() uri = url_object('http://w3af.org/?id=2') pdr1 = httpPostDataRequest(uri, method='GET', headers={'Referer': 'http://w3af.org/'}) uri = url_object('http://w3af.org/?id=3') pdr2 = httpPostDataRequest(uri, method='GET', headers={'Referer': 'http://w3af.com/'}) uri = url_object('http://w3af.org/?id=7') pdr3 = httpPostDataRequest(uri, method='FOO', headers={'Referer': 'http://w3af.com/'}) ds.add( pdr1 ) ds.add( pdr2 ) ds.add( pdr2 ) ds.add( pdr1 ) self.assertEqual( ds[0] , pdr1) self.assertEqual( ds[1] , pdr2) self.assertFalse( pdr3 in ds ) self.assertTrue( pdr2 in ds ) self.assertEqual( len(ds) , 2) # This forces an internal change in the URL object pdr2.getURL().url_string self.assertTrue( pdr2 in ds )
def GET2POST( self, vuln ): ''' This method changes a vulnerability mutant, so all the data that was sent in the query string, is now sent in the postData; of course, the HTTP method is also changed from GET to POST. ''' vulnCopy = copy.deepcopy( vuln ) mutant = vulnCopy.getMutant() # Sometimes there is no mutant (php_sca). if mutant is None: return vulnCopy if mutant.getMethod() == 'POST': # No need to work ! return vulnCopy else: pdr = httpPostDataRequest.httpPostDataRequest( mutant.getURL(), headers=mutant.getHeaders(), cookie=mutant.getCookie(), dc=mutant.getDc() ) mutant.setFuzzableReq(pdr) return vulnCopy
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.")
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 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 any( lambda attr: attr is None, (self._url, self._method, self._data, self._injvar) ): raise w3afException('You have to configure the plugin parameters') else: if self._method == 'POST': freq = httpPostDataRequest(self._url) elif self._method == 'GET': freq = HTTPQSRequest(self._url) else: raise w3afException('Method not supported.') freq.setDc(parse_qs(self._data)) bsql = blind_sqli_response_diff(self._uri_opener) bsql.set_eq_limit(self._eq_limit) fake_mutants = createMutants(freq, [''], fuzzableParamList=[self._injvar,]) for mutant in fake_mutants: vuln_obj = bsql.is_injectable(mutant) if vuln_obj is not None: om.out.console('SQL injection 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, ] else: 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
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
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
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