class dotNetErrors(baseDiscoveryPlugin): ''' Request specially crafted URLs that generate ASP.NET errors in order to gather information. @author: Andres Riancho ( [email protected] ) ''' def __init__(self): baseDiscoveryPlugin.__init__(self) # Internal variables self._already_tested = ScalableBloomFilter() def discover(self, fuzzableRequest ): ''' Requests the special filenames. @parameter fuzzableRequest: A fuzzableRequest instance that contains (among other things) the URL to test. ''' if fuzzableRequest.getURL() not in self._already_tested: self._already_tested.add( fuzzableRequest.getURL() ) # Generate the URLs to GET to_test = self._generate_URLs( fuzzableRequest.getURL() ) for url in to_test: try: response = self._urlOpener.GET( url, useCache=True ) except KeyboardInterrupt,e: raise e except w3afException,w3: om.out.error( str(w3) ) else: self._analyze_response( response )
class frontpage_version(baseDiscoveryPlugin): ''' Search FrontPage Server Info file and if it finds it will determine its version. @author: Viktor Gazdag ( [email protected] ) ''' def __init__(self): baseDiscoveryPlugin.__init__(self) # Internal variables self._analyzed_dirs = ScalableBloomFilter() self._exec = True def discover(self, fuzzableRequest ): ''' For every directory, fetch a list of files and analyze the response. @parameter fuzzableRequest: A fuzzableRequest instance that contains (among other things) the URL to test. ''' fuzzable_return_value = [] if not self._exec: # This will remove the plugin from the discovery plugins to be runned. raise w3afRunOnce() else: # Run the plugin. self._exec = False for domain_path in urlParser.getDirectories(fuzzableRequest.getURL() ): if domain_path not in self._analyzed_dirs: # Save the domain_path so I know I'm not working in vane self._analyzed_dirs.add( domain_path ) # Request the file frontpage_info_url = urlParser.urlJoin( domain_path , "_vti_inf.html" ) try: response = self._urlOpener.GET( frontpage_info_url, useCache=True ) om.out.debug( '[frontpage_version] Testing "' + frontpage_info_url + '".' ) except w3afException, w3: msg = 'Failed to GET Frontpage Server _vti_inf.html file: "' msg += frontpage_info_url + '". Exception: "' + str(w3) + '".' om.out.debug( msg ) else: # Check if it's a Fronpage Info file if not is_404( response ): fuzzable_return_value.extend( self._createFuzzableRequests( response ) ) self._analyze_response( response ) return fuzzable_return_value
def __init__(self): baseGrepPlugin.__init__(self) self._rss_tag_attr = [('rss', 'version', 'RSS'),# <rss version="..."> ('feed', 'version', 'OPML'),# <feed version="..." ('opml', 'version', 'OPML') # <opml version="..."> ] self._already_inspected = ScalableBloomFilter()
def __init__(self): baseDiscoveryPlugin.__init__(self) # Internal variables self._exec = True self._already_tested = ScalableBloomFilter() self._bad_codes = [ httpConstants.UNAUTHORIZED, httpConstants.NOT_IMPLEMENTED, httpConstants.METHOD_NOT_ALLOWED, httpConstants.FORBIDDEN] # Methods self._dav_methods = [ 'DELETE', 'PROPFIND', 'PROPPATCH', 'COPY', 'MOVE', 'LOCK', 'UNLOCK', 'MKCOL'] self._common_methods = [ 'OPTIONS', 'GET', 'HEAD', 'POST', 'TRACE', 'PUT'] self._uncommon_methods = ['*', 'SUBSCRIPTIONS', 'NOTIFY', 'DEBUG', 'TRACK', 'POLL', 'PIN', 'INVOKE', 'SUBSCRIBE', 'UNSUBSCRIBE'] # Methods taken from http://www.w3.org/Protocols/HTTP/Methods.html self._proposed_methods = [ 'CHECKOUT', 'SHOWMETHOD', 'LINK', 'UNLINK', 'CHECKIN', 'TEXTSEARCH', 'SPACEJUMP', 'SEARCH', 'REPLY'] self._extra_methods = [ 'CONNECT', 'RMDIR', 'MKDIR', 'REPORT', 'ACL', 'DELETE', 'INDEX', 'LABEL', 'INVALID'] self._version_control = [ 'VERSION_CONTROL', 'CHECKIN', 'UNCHECKOUT', 'PATCH', 'MERGE', 'MKWORKSPACE', 'MKACTIVITY', 'BASELINE_CONTROL'] self._supported_methods = self._dav_methods + self._common_methods + self._uncommon_methods self._supported_methods += self._proposed_methods + self._extra_methods self._supported_methods += self._version_control # User configured variables self._exec_one_time = True self._report_dav_only = True
def __init__(self): baseDiscoveryPlugin.__init__(self) # internal variables self._exec = True self._already_visited = ScalableBloomFilter() self._first_time = True self._show_remote_server = True # User configured parameters self._db_file = 'plugins' + os.path.sep + 'discovery' + os.path.sep + 'pykto' self._db_file += os.path.sep + 'scan_database.db' self._extra_db_file = 'plugins' + os.path.sep + 'discovery' + os.path.sep self._extra_db_file += 'pykto' + os.path.sep + 'w3af_scan_database.db' self._cgi_dirs = ['/cgi-bin/'] self._admin_dirs = ['/admin/', '/adm/'] self._users = ['adm', 'bin', 'daemon', 'ftp', 'guest', 'listen', 'lp', 'mysql', 'noaccess', 'nobody', 'nobody4', 'nuucp', 'operator', 'root', 'smmsp', 'smtp', 'sshd', 'sys', 'test', 'unknown'] self._nuke = ['/', '/postnuke/', '/postnuke/html/', '/modules/', '/phpBB/', '/forum/'] self._mutate_tests = False self._generic_scan = False self._update_scandb = False self._source = ''
def __init__(self): baseGrepPlugin.__init__(self) self._already_reported = ScalableBloomFilter() # regex to split between words self._split_re = re.compile('[^\w]')
def __init__(self): baseDiscoveryPlugin.__init__(self) # Internal variables self._already_visited = ScalableBloomFilter() # User configured parameters self._max_depth = 3
def __init__(self): baseGrepPlugin.__init__(self) self._tag_names = [] self._tag_names.append('object') self._tag_names.append('applet') self._already_analyzed = ScalableBloomFilter()
def __init__(self): baseDiscoveryPlugin.__init__(self) # Internal variables self._first_exec = True self._already_queried = ScalableBloomFilter() self._can_resolve_domain_names = False self._non_existant_response = None
def __init__(self): baseGrepPlugin.__init__(self) # Only generate the lists once. # Adding 0,001% performance ;) self._already_inspected = ScalableBloomFilter() self._wsdl_strings = self._get_WSDL_strings() self._disco_strings = ['disco:discovery ']
def __init__(self): baseGrepPlugin.__init__(self) self._already_visited = ScalableBloomFilter() # Added performance by compiling all the regular expressions # before using them. The setup time of the whole plugin raises, # but the execution time is lowered *a lot*. self._compiled_regex_list = [ re.compile(regex, re.IGNORECASE | re.DOTALL) for regex in self._get_indexing_regex() ]
def __init__(self): baseGrepPlugin.__init__(self) # Internal variables self._already_inspected = ScalableBloomFilter() # Create the regular expression to search for AJAX ajax_regex_string = '(XMLHttpRequest|eval\(|ActiveXObject|Msxml2\.XMLHTTP|' ajax_regex_string += 'ActiveXObject|Microsoft\.XMLHTTP)' self._ajax_regex_re = re.compile( ajax_regex_string, re.IGNORECASE )
def __init__(self): baseDiscoveryPlugin.__init__(self) self._already_visited = ScalableBloomFilter() self._first_time = True # This is for the Referer self._headers = {} # User options self._fuzz_images = False self._max_digit_sections = 4
def __init__(self): baseGrepPlugin.__init__(self) self._already_inspected = ScalableBloomFilter() # Add the regex to match something like this: # # $Id: lzio.c,v 1.24 2003/03/20 16:00:56 roberto Exp $ # $Id: file name, version, timestamp, creator Exp $ # regex = '\$.{1,12}: .*? .*? \d{4}[-/]\d{1,2}[-/]\d{1,2}' regex += ' \d{1,2}:\d{1,2}:\d{1,2}.*? (.*?) (Exp )?\$' self._regex_list = [ re.compile(regex) ]
def __init__(self): baseGrepPlugin.__init__(self) self._comments = {} self._search404 = False self._interesting_words = {'user':None, 'pass':None, 'microsoft':None, 'visual':None, 'linux':None, 'source':None, 'author':None, 'release':None, 'version':None, 'verify-v1':'Google Sitemap' } self._already_inspected = ScalableBloomFilter() '''
def __init__(self): baseGrepPlugin.__init__(self) self._already_inspected = ScalableBloomFilter() # re that searches for #GET / HTTP/1.0 self._re_request = re.compile('[a-zA-Z]{3,6} .*? HTTP/1.[01]') # re that searches for #HTTP/1.1 200 OK self._re_response = re.compile('HTTP/1.[01] [0-9][0-9][0-9] [a-zA-Z]*')
def __init__(self): baseGrepPlugin.__init__(self) vsRegex = r'<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value=".*?" />' self._viewstate = re.compile( vsRegex, re.IGNORECASE|re.DOTALL) evRegex = r'<input type="hidden" name="__EVENTVALIDATION" ' evRegex += 'id="__EVENTVALIDATION" value=".*?" />' self._eventvalidation = re.compile( evRegex, re.IGNORECASE|re.DOTALL) encryptedVsRegex = r'<input type="hidden" name="__VIEWSTATEENCRYPTED" ' encryptedVsRegex += 'id="__VIEWSTATEENCRYPTED" value=".*?" />' self._encryptedVs = re.compile( encryptedVsRegex, re.IGNORECASE|re.DOTALL) self._already_reported = ScalableBloomFilter()
def __init__(self): baseDiscoveryPlugin.__init__(self) # Internal variables self._compiled_ignore_re = None self._compiled_follow_re = None self._brokenLinks = [] self._fuzzableRequests = [] self._first_run = True self._already_crawled = disk_list() self._already_filled_form = ScalableBloomFilter() # User configured variables self._ignore_regex = "" self._follow_regex = ".*" self._only_forward = False self._compileRE()
class phpEggs(baseDiscoveryPlugin): ''' Fingerprint the PHP version using documented easter eggs that exist in PHP. @author: Andres Riancho ( [email protected] ) ''' def __init__(self): baseDiscoveryPlugin.__init__(self) self._exec = True # Already analyzed extensions self._already_analyzed_ext = ScalableBloomFilter() # This is a list of hashes and description of the egg for every PHP version. self._egg_DB = {} self._egg_DB["4.1.2"] = [ ("744aecef04f9ed1bc39ae773c40017d1", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("85be3b4be7bfe839cbb3b4f2d30ff983", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.2.2"] = [ ("758ccaa9094cdeedcfc60017e768137e", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("85be3b4be7bfe839cbb3b4f2d30ff983", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.3.10"] = [ ("1e8fe4ae1bf06be222c1643d32015f0c", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("a57bd73e27be03a62dd6b3e1b537a72c", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.3.10-18"] = [ ("1e8fe4ae1bf06be222c1643d32015f0c", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("4b2c92409cf0bcf465d199e93a15ac3f", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.3.11"] = [ ("1e8fe4ae1bf06be222c1643d32015f0c", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("a8ad323e837fa00771eda6b709f40e37", "PHP Logo 2"), ("a8ad323e837fa00771eda6b709f40e37", "Zend Logo") ] self._egg_DB["4.3.2"] = [ ("8a8b4a419103078d82707cf68226a482", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("a57bd73e27be03a62dd6b3e1b537a72c", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.3.8"] = [ ("96714a0fbe23b5c07c8be343adb1ba90", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("a57bd73e27be03a62dd6b3e1b537a72c", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.3.9"] = [ ("f9b56b361fafd28b668cc3498425a23b", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB['4.3.10'] = [ ('7b27e18dc6f846b80e2f29ecf67e4133', 'PHP Logo'), ('43af90bcfa66f16af62744e8c599703d', 'Zend Logo'), ('b233cc756b06655f47489aa2779413d7', 'PHP Credits'), ('185386dd4b2eff044bd635d22ae7dd9e', 'PHP Logo 2')] self._egg_DB["4.4.0"] = [ ("ddf16ec67e070ec6247ec1908c52377e", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("4b2c92409cf0bcf465d199e93a15ac3f", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.4.0 for Windows"] = [ ("6d974373683ecfcf30a7f6873f2d234a", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("4b2c92409cf0bcf465d199e93a15ac3f", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.4.4"] = [ ("bed7ceff09e9666d96fdf3518af78e0e", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("4b2c92409cf0bcf465d199e93a15ac3f", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.4.4-8+etch6"] = [ ("31a2553efc348a21b85e606e5e6c2424", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("4b2c92409cf0bcf465d199e93a15ac3f", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.4.7"] = [ ("72b7ad604fe1362f1e8bf4f6d80d4edc", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("4b2c92409cf0bcf465d199e93a15ac3f", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB['4.4.7, PleskWin, ASP.NET'] = [ ('b8477b9b88e90f12e3200660a70eb765', 'Zend Logo'), ('b8477b9b88e90f12e3200660a70eb765', 'PHP Credits'), ('b8477b9b88e90f12e3200660a70eb765', 'PHP Logo 2'), ('b8477b9b88e90f12e3200660a70eb765', 'PHP Logo')] self._egg_DB["4.4.8"] = [ ("4cdfec8ca11691a46f4f63839e559fc5", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("4b2c92409cf0bcf465d199e93a15ac3f", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["5.0.3"] = [ ("def61a12c3b0a533146810403d325451", "PHP Credits"), ("8ac5a686135b923664f64fe718ea55cd", "PHP Logo"), ("37e194b799d4aaff10e39c4e3b2679a2", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.1.1"] = [ ("5518a02af41478cfc492c930ace45ae5", "PHP Credits"), ("8ac5a686135b923664f64fe718ea55cd", "PHP Logo"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.1.6"] = [ ("4b689316409eb09b155852e00657a0ae", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.0"] = [ ("e566715bcb0fd2cb1dc43ed076c091f1", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.0-8+etch10"] = [ ("e566715bcb0fd2cb1dc43ed076c091f1", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.0-8+etch7"] = [ ("307f5a1c02155ca38744647eb94b3543", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.1"] = [ ("d3894e19233d979db07d623f608b6ece", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.2"] = [ ("56f9383587ebcc94558e11ec08584f05", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.3-1+b1"] = [ ("c37c96e8728dc959c55219d47f2d543f", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.4"] = [ ("74c33ab9745d022ba61bc43a5db717eb", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.5"] = [ ("f26285281120a2296072f21e21e7b4b0", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.4-2ubuntu5.3"] = [ ("f26285281120a2296072f21e21e7b4b0", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.5-3"] = [ ("b7e4385bd7f07e378d92485b4722c169", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("0152ed695f4291488741d98ba066d280", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.6"] = [ ("bbd44c20d561a0fc5a4aa76093d5400f", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.6RC4-pl0-gentoo"] = [ ("d03b2481f60d9e64cb5c0f4bd0c87ec1", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB['5.2.8-pl1-gentoo'] = [ ('c48b07899917dfb5d591032007041ae3', 'PHP Logo'), ('40410284d460552a6c9e10c1f5ae7223', 'PHP Credits'), ('50caaf268b4f3d260d720a1a29c5fe21', 'PHP Logo 2'), ('7675f1d01c927f9e6a4752cf182345a2', 'Zend Logo')] def discover(self, fuzzableRequest ): ''' Nothing strange, just do some GET requests to the eggs and analyze the response. @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: # Get the extension of the URL (.html, .php, .. etc) ext = urlParser.getExtension( fuzzableRequest.getURL() ) # Only perform this analysis if we haven't already analyzed this type of extension # OR if we get an URL like http://f00b5r/4/ (Note that it has no extension) # This logic will perform some extra tests... but we won't miss some special cases # Also, we aren't doing something like "if 'php' in ext:" because we never depend # on something so changable as extensions to make decisions. if ext == '' or ext not in self._already_analyzed_ext: # Init some internal variables GET_results = [] original_response = self._urlOpener.GET( fuzzableRequest.getURL(), useCache=True ) # Perform the GET requests to see if we have a phpegg for egg, egg_desc in self._get_eggs(): egg_URL = urlParser.uri2url( fuzzableRequest.getURL() ) + egg try: response = self._urlOpener.GET( egg_URL, useCache=True ) except KeyboardInterrupt,e: raise e except w3afException, w3: raise w3 else: GET_results.append( (response, egg_desc, egg_URL) ) # # Now I analyze if this is really a PHP eggs thing, or simply a response that # changes a lot on each request. Before, I had something like this: # # if relative_distance(original_response.getBody(), response.getBody()) < 0.1: # # But I got some reports about false positives with this approach, so now I'm # changing it to something a little bit more specific. images = 0 not_images = 0 for response, egg_desc, egg_URL in GET_results: if 'image' in response.getContentType(): images += 1 else: not_images += 1 if images == 3 and not_images == 1: # # The remote web server has expose_php = On. Report all the findings. # for response, egg_desc, egg_URL in GET_results: i = info.info() i.setPluginName(self.getName()) i.setName('PHP Egg - ' + egg_desc) i.setURL( egg_URL ) desc = 'The PHP framework running on the remote server has a "' desc += egg_desc +'" easter egg, access to the PHP egg is possible' desc += ' through the URL: "'+ egg_URL + '".' i.setDesc( desc ) kb.kb.append( self, 'eggs', i ) om.out.information( i.getDesc() ) # Only run once. self._exec = False # analyze the info to see if we can identify the version self._analyze_egg( GET_results ) # Now we save the extension as one of the already analyzed if ext != '': self._already_analyzed_ext.add(ext)
class metaTags(baseGrepPlugin): ''' Grep every page for interesting meta tags. @author: Andres Riancho ( [email protected] ) ''' def __init__(self): baseGrepPlugin.__init__(self) self._comments = {} self._search404 = False self._interesting_words = {'user':None, 'pass':None, 'microsoft':None, 'visual':None, 'linux':None, 'source':None, 'author':None, 'release':None, 'version':None, 'verify-v1':'Google Sitemap' } self._already_inspected = ScalableBloomFilter() ''' Can someone explain what this meta tag does? <meta name="verify-v1" content="/JBoXnwT1d7TbbWCwL8tXe+Ts2I2LXYrdnnK50g7kdY=" /> Answer: That's one of the verification elements used by Google Sitemaps. When you sign up for Sitemaps you have to add that element to a root page to demonstrate to Google that you're the site owner. So there is probably a Sitemaps account for the site, if you haven't found it already. ''' def grep(self, request, response): ''' Plugin entry point, search for meta tags. @parameter request: The HTTP request object. @parameter response: The HTTP response object @return: None ''' uri = response.getURI() if response.is_text_or_html() and not is_404( response ) and \ uri not in self._already_inspected: self._already_inspected.add(uri) try: dp = dpCache.dpc.getDocumentParserFor( response ) except w3afException: pass else: meta_tag_list = dp.getMetaTags() for tag in meta_tag_list: name = self._find_name( tag ) for attr in tag: for word in self._interesting_words: # Check if we have something interesting # and WHERE that thing actually is where = value = None if ( word in attr[0].lower() ): where = 'name' value = attr[0].lower() elif ( word in attr[1].lower() ): where = 'value' value = attr[1].lower() # Now... if we found something, report it =) if where: # The atribute is interesting! i = info.info() i.setPluginName(self.getName()) i.setName('Interesting META tag') i.setURI( response.getURI() ) i.setId( response.id ) msg = 'The URI: "' + i.getURI() + '" sent a META tag with ' msg += 'attribute '+ where +' "'+ value +'" which' msg += ' looks interesting.' i.addToHighlight( where, value ) if self._interesting_words.get(name, None): msg += ' The tag is used for ' msg += self._interesting_words[name] + '.' i.setDesc( msg ) kb.kb.append( self , 'metaTags' , i ) else: # The attribute is not interesting pass def _find_name( self, tag ): ''' @return: the tag name. ''' for attr in tag: if attr[0].lower() == 'name': return attr[1] return '' def setOptions( self, optionsMap ): self._search404 = optionsMap['search404'].getValue() def getOptions( self ): ''' @return: A list of option objects for this plugin. ''' d1 = 'Search for meta tags in 404 pages.' o1 = option('search404', self._search404, d1, 'boolean') ol = optionList() ol.add(o1) return ol def end(self): ''' This method is called when the plugin wont be used anymore. ''' # Now print the information objects self.printUniq( kb.kb.getData( 'metaTags', 'metaTags' ), 'URL' ) def getPluginDeps( self ): ''' @return: A list with the names of the plugins that should be runned before the current one. ''' return [] def getLongDesc( self ): ''' @return: A DETAILED description of the plugin functions and features. ''' return '''
def __init__(self): baseDiscoveryPlugin.__init__(self) # Internal variables self._already_tested = ScalableBloomFilter() self._new_fuzzable_requests = []
class wsdlFinder(baseDiscoveryPlugin): ''' Find web service definitions files. @author: Andres Riancho ( [email protected] ) ''' def __init__(self): baseDiscoveryPlugin.__init__(self) # Internal variables self._already_tested = ScalableBloomFilter() self._new_fuzzable_requests = [] def discover(self, fuzzableRequest ): ''' If url not in _tested, append a ?wsdl and check the response. @parameter fuzzableRequest: A fuzzableRequest instance that contains (among other things) the URL to test. ''' url = urlParser.uri2url( fuzzableRequest.getURL() ) if url not in self._already_tested: self._already_tested.add( url ) # perform the requests for wsdl_parameter in self._get_WSDL(): url_to_request = url + wsdl_parameter # Send the requests using threads: targs = ( url_to_request, ) self._tm.startFunction( target=self._do_request, args=targs, ownerObj=self ) # Wait for all threads to finish self._tm.join( self ) return self._new_fuzzable_requests def _do_request(self, url_to_request): ''' Perform an HTTP request to the url_to_request parameter. @return: None. ''' try: self._urlOpener.GET( url_to_request, useCache=True ) except w3afException: om.out.debug('Failed to request the WSDL file: ' + url_to_request) else: # The response is analyzed by the wsdlGreper plugin pass def _get_WSDL( self ): ''' @return: A list of parameters that are used to request the WSDL ''' res = [] res.append( '?wsdl' ) res.append( '?WSDL' ) return res def getOptions( self ): ''' @return: A list of option objects for this plugin. ''' ol = optionList() return ol def setOptions( self, OptionList ): ''' 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. ''' pass def getPluginDeps( self ): ''' @return: A list with the names of the plugins that should be run before the current one. ''' return ['grep.wsdlGreper'] def getLongDesc( self ): ''' @return: A DETAILED description of the plugin functions and features. ''' return '''
def __init__(self): baseGrepPlugin.__init__(self) self._already_reported = ScalableBloomFilter()
class blankBody(baseGrepPlugin): ''' Find responses with empty body. @author: Andres Riancho ( [email protected] ) ''' def __init__(self): baseGrepPlugin.__init__(self) self._already_reported = ScalableBloomFilter() def grep(self, request, response): ''' Plugin entry point, find the blank bodies and report them. @parameter request: The HTTP request object. @parameter response: The HTTP response object @return: None Init >>> from core.data.url.httpResponse import httpResponse >>> from core.data.request.fuzzableRequest import fuzzableRequest >>> from core.controllers.misc.temp_dir import create_temp_dir >>> o = create_temp_dir() Simple test, empty string. >>> body = '' >>> url = 'http://www.w3af.com/' >>> headers = {'content-type': 'text/html'} >>> response = httpResponse(200, body , headers, url, url) >>> request = fuzzableRequest() >>> request.setURL( url ) >>> request.setMethod( 'GET' ) >>> b = blankBody() >>> b.grep(request, response) >>> assert len(kb.kb.getData('blankBody', 'blankBody')) == 1 With some content. >>> kb.kb.save('blankBody','blankBody',[]) >>> body = 'header body footer' >>> headers = {'content-type': 'text/html'} >>> response = httpResponse(200, body , headers, url, url) >>> b.grep(request, response) >>> assert len(kb.kb.getData('ssn', 'ssn')) == 0 Strange method, empty body. >>> kb.kb.save('blankBody','blankBody',[]) >>> body = '' >>> headers = {'content-type': 'text/html'} >>> response = httpResponse(200, body , headers, url, url) >>> request = fuzzableRequest() >>> request.setURL( url ) >>> request.setMethod( 'ARGENTINA' ) >>> b.grep(request, response) >>> assert len(kb.kb.getData('ssn', 'ssn')) == 0 Response codes, >>> kb.kb.save('blankBody','blankBody',[]) >>> body = '' >>> headers = {'content-type': 'text/html'} >>> response = httpResponse(401, body , headers, url, url) >>> request = fuzzableRequest() >>> request.setURL( url ) >>> request.setMethod( 'GET' ) >>> b.grep(request, response) >>> len(kb.kb.getData('ssn', 'ssn')) 0 ''' if response.getBody() == '' and request.getMethod() in ['GET', 'POST']\ and response.getCode() not in [401, 304, 204] and 'location' not in response.getLowerCaseHeaders()\ and response.getURL() not in self._already_reported: # report these informations only once self._already_reported.add( response.getURL() ) # append the info object to the KB. i = info.info() i.setPluginName(self.getName()) i.setName('Blank body') i.setURL( response.getURL() ) i.setId( response.id ) msg = 'The URL: "'+ response.getURL() + '" returned an empty body. ' msg += 'This could indicate an error.' i.setDesc(msg) kb.kb.append( self, 'blankBody', i ) def setOptions( self, OptionList ): ''' Nothing to do here, no options. ''' pass def getOptions( self ): ''' @return: A list of option objects for this plugin. ''' ol = optionList() return ol def end(self): ''' This method is called when the plugin wont be used anymore. ''' self.printUniq( kb.kb.getData( 'blankBody', 'blankBody' ), None ) def getPluginDeps( self ): ''' @return: A list with the names of the plugins that should be runned before the current one. ''' return [] def getLongDesc( self ): ''' @return: A DETAILED description of the plugin functions and features. ''' return '''
class httpInBody (baseGrepPlugin): """ Search for HTTP request/response string in response body. @author: Andres Riancho ( [email protected] ) """ def __init__(self): baseGrepPlugin.__init__(self) self._already_inspected = ScalableBloomFilter() # re that searches for #GET / HTTP/1.0 self._re_request = re.compile('[a-zA-Z]{3,6} .*? HTTP/1.[01]') # re that searches for #HTTP/1.1 200 OK self._re_response = re.compile('HTTP/1.[01] [0-9][0-9][0-9] [a-zA-Z]*') 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. ''' uri = response.getURI() # 501 Code is "Not Implemented" which in some cases responds with this in the body: # <body><h2>HTTP/1.1 501 Not Implemented</h2></body> # Which creates a false positive. if response.getCode() != 501 and uri not in self._already_inspected \ and response.is_text_or_html(): # Don't repeat URLs self._already_inspected.add(uri) # First if, mostly for performance. # Remember that httpResponse objects have a faster "__in__" than # the one in strings; so string in response.getBody() is slower than # string in response if 'HTTP/1' in response and response.getClearTextBody() is not None: # Now, remove tags body_without_tags = response.getClearTextBody() res = self._re_request.search(body_without_tags) if res: i = info.info() i.setPluginName(self.getName()) i.setName('HTTP Request in HTTP body') i.setURI(uri) i.setId(response.id) i.setDesc('An HTTP request was found in the HTTP body of a response') i.addToHighlight(res.group(0)) kb.kb.append(self, 'request', i) res = self._re_response.search(body_without_tags) if res: i = info.info() i.setPluginName(self.getName()) i.setName('HTTP Response in HTTP body') i.setURI(uri) i.setId(response.id) i.setDesc('An HTTP response was found in the HTTP body of a response') kb.kb.append(self, 'response', i) def setOptions( self, optionsMap ): pass def getOptions( self ): ''' @return: A list of option objects for this plugin. ''' ol = optionList() return ol def end(self): ''' This method is called when the plugin wont be used anymore. ''' for info_type in ['request', 'response']: if kb.kb.getData('httpInBody', info_type): msg = 'The following URLs have an HTTP '+ info_type +' in the HTTP response body:' om.out.information(msg) for i in kb.kb.getData('httpInBody', info_type): om.out.information('- ' + i.getURI() + ' (id:' + str(i.getId()) + ')' ) def getPluginDeps( self ): ''' @return: A list with the names of the plugins that should be runned before the current one. ''' return [] def getLongDesc( self ): ''' @return: A DETAILED description of the plugin functions and features. ''' return '''
class allowedMethods(baseDiscoveryPlugin): ''' Enumerate the allowed methods of an URL. @author: Andres Riancho ( [email protected] ) ''' def __init__(self): baseDiscoveryPlugin.__init__(self) # Internal variables self._exec = True self._already_tested = ScalableBloomFilter() self._bad_codes = [ httpConstants.UNAUTHORIZED, httpConstants.NOT_IMPLEMENTED, httpConstants.METHOD_NOT_ALLOWED, httpConstants.FORBIDDEN] # Methods self._dav_methods = [ 'DELETE', 'PROPFIND', 'PROPPATCH', 'COPY', 'MOVE', 'LOCK', 'UNLOCK', 'MKCOL'] self._common_methods = [ 'OPTIONS', 'GET', 'HEAD', 'POST', 'TRACE', 'PUT'] self._uncommon_methods = ['*', 'SUBSCRIPTIONS', 'NOTIFY', 'DEBUG', 'TRACK', 'POLL', 'PIN', 'INVOKE', 'SUBSCRIBE', 'UNSUBSCRIBE'] # Methods taken from http://www.w3.org/Protocols/HTTP/Methods.html self._proposed_methods = [ 'CHECKOUT', 'SHOWMETHOD', 'LINK', 'UNLINK', 'CHECKIN', 'TEXTSEARCH', 'SPACEJUMP', 'SEARCH', 'REPLY'] self._extra_methods = [ 'CONNECT', 'RMDIR', 'MKDIR', 'REPORT', 'ACL', 'DELETE', 'INDEX', 'LABEL', 'INVALID'] self._version_control = [ 'VERSION_CONTROL', 'CHECKIN', 'UNCHECKOUT', 'PATCH', 'MERGE', 'MKWORKSPACE', 'MKACTIVITY', 'BASELINE_CONTROL'] self._supported_methods = self._dav_methods + self._common_methods + self._uncommon_methods self._supported_methods += self._proposed_methods + self._extra_methods self._supported_methods += self._version_control # User configured variables self._exec_one_time = True self._report_dav_only = True def discover(self, fuzzableRequest ): ''' Uses several technics to try to find out what methods are allowed for an URL. @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: # Run the plugin. if self._exec_one_time: self._exec = False domain_path = urlParser.getDomainPath( fuzzableRequest.getURL() ) if domain_path not in self._already_tested: self._already_tested.add( domain_path ) self._check_methods( domain_path ) return [] def _check_methods( self, url ): ''' Find out what methods are allowed. @parameter url: Where to check. ''' allowed_methods = [] with_options = False id_list = [] # First, try to check available methods using OPTIONS, if OPTIONS isn't # enabled, do it manually res = self._urlOpener.OPTIONS( url ) headers = res.getLowerCaseHeaders() for header_name in ['allow', 'public']: if header_name in headers: allowed_methods.extend( headers[header_name].split(',') ) allowed_methods = [ x.strip() for x in allowed_methods ] with_options = True allowed_methods = list(set(allowed_methods)) # Save the ID for later if with_options: id_list.append( res.id ) else: # # Before doing anything else, I'll send a request with a non-existant method # If that request succeds, then all will... # try: non_exist_response = self._urlOpener.ARGENTINA( url ) get_response = self._urlOpener.GET( url ) except: pass else: if non_exist_response.getCode() not in self._bad_codes\ and get_response.getBody() == non_exist_response.getBody(): i = info.info() i.setPluginName(self.getName()) i.setName( 'Non existent methods default to GET' ) i.setURL( url ) i.setId( [non_exist_response.getId(), get_response.getId()] ) msg = 'The remote Web server has a custom configuration, in which any non' msg += ' existent methods that are invoked are defaulted to GET instead of' msg += ' returning a "Not Implemented" response.' i.setDesc( msg ) kb.kb.append( self , 'custom-configuration' , i ) # # It makes no sense to continue working, all methods will appear as enabled # because of this custom configuration. # return [] # 'DELETE' is not tested! I don't want to remove anything... # 'PUT' is not tested! I don't want to overwrite anything... methods_to_test = self._supported_methods[:] # remove dups, and dangerous methods. methods_to_test = list(set(methods_to_test)) methods_to_test.remove('DELETE') methods_to_test.remove('PUT') for method in methods_to_test: method_functor = getattr( self._urlOpener, method ) try: response = apply( method_functor, (url,) , {} ) code = response.getCode() except: pass else: if code not in self._bad_codes: allowed_methods.append( method ) # Added this to make the output a little more readable. allowed_methods.sort() # Check for DAV if len( set( allowed_methods ).intersection( self._dav_methods ) ) != 0: # dav is enabled! # Save the results in the KB so that other plugins can use this information i = info.info() i.setPluginName(self.getName()) i.setName('Allowed methods for ' + url ) i.setURL( url ) i.setId( id_list ) i['methods'] = allowed_methods msg = 'The URL "' + url + '" has the following allowed methods, which' msg += ' include DAV methods: ' + ', '.join(allowed_methods) i.setDesc( msg ) kb.kb.append( self , 'dav-methods' , i ) else: # Save the results in the KB so that other plugins can use this information # Do not remove these information, other plugins REALLY use it ! i = info.info() i.setPluginName(self.getName()) i.setName('Allowed methods for ' + url ) i.setURL( url ) i.setId( id_list ) i['methods'] = allowed_methods msg = 'The URL "' + url + '" has the following allowed methods:' msg += ' ' + ', '.join(allowed_methods) i.setDesc( msg ) kb.kb.append( self , 'methods' , i ) return [] def end( self ): ''' Print the results. ''' # First I get the data from the kb all_info_obj = kb.kb.getData( 'allowedMethods', 'methods' ) dav_info_obj = kb.kb.getData( 'allowedMethods', 'dav-methods' ) # Now I transform it to something I can use with groupbyMinKey allMethods = [] for i in all_info_obj: allMethods.append( (i.getURL() , i['methods']) ) davMethods = [] for i in dav_info_obj: davMethods.append( (i.getURL() , i['methods']) ) # Now I work the data... to_show, method_type = davMethods, ' DAV' if not self._report_dav_only: to_show, method_type = allMethods, '' # Make it hashable tmp = [] for url, methodList in to_show: tmp.append( (url, ', '.join( methodList ) ) ) result_dict, itemIndex = groupbyMinKey( tmp ) for k in result_dict: if itemIndex == 0: # Grouped by URLs msg = 'The URL: "%s" has the following' + method_type + ' methods enabled:' om.out.information(msg % k) else: # Grouped by Methods msg = 'The methods: ' + k + ' are enabled on the following URLs:' om.out.information(msg) for i in result_dict[k]: om.out.information('- ' + i ) def getOptions( self ): ''' @return: A list of option objects for this plugin. ''' d1 = 'Execute plugin only one time' h1 = 'Generally the methods allowed for a URL are \ configured system wide, so executing this plugin only one \ time is the faster choice. The safest choice is to run it against every URL.' o1 = option('execOneTime', self._exec_one_time, d1, 'boolean', help=h1) d2 = 'Only report findings if uncommon methods are found' o2 = option('reportDavOnly', self._report_dav_only, d2, 'boolean') ol = optionList() ol.add(o1) ol.add(o2) return ol 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._exec_one_time = optionsMap['execOneTime'].getValue() self._report_dav_only = optionsMap['reportDavOnly'].getValue() def getPluginDeps( self ): ''' @return: A list with the names of the plugins that should be runned before the current one. ''' return [] def getLongDesc( self ): ''' @return: A DETAILED description of the plugin functions and features. ''' return '''
class objects(baseGrepPlugin): ''' Grep every page for objects and applets. @author: Andres Riancho ( [email protected] ) ''' def __init__(self): baseGrepPlugin.__init__(self) self._tag_names = [] self._tag_names.append('object') self._tag_names.append('applet') self._already_analyzed = ScalableBloomFilter() def grep(self, request, response): ''' Plugin entry point. Parse the object tags. @parameter request: The HTTP request object. @parameter response: The HTTP response object @return: None ''' url = response.getURL() if response.is_text_or_html() and url not in self._already_analyzed: self._already_analyzed.add(url) dom = response.getDOM() # In some strange cases, we fail to normalize the document if dom is not None: for tag_name in self._tag_names: # Find all input tags with a type file attribute element_list = dom.xpath('//%s' % tag_name ) if element_list: i = info.info() i.setPluginName(self.getName()) i.setName(tag_name.title() + ' tag') i.setURL(url) i.setId( response.id ) i.setDesc( 'The URL: "' + i.getURL() + '" has an '+ tag_name + ' tag.' ) i.addToHighlight( tag_name ) kb.kb.append( self, tag_name, i ) def setOptions( self, OptionList ): pass def getOptions( self ): ''' @return: A list of option objects for this plugin. ''' ol = optionList() return ol def end(self): ''' This method is called when the plugin wont be used anymore. ''' # Print objects self.printUniq( kb.kb.getData( 'objects', 'object' ), 'URL' ) # Print applets self.printUniq( kb.kb.getData( 'objects', 'applet' ), 'URL' ) def getPluginDeps( self ): ''' @return: A list with the names of the plugins that should be runned before the current one. ''' return [] def getLongDesc( self ): ''' @return: A DETAILED description of the plugin functions and features. ''' return '''
class getMails(baseGrepPlugin): ''' Find email accounts. @author: Andres Riancho ( [email protected] ) ''' def __init__(self): baseGrepPlugin.__init__(self) # User configured variables self._only_target_domain = True self._already_inspected = ScalableBloomFilter() def grep(self, request, response): ''' Plugin entry point, get the emails and save them to the kb. @parameter request: The HTTP request @parameter request: The HTTP response @return: None ''' uri = response.getURI() if uri not in self._already_inspected: self._already_inspected.add(uri) self._grep_worker(request, response, 'mails', \ urlParser.getRootDomain(response.getURL())) if not self._only_target_domain: self._grep_worker(request, response, 'external_mails') def _grep_worker(self, request, response, kb_key, domain=None): ''' Helper method for using in self.grep() @parameter request: The HTTP request @parameter request: The HTTP response @parameter kb_key: Knowledge base dict key @parameter domain: Target domain for getEmails filter @return: None ''' # Modified when I added the pdfParser #if isTextOrHtml(response.getHeaders()): try: dp = dpCache.dpc.getDocumentParserFor( response ) except w3afException: msg = 'If I can\'t parse the document, I won\'t be able to find any emails.' msg += ' Ignoring the response for "' + response.getURL() + '".' om.out.debug( msg ) return mails = dp.getEmails(domain) for mail_address in mails: # Reduce false positives if request.sent( mail_address ): continue # Email address are case insensitive mail_address = mail_address.lower() url = response.getURL() email_map = {} for info_obj in kb.kb.getData( 'mails', 'mails'): mail_string = info_obj['mail'] email_map[ mail_string ] = info_obj if mail_address not in email_map: # Create a new info object, and report it i = info.info() i.setPluginName(self.getName()) i.setURL(url) i.setId( response.id ) i.setName( mail_address ) desc = 'The mail account: "'+ mail_address + '" was found in: ' desc += '\n- ' + url desc += ' - In request with id: '+ str(response.id) i.setDesc( desc ) i['mail'] = mail_address i['url_list'] = [url] i['user'] = mail_address.split('@')[0] i.addToHighlight( mail_address ) kb.kb.append( 'mails', kb_key, i ) else: # Get the corresponding info object. i = email_map[ mail_address ] # And work if url not in i['url_list']: # This email was already found in some other URL # I'm just going to modify the url_list and the description message # of the information object. id_list_of_info = i.getId() id_list_of_info.append( response.id ) i.setId( id_list_of_info ) i.setURL('') desc = i.getDesc() desc += '\n- ' + url desc += ' - In request with id: '+ str(response.id) i.setDesc( desc ) i['url_list'].append(url) def setOptions( self, optionsMap ): self._only_target_domain = optionsMap['onlyTargetDomain'].getValue() def getOptions( self ): ''' @return: A list of option objects for this plugin. ''' ol = optionList() d1 = 'When greping, only search mails for domain of target' o1 = option('onlyTargetDomain', self._only_target_domain, d1, 'boolean') ol = optionList() ol.add(o1) return ol def end(self): ''' This method is called when the plugin wont be used anymore. ''' self.printUniq( kb.kb.getData( 'mails', 'mails' ), None ) self.printUniq( kb.kb.getData( 'mails', 'external_mails' ), None ) def getPluginDeps( self ): ''' @return: A list with the names of the plugins that should be runned before the current one. ''' return [] def getLongDesc( self ): ''' @return: A DETAILED description of the plugin functions and features. ''' return '''
def __init__(self): baseGrepPlugin.__init__(self) # User configured variables self._only_target_domain = True self._already_inspected = ScalableBloomFilter()
def __init__(self): baseDiscoveryPlugin.__init__(self) self._exec = True # Already analyzed extensions self._already_analyzed_ext = ScalableBloomFilter() # This is a list of hashes and description of the egg for every PHP version. self._egg_DB = {} self._egg_DB["4.1.2"] = [ ("744aecef04f9ed1bc39ae773c40017d1", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("85be3b4be7bfe839cbb3b4f2d30ff983", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.2.2"] = [ ("758ccaa9094cdeedcfc60017e768137e", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("85be3b4be7bfe839cbb3b4f2d30ff983", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.3.10"] = [ ("1e8fe4ae1bf06be222c1643d32015f0c", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("a57bd73e27be03a62dd6b3e1b537a72c", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.3.10-18"] = [ ("1e8fe4ae1bf06be222c1643d32015f0c", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("4b2c92409cf0bcf465d199e93a15ac3f", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.3.11"] = [ ("1e8fe4ae1bf06be222c1643d32015f0c", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("a8ad323e837fa00771eda6b709f40e37", "PHP Logo 2"), ("a8ad323e837fa00771eda6b709f40e37", "Zend Logo") ] self._egg_DB["4.3.2"] = [ ("8a8b4a419103078d82707cf68226a482", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("a57bd73e27be03a62dd6b3e1b537a72c", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.3.8"] = [ ("96714a0fbe23b5c07c8be343adb1ba90", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("a57bd73e27be03a62dd6b3e1b537a72c", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.3.9"] = [ ("f9b56b361fafd28b668cc3498425a23b", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB['4.3.10'] = [ ('7b27e18dc6f846b80e2f29ecf67e4133', 'PHP Logo'), ('43af90bcfa66f16af62744e8c599703d', 'Zend Logo'), ('b233cc756b06655f47489aa2779413d7', 'PHP Credits'), ('185386dd4b2eff044bd635d22ae7dd9e', 'PHP Logo 2')] self._egg_DB["4.4.0"] = [ ("ddf16ec67e070ec6247ec1908c52377e", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("4b2c92409cf0bcf465d199e93a15ac3f", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.4.0 for Windows"] = [ ("6d974373683ecfcf30a7f6873f2d234a", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("4b2c92409cf0bcf465d199e93a15ac3f", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.4.4"] = [ ("bed7ceff09e9666d96fdf3518af78e0e", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("4b2c92409cf0bcf465d199e93a15ac3f", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.4.4-8+etch6"] = [ ("31a2553efc348a21b85e606e5e6c2424", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("4b2c92409cf0bcf465d199e93a15ac3f", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["4.4.7"] = [ ("72b7ad604fe1362f1e8bf4f6d80d4edc", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("4b2c92409cf0bcf465d199e93a15ac3f", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB['4.4.7, PleskWin, ASP.NET'] = [ ('b8477b9b88e90f12e3200660a70eb765', 'Zend Logo'), ('b8477b9b88e90f12e3200660a70eb765', 'PHP Credits'), ('b8477b9b88e90f12e3200660a70eb765', 'PHP Logo 2'), ('b8477b9b88e90f12e3200660a70eb765', 'PHP Logo')] self._egg_DB["4.4.8"] = [ ("4cdfec8ca11691a46f4f63839e559fc5", "PHP Credits"), ("11b9cfe306004fce599a1f8180b61266", "PHP Logo"), ("4b2c92409cf0bcf465d199e93a15ac3f", "PHP Logo 2"), ("da2dae87b166b7709dbd4061375b74cb", "Zend Logo") ] self._egg_DB["5.0.3"] = [ ("def61a12c3b0a533146810403d325451", "PHP Credits"), ("8ac5a686135b923664f64fe718ea55cd", "PHP Logo"), ("37e194b799d4aaff10e39c4e3b2679a2", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.1.1"] = [ ("5518a02af41478cfc492c930ace45ae5", "PHP Credits"), ("8ac5a686135b923664f64fe718ea55cd", "PHP Logo"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.1.6"] = [ ("4b689316409eb09b155852e00657a0ae", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.0"] = [ ("e566715bcb0fd2cb1dc43ed076c091f1", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.0-8+etch10"] = [ ("e566715bcb0fd2cb1dc43ed076c091f1", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.0-8+etch7"] = [ ("307f5a1c02155ca38744647eb94b3543", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.1"] = [ ("d3894e19233d979db07d623f608b6ece", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.2"] = [ ("56f9383587ebcc94558e11ec08584f05", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.3-1+b1"] = [ ("c37c96e8728dc959c55219d47f2d543f", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.4"] = [ ("74c33ab9745d022ba61bc43a5db717eb", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.5"] = [ ("f26285281120a2296072f21e21e7b4b0", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.4-2ubuntu5.3"] = [ ("f26285281120a2296072f21e21e7b4b0", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.5-3"] = [ ("b7e4385bd7f07e378d92485b4722c169", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("0152ed695f4291488741d98ba066d280", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.6"] = [ ("bbd44c20d561a0fc5a4aa76093d5400f", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB["5.2.6RC4-pl0-gentoo"] = [ ("d03b2481f60d9e64cb5c0f4bd0c87ec1", "PHP Credits"), ("c48b07899917dfb5d591032007041ae3", "PHP Logo"), ("50caaf268b4f3d260d720a1a29c5fe21", "PHP Logo 2"), ("7675f1d01c927f9e6a4752cf182345a2", "Zend Logo") ] self._egg_DB['5.2.8-pl1-gentoo'] = [ ('c48b07899917dfb5d591032007041ae3', 'PHP Logo'), ('40410284d460552a6c9e10c1f5ae7223', 'PHP Credits'), ('50caaf268b4f3d260d720a1a29c5fe21', 'PHP Logo 2'), ('7675f1d01c927f9e6a4752cf182345a2', 'Zend Logo')]