Plugin updates, bug fix, and feature update.
A few manual plugin updates (command formatting etc.) Fixed bug where processes were left running after AutoRecon is cancelled and/or times out. Status messages now include PIDs of running processes if verbosity >= 2. Closes #183 Fixes #184
This commit is contained in:
		
							parent
							
								
									65fc104b2d
								
							
						
					
					
						commit
						851ffbd316
					
				|  | @ -0,0 +1,17 @@ | ||||||
|  | from autorecon.plugins import ServiceScan | ||||||
|  | 
 | ||||||
|  | class BruteforceSMB(ServiceScan): | ||||||
|  | 
 | ||||||
|  | 	def __init__(self): | ||||||
|  | 		super().__init__() | ||||||
|  | 		self.name = 'Bruteforce SMB' | ||||||
|  | 		self.tags = ['default', 'safe', 'active-directory'] | ||||||
|  | 
 | ||||||
|  | 	def configure(self): | ||||||
|  | 		self.match_service('tcp', 445, '^microsoft\-ds') | ||||||
|  | 		self.match_service('tcp', 139, '^netbios') | ||||||
|  | 
 | ||||||
|  | 	def manual(self, service, plugin_was_run): | ||||||
|  | 		service.add_manual_command('Bruteforce SMB', [ | ||||||
|  | 			'crackmapexec smb {address} --port={port} -u "' + self.get_global('username_wordlist', default='/usr/share/seclists/Usernames/top-usernames-shortlist.txt') + '" -p "' + self.get_global('password_wordlist', default='/usr/share/seclists/Passwords/darkweb2017-top100.txt') + '"' | ||||||
|  | 		]) | ||||||
|  | @ -12,5 +12,5 @@ class LookupSID(ServiceScan): | ||||||
| 
 | 
 | ||||||
| 	def manual(self, service, plugin_was_run): | 	def manual(self, service, plugin_was_run): | ||||||
| 		service.add_manual_command('Lookup SIDs', [ | 		service.add_manual_command('Lookup SIDs', [ | ||||||
| 			'lookupsid.py [username]:[password]@{address}' | 			'impacket-lookupsid \'[username]:[password]@{address}\'' | ||||||
| 		]) | 		]) | ||||||
|  |  | ||||||
|  | @ -19,14 +19,14 @@ class WinRMDetection(ServiceScan): | ||||||
| 
 | 
 | ||||||
| 	def manual(self, service, plugin_was_run): | 	def manual(self, service, plugin_was_run): | ||||||
| 		service.add_manual_commands('Bruteforce logins:', [ | 		service.add_manual_commands('Bruteforce logins:', [ | ||||||
| 			'crackmapexec winrm {address} -d ' + self.get_global('domain', default='<domain>') + ' -u ' + self.get_global('username_wordlist', default='/usr/share/seclists/Usernames/top-usernames-shortlist.txt') + ' -p ' + self.get_global('password_wordlist', default='/usr/share/seclists/Passwords/darkweb2017-top100.txt') | 			'crackmapexec winrm {address} -d \'' + self.get_global('domain', default='<domain>') + '\' -u \'' + self.get_global('username_wordlist', default='/usr/share/seclists/Usernames/top-usernames-shortlist.txt') + '\' -p \'' + self.get_global('password_wordlist', default='/usr/share/seclists/Passwords/darkweb2017-top100.txt') + '\'' | ||||||
| 		]) | 		]) | ||||||
| 
 | 
 | ||||||
| 		service.add_manual_commands('Check login (requires credentials):', [ | 		service.add_manual_commands('Check login (requires credentials):', [ | ||||||
| 			'crackmapexec winrm {address} -d ' + self.get_global('domain', default='<domain>') + ' -u <username> -p <password> -x "whoami"' | 			'crackmapexec winrm {address} -d \'' + self.get_global('domain', default='<domain>') + '\' -u \'<username>\' -p \'<password>\'' | ||||||
| 		]) | 		]) | ||||||
| 
 | 
 | ||||||
| 		service.add_manual_commands('Evil WinRM (gem install evil-winrm):', [ | 		service.add_manual_commands('Evil WinRM (gem install evil-winrm):', [ | ||||||
| 			'evil-winrm -u <user> -p <password> -i {address}', | 			'evil-winrm -u \'<user>\' -p \'<password>\' -i {address}', | ||||||
| 			'evil-winrm -u <user> -H <hash> -i {address}' | 			'evil-winrm -u \'<user>\' -H \'<hash>\' -i {address}' | ||||||
| 		]) | 		]) | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ import argparse, asyncio, importlib.util, inspect, ipaddress, math, os, re, sele | ||||||
| from datetime import datetime | from datetime import datetime | ||||||
| 
 | 
 | ||||||
| try: | try: | ||||||
| 	import appdirs, colorama, impacket, requests, toml, unidecode | 	import appdirs, colorama, impacket, psutil, requests, toml, unidecode | ||||||
| 	from colorama import Fore, Style | 	from colorama import Fore, Style | ||||||
| except ModuleNotFoundError: | except ModuleNotFoundError: | ||||||
| 	print('One or more required modules was not installed. Please run or re-run: ' + ('sudo ' if os.getuid() == 0 else '') + 'python3 -m pip install -r requirements.txt') | 	print('One or more required modules was not installed. Please run or re-run: ' + ('sudo ' if os.getuid() == 0 else '') + 'python3 -m pip install -r requirements.txt') | ||||||
|  | @ -17,7 +17,7 @@ from autorecon.io import slugify, e, fformat, cprint, debug, info, warn, error, | ||||||
| from autorecon.plugins import Pattern, PortScan, ServiceScan, Report, AutoRecon | from autorecon.plugins import Pattern, PortScan, ServiceScan, Report, AutoRecon | ||||||
| from autorecon.targets import Target, Service | from autorecon.targets import Target, Service | ||||||
| 
 | 
 | ||||||
| VERSION = "2.0.30" | VERSION = "2.0.31" | ||||||
| 
 | 
 | ||||||
| if not os.path.exists(config['config_dir']): | if not os.path.exists(config['config_dir']): | ||||||
| 	shutil.rmtree(config['config_dir'], ignore_errors=True, onerror=None) | 	shutil.rmtree(config['config_dir'], ignore_errors=True, onerror=None) | ||||||
|  | @ -92,18 +92,36 @@ def calculate_elapsed_time(start_time, short=False): | ||||||
| 	else: | 	else: | ||||||
| 		return ', '.join(elapsed_time) | 		return ', '.join(elapsed_time) | ||||||
| 
 | 
 | ||||||
| def cancel_all_tasks(signal, frame): | # sig and frame args are only present so the function | ||||||
|  | # works with signal.signal() and handles Ctrl-C. | ||||||
|  | # They are not used for any other purpose. | ||||||
|  | def cancel_all_tasks(sig, frame): | ||||||
| 	for task in asyncio.all_tasks(): | 	for task in asyncio.all_tasks(): | ||||||
| 		task.cancel() | 		task.cancel() | ||||||
| 
 | 
 | ||||||
|  | 	processes = [] | ||||||
|  | 
 | ||||||
| 	for target in autorecon.scanning_targets: | 	for target in autorecon.scanning_targets: | ||||||
| 		for process_list in target.running_tasks.values(): | 		for process_list in target.running_tasks.values(): | ||||||
| 			for process_dict in process_list['processes']: | 			for process_dict in process_list['processes']: | ||||||
| 				try: | 				try: | ||||||
| 					process_dict['process'].kill() | 					parent = psutil.Process(process_dict['process'].pid) | ||||||
| 				except ProcessLookupError: # Will get raised if the process finishes before we get to killing it. | 					processes.extend(parent.children(recursive=True)) | ||||||
|  | 					processes.append(parent) | ||||||
|  | 				except psutil.NoSuchProcess: | ||||||
| 					pass | 					pass | ||||||
| 	 | 	 | ||||||
|  | 	for process in processes: | ||||||
|  | 		try: | ||||||
|  | 			process.send_signal(signal.SIGKILL) | ||||||
|  | 		except psutil.NoSuchProcess: # Will get raised if the process finishes before we get to killing it. | ||||||
|  | 			pass | ||||||
|  | 					 | ||||||
|  | 	_, alive = psutil.wait_procs(processes, timeout=10) | ||||||
|  | 	if len(alive) > 0: | ||||||
|  | 		error('The following process IDs could not be killed: ' + ', '.join([str(x.pid) for x in sorted(alive, key=lambda x: x.pid)])) | ||||||
|  | 				 | ||||||
|  | 
 | ||||||
| 	if not config['disable_keyboard_control']: | 	if not config['disable_keyboard_control']: | ||||||
| 		# Restore original terminal settings. | 		# Restore original terminal settings. | ||||||
| 		termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, terminal_settings) | 		termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, terminal_settings) | ||||||
|  | @ -114,9 +132,28 @@ async def start_heartbeat(target, period=60): | ||||||
| 		async with target.lock: | 		async with target.lock: | ||||||
| 			count = len(target.running_tasks) | 			count = len(target.running_tasks) | ||||||
| 
 | 
 | ||||||
| 			tasks_list = '' | 			tasks_list = [] | ||||||
| 			if config['verbose'] >= 1: | 			if config['verbose'] >= 1: | ||||||
| 				tasks_list = ': {bblue}' + ', '.join(target.running_tasks.keys()) + '{rst}' | 				for tag, task in target.running_tasks.items(): | ||||||
|  | 					task_str = tag | ||||||
|  | 
 | ||||||
|  | 					if config['verbose'] >= 2: | ||||||
|  | 						processes = [] | ||||||
|  | 						for process_dict in task['processes']: | ||||||
|  | 							if process_dict['process'].returncode is None: | ||||||
|  | 								processes.append(str(process_dict['process'].pid)) | ||||||
|  | 								try: | ||||||
|  | 									for child in psutil.Process(process_dict['process'].pid).children(recursive=True): | ||||||
|  | 										processes.append(str(child.pid)) | ||||||
|  | 								except psutil.NoSuchProcess: | ||||||
|  | 									pass | ||||||
|  | 						 | ||||||
|  | 						if processes: | ||||||
|  | 							task_str += ' (PID' + ('s' if len(processes) > 1 else '') + ': ' + ', '.join(processes) + ')' | ||||||
|  | 						 | ||||||
|  | 					tasks_list.append(task_str) | ||||||
|  | 
 | ||||||
|  | 				tasks_list = ': {bblue}' + ', '.join(tasks_list) + '{rst}' | ||||||
| 
 | 
 | ||||||
| 			current_time = datetime.now().strftime('%H:%M:%S') | 			current_time = datetime.now().strftime('%H:%M:%S') | ||||||
| 
 | 
 | ||||||
|  | @ -153,13 +190,31 @@ async def keyboard(): | ||||||
| 				if len(input) > 0 and input[0] == 's': | 				if len(input) > 0 and input[0] == 's': | ||||||
| 					input = input[1:] | 					input = input[1:] | ||||||
| 					for target in autorecon.scanning_targets: | 					for target in autorecon.scanning_targets: | ||||||
|  | 						async with target.lock: | ||||||
| 							count = len(target.running_tasks) | 							count = len(target.running_tasks) | ||||||
| 
 | 
 | ||||||
| 							tasks_list = [] | 							tasks_list = [] | ||||||
| 							if config['verbose'] >= 1: | 							if config['verbose'] >= 1: | ||||||
| 							for key, value in target.running_tasks.items(): | 								for tag, task in target.running_tasks.items(): | ||||||
| 								elapsed_time = calculate_elapsed_time(value['start'], short=True) | 									elapsed_time = calculate_elapsed_time(task['start'], short=True) | ||||||
| 								tasks_list.append('{bblue}' + key + '{rst}' + ' (elapsed: ' + elapsed_time + ')') | 
 | ||||||
|  | 									task_str = '{bblue}' + tag + '{rst}' + ' (elapsed: ' + elapsed_time + ')' | ||||||
|  | 
 | ||||||
|  | 									if config['verbose'] >= 2: | ||||||
|  | 										processes = [] | ||||||
|  | 										for process_dict in task['processes']: | ||||||
|  | 											if process_dict['process'].returncode is None: | ||||||
|  | 												processes.append(str(process_dict['process'].pid)) | ||||||
|  | 												try: | ||||||
|  | 													for child in psutil.Process(process_dict['process'].pid).children(recursive=True): | ||||||
|  | 														processes.append(str(child.pid)) | ||||||
|  | 												except psutil.NoSuchProcess: | ||||||
|  | 													pass | ||||||
|  | 										 | ||||||
|  | 										if processes: | ||||||
|  | 											task_str += ' (PID' + ('s' if len(processes) > 1 else '') + ': ' + ', '.join(processes) + ')' | ||||||
|  | 									 | ||||||
|  | 									tasks_list.append(task_str) | ||||||
| 
 | 
 | ||||||
| 								tasks_list = ':\n    ' + '\n    '.join(tasks_list) | 								tasks_list = ':\n    ' + '\n    '.join(tasks_list) | ||||||
| 							else: | 							else: | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| [tool.poetry] | [tool.poetry] | ||||||
| name = "autorecon" | name = "autorecon" | ||||||
| version = "2.0.30" | version = "2.0.31" | ||||||
| description = "A multi-threaded network reconnaissance tool which performs automated enumeration of services." | description = "A multi-threaded network reconnaissance tool which performs automated enumeration of services." | ||||||
| authors = ["Tib3rius"] | authors = ["Tib3rius"] | ||||||
| license = "GNU GPL v3" | license = "GNU GPL v3" | ||||||
|  | @ -14,6 +14,7 @@ python = "^3.8" | ||||||
| appdirs = "^1.4.4" | appdirs = "^1.4.4" | ||||||
| colorama = "^0.4.5" | colorama = "^0.4.5" | ||||||
| impacket = "^0.10.0" | impacket = "^0.10.0" | ||||||
|  | psutil = "^5.9.4" | ||||||
| requests = "^2.28.1" | requests = "^2.28.1" | ||||||
| toml = "^0.10.2" | toml = "^0.10.2" | ||||||
| Unidecode = "^1.3.1" | Unidecode = "^1.3.1" | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| appdirs | appdirs | ||||||
| colorama | colorama | ||||||
| impacket | impacket | ||||||
|  | psutil | ||||||
| requests | requests | ||||||
| toml | toml | ||||||
| unidecode | unidecode | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue