From 36db0fc48b690a69b91e263d68733fc717a796ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diogo=20Os=C3=B3rio?= Date: Sun, 8 Oct 2017 18:23:49 +0100 Subject: [PATCH 01/15] Add pep8 to the test-requiements.txt file --- test-requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test-requirements.txt b/test-requirements.txt index 6fd5b17..40dfab1 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,4 +1,5 @@ -r requirements.txt pytest==3.2.3 -pytest-mock==1.6.3 \ No newline at end of file +pytest-mock==1.6.3 +pep8==1.7.0 \ No newline at end of file From f44ea86c8e2921209d8e89b7f9e7a41ba958ccfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diogo=20Os=C3=B3rio?= Date: Sun, 8 Oct 2017 18:26:34 +0100 Subject: [PATCH 02/15] Make the lib/core/discovered_host.py file adhere to the PEP8 convention --- lib/core/discovered_host.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/discovered_host.py b/lib/core/discovered_host.py index 88b7af4..6fa26d4 100644 --- a/lib/core/discovered_host.py +++ b/lib/core/discovered_host.py @@ -8,4 +8,4 @@ def __init__(self): self.response_code = 0 self.hash = '' self.keys = [] - self.content = b'' \ No newline at end of file + self.content = b'' From d0a34f1aa9cee7d0474df42f328de1b6b092bee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diogo=20Os=C3=B3rio?= Date: Sun, 8 Oct 2017 18:27:24 +0100 Subject: [PATCH 03/15] Make the bli/core/__init__.py file adhere to the PEP8 convention --- lib/core/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/__init__.py b/lib/core/__init__.py index 35a38fb..b6bcc08 100644 --- a/lib/core/__init__.py +++ b/lib/core/__init__.py @@ -5,4 +5,4 @@ See the file 'doc/COPYING' for copying permission """ -pass \ No newline at end of file +pass From 540e974eb50691e89255af3f3198bef0a1f164c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diogo=20Os=C3=B3rio?= Date: Sun, 8 Oct 2017 18:28:05 +0100 Subject: [PATCH 04/15] Make the lib/core/__version__.py adhere to the pep8 convention --- lib/core/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/__version__.py b/lib/core/__version__.py index 8a4f27b..3f3cfbe 100644 --- a/lib/core/__version__.py +++ b/lib/core/__version__.py @@ -1,4 +1,4 @@ -# +-+-+-+-+-+-+-+-+-+ +# +-+-+-+-+-+-+-+-+-+ # |V|H|o|s|t|S|c|a|n| Developed by @codingo_ & @__timk # +-+-+-+-+-+-+-+-+-+ https://github.com/codingo/VHostScan From 277117a5ab2673043e95cf5e7e3c5c7249840ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diogo=20Os=C3=B3rio?= Date: Sun, 8 Oct 2017 18:44:14 +0100 Subject: [PATCH 05/15] Make the lib/core/virtual_host_scanner.py adhere to the pep8 convention --- lib/core/virtual_host_scanner.py | 108 +++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 35 deletions(-) diff --git a/lib/core/virtual_host_scanner.py b/lib/core/virtual_host_scanner.py index 947d112..806f36f 100644 --- a/lib/core/virtual_host_scanner.py +++ b/lib/core/virtual_host_scanner.py @@ -8,19 +8,26 @@ from lib.core.discovered_host import * from urllib3.util import ssl_ -DEFAULT_USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36' +DEFAULT_USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) '\ + 'AppleWebKit/537.36 (KHTML, like Gecko) '\ + 'Chrome/61.0.3163.100 Safari/537.36' _target_host = None _ssl_wrap_socket = ssl_.ssl_wrap_socket + + def ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None, ca_certs=None, server_hostname=None, ssl_version=None, ciphers=None, ssl_context=None, ca_cert_dir=None): - ssl_wrap_socket_(sock, keyfile=keyfile, certfile=certfile, cert_reqs=cert_reqs, - ca_certs=ca_certs, server_hostname=_target_host, - ssl_version=ssl_version, ciphers=ciphers, ssl_context=ssl_context, - ca_cert_dir=ca_cert_dir) -ssl_.ssl_wrap_socket = _ssl_wrap_socket + ssl_wrap_socket_(sock, keyfile=keyfile, certfile=certfile, + cert_reqs=cert_reqs, ca_certs=ca_certs, + server_hostname=_target_host, ssl_version=ssl_version, + ciphers=ciphers, ssl_context=ssl_context, + ca_cert_dir=ca_cert_dir) + +ssl_.ssl_wrap_socket = _ssl_wrap_socket + class virtual_host_scanner(object): """Virtual host scanning class @@ -35,8 +42,6 @@ class virtual_host_scanner(object): ignore_content_length: integer value of content length to ignore output: folder to write output file to """ - - def __init__(self, target, wordlist, **kwargs): self.target = target self.wordlist = wordlist @@ -44,25 +49,35 @@ def __init__(self, target, wordlist, **kwargs): self.rate_limit = int(kwargs.get('rate_limit', 0)) self.port = int(kwargs.get('port', 80)) self.real_port = int(kwargs.get('real_port', 80)) - self.ignore_content_length = int(kwargs.get('ignore_content_length', 0)) self.ssl = kwargs.get('ssl', False) self.fuzzy_logic = kwargs.get('fuzzy_logic', False) - self.add_waf_bypass_headers = kwargs.get('add_waf_bypass_headers', False) self.unique_depth = int(kwargs.get('unique_depth', 1)) self.ignore_http_codes = kwargs.get('ignore_http_codes', '404') self.first_hit = kwargs.get('first_hit') + self.ignore_content_length = int( + kwargs.get('ignore_content_length', 0) + ) + + self.add_waf_bypass_headers = kwargs.get( + 'add_waf_bypass_headers', + False + ) + # this can be made redundant in future with better exceptions - self.completed_scan=False - - # this is maintained until likely-matches is refactored to use new class + self.completed_scan = False + + # this is maintained until likely-matches is refactored to use + # new class self.results = [] - - # store associated data for discovered hosts in array for oN, oJ, etc' + + # store associated data for discovered hosts + # in array for oN, oJ, etc' self.hosts = [] # available user-agents - self.user_agents = list(kwargs.get('user_agents')) or [DEFAULT_USER_AGENT] + self.user_agents = list(kwargs.get('user_agents')) \ + or [DEFAULT_USER_AGENT] @property def ignore_http_codes(self): @@ -70,8 +85,9 @@ def ignore_http_codes(self): @ignore_http_codes.setter def ignore_http_codes(self, codes): - self._ignore_http_codes = [int(code) for code in codes.replace(' ', '').split(',')] - + self._ignore_http_codes = [ + int(code) for code in codes.replace(' ', '').split(',') + ] def scan(self): if not self.base_host: @@ -83,9 +99,14 @@ def scan(self): for virtual_host in self.wordlist: hostname = virtual_host.replace('%s', self.base_host) + if self.real_port == 80: + host_header = hostname + else: + host_header = '{}:{}'.format(hostname, self.real_port) + headers = { 'User-Agent': random.choice(self.user_agents), - 'Host': hostname if self.real_port == 80 else '{}:{}'.format(hostname, self.real_port), + 'Host': host_header, 'Accept': '*/*' } @@ -96,8 +117,13 @@ def scan(self): 'X-Remote-IP': '127.0.0.1', 'X-Remote-Addr': '127.0.0.1' }) - - dest_url = '{}://{}:{}/'.format('https' if self.ssl else 'http', self.target, self.port) + + dest_url = '{}://{}:{}/'.format( + 'https' if self.ssl else 'http', + self.target, + self.port + ) + _target_host = hostname try: @@ -108,7 +134,9 @@ def scan(self): if res.status_code in self.ignore_http_codes: continue - if self.ignore_content_length > 0 and self.ignore_content_length == int(res.headers.get('content-length')): + response_length = int(res.headers.get('content-length')) + if self.ignore_content_length and \ + self.ignore_content_length == response_length: continue # hash the page results to aid in identifing unique content @@ -122,26 +150,31 @@ def scan(self): if len(self.hosts) == 2 and self.first_hit: break - #rate limit the connection, if the int is 0 it is ignored + # rate limit the connection, if the int is 0 it is ignored time.sleep(self.rate_limit) - self.completed_scan=True - + self.completed_scan = True def likely_matches(self): if self.completed_scan is False: - print("[!] Likely matches cannot be printed as a scan has not yet been run.") - return + print("[!] Likely matches cannot be printed " + "as a scan has not yet been run.") + return # segment results from previous scan into usable results - segmented_data={} + segmented_data = {} for item in self.results: result = item.split(",") segmented_data[result[0]] = result[1] - dataframe = pd.DataFrame([[key, value] for key, value in segmented_data.items()], columns=["key_col", "val_col"]) - segmented_data = dataframe.groupby("val_col").filter(lambda x: len(x) <= self.unique_depth) - matches = ((segmented_data["key_col"].values).tolist()) + dataframe = pd.DataFrame([ + [key, value] for key, value in segmented_data.items()], + columns=["key_col", "val_col"] + ) + + segmented_data = dataframe.groupby("val_col").filter( + lambda x: len(x) <= self.unique_depth + ) return matches @@ -150,13 +183,18 @@ def create_host(self, response, hostname, page_hash): Creates a host using the responce and the hash. Prints current result in real time. """ - output = '[#] Found: {} (code: {}, length: {}, hash: {})\n'.format(hostname, response.status_code, - response.headers.get('content-length'), page_hash) + output = '[#] Found: {} (code: {}, length: {}, hash: {})\n'.format( + hostname, + response.status_code, + response.headers.get('content-length'), + page_hash + ) + host = discovered_host() host.hostname = hostname host.response_code = response.status_code host.hash = page_hash - host.content = response.content + host.contnet = response.content for key, val in response.headers.items(): output += ' {}: {}\n'.format(key, val) @@ -164,4 +202,4 @@ def create_host(self, response, hostname, page_hash): print(output) - return host \ No newline at end of file + return host From e4ee19755e8844ae0c069b18374ca64cde8be362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diogo=20Os=C3=B3rio?= Date: Sun, 8 Oct 2017 18:44:57 +0100 Subject: [PATCH 06/15] Make the lib/helpers/__init__.py adhere to the pep8 convention --- lib/helpers/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers/__init__.py b/lib/helpers/__init__.py index 35a38fb..b6bcc08 100644 --- a/lib/helpers/__init__.py +++ b/lib/helpers/__init__.py @@ -5,4 +5,4 @@ See the file 'doc/COPYING' for copying permission """ -pass \ No newline at end of file +pass From 64eca91e381d740d1ecc6928831fa407c77305ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diogo=20Os=C3=B3rio?= Date: Sun, 8 Oct 2017 18:45:44 +0100 Subject: [PATCH 07/15] Make the lib/helpers/file_helper_.py adhere to the pep8 convention --- lib/helpers/file_helper.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/helpers/file_helper.py b/lib/helpers/file_helper.py index 5a36ee4..29aaf21 100644 --- a/lib/helpers/file_helper.py +++ b/lib/helpers/file_helper.py @@ -8,7 +8,7 @@ def __init__(self, output_file): def check_directory(self): directory = os.path.dirname(self.output_file) - + try: os.stat(directory) except: @@ -18,7 +18,7 @@ def check_directory(self): # placeholder for error checking on -oJ implementation def is_json(json_file): try: - with open(json_file, "r") as f: + with open(json_file, "r") as f: json_object = json.load(f) except ValueError: return False @@ -27,7 +27,7 @@ def is_json(json_file): def write_file(self, contents): # check if host directory exists, if not create it self.check_directory() - + with open(self.output_file, "w") as o: o.write(contents) From 4ce6cf08c3f8cb0141a379a4740408d7d49aeebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diogo=20Os=C3=B3rio?= Date: Sun, 8 Oct 2017 18:51:25 +0100 Subject: [PATCH 08/15] Make the lib/helpers/output_helper_.py adhere to the pep8 convention --- lib/helpers/output_helper.py | 95 ++++++++++++++++++++++++------------ 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/lib/helpers/output_helper.py b/lib/helpers/output_helper.py index 7a6aa2d..b63bbea 100644 --- a/lib/helpers/output_helper.py +++ b/lib/helpers/output_helper.py @@ -13,7 +13,6 @@ def __init__(self, scanner, arguments): self.arguments = arguments def write_normal(self, filename): - file = file_helper(filename) # todo: finish check_directory (needs regex to split out filename) @@ -21,33 +20,33 @@ def write_normal(self, filename): output = self.generate_header() output += self.output_normal_likely() - + if(self.arguments.fuzzy_logic): output += self.output_fuzzy() - + output += self.output_normal_detail() - + file.write_file(output) def output_normal_likely(self): uniques = False depth = str(self.scanner.unique_depth) - output = "\n[+] Most likely matches with a unique count of {} or less:".format(depth) - - for p in self.scanner.likely_matches(): + output = "\n[+] Most likely matches with a unique count "\ + "of {} or less:".format(depth) + + for p in self.scanner.likely_matches(): output += "\n\t[>] {}".format(p) uniques = True - + if(uniques): return output else: - return "\n[!] No matches with a unique count of {} or less.".format(depth) - + return "\n[!] No matches with an" \ + " unique count of {} or less.".format(depth) def output_json(self, filename): file = file_helper(filename) output = dict() - output['Start Time'] = '{} {}'.format(time.strftime("%d/%m/%Y"), time.strftime("%H:%M:%S")) output['Target'] = self.scanner.target output['Base Host'] = self.scanner.base_host output['Port'] = self.scanner.port @@ -57,46 +56,82 @@ def output_json(self, filename): output['Wordlist'] = self.scanner.wordlist output['Unique Depth'] = self.scanner.unique_depth output['SSL'] = self.scanner.ssl + output['Start Time'] = '{} {}'.format( + time.strftime("%d/%m/%Y"), + time.strftime("%H:%M:%S") + ) + result = dict() for host in self.scanner.hosts: headers = dict() for header in host.keys: headers[header.split(':')[0]] = header.split(':')[1].strip() - result[host.hostname] = {'Code': host.response_code, - 'Hash': host.hash, - 'Headers': headers} + result[host.hostname] = { + 'Code': host.response_code, + 'Hash': host.hash, + 'Headers': headers + } + output['Result'] = result file.write_file(json.dumps(output, indent=2)) - def output_fuzzy(self): output = "\n\n[+] Match similarity using fuzzy logic:" request_hashes = {} - + for host in self.scanner.hosts: request_hashes[host.hash] = host.content - + for a, b in itertools.combinations(request_hashes.keys(), 2): - output += "\n\t[>] {} is {}% similar to {}".format(a, fuzz.ratio(request_hashes[a], request_hashes[b]), b) - - return output + output += "\n\t[>] {} is {}% similar to {}".format( + a, + fuzz.ratio(request_hashes[a], request_hashes[b]), + b + ) + return output def output_normal_detail(self): output = "\n\n[+] Full scan results" - for host in self.scanner.hosts: - output += "\n\n{} (Code: {}) hash: {}".format(str(host.hostname), str(host.response_code), str(host.hash)) - for key in host.keys: output += "\n\t{}".format(key) - - return output + for host in self.scanner.hosts: + output += "\n\n{} (Code: {}) hash: {}".format( + str(host.hostname), + str(host.response_code), + str(host.hash) + ) + + for key in host.keys: + output += "\n\t{}".format(key) + return output def generate_header(self): - output = "VHostScanner Log: {} {}\n".format(time.strftime("%d/%m/%Y"), time.strftime("%H:%M:%S")) - output += "\tTarget: {}\n\tBase Host: {}\n\tPort: {}".format(self.scanner.target, self.scanner.base_host, self.scanner.port) - output += "\n\tReal Port {}\n\tIgnore HTTP Codes: {}".format(self.scanner.real_port,self.scanner.ignore_http_codes) - output += "\n\tIgnore Content Length: {}\n\tWordlist: {}".format(self.scanner.ignore_content_length, self.scanner.wordlist) - output += "\n\tUnique Depth: {}\n\tSSL: {}\n\t".format(self.scanner.unique_depth, self.scanner.ssl) + output = "VHostScanner Log: {} {}\n".format( + time.strftime("%d/%m/%Y"), + time.strftime("%H:%M:%S") + ) + + output += "\tTarget: {}\n\tBase Host: {}\n\tPort: {}".format( + self.scanner.target, + self.scanner.base_host, + self.scanner.port + ) + + output += "\n\tReal Port {}\n\tIgnore HTTP Codes: {}".format( + self.scanner.real_port, + self.scanner.ignore_http_codes + ) + + output += "\n\tIgnore Content Length: {}\n\tWordlist: {}".format( + self.scanner.ignore_content_length, + self.scanner.wordlist + ) + + output += "\n\tUnique Depth: {}\n\tSSL: {}\n\t".format( + self.scanner.unique_depth, + self.scanner.ssl + ) + return output From cc518bab6b542fe469f80c86e1111bf61fc4913d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diogo=20Os=C3=B3rio?= Date: Sun, 8 Oct 2017 18:51:48 +0100 Subject: [PATCH 09/15] Make the lib/__init__.py adhere to the pep8 convention --- lib/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/__init__.py b/lib/__init__.py index 35a38fb..b6bcc08 100644 --- a/lib/__init__.py +++ b/lib/__init__.py @@ -5,4 +5,4 @@ See the file 'doc/COPYING' for copying permission """ -pass \ No newline at end of file +pass From f58319a9f0fde47018f144dc65a6fe4a2fb3f364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diogo=20Os=C3=B3rio?= Date: Mon, 9 Oct 2017 19:04:31 +0100 Subject: [PATCH 10/15] Make the lib/input.py file adhere to the PEP8 convention --- lib/input.py | 65 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/lib/input.py b/lib/input.py index 0ceac2c..9d21cd0 100644 --- a/lib/input.py +++ b/lib/input.py @@ -1,9 +1,10 @@ from argparse import ArgumentParser + class cli_argument_parser(object): def __init__(self): self._parser = self.setup_parser() - + def parse(self, argv): return self._parser.parse_args(argv) @@ -18,12 +19,14 @@ def setup_parser(): parser.add_argument( '-w', dest='wordlists', - help='Set the wordlists to use (default ./wordlists/virtual-host-scanning.txt)' + help='Set the wordlists to use (default ' + './wordlists/virtual-host-scanning.txt)' ) parser.add_argument( '-b', dest='base_host', default=False, - help='Set host to be used during substitution in wordlist (default to TARGET).' + help='Set host to be used during substitution in ' + 'wordlist (default to TARGET).' ) parser.add_argument( @@ -33,74 +36,92 @@ def setup_parser(): parser.add_argument( '-r', dest='real_port', type=int, default=False, - help='The real port of the webserver to use in headers when not 80 (see RFC2616 14.23), useful when pivoting through ssh/nc etc (default to PORT).' + help='The real port of the webserver to use in headers when ' + 'not 80 (see RFC2616 14.23), useful when pivoting through ' + 'ssh/nc etc (default to PORT).' ) parser.add_argument( '--ignore-http-codes', dest='ignore_http_codes', default='404', - help='Comma separated list of http codes to ignore with virtual host scans (default 404).' + help='Comma separated list of http codes to ignore with virtual ' + 'host scans (default 404).' ) parser.add_argument( - '--ignore-content-length', dest='ignore_content_length', type=int, default=0, - help='Ignore content lengths of specificed amount (default 0).' + '--ignore-content-length', dest='ignore_content_length', type=int, + default=0, help='Ignore content lengths of specificed amount ' + '(default 0).' ) parser.add_argument( - '--first-hit', dest='first_hit', action='store_true', default=False, - help='Return first successful result. Only use in scenarios where you are sure no catch-all is configured (such as a CTF).' + '--first-hit', dest='first_hit', action='store_true', + default=False, + help='Return first successful result. Only use in scenarios where ' + 'you are sure no catch-all is configured (such as a CTF).' ) parser.add_argument( '--unique-depth', dest='unique_depth', type=int, default=1, - help='Show likely matches of page content that is found x times (default 1).' + help='Show likely matches of page content that is found x times ' + '(default 1).' ) parser.add_argument( '--ssl', dest='ssl', action='store_true', default=False, - help='If set then connections will be made over HTTPS instead of HTTP (default http).' + help='If set then connections will be made over HTTPS instead of ' + 'HTTP (default http).' ) parser.add_argument( - '--fuzzy-logic', dest='fuzzy_logic', action='store_true', default=False, - help='If set then fuzzy match will be performed against unique hosts (default off).' + '--fuzzy-logic', dest='fuzzy_logic', action='store_true', + default=False, + help='If set then fuzzy match will be performed against unique ' + 'hosts (default off).' ) parser.add_argument( - '--no-lookups', dest='no_lookup', action='store_true', default=False, - help='Disable reverse lookups (identifies new targets and appends to wordlist, on by default).' + '--no-lookups', dest='no_lookup', action='store_true', + default=False, + help='Disable reverse lookups (identifies new targets and appends ' + 'to wordlist, on by default).' ) parser.add_argument( '--rate-limit', dest='rate_limit', type=int, default=0, - help='Amount of time in seconds to delay between each scan (default 0).' + help='Amount of time in seconds to delay between each scan ' + '(default 0).' ) parser.add_argument( - '--waf', dest='add_waf_bypass_headers', action='store_true', default=False, + '--waf', dest='add_waf_bypass_headers', action='store_true', + default=False, help='If set then simple WAF bypass headers will be sent.' ) parser.add_argument( '-', dest='stdin', action='store_true', default=False, - help="By passing a blank '-' you tell VHostScan to expect input from stdin (pipe)." + help="By passing a blank '-' you tell VHostScan to expect input " + "from stdin (pipe)." ) output = parser.add_mutually_exclusive_group() output.add_argument( '-oN', dest='output_normal', - help='Normal output printed to a file when the -oN option is specified with a filename argument.' + help='Normal output printed to a file when the -oN option is ' + 'specified with a filename argument.' ) output.add_argument( '-oJ', dest='output_json', - help='JSON output printed to a file when the -oJ option is specified with a filename argument.' + help='JSON output printed to a file when the -oJ option is ' + 'specified with a filename argument.' ) user_agent = parser.add_mutually_exclusive_group() user_agent.add_argument( - '--random-agent', dest='random_agent', action='store_true', default=False, - help='If set, then each scan will use random user-agent from predefined list.' + '--random-agent', dest='random_agent', action='store_true', + default=False, help='If set, then each scan will use random ' + 'user-agent from predefined list.' ) user_agent.add_argument( From 4f38ca5c5d0918f5ea508aaf88d90f2d31d2ea89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diogo=20Os=C3=B3rio?= Date: Sun, 8 Oct 2017 19:11:34 +0100 Subject: [PATCH 11/15] Make the VHostScan.py adhere to the pep8 convention --- VHostScan.py | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/VHostScan.py b/VHostScan.py index 72de135..e36702a 100644 --- a/VHostScan.py +++ b/VHostScan.py @@ -7,10 +7,17 @@ from socket import gethostbyaddr from lib.core.virtual_host_scanner import * from lib.helpers.output_helper import * -from lib.helpers.file_helper import get_combined_word_lists, load_random_user_agents +from lib.helpers.file_helper import get_combined_word_lists +from lib.helpers.file_helper import load_random_user_agents from lib.core.__version__ import __version__ from lib.input import cli_argument_parser +DEFAULT_WORDLIST_FILE = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + 'wordlists', + 'virtual-host-scanning.txt' +) + def print_banner(): print("+-+-+-+-+-+-+-+-+-+ v. %s" % __version__) @@ -20,13 +27,14 @@ def print_banner(): def main(): print_banner() - + parser = cli_argument_parser() arguments = parser.parse(sys.argv[1:]) wordlist = [] word_list_types = [] - default_wordlist = "./wordlists/virtual-host-scanning.txt" if not arguments.stdin else None + + default_wordlist = DEFAULT_WORDLIST_FILE if not arguments.stdin else None if arguments.stdin: word_list_types.append('stdin') @@ -42,11 +50,14 @@ def main(): print("[!] No words found in provided wordlists, unable to scan.") sys.exit(1) - print("[+] Starting virtual host scan for {host} using port {port} and {inputs}".format( - host=arguments.target_hosts, - port=arguments.port, - inputs=', '.join(word_list_types), - )) + print( + "[+] Starting virtual host scan for {host} using " + "port {port} and {inputs}".format( + host=arguments.target_hosts, + port=arguments.port, + inputs=', '.join(word_list_types), + ) + ) user_agents = [] if arguments.user_agent: @@ -62,10 +73,14 @@ def main(): if(arguments.add_waf_bypass_headers): print("[>] WAF flag set, sending simple WAF bypass headers.") - print("[>] Ignoring HTTP codes: %s" % (arguments.ignore_http_codes)) + print("[>] Ignoring HTTP codes: {}".format(arguments.ignore_http_codes)) if(arguments.ignore_content_length > 0): - print("[>] Ignoring Content length: %s" % (arguments.ignore_content_length)) + print( + "[>] Ignoring Content length: {}".format( + arguments.ignore_content_length + ) + ) if arguments.first_hit: print("[>] First hit is set.") @@ -78,7 +93,12 @@ def main(): wordlist.extend(aliases) scanner_args = vars(arguments) - scanner_args.update({'target': arguments.target_hosts, 'wordlist': wordlist, 'user_agents': user_agents}) + scanner_args.update({ + 'target': arguments.target_hosts, + 'wordlist': wordlist, + 'user_agents': user_agents + }) + scanner = virtual_host_scanner(**scanner_args) scanner.scan() output = output_helper(scanner, arguments) From 5dd38a91939c98fbd08f9dc67303cdc98f141ecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diogo=20Os=C3=B3rio?= Date: Sun, 8 Oct 2017 19:16:52 +0100 Subject: [PATCH 12/15] =?UTF-8?q?Default=20the=20Content-Length=20response?= =?UTF-8?q?=20header=20to=200=C2=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the response payload doesn't contain a 'Content-Length' header and the '--ignore-content-length' parameter is provided, the script was trying to cast a None type into an integer. This commit fixes that by return '0' has the 'Content-Length' if the header isn't present. --- lib/core/virtual_host_scanner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/virtual_host_scanner.py b/lib/core/virtual_host_scanner.py index 806f36f..c08b41d 100644 --- a/lib/core/virtual_host_scanner.py +++ b/lib/core/virtual_host_scanner.py @@ -134,7 +134,7 @@ def scan(self): if res.status_code in self.ignore_http_codes: continue - response_length = int(res.headers.get('content-length')) + response_length = int(res.headers.get('content-length', 0)) if self.ignore_content_length and \ self.ignore_content_length == response_length: continue From 495d1007dfdf1e29f83b959387a1d9c2bf72c6c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diogo=20Os=C3=B3rio?= Date: Sun, 8 Oct 2017 19:18:53 +0100 Subject: [PATCH 13/15] Remove the exclusions from the pep8 CI invocation With the codebase adhering to PEP 8, there's no longer any need to omit certain rules when validating the pep8 convention. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0842465..94b5c82 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,9 +5,9 @@ python: - 3.6 install: - pip --version - - pip install -r requirements.txt + - pip install -r test-requirements.txt - pip install pep8 before_script: - - pep8 --ignore=E501,W293,E202,E241,W291 *.py + - pep8 -v *.py lib/ script: - pytest From 4d177dada9bf09a6c5759cd01edb44791d6dc405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diogo=20Os=C3=B3rio?= Date: Mon, 9 Oct 2017 19:09:54 +0100 Subject: [PATCH 14/15] Bump the application version to 1.6.2 --- lib/core/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/__version__.py b/lib/core/__version__.py index 3f3cfbe..27ab71c 100644 --- a/lib/core/__version__.py +++ b/lib/core/__version__.py @@ -2,4 +2,4 @@ # |V|H|o|s|t|S|c|a|n| Developed by @codingo_ & @__timk # +-+-+-+-+-+-+-+-+-+ https://github.com/codingo/VHostScan -__version__ = '1.6.1' +__version__ = '1.6.2' From a3ba052e877a56d2b8c318288e59076f52947b49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diogo=20Os=C3=B3rio?= Date: Mon, 9 Oct 2017 19:10:14 +0100 Subject: [PATCH 15/15] Correct the `first_run` parameter usage on the scanner --- lib/core/virtual_host_scanner.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/virtual_host_scanner.py b/lib/core/virtual_host_scanner.py index c08b41d..1ea489d 100644 --- a/lib/core/virtual_host_scanner.py +++ b/lib/core/virtual_host_scanner.py @@ -147,7 +147,7 @@ def scan(self): # add url and hash into array for likely matches self.results.append(hostname + ',' + page_hash) - if len(self.hosts) == 2 and self.first_hit: + if len(self.hosts) >= 1 and self.first_hit: break # rate limit the connection, if the int is 0 it is ignored @@ -176,7 +176,7 @@ def likely_matches(self): lambda x: len(x) <= self.unique_depth ) - return matches + return segmented_data["key_col"].values.tolist() def create_host(self, response, hostname, page_hash): """