Skip to content

Commit ebd52de

Browse files
authored
Merge branch 'master' into codingo-refactoring
2 parents 23bf6f8 + f7c8611 commit ebd52de

File tree

3 files changed

+33
-10
lines changed

3 files changed

+33
-10
lines changed

README.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
# VHostScan
22
A virtual host scanner that detects catch-all scenarios and attempts to work around dynamic default pages
33

4-
# Credit / Origins
4+
[![Python 3.2|3.6](https://img.shields.io/badge/python-3.2|3.6-green.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPL3-_red.svg)](https://www.gnu.org/licenses/gpl-3.0.en.html) [![Twitter](https://img.shields.io/badge/twitter-@____timk-blue.svg)](https://twitter.com/__timk) [![Twitter](https://img.shields.io/badge/twitter-@codingo__-blue.svg)](https://twitter.com/codingo_)
55

6-
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).
6+
## Usage
7+
8+
| Argument | Description |
9+
| ------------- |:-------------|
10+
| -h, --help | Display help message and exit |
11+
| -t TARGET_HOSTS | Set the target host. |
12+
| -b BASE_HOST | Set host to be used during substitution in wordlist (default to TARGET).|
13+
| -w WORDLIST | Set the wordlist to use for generated commands. Ex /usr/share/wordlist.txt |
14+
| -p PORT | Set the port to use (default 80). |
15+
| -r REAL_PORT | 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). |
16+
| --ignore-http-codes IGNORE_HTTP_CODES | Comma separated list of http codes to ignore with virtual host scans (default 404). |
17+
| --ignore-content-length IGNORE_CONTENT_LENGTH | Ignore content lengths of specificed amount. |
18+
| --unique-depth UNIQUE_DEPTH | Show likely matches of page content that is found x times (default 1). |
19+
| --ssl | If set then connections will be made over HTTPS instead of HTTP. |

VHostScan.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88

99
def print_banner():
10-
print("+-+-+-+-+-+-+-+-+-+ v. 0.1")
10+
print("+-+-+-+-+-+-+-+-+-+ v. 0.2")
1111
print("|V|H|o|s|t|S|c|a|n| Developed by @codingo_ & @__timk")
1212
print("+-+-+-+-+-+-+-+-+-+ https://github.com/codingo/VHostScan\n")
1313

@@ -17,7 +17,9 @@ def main():
1717
parser = ArgumentParser()
1818
parser.add_argument("-t", dest="target_hosts", required=True, help="Set a target range of addresses to target. Ex 10.11.1.1-255" )
1919
parser.add_argument("-w", dest="wordlist", required=False, type=str, help="Set the wordlist to use (default ./wordlists/virtual-host-scanning.txt)", default="./wordlists/virtual-host-scanning.txt")
20+
parser.add_argument("-b", dest="base_host", required=False, help="Set host to be used during substitution in wordlist (default to TARGET).", default=False)
2021
parser.add_argument("-p", dest="port", required=False, help="Set the port to use (default 80).", default=80)
22+
parser.add_argument("-r", dest="real_port", required=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).", default=False)
2123

2224
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')
2325
parser.add_argument('--ignore-content-length', dest='ignore_content_length', type=int, help='Ignore content lengths of specificed amount (default 0).', default=0)
@@ -41,7 +43,7 @@ def main():
4143
if(arguments.ignore_content_length > 0):
4244
print("[>] Ignoring Content length: %s" % (arguments.ignore_content_length))
4345

44-
scanner = virtual_host_scanner(arguments.target_hosts, arguments.port, arguments.ssl, arguments.unique_depth,
46+
scanner = virtual_host_scanner(arguments.target_hosts, arguments.base_host, arguments.port, arguments.real_port, arguments.ssl, arguments.unique_depth,
4547
arguments.ignore_http_codes, arguments.ignore_content_length, arguments.wordlist)
4648

4749
scanner.scan()
@@ -50,4 +52,4 @@ def main():
5052
for p in scanner.likely_matches(): print(" [>] %s" % p)
5153

5254
if __name__ == "__main__":
53-
main()
55+
main()

lib/core/virtual_host_scanner.py

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

20-
def __init__(self, target, port=80, ssl=False, unique_depth=1, ignore_http_codes='404', ignore_content_length=0,
20+
def __init__(self, target, base_host, port=80, real_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.port = port
23+
self.base_host = base_host
24+
self.port = int(port)
25+
self.real_port = int(real_port)
2426
self.ignore_http_codes = list(map(int, ignore_http_codes.replace(' ', '').split(',')))
2527
self.ignore_content_length = ignore_content_length
2628
self.wordlist = wordlist
@@ -34,11 +36,17 @@ def __init__(self, target, port=80, ssl=False, unique_depth=1, ignore_http_codes
3436
def scan(self):
3537
virtual_host_list = open(self.wordlist).read().splitlines()
3638

39+
if not self.base_host:
40+
self.base_host = self.target
41+
42+
if not self.real_port:
43+
self.real_port = self.port
44+
3745
for virtual_host in virtual_host_list:
38-
hostname = virtual_host.replace('%s', self.target)
46+
hostname = virtual_host.replace('%s', self.base_host)
3947

4048
headers = {
41-
'Host': hostname if self.port == 80 else '{}:{}'.format(hostname, self.port),
49+
'Host': hostname if self.real_port == 80 else '{}:{}'.format(hostname, self.real_port),
4250
'Accept': '*/*'
4351
}
4452

@@ -87,4 +95,4 @@ def likely_matches(self):
8795
segmented_data = dataframe.groupby("val_col").filter(lambda x: len(x) <= self.unique_depth)
8896
matches = ((segmented_data["key_col"].values).tolist())
8997

90-
return matches
98+
return matches

0 commit comments

Comments
 (0)