This plugin doesn't have any user configured options.
Source
For more information about this plugin and the associated tests, there's always the source code to understand exactly what's under the hood: Plugin source code Unittest source code
Dependencies
This plugin has no dependencies.
"""
hash_analysis.py
Copyright 2006 Andres Riancho
This file is part of w3af, http://w3af.org/ .
w3af is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation version 2 of the License.
w3af is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with w3af; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import re
from w3af.core.controllers.plugins.grep_plugin import GrepPlugin
from w3af.core.data.bloomfilter.scalable_bloom import ScalableBloomFilter
from w3af.core.data.kb.info import Info
class hash_analysis(GrepPlugin):
"""
Identify hashes in HTTP responses.
:author: Andres Riancho (andres.riancho@gmail.com)
"""
def __init__(self):
GrepPlugin.__init__(self)
self._already_reported = ScalableBloomFilter()
# regex to split between words
self._split_re = re.compile('[^\w]')
def grep(self, request, response):
"""
Plugin entry point, identify hashes in the HTTP response.
:param request: The HTTP request object.
:param response: The HTTP response object
:return: None
"""
# I know that by doing this I loose the chance of finding hashes in
# PDF files, but... this is much faster
if not response.is_text_or_html():
return
body = response.get_body()
splitted_body = self._split_re.split(body)
for possible_hash in splitted_body:
# This is a performance enhancement that cuts the execution
# time of this plugin in half.
if len(possible_hash) < 31 or\
len(possible_hash) > 129 :
return
hash_type = self._get_hash_type(possible_hash)
if not hash_type:
return
possible_hash = possible_hash.lower()
if self._has_hash_distribution(possible_hash):
if (possible_hash, response.get_url()) not in self._already_reported:
desc = 'The URL: "%s" returned a response that may contain'\
' a "%s" hash. The hash string is: "%s". This is'\
' uncommon and requires human verification.'
desc = desc % (response.get_url(), hash_type, possible_hash)
i = Info('Hash string in HTML content', desc,
response.id, self.get_name())
i.set_url(response.get_url())
i.add_to_highlight(possible_hash)
self.kb_append(self, 'hash_analysis', i)
self._already_reported.add( (possible_hash,
response.get_url()) )
def _has_hash_distribution(self, possible_hash):
"""
:param possible_hash: A string that may be a hash.
:return: True if the possible_hash has an equal (aprox.) distribution
of numbers and letters and only has hex characters (0-9, a-f)
"""
numbers = 0
letters = 0
for char in possible_hash:
if char.isdigit():
numbers += 1
elif char in 'abcdef':
letters += 1
else:
return False
low = letters - len(possible_hash) / 2
high = letters + len(possible_hash) / 2
if low < numbers < high:
# Seems to be a hash, let's make a final test to avoid false positives with
# strings like:
# 2222222222222222222aaaaaaaaaaaaa
is_hash = True
for char in possible_hash:
if possible_hash.count(char) > len(possible_hash) / 5:
is_hash = False
break
return is_hash
else:
return False
def _get_hash_type(self, possible_hash):
"""
:param possible_hash: A string that may be a hash.
:return: The hash type if the string seems to be a md5 / sha1 hash.
None otherwise.
"""
# When adding something here, please review the code above where
# we also check the length.
hash_type_len = {
'MD5': 32,
'SHA1': 40,
'SHA224': 56,
'SHA256': 64,
'SHA384': 96,
'SHA512': 128,
}
for hash_type, hash_len in hash_type_len.items():
if len(possible_hash) == hash_len:
return hash_type
return None
def get_long_desc(self):
"""
:return: A DETAILED description of the plugin functions and features.
"""
return """
This plugin identifies hashes in HTTP responses.
"""
{"id": "W3AF:CE5A3BCAE1C721A3FD5E9E7F8131010E", "bulletinFamily": "scanner", "title": "hash_analysis", "description": "This plugin identifies hashes in HTTP responses. \n\n### Plugin type\n\n[Grep](<http://w3af.org/plugins/grep> \"Grep\" )\n\n### Options\n\nThis plugin doesn't have any user configured options.\n\n### Source\n\nFor more information about this plugin and the associated tests, there's always the source code to understand exactly what's under the hood: \n[Plugin source code](<https://github.com/andresriancho/w3af/tree/master/w3af/plugins/grep/hash_analysis.py> \"hash_analysis.py source code\" ) \n[Unittest source code](<https://github.com/andresriancho/w3af/tree/master/w3af/plugins/tests/grep/hash_analysis.py> \"hash_analysis.py unittests\" )\n\n### Dependencies\n\nThis plugin has no dependencies.\n", "published": "2013-06-10T23:02:10", "modified": "2018-02-15T21:17:20", "cvss": {"score": 0.0, "vector": "NONE"}, "href": "http://w3af.org/plugins/grep/hash_analysis", "reporter": "andresriancho", "references": [], "cvelist": [], "type": "w3af", "lastseen": "2018-08-12T23:27:13", "history": [{"bulletin": {"bulletinFamily": "scanner", "cvelist": [], "cvss": {"score": 0.0, "vector": "NONE"}, "description": "This plugin identifies hashes in HTTP responses. \n\n### Plugin type\n\n[Grep](<http://w3af.org/plugins/grep> \"Grep\" )\n\n### Options\n\nThis plugin doesn't have any user configured options.\n\n### Source\n\nFor more information about this plugin and the associated tests, there's always the source code to understand exactly what's under the hood: \n[Plugin source code](<https://github.com/andresriancho/w3af/tree/master/w3af/plugins/grep/hash_analysis.py> \"hash_analysis.py source code\" ) \n[Unittest source code](<https://github.com/andresriancho/w3af/tree/master/w3af/plugins/tests/grep/hash_analysis.py> \"hash_analysis.py unittests\" )\n\n### Dependencies\n\nThis plugin has no dependencies.\n", "edition": 3, "enchantments": {"score": {"modified": "2017-08-21T19:11:10", "value": 5.4, "vector": "AV:N/AC:M/Au:M/C:P/I:P/A:P/"}}, "hash": "68dbbfa3d3c0e7bf16f788d99d5ea8d854d5b4e2db62bbd18c9bdfbe8b9645de", "hashmap": [{"hash": "8366abde8908f99f44d5164a67b69bdb", "key": "published"}, {"hash": "d41d8cd98f00b204e9800998ecf8427e", "key": "references"}, {"hash": "b3e069f6c895a01210ed3501537e5fe4", "key": "modified"}, {"hash": "5870e494c4afdcb8e09725c735e5e27e", "key": "type"}, {"hash": "ce5a3bcae1c721a3fd5e9e7f8131010e", "key": "href"}, {"hash": "b32e1b2598f0f240d48742472961aa81", "key": "w3af"}, {"hash": "d41d8cd98f00b204e9800998ecf8427e", "key": "cvelist"}, {"hash": "8cd4821cb504d25572038ed182587d85", "key": "cvss"}, {"hash": "bbdaea376f500d25f6b0c1050311dd07", "key": "bulletinFamily"}, {"hash": "d0a5ad891a453d8412742541dc189e1b", "key": "sourceData"}, {"hash": "bb4124a0fec93e24d8db1b895ac8fb87", "key": "description"}, {"hash": "11febfa09cc485f3561f64dae4810a53", "key": "reporter"}, {"hash": "60bd3435e882a3482ed570cbdac6d61a", "key": "title"}], "history": [], "href": "http://w3af.org/plugins/grep/hash_analysis", "id": "W3AF:CE5A3BCAE1C721A3FD5E9E7F8131010E", "lastseen": "2017-08-21T19:11:10", "modified": "2014-02-27T13:32:27", "objectVersion": "1.3", "published": "2013-06-10T23:02:10", "references": [], "reporter": "andresriancho", "sourceData": "\"\"\"\nhash_analysis.py\n\nCopyright 2006 Andres Riancho\n\nThis file is part of w3af, http://w3af.org/ .\n\nw3af is free software; you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation version 2 of the License.\n\nw3af is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with w3af; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n\n\"\"\"\nimport re\n\nfrom w3af.core.controllers.plugins.grep_plugin import GrepPlugin\nfrom w3af.core.data.bloomfilter.scalable_bloom import ScalableBloomFilter\nfrom w3af.core.data.kb.info import Info\n\n\nclass hash_analysis(GrepPlugin):\n \"\"\"\n Identify hashes in HTTP responses.\n\n :author: Andres Riancho (andres.riancho@gmail.com)\n \"\"\"\n\n def __init__(self):\n GrepPlugin.__init__(self)\n\n self._already_reported = ScalableBloomFilter()\n\n # regex to split between words\n self._split_re = re.compile('[^\\w]')\n\n def grep(self, request, response):\n \"\"\"\n Plugin entry point, identify hashes in the HTTP response.\n\n :param request: The HTTP request object.\n :param response: The HTTP response object\n :return: None\n \"\"\"\n # I know that by doing this I loose the chance of finding hashes in\n # PDF files, but... this is much faster\n if not response.is_text_or_html():\n return\n\n body = response.get_body()\n splitted_body = self._split_re.split(body)\n for possible_hash in splitted_body:\n\n # This is a performance enhancement that cuts the execution\n # time of this plugin in half.\n if len(possible_hash) < 31 or\\\n len(possible_hash) > 129 :\n return\n \n hash_type = self._get_hash_type(possible_hash)\n if not hash_type:\n return\n\n possible_hash = possible_hash.lower()\n if self._has_hash_distribution(possible_hash):\n if (possible_hash, response.get_url()) not in self._already_reported:\n desc = 'The URL: \"%s\" returned a response that may contain'\\\n ' a \"%s\" hash. The hash string is: \"%s\". This is'\\\n ' uncommon and requires human verification.'\n desc = desc % (response.get_url(), hash_type, possible_hash)\n \n i = Info('Hash string in HTML content', desc,\n response.id, self.get_name())\n i.set_url(response.get_url())\n i.add_to_highlight(possible_hash)\n \n self.kb_append(self, 'hash_analysis', i)\n\n self._already_reported.add( (possible_hash,\n response.get_url()) )\n\n def _has_hash_distribution(self, possible_hash):\n \"\"\"\n :param possible_hash: A string that may be a hash.\n :return: True if the possible_hash has an equal (aprox.) distribution\n of numbers and letters and only has hex characters (0-9, a-f)\n \"\"\"\n numbers = 0\n letters = 0\n for char in possible_hash:\n if char.isdigit():\n numbers += 1\n elif char in 'abcdef':\n letters += 1\n else:\n return False\n\n if numbers in range(letters - len(possible_hash) / 2, letters + len(possible_hash) / 2):\n # Seems to be a hash, let's make a final test to avoid false positives with\n # strings like:\n # 2222222222222222222aaaaaaaaaaaaa\n is_hash = True\n for char in possible_hash:\n if possible_hash.count(char) > len(possible_hash) / 5:\n is_hash = False\n break\n return is_hash\n\n else:\n return False\n\n def _get_hash_type(self, possible_hash):\n \"\"\"\n :param possible_hash: A string that may be a hash.\n :return: The hash type if the string seems to be a md5 / sha1 hash.\n None otherwise.\n \"\"\"\n # When adding something here, please review the code above where\n # we also check the length.\n hash_type_len = {\n 'MD5': 32,\n 'SHA1': 40,\n 'SHA224': 56,\n 'SHA256': 64,\n 'SHA384': 96,\n 'SHA512': 128,\n }\n for hash_type, hash_len in hash_type_len.items(): \n if len(possible_hash) == hash_len:\n return hash_type\n \n return None\n\n def get_long_desc(self):\n \"\"\"\n :return: A DETAILED description of the plugin functions and features.\n \"\"\"\n return \"\"\"\n This plugin identifies hashes in HTTP responses.\n \"\"\"\n", "title": "hash_analysis", "type": "w3af", "viewCount": 1, "w3af": {"pluginType": "Grep"}}, "differentElements": ["modified", "sourceData"], "edition": 3, "lastseen": "2017-08-21T19:11:10"}, {"bulletin": {"bulletinFamily": "scanner", "cvelist": [], "cvss": {"score": 0.0, "vector": "NONE"}, "description": "This plugin identifies hashes in HTTP responses. \n\n### Plugin type\n\n[Grep](<http://w3af.org/plugins/grep> \"Grep\" )\n\n### Options\n\nThis plugin doesn't have any user configured options.\n\n### Source\n\nFor more information about this plugin and the associated tests, there's always the source code to understand exactly what's under the hood: \n[Plugin source code](<https://github.com/andresriancho/w3af/tree/master/w3af/plugins/grep/hash_analysis.py> \"hash_analysis.py source code\" ) \n[Unittest source code](<https://github.com/andresriancho/w3af/tree/master/w3af/plugins/tests/grep/hash_analysis.py> \"hash_analysis.py unittests\" )\n\n### Dependencies\n\nThis plugin has no dependencies.\n", "edition": 5, "enchantments": {"score": {"value": 5.0, "vector": "NONE"}}, "hash": "161a007bf87219d1ec9d0294d597f0c7569db7170f7ac937d8b2d746840fbbfd", "hashmap": [{"hash": "8366abde8908f99f44d5164a67b69bdb", "key": "published"}, {"hash": "d41d8cd98f00b204e9800998ecf8427e", "key": "references"}, {"hash": "5870e494c4afdcb8e09725c735e5e27e", "key": "type"}, {"hash": "ce5a3bcae1c721a3fd5e9e7f8131010e", "key": "href"}, {"hash": "b32e1b2598f0f240d48742472961aa81", "key": "w3af"}, {"hash": "d41d8cd98f00b204e9800998ecf8427e", "key": "cvelist"}, {"hash": "1110945f7a987e7d4c5f5c40205da462", "key": "sourceData"}, {"hash": "8cd4821cb504d25572038ed182587d85", "key": "cvss"}, {"hash": "bbdaea376f500d25f6b0c1050311dd07", "key": "bulletinFamily"}, {"hash": "c53d596d1b00f960c2b24e8a5a7da0e8", "key": "modified"}, {"hash": "bb4124a0fec93e24d8db1b895ac8fb87", "key": "description"}, {"hash": "11febfa09cc485f3561f64dae4810a53", "key": "reporter"}, {"hash": "60bd3435e882a3482ed570cbdac6d61a", "key": "title"}], "history": [], "href": "http://w3af.org/plugins/grep/hash_analysis", "id": "W3AF:CE5A3BCAE1C721A3FD5E9E7F8131010E", "lastseen": "2018-07-05T08:12:08", "modified": "2018-02-15T21:17:20", "objectVersion": "1.3", "published": "2013-06-10T23:02:10", "references": [], "reporter": "andresriancho", "sourceData": "\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html>\n <head>\n <title>503 Backend is unhealthy</title>\n </head>\n <body>\n <h1>Error 503 Backend is unhealthy</h1>\n <p>Backend is unhealthy</p>\n <h3>Guru Mediation:</h3>\n <p>Details: cache-ams4124-AMS 1530767524 1003833204</p>\n <hr>\n <p>Varnish cache server</p>\n </body>\n</html>\n", "title": "hash_analysis", "type": "w3af", "viewCount": 1, "w3af": {"pluginType": "Grep"}}, "differentElements": ["sourceData"], "edition": 5, "lastseen": "2018-07-05T08:12:08"}, {"bulletin": {"bulletinFamily": "scanner", "cvelist": [], "cvss": {"score": 0.0, "vector": "NONE"}, "description": "This plugin identifies hashes in HTTP responses. \n\n### Plugin type\n\n[Grep](<http://w3af.org/plugins/grep> \"Grep\" )\n\n### Options\n\nThis plugin doesn't have any user configured options.\n\n### Source\n\nFor more information about this plugin and the associated tests, there's always the source code to understand exactly what's under the hood: \n[Plugin source code](<https://github.com/andresriancho/w3af/tree/master/w3af/plugins/grep/hash_analysis.py> \"hash_analysis.py source code\" ) \n[Unittest source code](<https://github.com/andresriancho/w3af/tree/master/w3af/plugins/tests/grep/hash_analysis.py> \"hash_analysis.py unittests\" )\n\n### Dependencies\n\nThis plugin has no dependencies.\n", "edition": 8, "enchantments": {"score": {"value": 5.0, "vector": "NONE"}}, "hash": "d392e0e24e981b3b3b683a7990c22c22dea59ac29652c0c13f788630be084253", "hashmap": [{"hash": "8366abde8908f99f44d5164a67b69bdb", "key": "published"}, {"hash": "d41d8cd98f00b204e9800998ecf8427e", "key": "references"}, {"hash": "5870e494c4afdcb8e09725c735e5e27e", "key": "type"}, {"hash": "ce5a3bcae1c721a3fd5e9e7f8131010e", "key": "href"}, {"hash": "b32e1b2598f0f240d48742472961aa81", "key": "w3af"}, {"hash": "d41d8cd98f00b204e9800998ecf8427e", "key": "cvelist"}, {"hash": "8cd4821cb504d25572038ed182587d85", "key": "cvss"}, {"hash": "bbdaea376f500d25f6b0c1050311dd07", "key": "bulletinFamily"}, {"hash": "c53d596d1b00f960c2b24e8a5a7da0e8", "key": "modified"}, {"hash": "9c92c63fb3cb21f50de3c0e2e2b236c5", "key": "sourceData"}, {"hash": "bb4124a0fec93e24d8db1b895ac8fb87", "key": "description"}, {"hash": "11febfa09cc485f3561f64dae4810a53", "key": "reporter"}, {"hash": "60bd3435e882a3482ed570cbdac6d61a", "key": "title"}], "history": [], "href": "http://w3af.org/plugins/grep/hash_analysis", "id": "W3AF:CE5A3BCAE1C721A3FD5E9E7F8131010E", "lastseen": "2018-08-12T21:27:31", "modified": "2018-02-15T21:17:20", "objectVersion": "1.3", "published": "2013-06-10T23:02:10", "references": [], "reporter": "andresriancho", "sourceData": "502: Failure\n", "title": "hash_analysis", "type": "w3af", "viewCount": 1, "w3af": {"pluginType": "Grep"}}, "differentElements": ["sourceData"], "edition": 8, "lastseen": "2018-08-12T21:27:31"}, {"bulletin": {"bulletinFamily": "scanner", "cvelist": [], "cvss": {"score": 0.0, "vector": "NONE"}, "description": "This plugin identifies hashes in HTTP responses. \n\n### Plugin type\n\n[Grep](<http://w3af.org/plugins/grep> \"Grep\" )\n\n### Options\n\nThis plugin doesn't have any user configured options.\n\n### Source\n\nFor more information about this plugin and the associated tests, there's always the source code to understand exactly what's under the hood: \n[Plugin source code](<https://github.com/andresriancho/w3af/tree/master/w3af/plugins/grep/hash_analysis.py> \"hash_analysis.py source code\" ) \n[Unittest source code](<https://github.com/andresriancho/w3af/tree/master/w3af/plugins/tests/grep/hash_analysis.py> \"hash_analysis.py unittests\" )\n\n### Dependencies\n\nThis plugin has no dependencies.\n", "edition": 7, "enchantments": {"score": {"value": 5.0, "vector": "NONE"}}, "hash": "e1e86ca06df215dd28d6c99d13f0236edc405600118fc5e8c348f6223485f164", "hashmap": [{"hash": "8366abde8908f99f44d5164a67b69bdb", "key": "published"}, {"hash": "d41d8cd98f00b204e9800998ecf8427e", "key": "references"}, {"hash": "5870e494c4afdcb8e09725c735e5e27e", "key": "type"}, {"hash": "ce5a3bcae1c721a3fd5e9e7f8131010e", "key": "href"}, {"hash": "b32e1b2598f0f240d48742472961aa81", "key": "w3af"}, {"hash": "d41d8cd98f00b204e9800998ecf8427e", "key": "cvelist"}, {"hash": "dc82373af19313b87cdbbe65f22109d8", "key": "sourceData"}, {"hash": "8cd4821cb504d25572038ed182587d85", "key": "cvss"}, {"hash": "bbdaea376f500d25f6b0c1050311dd07", "key": "bulletinFamily"}, {"hash": "c53d596d1b00f960c2b24e8a5a7da0e8", "key": "modified"}, {"hash": "bb4124a0fec93e24d8db1b895ac8fb87", "key": "description"}, {"hash": "11febfa09cc485f3561f64dae4810a53", "key": "reporter"}, {"hash": "60bd3435e882a3482ed570cbdac6d61a", "key": "title"}], "history": [], "href": "http://w3af.org/plugins/grep/hash_analysis", "id": "W3AF:CE5A3BCAE1C721A3FD5E9E7F8131010E", "lastseen": "2018-07-05T11:39:12", "modified": "2018-02-15T21:17:20", "objectVersion": "1.3", "published": "2013-06-10T23:02:10", "references": [], "reporter": "andresriancho", "sourceData": "\"\"\"\nhash_analysis.py\n\nCopyright 2006 Andres Riancho\n\nThis file is part of w3af, http://w3af.org/ .\n\nw3af is free software; you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation version 2 of the License.\n\nw3af is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with w3af; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n\n\"\"\"\nimport re\n\nfrom w3af.core.controllers.plugins.grep_plugin import GrepPlugin\nfrom w3af.core.data.bloomfilter.scalable_bloom import ScalableBloomFilter\nfrom w3af.core.data.kb.info import Info\n\n\nclass hash_analysis(GrepPlugin):\n \"\"\"\n Identify hashes in HTTP responses.\n\n :author: Andres Riancho (andres.riancho@gmail.com)\n \"\"\"\n\n def __init__(self):\n GrepPlugin.__init__(self)\n\n self._already_reported = ScalableBloomFilter()\n\n # regex to split between words\n self._split_re = re.compile('[^\\w]')\n\n def grep(self, request, response):\n \"\"\"\n Plugin entry point, identify hashes in the HTTP response.\n\n :param request: The HTTP request object.\n :param response: The HTTP response object\n :return: None\n \"\"\"\n # I know that by doing this I loose the chance of finding hashes in\n # PDF files, but... this is much faster\n if not response.is_text_or_html():\n return\n\n body = response.get_body()\n splitted_body = self._split_re.split(body)\n for possible_hash in splitted_body:\n\n # This is a performance enhancement that cuts the execution\n # time of this plugin in half.\n if len(possible_hash) < 31 or\\\n len(possible_hash) > 129 :\n return\n \n hash_type = self._get_hash_type(possible_hash)\n if not hash_type:\n return\n\n possible_hash = possible_hash.lower()\n if self._has_hash_distribution(possible_hash):\n if (possible_hash, response.get_url()) not in self._already_reported:\n desc = 'The URL: \"%s\" returned a response that may contain'\\\n ' a \"%s\" hash. The hash string is: \"%s\". This is'\\\n ' uncommon and requires human verification.'\n desc = desc % (response.get_url(), hash_type, possible_hash)\n \n i = Info('Hash string in HTML content', desc,\n response.id, self.get_name())\n i.set_url(response.get_url())\n i.add_to_highlight(possible_hash)\n \n self.kb_append(self, 'hash_analysis', i)\n\n self._already_reported.add( (possible_hash,\n response.get_url()) )\n\n def _has_hash_distribution(self, possible_hash):\n \"\"\"\n :param possible_hash: A string that may be a hash.\n :return: True if the possible_hash has an equal (aprox.) distribution\n of numbers and letters and only has hex characters (0-9, a-f)\n \"\"\"\n numbers = 0\n letters = 0\n for char in possible_hash:\n if char.isdigit():\n numbers += 1\n elif char in 'abcdef':\n letters += 1\n else:\n return False\n\n low = letters - len(possible_hash) / 2\n high = letters + len(possible_hash) / 2\n if low < numbers < high:\n # Seems to be a hash, let's make a final test to avoid false positives with\n # strings like:\n # 2222222222222222222aaaaaaaaaaaaa\n is_hash = True\n for char in possible_hash:\n if possible_hash.count(char) > len(possible_hash) / 5:\n is_hash = False\n break\n return is_hash\n\n else:\n return False\n\n def _get_hash_type(self, possible_hash):\n \"\"\"\n :param possible_hash: A string that may be a hash.\n :return: The hash type if the string seems to be a md5 / sha1 hash.\n None otherwise.\n \"\"\"\n # When adding something here, please review the code above where\n # we also check the length.\n hash_type_len = {\n 'MD5': 32,\n 'SHA1': 40,\n 'SHA224': 56,\n 'SHA256': 64,\n 'SHA384': 96,\n 'SHA512': 128,\n }\n for hash_type, hash_len in hash_type_len.items(): \n if len(possible_hash) == hash_len:\n return hash_type\n \n return None\n\n def get_long_desc(self):\n \"\"\"\n :return: A DETAILED description of the plugin functions and features.\n \"\"\"\n return \"\"\"\n This plugin identifies hashes in HTTP responses.\n \"\"\"\n", "title": "hash_analysis", "type": "w3af", "viewCount": 1, "w3af": {"pluginType": "Grep"}}, "differentElements": ["sourceData"], "edition": 7, "lastseen": "2018-07-05T11:39:12"}, {"bulletin": {"bulletinFamily": "scanner", "cvelist": [], "cvss": {"score": 0.0, "vector": "NONE"}, "description": "This plugin identifies hashes in HTTP responses. \n\n### Plugin type\n\n[Grep](<http://w3af.org/plugins/grep> \"Grep\" )\n\n### Options\n\nThis plugin doesn't have any user configured options.\n\n### Source\n\nFor more information about this plugin and the associated tests, there's always the source code to understand exactly what's under the hood: \n[Plugin source code](<https://github.com/andresriancho/w3af/tree/master/w3af/plugins/grep/hash_analysis.py> \"hash_analysis.py source code\" ) \n[Unittest source code](<https://github.com/andresriancho/w3af/tree/master/w3af/plugins/tests/grep/hash_analysis.py> \"hash_analysis.py unittests\" )\n\n### Dependencies\n\nThis plugin has no dependencies.\n", "edition": 6, "enchantments": {"score": {"value": 5.0, "vector": "NONE"}}, "hash": "5b19d8773acd5fca36dfb17e06a746ec49be84c031da40a9527968f40beef2f5", "hashmap": [{"hash": "8366abde8908f99f44d5164a67b69bdb", "key": "published"}, {"hash": "d41d8cd98f00b204e9800998ecf8427e", "key": "references"}, {"hash": "5870e494c4afdcb8e09725c735e5e27e", "key": "type"}, {"hash": "ce5a3bcae1c721a3fd5e9e7f8131010e", "key": "href"}, {"hash": "b32e1b2598f0f240d48742472961aa81", "key": "w3af"}, {"hash": "d41d8cd98f00b204e9800998ecf8427e", "key": "cvelist"}, {"hash": "8cd4821cb504d25572038ed182587d85", "key": "cvss"}, {"hash": "bbdaea376f500d25f6b0c1050311dd07", "key": "bulletinFamily"}, {"hash": "0c04d5d304b2ef1444cbec452641a31e", "key": "sourceData"}, {"hash": "c53d596d1b00f960c2b24e8a5a7da0e8", "key": "modified"}, {"hash": "bb4124a0fec93e24d8db1b895ac8fb87", "key": "description"}, {"hash": "11febfa09cc485f3561f64dae4810a53", "key": "reporter"}, {"hash": "60bd3435e882a3482ed570cbdac6d61a", "key": "title"}], "history": [], "href": "http://w3af.org/plugins/grep/hash_analysis", "id": "W3AF:CE5A3BCAE1C721A3FD5E9E7F8131010E", "lastseen": "2018-07-05T09:39:55", "modified": "2018-02-15T21:17:20", "objectVersion": "1.3", "published": "2013-06-10T23:02:10", "references": [], "reporter": "andresriancho", "sourceData": "\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html>\n <head>\n <title>503 Backend is unhealthy</title>\n </head>\n <body>\n <h1>Error 503 Backend is unhealthy</h1>\n <p>Backend is unhealthy</p>\n <h3>Guru Mediation:</h3>\n <p>Details: cache-ams4124-AMS 1530772788 1026800010</p>\n <hr>\n <p>Varnish cache server</p>\n </body>\n</html>\n", "title": "hash_analysis", "type": "w3af", "viewCount": 1, "w3af": {"pluginType": "Grep"}}, "differentElements": ["sourceData"], "edition": 6, "lastseen": "2018-07-05T09:39:55"}, {"bulletin": {"bulletinFamily": "scanner", "cvelist": [], "cvss": {"score": 0.0, "vector": "NONE"}, "description": "This plugin identifies hashes in HTTP responses. \n\n### Plugin type\n\n[Grep](<http://w3af.org/plugins/grep> \"Grep\" )\n\n### Options\n\nThis plugin doesn't have any user configured options.\n\n### Source\n\nFor more information about this plugin and the associated tests, there's always the source code to understand exactly what's under the hood: \n[Plugin source code](<https://github.com/andresriancho/w3af/tree/master/w3af/plugins/grep/hash_analysis.py> \"hash_analysis.py source code\" ) \n[Unittest source code](<https://github.com/andresriancho/w3af/tree/master/w3af/plugins/tests/grep/hash_analysis.py> \"hash_analysis.py unittests\" )\n\n### Dependencies\n\nThis plugin has no dependencies.\n", "edition": 1, "enchantments": {}, "hash": "68dbbfa3d3c0e7bf16f788d99d5ea8d854d5b4e2db62bbd18c9bdfbe8b9645de", "hashmap": [{"hash": "8366abde8908f99f44d5164a67b69bdb", "key": "published"}, {"hash": "d41d8cd98f00b204e9800998ecf8427e", "key": "references"}, {"hash": "b3e069f6c895a01210ed3501537e5fe4", "key": "modified"}, {"hash": "5870e494c4afdcb8e09725c735e5e27e", "key": "type"}, {"hash": "ce5a3bcae1c721a3fd5e9e7f8131010e", "key": "href"}, {"hash": "b32e1b2598f0f240d48742472961aa81", "key": "w3af"}, {"hash": "d41d8cd98f00b204e9800998ecf8427e", "key": "cvelist"}, {"hash": "8cd4821cb504d25572038ed182587d85", "key": "cvss"}, {"hash": "bbdaea376f500d25f6b0c1050311dd07", "key": "bulletinFamily"}, {"hash": "d0a5ad891a453d8412742541dc189e1b", "key": "sourceData"}, {"hash": "bb4124a0fec93e24d8db1b895ac8fb87", "key": "description"}, {"hash": "11febfa09cc485f3561f64dae4810a53", "key": "reporter"}, {"hash": "60bd3435e882a3482ed570cbdac6d61a", "key": "title"}], "history": [], "href": "http://w3af.org/plugins/grep/hash_analysis", "id": "W3AF:CE5A3BCAE1C721A3FD5E9E7F8131010E", "lastseen": "2016-09-17T13:10:17", "modified": "2014-02-27T13:32:27", "objectVersion": "1.2", "published": "2013-06-10T23:02:10", "references": [], "reporter": "andresriancho", "sourceData": "\"\"\"\nhash_analysis.py\n\nCopyright 2006 Andres Riancho\n\nThis file is part of w3af, http://w3af.org/ .\n\nw3af is free software; you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation version 2 of the License.\n\nw3af is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with w3af; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n\n\"\"\"\nimport re\n\nfrom w3af.core.controllers.plugins.grep_plugin import GrepPlugin\nfrom w3af.core.data.bloomfilter.scalable_bloom import ScalableBloomFilter\nfrom w3af.core.data.kb.info import Info\n\n\nclass hash_analysis(GrepPlugin):\n \"\"\"\n Identify hashes in HTTP responses.\n\n :author: Andres Riancho (andres.riancho@gmail.com)\n \"\"\"\n\n def __init__(self):\n GrepPlugin.__init__(self)\n\n self._already_reported = ScalableBloomFilter()\n\n # regex to split between words\n self._split_re = re.compile('[^\\w]')\n\n def grep(self, request, response):\n \"\"\"\n Plugin entry point, identify hashes in the HTTP response.\n\n :param request: The HTTP request object.\n :param response: The HTTP response object\n :return: None\n \"\"\"\n # I know that by doing this I loose the chance of finding hashes in\n # PDF files, but... this is much faster\n if not response.is_text_or_html():\n return\n\n body = response.get_body()\n splitted_body = self._split_re.split(body)\n for possible_hash in splitted_body:\n\n # This is a performance enhancement that cuts the execution\n # time of this plugin in half.\n if len(possible_hash) < 31 or\\\n len(possible_hash) > 129 :\n return\n \n hash_type = self._get_hash_type(possible_hash)\n if not hash_type:\n return\n\n possible_hash = possible_hash.lower()\n if self._has_hash_distribution(possible_hash):\n if (possible_hash, response.get_url()) not in self._already_reported:\n desc = 'The URL: \"%s\" returned a response that may contain'\\\n ' a \"%s\" hash. The hash string is: \"%s\". This is'\\\n ' uncommon and requires human verification.'\n desc = desc % (response.get_url(), hash_type, possible_hash)\n \n i = Info('Hash string in HTML content', desc,\n response.id, self.get_name())\n i.set_url(response.get_url())\n i.add_to_highlight(possible_hash)\n \n self.kb_append(self, 'hash_analysis', i)\n\n self._already_reported.add( (possible_hash,\n response.get_url()) )\n\n def _has_hash_distribution(self, possible_hash):\n \"\"\"\n :param possible_hash: A string that may be a hash.\n :return: True if the possible_hash has an equal (aprox.) distribution\n of numbers and letters and only has hex characters (0-9, a-f)\n \"\"\"\n numbers = 0\n letters = 0\n for char in possible_hash:\n if char.isdigit():\n numbers += 1\n elif char in 'abcdef':\n letters += 1\n else:\n return False\n\n if numbers in range(letters - len(possible_hash) / 2, letters + len(possible_hash) / 2):\n # Seems to be a hash, let's make a final test to avoid false positives with\n # strings like:\n # 2222222222222222222aaaaaaaaaaaaa\n is_hash = True\n for char in possible_hash:\n if possible_hash.count(char) > len(possible_hash) / 5:\n is_hash = False\n break\n return is_hash\n\n else:\n return False\n\n def _get_hash_type(self, possible_hash):\n \"\"\"\n :param possible_hash: A string that may be a hash.\n :return: The hash type if the string seems to be a md5 / sha1 hash.\n None otherwise.\n \"\"\"\n # When adding something here, please review the code above where\n # we also check the length.\n hash_type_len = {\n 'MD5': 32,\n 'SHA1': 40,\n 'SHA224': 56,\n 'SHA256': 64,\n 'SHA384': 96,\n 'SHA512': 128,\n }\n for hash_type, hash_len in hash_type_len.items(): \n if len(possible_hash) == hash_len:\n return hash_type\n \n return None\n\n def get_long_desc(self):\n \"\"\"\n :return: A DETAILED description of the plugin functions and features.\n \"\"\"\n return \"\"\"\n This plugin identifies hashes in HTTP responses.\n \"\"\"\n", "title": "hash_analysis", "type": "w3af", "viewCount": 1, "w3af": {"pluginType": "Grep"}}, "differentElements": ["sourceData"], "edition": 1, "lastseen": "2016-09-17T13:10:17"}, {"bulletin": {"bulletinFamily": "scanner", "cvelist": [], "cvss": {"score": 0.0, "vector": "NONE"}, "description": "This plugin identifies hashes in HTTP responses. \n\n### Plugin type\n\n[Grep](<http://w3af.org/plugins/grep> \"Grep\" )\n\n### Options\n\nThis plugin doesn't have any user configured options.\n\n### Source\n\nFor more information about this plugin and the associated tests, there's always the source code to understand exactly what's under the hood: \n[Plugin source code](<https://github.com/andresriancho/w3af/tree/master/w3af/plugins/grep/hash_analysis.py> \"hash_analysis.py source code\" ) \n[Unittest source code](<https://github.com/andresriancho/w3af/tree/master/w3af/plugins/tests/grep/hash_analysis.py> \"hash_analysis.py unittests\" )\n\n### Dependencies\n\nThis plugin has no dependencies.\n", "edition": 4, "enchantments": {"score": {"value": 5.0, "vector": "NONE"}}, "hash": "e1e86ca06df215dd28d6c99d13f0236edc405600118fc5e8c348f6223485f164", "hashmap": [{"hash": "8366abde8908f99f44d5164a67b69bdb", "key": "published"}, {"hash": "d41d8cd98f00b204e9800998ecf8427e", "key": "references"}, {"hash": "5870e494c4afdcb8e09725c735e5e27e", "key": "type"}, {"hash": "ce5a3bcae1c721a3fd5e9e7f8131010e", "key": "href"}, {"hash": "b32e1b2598f0f240d48742472961aa81", "key": "w3af"}, {"hash": "d41d8cd98f00b204e9800998ecf8427e", "key": "cvelist"}, {"hash": "dc82373af19313b87cdbbe65f22109d8", "key": "sourceData"}, {"hash": "8cd4821cb504d25572038ed182587d85", "key": "cvss"}, {"hash": "bbdaea376f500d25f6b0c1050311dd07", "key": "bulletinFamily"}, {"hash": "c53d596d1b00f960c2b24e8a5a7da0e8", "key": "modified"}, {"hash": "bb4124a0fec93e24d8db1b895ac8fb87", "key": "description"}, {"hash": "11febfa09cc485f3561f64dae4810a53", "key": "reporter"}, {"hash": "60bd3435e882a3482ed570cbdac6d61a", "key": "title"}], "history": [], "href": "http://w3af.org/plugins/grep/hash_analysis", "id": "W3AF:CE5A3BCAE1C721A3FD5E9E7F8131010E", "lastseen": "2018-04-03T16:57:42", "modified": "2018-02-15T21:17:20", "objectVersion": "1.3", "published": "2013-06-10T23:02:10", "references": [], "reporter": "andresriancho", "sourceData": "\"\"\"\nhash_analysis.py\n\nCopyright 2006 Andres Riancho\n\nThis file is part of w3af, http://w3af.org/ .\n\nw3af is free software; you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation version 2 of the License.\n\nw3af is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with w3af; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n\n\"\"\"\nimport re\n\nfrom w3af.core.controllers.plugins.grep_plugin import GrepPlugin\nfrom w3af.core.data.bloomfilter.scalable_bloom import ScalableBloomFilter\nfrom w3af.core.data.kb.info import Info\n\n\nclass hash_analysis(GrepPlugin):\n \"\"\"\n Identify hashes in HTTP responses.\n\n :author: Andres Riancho (andres.riancho@gmail.com)\n \"\"\"\n\n def __init__(self):\n GrepPlugin.__init__(self)\n\n self._already_reported = ScalableBloomFilter()\n\n # regex to split between words\n self._split_re = re.compile('[^\\w]')\n\n def grep(self, request, response):\n \"\"\"\n Plugin entry point, identify hashes in the HTTP response.\n\n :param request: The HTTP request object.\n :param response: The HTTP response object\n :return: None\n \"\"\"\n # I know that by doing this I loose the chance of finding hashes in\n # PDF files, but... this is much faster\n if not response.is_text_or_html():\n return\n\n body = response.get_body()\n splitted_body = self._split_re.split(body)\n for possible_hash in splitted_body:\n\n # This is a performance enhancement that cuts the execution\n # time of this plugin in half.\n if len(possible_hash) < 31 or\\\n len(possible_hash) > 129 :\n return\n \n hash_type = self._get_hash_type(possible_hash)\n if not hash_type:\n return\n\n possible_hash = possible_hash.lower()\n if self._has_hash_distribution(possible_hash):\n if (possible_hash, response.get_url()) not in self._already_reported:\n desc = 'The URL: \"%s\" returned a response that may contain'\\\n ' a \"%s\" hash. The hash string is: \"%s\". This is'\\\n ' uncommon and requires human verification.'\n desc = desc % (response.get_url(), hash_type, possible_hash)\n \n i = Info('Hash string in HTML content', desc,\n response.id, self.get_name())\n i.set_url(response.get_url())\n i.add_to_highlight(possible_hash)\n \n self.kb_append(self, 'hash_analysis', i)\n\n self._already_reported.add( (possible_hash,\n response.get_url()) )\n\n def _has_hash_distribution(self, possible_hash):\n \"\"\"\n :param possible_hash: A string that may be a hash.\n :return: True if the possible_hash has an equal (aprox.) distribution\n of numbers and letters and only has hex characters (0-9, a-f)\n \"\"\"\n numbers = 0\n letters = 0\n for char in possible_hash:\n if char.isdigit():\n numbers += 1\n elif char in 'abcdef':\n letters += 1\n else:\n return False\n\n low = letters - len(possible_hash) / 2\n high = letters + len(possible_hash) / 2\n if low < numbers < high:\n # Seems to be a hash, let's make a final test to avoid false positives with\n # strings like:\n # 2222222222222222222aaaaaaaaaaaaa\n is_hash = True\n for char in possible_hash:\n if possible_hash.count(char) > len(possible_hash) / 5:\n is_hash = False\n break\n return is_hash\n\n else:\n return False\n\n def _get_hash_type(self, possible_hash):\n \"\"\"\n :param possible_hash: A string that may be a hash.\n :return: The hash type if the string seems to be a md5 / sha1 hash.\n None otherwise.\n \"\"\"\n # When adding something here, please review the code above where\n # we also check the length.\n hash_type_len = {\n 'MD5': 32,\n 'SHA1': 40,\n 'SHA224': 56,\n 'SHA256': 64,\n 'SHA384': 96,\n 'SHA512': 128,\n }\n for hash_type, hash_len in hash_type_len.items(): \n if len(possible_hash) == hash_len:\n return hash_type\n \n return None\n\n def get_long_desc(self):\n \"\"\"\n :return: A DETAILED description of the plugin functions and features.\n \"\"\"\n return \"\"\"\n This plugin identifies hashes in HTTP responses.\n \"\"\"\n", "title": "hash_analysis", "type": "w3af", "viewCount": 1, "w3af": {"pluginType": "Grep"}}, "differentElements": ["sourceData"], "edition": 4, "lastseen": "2018-04-03T16:57:42"}, {"bulletin": {"bulletinFamily": "scanner", "cvelist": [], "cvss": {"score": 0.0, "vector": "NONE"}, "description": "This plugin identifies hashes in HTTP responses. \n\n### Plugin type\n\n[Grep](<http://w3af.org/plugins/grep> \"Grep\" )\n\n### Options\n\nThis plugin doesn't have any user configured options.\n\n### Source\n\nFor more information about this plugin and the associated tests, there's always the source code to understand exactly what's under the hood: \n[Plugin source code](<https://github.com/andresriancho/w3af/tree/master/w3af/plugins/grep/hash_analysis.py> \"hash_analysis.py source code\" ) \n[Unittest source code](<https://github.com/andresriancho/w3af/tree/master/w3af/plugins/tests/grep/hash_analysis.py> \"hash_analysis.py unittests\" )\n\n### Dependencies\n\nThis plugin has no dependencies.\n", "edition": 2, "enchantments": {}, "hash": "b4f23c59e9851b94aa899fe9c995ad81858ccbe896d3a13ea031b13774ea83da", "hashmap": [{"hash": "8366abde8908f99f44d5164a67b69bdb", "key": "published"}, {"hash": "d41d8cd98f00b204e9800998ecf8427e", "key": "references"}, {"hash": "b3e069f6c895a01210ed3501537e5fe4", "key": "modified"}, {"hash": "5870e494c4afdcb8e09725c735e5e27e", "key": "type"}, {"hash": "ce5a3bcae1c721a3fd5e9e7f8131010e", "key": "href"}, {"hash": "b32e1b2598f0f240d48742472961aa81", "key": "w3af"}, {"hash": "d41d8cd98f00b204e9800998ecf8427e", "key": "cvelist"}, {"hash": "8cd4821cb504d25572038ed182587d85", "key": "cvss"}, {"hash": "bbdaea376f500d25f6b0c1050311dd07", "key": "bulletinFamily"}, {"hash": "51f1fd1f8a14372063e6f895a21756a1", "key": "sourceData"}, {"hash": "bb4124a0fec93e24d8db1b895ac8fb87", "key": "description"}, {"hash": "11febfa09cc485f3561f64dae4810a53", "key": "reporter"}, {"hash": "60bd3435e882a3482ed570cbdac6d61a", "key": "title"}], "history": [], "href": "http://w3af.org/plugins/grep/hash_analysis", "id": "W3AF:CE5A3BCAE1C721A3FD5E9E7F8131010E", "lastseen": "2017-08-21T17:15:20", "modified": "2014-02-27T13:32:27", "objectVersion": "1.3", "published": "2013-06-10T23:02:10", "references": [], "reporter": "andresriancho", "sourceData": "\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html>\n <head>\n <title>503 Backend is unhealthy</title>\n </head>\n <body>\n <h1>Error 503 Backend is unhealthy</h1>\n <p>Backend is unhealthy</p>\n <h3>Guru Mediation:</h3>\n <p>Details: cache-fra1235-FRA 1503324675 1217488801</p>\n <hr>\n <p>Varnish cache server</p>\n </body>\n</html>\n", "title": "hash_analysis", "type": "w3af", "viewCount": 1, "w3af": {"pluginType": "Grep"}}, "differentElements": ["sourceData"], "edition": 2, "lastseen": "2017-08-21T17:15:20"}], "edition": 9, "hashmap": [{"key": "bulletinFamily", "hash": "bbdaea376f500d25f6b0c1050311dd07"}, {"key": "cvelist", "hash": "d41d8cd98f00b204e9800998ecf8427e"}, {"key": "cvss", "hash": "8cd4821cb504d25572038ed182587d85"}, {"key": "description", "hash": "bb4124a0fec93e24d8db1b895ac8fb87"}, {"key": "href", "hash": "ce5a3bcae1c721a3fd5e9e7f8131010e"}, {"key": "modified", "hash": "c53d596d1b00f960c2b24e8a5a7da0e8"}, {"key": "published", "hash": "8366abde8908f99f44d5164a67b69bdb"}, {"key": "references", "hash": "d41d8cd98f00b204e9800998ecf8427e"}, {"key": "reporter", "hash": "11febfa09cc485f3561f64dae4810a53"}, {"key": "sourceData", "hash": "dc82373af19313b87cdbbe65f22109d8"}, {"key": "title", "hash": "60bd3435e882a3482ed570cbdac6d61a"}, {"key": "type", "hash": "5870e494c4afdcb8e09725c735e5e27e"}, {"key": "w3af", "hash": "b32e1b2598f0f240d48742472961aa81"}], "hash": "e1e86ca06df215dd28d6c99d13f0236edc405600118fc5e8c348f6223485f164", "viewCount": 1, "enchantments": {"score": {"value": 0.1, "vector": "NONE", "modified": "2018-08-12T23:27:13"}, "dependencies": {"references": [], "modified": "2018-08-12T23:27:13"}, "vulnersScore": 0.1}, "objectVersion": "1.3", "sourceData": "\"\"\"\nhash_analysis.py\n\nCopyright 2006 Andres Riancho\n\nThis file is part of w3af, http://w3af.org/ .\n\nw3af is free software; you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation version 2 of the License.\n\nw3af is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with w3af; if not, write to the Free Software\nFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n\n\"\"\"\nimport re\n\nfrom w3af.core.controllers.plugins.grep_plugin import GrepPlugin\nfrom w3af.core.data.bloomfilter.scalable_bloom import ScalableBloomFilter\nfrom w3af.core.data.kb.info import Info\n\n\nclass hash_analysis(GrepPlugin):\n \"\"\"\n Identify hashes in HTTP responses.\n\n :author: Andres Riancho (andres.riancho@gmail.com)\n \"\"\"\n\n def __init__(self):\n GrepPlugin.__init__(self)\n\n self._already_reported = ScalableBloomFilter()\n\n # regex to split between words\n self._split_re = re.compile('[^\\w]')\n\n def grep(self, request, response):\n \"\"\"\n Plugin entry point, identify hashes in the HTTP response.\n\n :param request: The HTTP request object.\n :param response: The HTTP response object\n :return: None\n \"\"\"\n # I know that by doing this I loose the chance of finding hashes in\n # PDF files, but... this is much faster\n if not response.is_text_or_html():\n return\n\n body = response.get_body()\n splitted_body = self._split_re.split(body)\n for possible_hash in splitted_body:\n\n # This is a performance enhancement that cuts the execution\n # time of this plugin in half.\n if len(possible_hash) < 31 or\\\n len(possible_hash) > 129 :\n return\n \n hash_type = self._get_hash_type(possible_hash)\n if not hash_type:\n return\n\n possible_hash = possible_hash.lower()\n if self._has_hash_distribution(possible_hash):\n if (possible_hash, response.get_url()) not in self._already_reported:\n desc = 'The URL: \"%s\" returned a response that may contain'\\\n ' a \"%s\" hash. The hash string is: \"%s\". This is'\\\n ' uncommon and requires human verification.'\n desc = desc % (response.get_url(), hash_type, possible_hash)\n \n i = Info('Hash string in HTML content', desc,\n response.id, self.get_name())\n i.set_url(response.get_url())\n i.add_to_highlight(possible_hash)\n \n self.kb_append(self, 'hash_analysis', i)\n\n self._already_reported.add( (possible_hash,\n response.get_url()) )\n\n def _has_hash_distribution(self, possible_hash):\n \"\"\"\n :param possible_hash: A string that may be a hash.\n :return: True if the possible_hash has an equal (aprox.) distribution\n of numbers and letters and only has hex characters (0-9, a-f)\n \"\"\"\n numbers = 0\n letters = 0\n for char in possible_hash:\n if char.isdigit():\n numbers += 1\n elif char in 'abcdef':\n letters += 1\n else:\n return False\n\n low = letters - len(possible_hash) / 2\n high = letters + len(possible_hash) / 2\n if low < numbers < high:\n # Seems to be a hash, let's make a final test to avoid false positives with\n # strings like:\n # 2222222222222222222aaaaaaaaaaaaa\n is_hash = True\n for char in possible_hash:\n if possible_hash.count(char) > len(possible_hash) / 5:\n is_hash = False\n break\n return is_hash\n\n else:\n return False\n\n def _get_hash_type(self, possible_hash):\n \"\"\"\n :param possible_hash: A string that may be a hash.\n :return: The hash type if the string seems to be a md5 / sha1 hash.\n None otherwise.\n \"\"\"\n # When adding something here, please review the code above where\n # we also check the length.\n hash_type_len = {\n 'MD5': 32,\n 'SHA1': 40,\n 'SHA224': 56,\n 'SHA256': 64,\n 'SHA384': 96,\n 'SHA512': 128,\n }\n for hash_type, hash_len in hash_type_len.items(): \n if len(possible_hash) == hash_len:\n return hash_type\n \n return None\n\n def get_long_desc(self):\n \"\"\"\n :return: A DETAILED description of the plugin functions and features.\n \"\"\"\n return \"\"\"\n This plugin identifies hashes in HTTP responses.\n \"\"\"\n", "w3af": {"pluginType": "Grep"}}