A virtual host scanner that can be used with pivot tools, detect catch-all scenarios, aliases and dynamic default pages. First presented at SecTalks BNE in September 2017 (slidedeck).
Key Benefits
- Quickly highlight unique content in catch-all scenarios
- Locate the outliers in catch-all scenarios where results have dynamic content on the page (such as the time)
- Identify aliases by tweaking the unique depth of matches
- Wordlist supports standard words and a variable to input a base hostname (for e.g. dev.%s from the wordlist would be run as dev.BASE_HOST)
- Work over HTTP and HTTPS
- Ability to set the real port of the webserver to use in headers when pivoting through ssh/nc
- Add simple response headers to bypass some WAF products
- Identify new targets by using reverse lookups and append to wordlist
Product Comparisons
Install Requirements
Using pip install via:
$ pip install -r requirements.txt
Usage
Argument | Description |
---|---|
-h, --help | Display help message and exit |
-t TARGET_HOSTS | Set the target host. |
-b BASE_HOST | Set host to be used during substitution in wordlist (default to TARGET). |
-w WORDLISTS | Set the wordlist(s) to use. You may specify multiple wordlists in comma delimited format (e.g. -w "./wordlists/simple.txt, ./wordlists/hackthebox.txt" (default ./wordlists/virtual-host-scanning.txt). |
-p PORT | Set the port to use (default 80). |
-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). |
--ignore-http-codes IGNORE_HTTP_CODES | Comma separated list of http codes to ignore with virtual host scans (default 404). |
--ignore-content-length IGNORE_CONTENT_LENGTH | Ignore content lengths of specificed amount. |
--unique-depth UNIQUE_DEPTH | Show likely matches of page content that is found x times (default 1). |
--ssl | If set then connections will be made over HTTPS instead of HTTP. |
--fuzzy-logic | If set then all unique content replies are compared and a similarity ratio is given for each pair. This helps to isolate vhosts in situations where a default page isn't static (such as having the time on it). |
--no-lookups | Disbale reverse lookups (identifies new targets and append to wordlist, on by default). |
--rate-limit | Amount of time in seconds to delay between each scan (default 0). |
--random-agent | If set, each scan will use a random user-agent from a predefined list. |
--user-agent | Specify a user agent to use for scans. |
--waf | If set then simple WAF bypass headers will be sent. |
-oN OUTPUT_NORMAL | Normal output printed to a file when the -oN option is specified with a filename argument. |
-oJ OUTPUT_JSON | JSON output printed to a file when the -oJ option is specified with a filename argument. |
- | By passing a blank '-' you tell VHostScan to expect input from stdin (pipe). |
Usage Examples
Note that a number of these examples reference 10.10.10.29. This IP refers to BANK.HTB, a retired target machine from HackTheBox (https://www.hackthebox.eu/).
Quick Example
The most straightforward example runs the default wordlist against example.com using the default of port 80:
$ VHostScan.py -t example.com
Port forwarding
Say you have an SSH port forward listening on port 4444 fowarding traffic to port 80 on example.com's development machine. You could use the following to make VHostScan connect through your SSH tunnel via localhost:4444 but format the header requests to suit connecting straight to port 80:
$ VHostScan.py -t localhost -b example.com -p 4444 -r 80
STDIN
If you want to pipe information into VHostScan you can use the
-
flag:$ cat bank.htb | VHostScan.py -t 10.10.10.29 -
You can still specify a wordlist to use along with stdin. In these cases wordlist information will be appended to stdin. For example:
$ echo -e 'a.example.com\b.example.com' | VhostScan.py -t localhost -w ./wordlists/wordlist.txt -
Fuzzy Logic
Here is an example with fuzzy logic enabled. You can see the last comparison is much more similar than the first two (it is comparing the content not the actual hashes):