Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wordlist prefix suffix #80

Merged
merged 9 commits into from
Oct 23, 2017
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ $ pip install -r requirements.txt
| -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. |
| --prefix PREFIX | Add a prefix to each item in the wordlist, to add dev-\<word\>, test-\<word\> etc |
| --suffix SUFFIX | Add a suffix to each item in the wordlist, to add \<word\>dev, \<word\>dev |
| --first-hit | Return first successful result. Only use in scenarios where you are sure no catch-all is configured (such as a CTF). |
| --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. |
Expand All @@ -52,6 +54,7 @@ $ pip install -r requirements.txt
| -oN OUTPUT_NORMAL | Normal output printed to a file when the -oN option is specified with a filename argument. |
| -oG OUTPUT_GREPABLE | Grepable output printed to a file when the -oG 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. |
| -v VERBOSE | Increase the output of the tool to show progress |


## Usage Examples
Expand Down
8 changes: 7 additions & 1 deletion VHostScan.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def main():

wordlist_helper = WordList()
wordlist, wordlist_types = wordlist_helper.get_wordlist(
arguments.wordlists)
arguments.wordlists, arguments.prefix, arguments.suffix)

if len(wordlist) == 0:
print("[!] No words found in provided wordlists, unable to scan.")
Expand Down Expand Up @@ -82,11 +82,17 @@ def main():
wordlist.append(str(ip))
wordlist.append(host)
wordlist.extend(aliases)
if arguments.verbose:
print("[!] Discovered {host}/{ip}. Adding...".
format(ip=str(ip), host=host))
except (dns.resolver.NXDOMAIN):
print("[!] Couldn't find any records (NXDOMAIN)")
except (dns.resolver.NoAnswer):
print("[!] Couldn't find any records (NoAnswer)")

if arguments.verbose:
print("[>] Scanning with %s items in wordlist" % len(wordlist))

scanner_args = vars(arguments)
scanner_args.update({
'target': arguments.target_hosts,
Expand Down
2 changes: 1 addition & 1 deletion lib/core/__version__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
# |V|H|o|s|t|S|c|a|n| Developed by @codingo_ & @__timk
# +-+-+-+-+-+-+-+-+-+ https://github.com/codingo/VHostScan

__version__ = '1.7.1'
__version__ = '1.8'
4 changes: 4 additions & 0 deletions lib/core/virtual_host_scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def __init__(self, target, wordlist, **kwargs):
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.verbose = kwargs.get('verbose')

self.ignore_content_length = int(
kwargs.get('ignore_content_length', 0)
Expand Down Expand Up @@ -104,6 +105,9 @@ def scan(self):
for virtual_host in self.wordlist:
hostname = virtual_host.replace('%s', self.base_host)

if self.verbose:
print("[*] Scanning {hostname}".format(hostname=hostname))

if self.real_port == 80:
host_header = hostname
else:
Expand Down
46 changes: 45 additions & 1 deletion lib/helpers/wordlist_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ def get_stdin_wordlist(self):
return list(line for line in sys.stdin.read().splitlines()) \
if not sys.stdin.isatty() else []

def get_wordlist(self, wordlist_files=None):
def get_wordlist(self,
wordlist_files=None,
wordlist_prefix=False,
wordlist_suffix=False):

default_wordlist_file = DEFAULT_WORDLIST_FILE

stdin_words = self.get_stdin_wordlist()
Expand All @@ -29,13 +33,53 @@ def get_wordlist(self, wordlist_files=None):

combined_files = wordlist_files or default_wordlist_file
combined = get_combined_word_lists(combined_files)

if combined:
words_type = 'wordlists: {}'.format(
', '.join(combined['file_paths']))
self.set_words(words_type=words_type, words=combined['words'])

# Apply prefixes
if wordlist_prefix:
prefixed = []
for word in self.wordlist:
if(word == '%s'):
continue
elif(self.valid_ip(word)):
continue
else:
prefixed.append(wordlist_prefix + word)

if len(prefixed) > 0:
self.wordlist = self.wordlist + prefixed

if wordlist_suffix:
suffixed = []
for word in self.wordlist:
if(word == '%s'):
continue
elif(self.valid_ip(word)):
continue
elif(".%s" in word):
split = word.split(".")
suffixed.append(split[0] + wordlist_suffix + ".%s")
else:
suffixed.append(word + wordlist_suffix)

if len(suffixed) > 0:
self.wordlist = self.wordlist + suffixed

return self.wordlist, self.wordlist_types

def set_words(self, words_type, words):
self.wordlist_types.append(words_type)
self.wordlist.extend(words)

def valid_ip(self, address):
try:
host_bytes = address.split('.')
valid = [int(b) for b in host_bytes]
valid = [b for b in valid if b >= 0 and b <= 255]
return len(host_bytes) == 4 and len(valid) == 4
except:
return False
15 changes: 15 additions & 0 deletions lib/input.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ def setup_parser():
help='Set the port to use (default 80).'
)

parser.add_argument(
'--prefix', dest='prefix', default=False,
help='Add a prefix to each item in the word list (dev, test etc)'
)

parser.add_argument(
'--suffix', dest='suffix', default=False,
help='Add a suffix to each item in the word list'
)

parser.add_argument(
'-r', dest='real_port', type=int, default=False,
help='The real port of the webserver to use in headers when '
Expand Down Expand Up @@ -98,6 +108,11 @@ def setup_parser():
help='If set then simple WAF bypass headers will be sent.'
)

parser.add_argument(
'-v', dest='verbose', action='store_true', default=False,
help='Print verbose output'
)

output = parser.add_mutually_exclusive_group()
output.add_argument(
'-oN', dest='output_normal',
Expand Down
53 changes: 52 additions & 1 deletion tests/helpers/test_wordlist_helper.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import unittest
import pytest
from mock import patch
from unittest.mock import patch

from lib.helpers.wordlist_helper import WordList
from lib.helpers.wordlist_helper import DEFAULT_WORDLIST_FILE
Expand All @@ -18,6 +18,7 @@ def user_wordlist(request, tmpdir_factory):

@pytest.mark.usefixtures('user_wordlist')
class TestWordList(unittest.TestCase):

def setUp(self):
self.wordlist = WordList()
with open(DEFAULT_WORDLIST_FILE, 'r') as word_file:
Expand Down Expand Up @@ -45,3 +46,53 @@ def test_using_default_wordlist(self):
with patch('lib.helpers.wordlist_helper.WordList.get_stdin_wordlist', return_value=stdin_wordlist):
wordlist, wordlist_types = self.wordlist.get_wordlist()
self.assertEqual(wordlist, self.default_wordlist)

def test_ip_using_prefix(self):
stdin_wordlist = ['127.0.0.1']
prefix = 'dev-'
with patch('lib.helpers.wordlist_helper.WordList.get_stdin_wordlist', return_value=stdin_wordlist):
wordlist, wordlist_types = self.wordlist.get_wordlist(None, prefix)
self.assertEqual(wordlist, stdin_wordlist)

def test_ip_using_suffix(self):
stdin_wordlist = ['127.0.0.1']
suffix = 'test'
with patch('lib.helpers.wordlist_helper.WordList.get_stdin_wordlist', return_value=stdin_wordlist):
wordlist, wordlist_types = self.wordlist.get_wordlist(None,None,suffix)
self.assertEqual(wordlist,stdin_wordlist)

def test_word_with_prefix(self):
stdin_wordlist = ['www','www2','www3']
expected_wordlist = stdin_wordlist + ['dev-www','dev-www2','dev-www3']
prefix = 'dev-'
with patch('lib.helpers.wordlist_helper.WordList.get_stdin_wordlist', return_value=stdin_wordlist):
wordlist, wordlist_types = self.wordlist.get_wordlist(None,prefix)
self.assertEqual(wordlist,expected_wordlist)

def test_words_with_suffix(self):
stdin_wordlist = ['www','www2','www3']
expected_wordlist = stdin_wordlist + ['wwwtest','www2test','www3test']
suffix = 'test'
with patch('lib.helpers.wordlist_helper.WordList.get_stdin_wordlist', return_value=stdin_wordlist):
wordlist, wordlist_types = self.wordlist.get_wordlist(None,None,suffix)
self.assertEqual(wordlist, expected_wordlist)

def test_words_with_host_and_prefix(self):
stdin_wordlist = ['www.%s']
expected_wordlist = stdin_wordlist + ['test-www.%s']
prefix = 'test-'
with patch('lib.helpers.wordlist_helper.WordList.get_stdin_wordlist', return_value=stdin_wordlist):
wordlist, wordlist_types = self.wordlist.get_wordlist(None, prefix)
self.assertEqual(wordlist, expected_wordlist)

def test_words_with_host_and_suffix(self):
stdin_wordlist = ['www.%s']
expected_wordlist = stdin_wordlist + ['wwwtest.%s']
suffix = 'test'
with patch('lib.helpers.wordlist_helper.WordList.get_stdin_wordlist', return_value=stdin_wordlist):
wordlist, wordlist_types = self.wordlist.get_wordlist(None,None,suffix)
self.assertEqual(wordlist, expected_wordlist)




9 changes: 9 additions & 0 deletions tests/test_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ def test_parse_arguments_default_value(tmpdir):
'output_json': None,
'output_grepable' : None,
'ssl': False,
'prefix': False,
'suffix': False,
'verbose': False
}

assert vars(arguments) == expected_arguments
Expand Down Expand Up @@ -59,6 +62,9 @@ def test_parse_arguments_custom_arguments(tmpdir):
'--user-agent', 'some-user-agent',
'--waf',
'-oN', '/tmp/on',
'--prefix','dev-',
'--suffix','test',
'-v'
]

arguments = cli_argument_parser().parse(argv)
Expand All @@ -83,6 +89,9 @@ def test_parse_arguments_custom_arguments(tmpdir):
'output_normal': '/tmp/on',
'output_json': None,
'output_grepable' : None,
'prefix': 'dev-',
'suffix': 'test',
'verbose': True
}

assert vars(arguments) == expected_arguments
Expand Down