AutoRecon/autorecon/targets.py

226 lines
7.3 KiB
Python

import asyncio, inspect, os
from typing import final
from autorecon.config import config
from autorecon.io import e, info, warn, error
class Target:
def __init__(self, address, ip, ipversion, type, autorecon):
self.address = address
self.ip = ip
self.ipversion = ipversion
self.type = type
self.autorecon = autorecon
self.basedir = ''
self.reportdir = ''
self.scandir = ''
self.lock = asyncio.Lock()
self.ports = None
self.pending_services = []
self.services = []
self.scans = {'ports':{}, 'services':{}}
self.running_tasks = {}
async def add_service(self, service):
async with self.lock:
self.pending_services.append(service)
def extract_service(self, line, regex=None):
return self.autorecon.extract_service(line, regex)
async def extract_services(self, stream, regex=None):
return await self.autorecon.extract_services(stream, regex)
@final
def info(self, msg, verbosity=0):
plugin = inspect.currentframe().f_back.f_locals['self']
info('{bright}[{yellow}' + self.address + '{crst}/{bgreen}' + plugin.slug + '{crst}]{rst} ' + msg)
@final
def warn(self, msg, verbosity=0):
plugin = inspect.currentframe().f_back.f_locals['self']
warn('{bright}[{yellow}' + self.address + '{crst}/{bgreen}' + plugin.slug + '{crst}]{rst} ' + msg)
@final
def error(self, msg, verbosity=0):
plugin = inspect.currentframe().f_back.f_locals['self']
error('{bright}[{yellow}' + self.address + '{crst}/{bgreen}' + plugin.slug + '{crst}]{rst} ' + msg)
async def execute(self, cmd, blocking=True, outfile=None, errfile=None, future_outfile=None):
target = self
# Create variables for command references.
address = target.address
addressv6 = target.address
ipaddress = target.ip
ipaddressv6 = target.ip
scandir = target.scandir
nmap_extra = target.autorecon.args.nmap
if target.autorecon.args.nmap_append:
nmap_extra += ' ' + target.autorecon.args.nmap_append
if target.ipversion == 'IPv6':
nmap_extra += ' -6'
if addressv6 == target.ip:
addressv6 = '[' + addressv6 + ']'
ipaddressv6 = '[' + ipaddressv6 + ']'
plugin = inspect.currentframe().f_back.f_locals['self']
if config['proxychains']:
nmap_extra += ' -sT'
cmd = e(cmd)
tag = plugin.slug
info('Port scan {bblue}' + plugin.name + ' {green}(' + tag + '){rst} is running the following command against {byellow}' + address + '{rst}: ' + cmd, verbosity=2)
if outfile is not None:
outfile = os.path.join(target.scandir, e(outfile))
if errfile is not None:
errfile = os.path.join(target.scandir, e(errfile))
if future_outfile is not None:
future_outfile = os.path.join(target.scandir, e(future_outfile))
target.scans['ports'][tag]['commands'].append([cmd, outfile if outfile is not None else future_outfile, errfile])
async with target.lock:
with open(os.path.join(target.scandir, '_commands.log'), 'a') as file:
file.writelines(cmd + '\n\n')
process, stdout, stderr = await target.autorecon.execute(cmd, target, tag, patterns=plugin.patterns, outfile=outfile, errfile=errfile)
target.running_tasks[tag]['processes'].append({'process': process, 'stderr': stderr, 'cmd': cmd})
# If process should block, sleep until stdout and stderr have finished.
if blocking:
while (not (stdout.ended and stderr.ended)):
await asyncio.sleep(0.1)
await process.wait()
return process, stdout, stderr
class Service:
def __init__(self, protocol, port, name, secure=False):
self.target = None
self.protocol = protocol.lower()
self.port = int(port)
self.name = name
self.secure = secure
self.manual_commands = {}
@final
def tag(self):
return self.protocol + '/' + str(self.port) + '/' + self.name
@final
def full_tag(self):
return self.protocol + '/' + str(self.port) + '/' + self.name + '/' + ('secure' if self.secure else 'insecure')
@final
def add_manual_commands(self, description, commands):
if not isinstance(commands, list):
commands = [commands]
if description not in self.manual_commands:
self.manual_commands[description] = []
# Merge in new unique commands, while preserving order.
[self.manual_commands[description].append(m) for m in commands if m not in self.manual_commands[description]]
@final
def add_manual_command(self, description, command):
self.add_manual_commands(description, command)
@final
def info(self, msg):
plugin = inspect.currentframe().f_back.f_locals['self']
info('{bright}[{yellow}' + self.target.address + '{crst}/{bgreen}' + self.tag() + '/' + plugin.slug + '{crst}]{rst} ' + msg)
@final
def warn(self, msg):
plugin = inspect.currentframe().f_back.f_locals['self']
warn('{bright}[{yellow}' + self.target.address + '{crst}/{bgreen}' + self.tag() + '/' + plugin.slug + '{crst}]{rst} ' + msg)
@final
def error(self, msg):
plugin = inspect.currentframe().f_back.f_locals['self']
error('{bright}[{yellow}' + self.target.address + '{crst}/{bgreen}' + self.tag() + '/' + plugin.slug + '{crst}]{rst} ' + msg)
@final
async def execute(self, cmd, blocking=True, outfile=None, errfile=None, future_outfile=None):
target = self.target
# Create variables for command references.
address = target.address
addressv6 = target.address
ipaddress = target.ip
ipaddressv6 = target.ip
scandir = target.scandir
protocol = self.protocol
port = self.port
name = self.name
if not config['no_port_dirs']:
scandir = os.path.join(scandir, protocol + str(port))
os.makedirs(scandir, exist_ok=True)
os.makedirs(os.path.join(scandir, 'xml'), exist_ok=True)
# Special cases for HTTP.
http_scheme = 'https' if 'https' in self.name or self.secure is True else 'http'
nmap_extra = target.autorecon.args.nmap
if target.autorecon.args.nmap_append:
nmap_extra += ' ' + target.autorecon.args.nmap_append
if protocol == 'udp':
nmap_extra += ' -sU'
if target.ipversion == 'IPv6':
nmap_extra += ' -6'
if addressv6 == target.ip:
addressv6 = '[' + addressv6 + ']'
ipaddressv6 = '[' + ipaddressv6 + ']'
if config['proxychains'] and protocol == 'tcp':
nmap_extra += ' -sT'
plugin = inspect.currentframe().f_back.f_locals['self']
cmd = e(cmd)
tag = self.tag() + '/' + plugin.slug
plugin_tag = tag
if plugin.run_once_boolean:
plugin_tag = plugin.slug
info('Service scan {bblue}' + plugin.name + ' {green}(' + tag + '){rst} is running the following command against {byellow}' + address + '{rst}: ' + cmd, verbosity=2)
if outfile is not None:
outfile = os.path.join(scandir, e(outfile))
if errfile is not None:
errfile = os.path.join(scandir, e(errfile))
if future_outfile is not None:
future_outfile = os.path.join(scandir, e(future_outfile))
target.scans['services'][self][plugin_tag]['commands'].append([cmd, outfile if outfile is not None else future_outfile, errfile])
async with target.lock:
with open(os.path.join(target.scandir, '_commands.log'), 'a') as file:
file.writelines(cmd + '\n\n')
process, stdout, stderr = await target.autorecon.execute(cmd, target, tag, patterns=plugin.patterns, outfile=outfile, errfile=errfile)
target.running_tasks[tag]['processes'].append({'process': process, 'stderr': stderr, 'cmd': cmd})
# If process should block, sleep until stdout and stderr have finished.
if blocking:
while (not (stdout.ended and stderr.ended)):
await asyncio.sleep(0.1)
await process.wait()
return process, stdout, stderr