Beispiel #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
 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) )
Beispiel #5
0
    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)
Beispiel #8
0
 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 []