Skip to content

Commit

Permalink
Merge pull request #80 from vortexau/wordlist-prefix-suffix
Browse files Browse the repository at this point in the history
Wordlist prefix suffix
  • Loading branch information
codingo authored Oct 23, 2017
2 parents 00d3b10 + e920824 commit b7565af
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 4 deletions.
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

0 comments on commit b7565af

Please sign in to comment.