Skip to content

Commit 4e557c9

Browse files
authored
Merge pull request #10 from codingo/codingo-refactoring
Added SSL flag, refactored main class and removed redundant code blocks
2 parents 077eed4 + aca58e6 commit 4e557c9

File tree

3 files changed

+39
-40
lines changed

3 files changed

+39
-40
lines changed

CREDITS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# September 2017
2+
The original class for this project was taken from [Reconnoitre](https://github.com/codingo/Reconnoitre) which adapted virtual host discovery code from [teknogeek's virtual-host-scan](https://github.com/teknogeek/virtual-host-discovery-py).
3+
4+
This in turn was adapted from [jobertabma's virtual-host-discovery](https://github.com/jobertabma/virtual-host-discovery).

VHostScan.py

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,37 +9,43 @@
99
def print_banner():
1010
print("+-+-+-+-+-+-+-+-+-+ v. 0.1")
1111
print("|V|H|o|s|t|S|c|a|n| Developed by @codingo_ & @__timk")
12-
print("+-+-+-+-+-+-+-+-+-+ https://github.com/codingo/VHostScan")
12+
print("+-+-+-+-+-+-+-+-+-+ https://github.com/codingo/VHostScan\n")
1313

1414

1515
def main():
16+
print_banner()
1617
parser = ArgumentParser()
1718
parser.add_argument("-t", dest="target_hosts", required=True, help="Set a target range of addresses to target. Ex 10.11.1.1-255" )
18-
parser.add_argument("-o", dest="output_directory", required=True, help="Set the output directory. Ex /root/Documents/labs/")
19-
parser.add_argument("-w", dest="wordlist", required=False, help="Set the wordlist to use for generated commands. Ex /usr/share/wordlist.txt", default="./wordlists/virtual-host-scanning.txt")
20-
parser.add_argument("-p", dest="port", required=False, help="Set the port to use. Leave blank to use discovered ports. Useful to force virtual host scanning on non-standard webserver ports (default 80).", default=80)
19+
parser.add_argument("-w", dest="wordlist", required=False, type=str, help="Set the wordlist to use for generated commands. Ex /usr/share/wordlist.txt", default="./wordlists/virtual-host-scanning.txt")
20+
parser.add_argument("-p", dest="port", required=False, help="Set the port to use (default 80).", default=80)
2121

2222
parser.add_argument('--ignore-http-codes', dest='ignore_http_codes', type=str, help='Comma separated list of http codes to ignore with virtual host scans (default 404).', default='404')
23-
parser.add_argument('--ignore-content-length', dest='ignore_content_length', type=int, help='Ignore content lengths of specificed amount. This may become useful when a server returns a static page on every virtual host guess.', default=0)
23+
parser.add_argument('--ignore-content-length', dest='ignore_content_length', type=int, help='Ignore content lengths of specificed amount.', default=0)
2424
parser.add_argument('--unique-depth', dest='unique_depth', type=int, help='Show likely matches of page content that is found x times (default 1).', default=1)
25+
parser.add_argument("--ssl", dest="ssl", action="store_true", help="If set then connections will be made over HTTPS instead of HTTP.", default=False)
2526
arguments = parser.parse_args()
2627

27-
if len(sys.argv) == 1:
28-
print_banner()
29-
parser.error("No arguments given.")
30-
parser.print_usage
28+
if not os.path.exists(arguments.wordlist):
29+
print("[!] Wordlist %s doesn't exist, ending scan." % arguments.wordlistt)
3130
sys.exit()
3231

33-
if arguments.output_directory.endswith('/' or '\\'):
34-
arguments.output_directory = arguments.output_directory[:-1]
35-
if arguments.target_hosts.endswith('/' or '\\'):
36-
arguments.target_hosts = arguments.target_hosts[:-1]
32+
print("[+] Starting virtual host scan for %s using port %s and wordlist %s" % (arguments.target_hosts, str(arguments.port), arguments.wordlist))
33+
34+
if(arguments.ssl):
35+
print("[>] SSL flag set, sending all results over HTTPS")
3736

38-
print_banner()
37+
print("[>] Ignoring HTTP codes: %s" % (arguments.ignore_http_codes))
38+
39+
if(arguments.ignore_content_length > 0):
40+
print("[>] Ignoring Content length: %s" % (arguments.ignore_content_length))
3941

40-
scanner = virtual_host_scanner(arguments.target_hosts, arguments.output_directory, arguments.port, arguments.unique_depth, arguments.ignore_http_codes, arguments.ignore_content_length, arguments.wordlist)
42+
scanner = virtual_host_scanner(arguments.target_hosts, arguments.port, arguments.ssl, arguments.unique_depth,
43+
arguments.ignore_http_codes, arguments.ignore_content_length, arguments.wordlist)
44+
4145
scanner.scan()
42-
print(scanner.likely_matches())
46+
47+
print("\n[+] Most likely matches with a unique count of %s or less:" % arguments.unique_depth)
48+
for p in scanner.likely_matches(): print(" [>] %s" % p)
4349

4450
if __name__ == "__main__":
4551
main()

lib/core/virtual_host_scanner.py

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,21 @@ class virtual_host_scanner(object):
1717
output: folder to write output file to
1818
"""
1919

20-
def __init__(self, target, output, port=80, unique_depth=1, ignore_http_codes='404', ignore_content_length=0,
20+
def __init__(self, target, port=80, ssl=False, unique_depth=1, ignore_http_codes='404', ignore_content_length=0,
2121
wordlist="./wordlists/virtual-host-scanning.txt"):
2222
self.target = target
23-
self.output = output + '/' + target + '_virtualhosts.txt'
2423
self.port = port
2524
self.ignore_http_codes = list(map(int, ignore_http_codes.replace(' ', '').split(',')))
2625
self.ignore_content_length = ignore_content_length
2726
self.wordlist = wordlist
2827
self.unique_depth = unique_depth
29-
28+
self.ssl = ssl
29+
3030
self.completed_scan=False
3131
self.results = []
3232

33+
3334
def scan(self):
34-
print("[+] Starting virtual host scan for %s using port %s and wordlist %s" % (self.target, str(self.port), self.wordlist))
35-
print("[>] Ignoring HTTP codes: %s" % (self.ignore_http_codes))
36-
if(self.ignore_content_length > 0):
37-
print("[>] Ignoring Content length: %s" % (self.ignore_content_length))
38-
39-
if not os.path.exists(self.wordlist):
40-
print("[!] Wordlist %s doesn't exist, ending scan." % self.wordlist)
41-
return
42-
4335
virtual_host_list = open(self.wordlist).read().splitlines()
4436

4537
for virtual_host in virtual_host_list:
@@ -50,8 +42,7 @@ def scan(self):
5042
'Accept': '*/*'
5143
}
5244

53-
# todo: to be made redundant/replaced with a --ssl flag? Current implementation limits ssl severely
54-
dest_url = '{}://{}:{}/'.format('https' if int(self.port) == 443 else 'http', self.target, self.port)
45+
dest_url = '{}://{}:{}/'.format('https' if self.ssl else 'http', self.target, self.port)
5546

5647
try:
5748
res = requests.get(dest_url, headers=headers, verify=False)
@@ -83,19 +74,17 @@ def scan(self):
8374

8475
def likely_matches(self):
8576
if self.completed_scan is False:
86-
print("Likely matches cannot be printed as a scan has not yet been run.")
77+
print("[!] Likely matches cannot be printed as a scan has not yet been run.")
8778
return
8879

89-
print("\n[#] Most likely matches with a unique count of %s or less:" % self.unique_depth)
90-
91-
d={}
92-
80+
# segment results from previous scan into usable results
81+
segmented_data={}
9382
for item in self.results:
94-
r=item.split(",")
95-
d[r[0]]=r[1]
83+
result = item.split(",")
84+
segmented_data[result[0]] = result[1]
9685

97-
df= pd.DataFrame([[key, value] for key, value in d.items()], columns=["key_col", "val_col"])
98-
d=df.groupby("val_col").filter(lambda x: len(x) <= self.unique_depth)
99-
matches=((d["key_col"].values).tolist())
86+
dataframe = pd.DataFrame([[key, value] for key, value in segmented_data.items()], columns=["key_col", "val_col"])
87+
segmented_data = dataframe.groupby("val_col").filter(lambda x: len(x) <= self.unique_depth)
88+
matches = ((segmented_data["key_col"].values).tolist())
10089

10190
return matches

0 commit comments

Comments
 (0)