diff --git a/autorecon.py b/autorecon.py
index 05cd4c0..2e35c99 100644
--- a/autorecon.py
+++ b/autorecon.py
@@ -1297,26 +1297,28 @@ async def main():
keyboard_monitor.cancel()
- for plugin in autorecon.plugin_types['report']:
- plugin_tag_set = set(plugin.tags)
+ # If there's only one target we don't need a combined report
+ if len(autorecon.completed_targets) > 1:
+ for plugin in autorecon.plugin_types['report']:
+ plugin_tag_set = set(plugin.tags)
- matching_tags = False
- for tag_group in autorecon.tags:
- if set(tag_group).issubset(plugin_tag_set):
- matching_tags = True
- break
+ matching_tags = False
+ for tag_group in autorecon.tags:
+ if set(tag_group).issubset(plugin_tag_set):
+ matching_tags = True
+ break
- excluded_tags = False
- for tag_group in autorecon.excluded_tags:
- if set(tag_group).issubset(plugin_tag_set):
- excluded_tags = True
- break
+ excluded_tags = False
+ for tag_group in autorecon.excluded_tags:
+ if set(tag_group).issubset(plugin_tag_set):
+ excluded_tags = True
+ break
- if matching_tags and not excluded_tags:
- pending.add(asyncio.create_task(generate_report(plugin, autorecon.completed_targets)))
+ if matching_tags and not excluded_tags:
+ pending.add(asyncio.create_task(generate_report(plugin, autorecon.completed_targets)))
- while pending:
- done, pending = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED, timeout=1)
+ while pending:
+ done, pending = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED, timeout=1)
if timed_out:
cancel_all_tasks(None, None)
diff --git a/plugins/reporting.py b/plugins/reporting.py
index 8c3bfea..e5b87be 100644
--- a/plugins/reporting.py
+++ b/plugins/reporting.py
@@ -8,12 +8,13 @@ class CherryTree(Report):
def __init__(self):
super().__init__()
self.name = 'CherryTree'
+ self.tags = []
async def run(self, targets):
if len(targets) > 1:
- report = os.path.join(config['outdir'], 'cherrytree.xml.ctd')
+ report = os.path.join(config['outdir'], 'report.xml.ctd')
elif len(targets) == 1:
- report = os.path.join(targets[0].reportdir, 'cherrytree.xml.ctd')
+ report = os.path.join(targets[0].reportdir, 'report.xml.ctd')
else:
return
@@ -27,24 +28,9 @@ class CherryTree(Report):
if target.scans['ports']:
output.writelines('\n')
for scan in target.scans['ports'].keys():
- output.writelines('\n')
- for command in target.scans['ports'][scan]['commands']:
- output.writelines('' + escape(command[0]))
- for filename in files:
- if filename in command[0] or (command[1] is not None and filename == command[1]) or (command[2] is not None and filename == command[2]):
- output.writelines('\n\n' + escape(filename) + ':\n\n')
- with open(filename, 'r') as file:
- output.writelines(escape(file.read()) + '\n')
- output.writelines('\n')
- output.writelines('\n')
- output.writelines('\n')
- if target.scans['services']:
- output.writelines('\n')
- for service in target.scans['services'].keys():
- output.writelines('\n')
- for plugin in target.scans['services'][service].keys():
- output.writelines('\n')
- for command in target.scans['services'][service][plugin]['commands']:
+ if len(target.scans['ports'][scan]['commands']) > 0:
+ output.writelines('\n')
+ for command in target.scans['ports'][scan]['commands']:
output.writelines('' + escape(command[0]))
for filename in files:
if filename in command[0] or (command[1] is not None and filename == command[1]) or (command[2] is not None and filename == command[2]):
@@ -53,6 +39,23 @@ class CherryTree(Report):
output.writelines(escape(file.read()) + '\n')
output.writelines('\n')
output.writelines('\n')
+ output.writelines('\n')
+ if target.scans['services']:
+ output.writelines('\n')
+ for service in target.scans['services'].keys():
+ output.writelines('\n')
+ for plugin in target.scans['services'][service].keys():
+ if len(target.scans['services'][service][plugin]['commands']) > 0:
+ output.writelines('\n')
+ for command in target.scans['services'][service][plugin]['commands']:
+ output.writelines('' + escape(command[0]))
+ for filename in files:
+ if filename in command[0] or (command[1] is not None and filename == command[1]) or (command[2] is not None and filename == command[2]):
+ output.writelines('\n\n' + escape(filename) + ':\n\n')
+ with open(filename, 'r') as file:
+ output.writelines(escape(file.read()) + '\n')
+ output.writelines('\n')
+ output.writelines('\n')
output.writelines('\n')
output.writelines('\n')
@@ -86,3 +89,75 @@ class CherryTree(Report):
output.writelines('\n')
output.writelines('')
+
+class Markdown(Report):
+
+ def __init__(self):
+ super().__init__()
+ self.name = 'Markdown'
+
+ async def run(self, targets):
+ if len(targets) > 1:
+ report = os.path.join(config['outdir'], 'report.md')
+ elif len(targets) == 1:
+ report = os.path.join(targets[0].reportdir, 'report.md')
+ else:
+ return
+
+ os.makedirs(report, exist_ok=True)
+
+ for target in targets:
+ os.makedirs(os.path.join(report, target.address), exist_ok=True)
+
+ files = [os.path.abspath(filename) for filename in glob.iglob(os.path.join(target.scandir, '**/*'), recursive=True) if os.path.isfile(filename) and filename.endswith(('.txt', '.html'))]
+
+ if target.scans['ports']:
+ os.makedirs(os.path.join(report, target.address, 'Port Scans'), exist_ok=True)
+ for scan in target.scans['ports'].keys():
+ if len(target.scans['ports'][scan]['commands']) > 0:
+ with open(os.path.join(report, target.address, 'Port Scans', 'PortScan - ' + target.scans['ports'][scan]['plugin'].name + '.md'), 'w') as output:
+ for command in target.scans['ports'][scan]['commands']:
+ output.writelines('```bash\n' + command[0] + '\n```')
+ for filename in files:
+ if filename in command[0] or (command[1] is not None and filename == command[1]) or (command[2] is not None and filename == command[2]):
+ output.writelines('\n\n[' + filename + '](file://' + filename + '):\n\n')
+ with open(filename, 'r') as file:
+ output.writelines('```\n' + file.read() + '\n```\n')
+ if target.scans['services']:
+ os.makedirs(os.path.join(report, target.address, 'Services'), exist_ok=True)
+ for service in target.scans['services'].keys():
+ os.makedirs(os.path.join(report, target.address, 'Services', 'Service - ' + service.tag().replace('/', '-')), exist_ok=True)
+ for plugin in target.scans['services'][service].keys():
+ if len(target.scans['services'][service][plugin]['commands']) > 0:
+ with open(os.path.join(report, target.address, 'Services', 'Service - ' + service.tag().replace('/', '-'), target.scans['services'][service][plugin]['plugin'].name + '.md'), 'w') as output:
+ for command in target.scans['services'][service][plugin]['commands']:
+ output.writelines('```bash\n' + command[0] + '\n```')
+ for filename in files:
+ if filename in command[0] or (command[1] is not None and filename == command[1]) or (command[2] is not None and filename == command[2]):
+ output.writelines('\n\n[' + filename + '](file://' + filename + '):\n\n')
+ with open(filename, 'r') as file:
+ output.writelines('```\n' + file.read() + '\n```\n')
+
+ manual_commands = os.path.join(target.scandir, '_manual_commands.txt')
+ if os.path.isfile(manual_commands):
+ with open(os.path.join(report, target.address, 'Manual Commands' + '.md'), 'w') as output:
+ with open(manual_commands, 'r') as file:
+ output.writelines('```bash\n' + file.read() + '\n```')
+
+ patterns = os.path.join(target.scandir, '_patterns.log')
+ if os.path.isfile(patterns):
+ with open(os.path.join(report, target.address, 'Patterns' + '.md'), 'w') as output:
+ with open(patterns, 'r') as file:
+ output.writelines(file.read())
+
+ commands = os.path.join(target.scandir, '_commands.log')
+ if os.path.isfile(commands):
+ with open(os.path.join(report, target.address, 'Commands' + '.md'), 'w') as output:
+ with open(commands, 'r') as file:
+ output.writelines('```bash\n' + file.read() + '\n```')
+
+ errors = os.path.join(target.scandir, '_errors.log')
+ if os.path.isfile(errors):
+ with open(os.path.join(report, target.address, 'Errors' + '.md'), 'w') as output:
+ with open(errors, 'r') as file:
+ output.writelines('```\n' + file.read() + '\n```')