From 99532a1a9189dd3e9bfb8a1a665b2660abcb523c Mon Sep 17 00:00:00 2001 From: svo80 Date: Mon, 29 Apr 2019 01:23:41 +0200 Subject: [PATCH] Provide support for creating elementary summary reports in PDF format (requires enscript). --- README.md | 10 ++++++---- autorecon.py | 42 ++++++++++++++++++++++++++++++++++++------ config/config.toml | 4 ++++ 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 15dea42..cecc5dd 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,11 @@ AutoRecon was inspired by three tools which the author used during the OSCP labs ## Requirements * Python 3 +* enscript * colorama * toml -Once Python 3 is installed, pip3 can be used to install the other requirements: +Once Python 3 and enscript are installed, pip3 can be used to install the other requirements: ```bash $ pip3 install -r requirements.txt @@ -461,14 +462,15 @@ In fact, enum4linux will always try these ports when it is run. So if the SMB se With the help of the --run-level parameter, the user has the possibility of better balancing required scanning time and scanning depth. Programs that require a longer runtime can also be run individually by making use of the --run-only parameter. Thereby, the user may run a quick scan first, followed by a more in-depth scan, e.g., +``` # run any extended service enumeration program with a complexity level of 2 or lower -python3 autorecon.py 127.0.0.1 --run-level 2 +$ python3 autorecon.py 127.0.0.1 --run-level 2 # only run programs with a complexity level of 3 -python3 autorecon.py 127.0.0.1 --run-level 3 --run-only +$ python3 autorecon.py 127.0.0.1 --run-level 3 --run-only The user may also skip extended service scanning entirely by specifying the --skip-service-scan parameter. In this case, respective commands will be only documented but not executed, giving the tester a good check list for later service analysis and planning the attack more carefully. - +``` ## Testimonials diff --git a/autorecon.py b/autorecon.py index d67ce1f..bc37047 100644 --- a/autorecon.py +++ b/autorecon.py @@ -19,6 +19,7 @@ import string from datetime import datetime import sys import toml +import glob __version__ = '0.1.1' @@ -39,9 +40,10 @@ applications = {} files = { 'commands' : '_commands.log', 'manual_commands' : '_manual_commands.log', - 'patterns' : '_patterns.log', - 'notes' : '_notes.txt', 'errors' : '_errors.log', + 'notes' : '_notes.txt', + 'patterns' : '_patterns.txt', + 'report' : 'report.pdf', } username_wordlist = '/usr/share/seclists/Usernames/top-usernames-shortlist.txt' @@ -141,7 +143,6 @@ def read_configuration_file(filename, replace_values = {}): return data - def get_configuration(): applications_config = read_configuration_file('config.toml') if len(applications_config) > 0 and 'applications' in applications_config: @@ -179,7 +180,6 @@ def get_configuration(): return True - async def read_stream(stream, target, tag='?', patterns=[], color=Fore.BLUE): address = target.address while True: @@ -274,7 +274,6 @@ async def parse_port_scan(stream, tag, target, pattern): if parse_match: ports.append(parse_match.group('port')) - for p in global_patterns: matches = re.findall(p['pattern'], line) if 'description' in p: @@ -428,7 +427,7 @@ async def scan_services(loop, semaphore, target): while True: if not pending: break - + done, pending = await asyncio.wait(pending, return_when=FIRST_COMPLETED) for task in done: @@ -580,6 +579,9 @@ async def scan_services(loop, semaphore, target): pending.add(asyncio.ensure_future(run_cmd(semaphore, e(command), target, category=category, tag=tag, patterns=patterns))) +# if not args.no_report: +# pending.add(asyncio.ensure_future(create_report(semaphore, target))) + def scan_host(target, concurrent_scans): info('Scanning target {byellow}{target.address}{rst}.') @@ -625,9 +627,36 @@ def scan_host(target, concurrent_scans): try: loop.run_until_complete(scan_services(loop, semaphore, target)) info('Finished scanning target {byellow}{target.address}{rst}.') + + if not args.no_report: + loop.run_until_complete(create_report(target)) except KeyboardInterrupt: sys.exit(1) +async def create_report(target): + address = target.address + scandir = target.scandir + reportdir = target.reportdir + + #types = ('*.txt') + #filenames = [] + #[filenames.extend(glob.glob(os.path.join(scandir, '*', filetype), recursive=True)) for filetype in types] + filenames = glob.glob(os.path.join(scandir, '**', '*.txt'), recursive=True) + filenames.sort() + report_order = ' '.join(filenames) + + # TODO: make us of config file + cmd = '/usr/bin/enscript {0} -o - | /usr/bin/ps2pdf - {1}'.format(report_order, os.path.join(reportdir, files['report'])) + + info('Creating report for target {byellow}{address}{rst}.') + process = await asyncio.create_subprocess_shell(cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, executable='/bin/bash') + await process.communicate() + + if process.returncode != 0: + error('{bred}Report creation{rst} for target {byellow}{address}{rst} returned non-zero exit code: {process.returncode}.') + else: + info('Report for target {byellow}{address}{rst} was created successfully.') + def prepare_log_files(scandir, target): for filename in files: @@ -733,6 +762,7 @@ if __name__ == '__main__': parser.add_argument('--run-level', action='store', type=int, default=[0], nargs="+", help='During extended service scanning, only run scanners of a certain complexity level or below.') parser.add_argument('--run-only', action='store_true', default=False, help='If enabled, only run scanners of the specified complexity level during extended service scanning.') parser.add_argument('-r', '--read', action='store', type=str, default='', dest='target_file', help='Read targets from file.') + parser.add_argument('--no-report', action='store_true', default=False, help='Do not create a summary report after completing scanning a target.') parser.add_argument('-v', '--verbose', action='count', default=0, help='Enable verbose output. Repeat for more verbosity.') parser.add_argument('--disable-sanity-checks', action='store_true', default=False, help='Disable sanity checks that would otherwise prevent the scans from running.') parser.error = lambda s: fail(s[0].upper() + s[1:]) diff --git a/config/config.toml b/config/config.toml index 58fb468..d106212 100644 --- a/config/config.toml +++ b/config/config.toml @@ -6,6 +6,10 @@ # system programs tee = '/usr/bin/tee' + # not installed on Kali by default + # install with (sudo) apt-get install enscript + enscript = '/usr/bin/enscript' + # password brute-forcing programs hydra = '/usr/bin/hydra' medusa = '/usr/bin/medusa'