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

Add scanning of multiple targets.(+ Minor improvements) #354

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
### 3.1.6
- Added scanning and brute-forcing of multiple targets
- Scanned targets now have a summary output
- Stop scanning if the "skip" parameter is provided

### 3.1.5
- Fix color bug that resulted in DOM XSS vulnerabilities not
being reported on certain systems (Windows, macOS, iOS)
Expand Down
8 changes: 8 additions & 0 deletions core/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,12 @@ def log_red_line(self, amount=60, level='INFO'):
_switch_to_default_loggers(self)


def log_yellow_summary_line(self, amount=60, level='INFO'):
_switch_to_no_format_loggers(self)
_get_level_and_log(self, f"{yellow}{'=' * amount}{end}", level)
_switch_to_default_loggers(self)


def log_no_format(self, msg='', level='INFO'):
_switch_to_no_format_loggers(self)
_get_level_and_log(self, msg, level)
Expand Down Expand Up @@ -187,6 +193,8 @@ def setup_logger(name='xsstrike'):

# Create logger method to only log a red line
logger.red_line = MethodType(log_red_line, logger)
# Create logger method to only log a yellow line
logger.yellow_summary_line = MethodType(log_yellow_summary_line, logger)
# Create logger method to log without format
logger.no_format = MethodType(log_no_format, logger)
# Create logger method to convert data to json and log with debug level
Expand Down
2 changes: 1 addition & 1 deletion modes/bruteforcer.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ def bruteforcer(target, paramData, payloadList, encoding, headers, delay, timeou
if encoding:
payload = encoding(payload)
if payload in response:
logger.info('%s %s' % (good, payload))
logger.good(payload)
progress += 1
logger.no_format('')
4 changes: 2 additions & 2 deletions modes/scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ def scan(target, paramData, encoding, headers, delay, timeout, skipDOM, skip):
if not skip:
choice = input(
'%s Would you like to continue scanning? [y/N] ' % que).lower()
if choice != 'y':
quit()
if skip or choice != 'y':
return target, loggerVector
elif bestEfficiency > minEfficiency:
logger.red_line()
logger.good('Payload: %s' % loggerVector)
Expand Down
33 changes: 27 additions & 6 deletions xsstrike.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

# Just a fancy ass banner
print('''%s
\tXSStrike %sv3.1.5
\tXSStrike %sv3.1.6
%s''' % (red, white, end))

try:
Expand Down Expand Up @@ -39,6 +39,7 @@
# Processing command line arguments, where dest var names will be mapped to local vars with the same name
parser = argparse.ArgumentParser()
parser.add_argument('-u', '--url', help='url', dest='target')
parser.add_argument('-ul', '--url_list', help='list of urls', dest='targets')
parser.add_argument('--data', help='post data', dest='paramData')
parser.add_argument('-e', '--encode', help='encode payloads', dest='encode')
parser.add_argument('--fuzzer', help='fuzzer',
Expand Down Expand Up @@ -85,6 +86,7 @@
# Pull all parameter values of dict from argparse namespace into local variables of name == key
# The following works, but the static checkers are too static ;-) locals().update(vars(args))
target = args.target
targets = args.targets
path = args.path
jsonData = args.jsonData
paramData = args.paramData
Expand Down Expand Up @@ -142,6 +144,12 @@
headers['Content-type'] = 'application/json'
paramData = converter(paramData)

target_list = []
if targets:
target_list = list(filter(None, reader(targets)))
elif target:
target_list.append(target)

if args_file:
if args_file == 'default':
payloadList = core.config.payloads
Expand All @@ -161,17 +169,30 @@
updater()
quit() # quitting because files have been changed

if not target and not args_seeds: # if the user hasn't supplied a url
if not target_list and not args_seeds: # if the user hasn't supplied a url
logger.no_format('\n' + parser.format_help().lower())
quit()

if fuzz:
singleFuzz(target, paramData, encoding, headers, delay, timeout)
elif not recursive and not args_seeds:
if args_file:
bruteforcer(target, paramData, payloadList, encoding, headers, delay, timeout)
else:
scan(target, paramData, encoding, headers, delay, timeout, skipDOM, skip)
results = []
for i, target in enumerate(target_list):
logger.red_line()
logger.info(f'Target: {target} ({i + 1}/{len(target_list)})')
if args_file:
bruteforcer(target, paramData, payloadList, encoding, headers, delay, timeout)
else:
result = scan(target, paramData, encoding, headers, delay, timeout, skipDOM, skip)
results.append(result) if result else 'The target is not vulnerable!'

if results:
logger.yellow_summary_line()
logger.run('SUMMARY')
logger.info(f'Total {len(target_list)} target{"s"[:len(target_list)^1]}')
logger.info(f'Vulnerable {len(results)} target{"s"[:len(results)^1]}')
for i, result in enumerate(results):
logger.good(f'Pwned {result[0]} ({result[1]})')
else:
if target:
seedList.append(target)
Expand Down