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
def discover(self, fuzzableRequest ): ''' Get www.site.com and site.com and compare responses. @parameter fuzzableRequest: A fuzzableRequest instance that contains (among other things) the URL to test. ''' if not self._exec : # This will remove the plugin from the discovery plugins to be runned. raise w3afRunOnce() else: # Only run once self._exec = False if not re.match('\d?\d?\d?\.\d?\d?\d?\.\d?\d?\d?\.\d?\d?\d?', urlParser.getDomain( fuzzableRequest.getURL() ) ): # Only do all this if this is a domain name! base_url = urlParser.baseUrl( fuzzableRequest.getURL() ) original_response = self._urlOpener.GET( base_url, useCache=True ) domain = urlParser.getDomain( fuzzableRequest.getURL() ) proto = urlParser.getProtocol( fuzzableRequest.getURL() ) if domain.startswith('www.'): dns_wildcard_url = proto + '://' + domain.replace('www.', '') + '/' else: dns_wildcard_url = proto + '://www.' + domain + '/' self._test_DNS( original_response, dns_wildcard_url ) self._test_IP( original_response, domain ) return []
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
def discover(self, fuzzableRequest ): ''' Sends the special request. @parameter fuzzableRequest: A fuzzableRequest instance that contains (among other things) the URL to test. ''' domain = urlParser.getDomain(fuzzableRequest.getURL()) extension = urlParser.getDomain(fuzzableRequest.getURL()) if (domain, extension) not in self._already_tested: # Do it only one time self._already_tested.append( (domain, extension) ) # Generate the new URL domain += '.' path = urlParser.getPath( fuzzableRequest.getURL() ) protocol = urlParser.getProtocol( fuzzableRequest.getURL() ) new_URL = protocol + '://' + domain + path try: # GET the original response original_response = self._urlOpener.GET( fuzzableRequest.getURL(), useCache=False ) # GET the response with the modified domain (with the trailing dot) response = self._urlOpener.GET( new_URL, useCache=False ) except KeyboardInterrupt,e: raise e except w3afException,w3: om.out.error( str(w3) )
def discover(self, fuzzableRequest ): ''' It calls the "main" from hmap and writes the results to the kb. @parameter fuzzableRequest: A fuzzableRequest instance that contains (among other things) the URL to test. ''' if not self._exec: # This will remove the plugin from the discovery plugins to be runned. raise w3afRunOnce() else: if self._runned_hmap: # Nothing else to do here. self._exec = False if not self._runned_hmap: self._runned_hmap = True msg = 'Hmap web server fingerprint is starting, this may take a while.' om.out.information( msg ) url = fuzzableRequest.getURL() protocol = urlParser.getProtocol( url ) server = urlParser.getNetLocation( url ) # Set some defaults that can be overriden later if protocol == 'https': port = 443 ssl = True else: port = 80 ssl = False # Override the defaults if server.count(':'): port = int( server.split(':')[1] ) server = server.split(':')[0] try: results = originalHmap.testServer( ssl, server, port, 1, self._genFpF ) except w3afException, w3: msg = 'A w3afException ocurred while running hmap: "' + str(w3) + '"' om.out.error( msg ) except Exception, e: msg = 'An unhandled exception ocurred while running hmap: "' + str(e) + '"' om.out.error( msg ) else:
def modifyRequest(self, request ): ''' Mangles the request @parameter request: urllib2.Request instance that is going to be modified by the evasion plugin ''' # We mangle the URL path = urlParser.getPathQs( request.get_full_url() ) path = path.replace('/','/./' ) # 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 , request.get_data(), request.headers, request.get_origin_req_host() ) return new_req
def _verifyURL(self, targetUrl, fileTarget=True): """ Verify if the URL is valid and raise an exception if w3af doesn't support it. """ protocol = urlParser.getProtocol(targetUrl) domain = urlParser.getDomain(targetUrl) or "" aFile = fileTarget and protocol == "file" and domain aHTTP = protocol in ["http", "https"] and urlParser.isValidURLDomain(targetUrl) if not (aFile or aHTTP): msg = ( 'Invalid format for target URL "%s", you have to specify ' "the protocol (http/https/file) and a domain or IP address. " "Examples: http://host.tld/ ; https://127.0.0.1/ ." % targetUrl ) raise w3afException(msg)
def modifyRequest(self, request ): ''' Mangles the request @parameter request: urllib2.Request instance that is going to be modified by the evasion plugin ''' # We mangle the URL path = urlParser.getPathQs( request.get_full_url() ) if re.match('^/', path): random_alnum = createRandAlNum() path = '/' + random_alnum + '/..' + path # 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 , request.get_data(), request.headers, request.get_origin_req_host() ) return new_req
def audit(self, freq ): ''' Get the cert and do some checks against it. @param freq: A fuzzableRequest ''' url = freq.getURL() if 'HTTPS' != getProtocol( url ).upper(): return domain = getDomain(url) # We need to check certificate only once per host if domain in self._already_tested_domains: return # Parse the domain:port splited = getNetLocation(url).split(':') port = 443 host = splited[0] if len( splited ) > 1: port = int(splited[1]) # Create the connection socket_obj = socket.socket() try: socket_obj.connect( ( host , port ) ) ctx = SSL.Context(SSL.SSLv23_METHOD) ssl_conn = SSL.Connection(ctx, socket_obj) # Go to client mode ssl_conn.set_connect_state() # If I don't send something here, the "get_peer_certificate" # method returns None. Don't ask me why! #ssl_conn.send('GET / HTTP/1.1\r\n\r\n') self.ssl_wrapper( ssl_conn, ssl_conn.send, ('GET / HTTP/1.1\r\n\r\n', ), {}) except Exception, e: om.out.error('Error in audit.sslCertificate: "' + repr(e) +'".')
def _test_IP( self, original_response, domain ): ''' Check if http://ip(domain)/ == http://domain/ ''' ip_address = socket.gethostbyname( domain ) ip_url = urlParser.getProtocol( original_response.getURL() ) + '://'+ ip_address + '/' try: modified_response = self._urlOpener.GET( ip_url, useCache=True ) except w3afException: om.out.debug('An error ocurred while fetching IP address URL in dnsWildcard plugin.') else: if modified_response.getBody() != original_response.getBody(): i = info.info() i.setPluginName(self.getName()) i.setName('Default domain') i.setURL( modified_response.getURL() ) i.setMethod( 'GET' ) msg = 'The contents of ' + modified_response.getURI() msg += ' differ from the contents of ' + original_response.getURI() i.setDesc( msg ) i.setId( modified_response.id ) kb.kb.append( self, 'dnsWildcard', i ) om.out.information( i.getDesc() )
def discover(self, fuzzableRequest ): ''' Get the server-status and parse it. @parameter fuzzableRequest: A fuzzableRequest instance that contains (among other things) the URL to test. ''' res = [] if not self._exec : # This will remove the plugin from the discovery plugins to be runned. raise w3afRunOnce() else: # Only run once self._exec = False base_url = urlParser.baseUrl( fuzzableRequest.getURL() ) server_status_url = urlParser.urlJoin( base_url , 'server-status' ) response = self._urlOpener.GET( server_status_url, useCache=True ) if not is_404( response ) and response.getCode() not in range(400, 404): msg = 'Apache server-status cgi exists. The URL is: "' + response.getURL() + '".' om.out.information( msg ) # Create some simple fuzzable requests res.extend( self._createFuzzableRequests( response ) ) # Get the server version # <dl><dt>Server Version: Apache/2.2.9 (Unix)</dt> for version in re.findall('<dl><dt>Server Version: (.*?)</dt>', response.getBody()): # Save the results in the KB so the user can look at it i = info.info() i.setPluginName(self.getName()) i.setURL( response.getURL() ) i.setId( response.id ) i.setName( 'Apache Server version' ) msg = 'The web server has the apache server status module enabled, ' msg += 'which discloses the following remote server version: "' + version + '".' i.setDesc( msg ) om.out.information(i.getDesc()) kb.kb.append( self, 'server', i ) # Now really parse the file and create custom made fuzzable requests regex = '<td>.*?<td nowrap>(.*?)</td><td nowrap>.*? (.*?) HTTP/1' for domain, path in re.findall(regex, response.getBody() ): if 'unavailable' in domain: domain = urlParser.getDomain( response.getURL() ) foundURL = urlParser.getProtocol( response.getURL() ) + '://' + domain + path # Check if the requested domain and the found one are equal. if urlParser.getDomain( foundURL ) == urlParser.getDomain( response.getURL() ): # They are equal, request the URL and create the fuzzable requests tmpRes = self._urlOpener.GET( foundURL, useCache=True ) if not is_404( tmpRes ): res.extend( self._createFuzzableRequests( tmpRes ) ) else: # This is a shared hosting server self._shared_hosting_hosts.append( domain ) # Now that we are outsite the for loop, we can report the possible vulns if len( self._shared_hosting_hosts ): v = vuln.vuln() v.setPluginName(self.getName()) v.setURL( fuzzableRequest.getURL() ) v.setId( response.id ) self._shared_hosting_hosts = list( set( self._shared_hosting_hosts ) ) v['alsoInHosting'] = self._shared_hosting_hosts v.setDesc( 'The web application under test seems to be in a shared hosting.' ) v.setName( 'Shared hosting' ) v.setSeverity(severity.MEDIUM) kb.kb.append( self, 'sharedHosting', v ) om.out.vulnerability( v.getDesc(), severity=v.getSeverity() ) msg = 'This list of domains, and the domain of the web application under test,' msg += ' all point to the same server:' om.out.vulnerability(msg, severity=severity.MEDIUM ) for url in self._shared_hosting_hosts: om.out.vulnerability('- ' + url, severity=severity.MEDIUM ) # Check if well parsed elif 'apache' in response.getBody().lower(): msg = 'Couldn\'t find any URLs in the apache server status page. Two things can' msg += ' trigger this:\n - The Apache web server sent a server-status page' msg += ' that the serverStatus plugin failed to parse or,\n - The remote ' msg += ' web server has no traffic. If you are sure about the first one, please' msg += ' report a bug.' om.out.information( msg ) om.out.debug('The server-status body is: "'+response.getBody()+'"') return res
def discover(self, fuzzableRequest): ''' Discovery task. Uses scapy.traceroute function in order to determine the distance between http and https ports for the target. Intended to be executed once during the discovery process. ''' if not self._has_permission(): raise w3afException(PERM_ERROR_MSG) def set_info(name, desc): inf = info.info() inf.setPluginName(self.getName()) inf.setName(name) inf.setDesc(desc) kb.kb.append(self, 'http_vs_https_dist', inf) target_url = fuzzableRequest.getURL() domain = uparser.getDomain(target_url) http_port = self._http_port https_port = self._https_port # Use target port if specified netloc = uparser.getNetLocation(target_url) try: port = int(netloc.split(':')[-1]) except ValueError: pass # Nothing to do. else: protocol = uparser.getProtocol(target_url) if protocol == 'https': https_port = port else: # it has to be 'http' http_port = port # First try with httpS https_troute = traceroute(domain, dport=https_port)[0].get_trace() # This destination was probably 'localhost' or a host reached through # a vpn? if not https_troute: return [] https_troute = https_troute.values()[0] https_ip_tuples = https_troute.values() last_https_ip = https_ip_tuples[-1] # Then with http http_troute = traceroute(domain, dport=http_port) http_troute = http_troute[0].get_trace().values()[0] http_ip_tuples = http_troute.values() last_http_ip = http_ip_tuples[-1] # Last IP should be True; otherwise the dest wasn't reached # Tuples have the next form: ('192.168.1.1', False) if not (last_https_ip[1] and last_http_ip[1]): desc = _('The port \'%s\' is not open on target %s') if not last_https_ip[1]: om.out.error(desc % (https_port, domain)) if not last_http_ip[1]: om.out.error(desc % (http_port, domain)) else: # Are routes different if http_ip_tuples != https_ip_tuples: header = ' TCP trace to %s:%s\n%s' trace_str = lambda iptuples: '\n'.join(' %s %s' % \ (t[0], t[1][0]) for t in enumerate(iptuples)) trc1 = header % (domain, http_port, trace_str(http_ip_tuples)) trc2 = header % (domain, https_port, trace_str(https_ip_tuples)) desc = _('Routes to target \'%s\' using ports \'%s\' and ' \ '\'%s\' are different:\n%s\n%s') % (domain, http_port, https_port, trc1, trc2) set_info('HTTP vs. HTTPS Distance', desc) om.out.information(desc) return []