initial version of dependent service scans.
This commit is contained in:
parent
52ba61e6eb
commit
42e2620f76
295
autorecon/io.py
295
autorecon/io.py
|
|
@ -2,182 +2,191 @@ import asyncio, colorama, os, re, string, sys, unidecode
|
||||||
from colorama import Fore, Style
|
from colorama import Fore, Style
|
||||||
from autorecon.config import config
|
from autorecon.config import config
|
||||||
|
|
||||||
|
|
||||||
def slugify(name):
|
def slugify(name):
|
||||||
return re.sub(r'[\W_]+', '-', unidecode.unidecode(name).lower()).strip('-')
|
return re.sub(r'[\W_]+', '-', unidecode.unidecode(name).lower()).strip('-')
|
||||||
|
|
||||||
|
|
||||||
def e(*args, frame_index=1, **kvargs):
|
def e(*args, frame_index=1, **kvargs):
|
||||||
frame = sys._getframe(frame_index)
|
frame = sys._getframe(frame_index)
|
||||||
|
|
||||||
vals = {}
|
vals = {}
|
||||||
|
|
||||||
vals.update(frame.f_globals)
|
vals.update(frame.f_globals)
|
||||||
vals.update(frame.f_locals)
|
vals.update(frame.f_locals)
|
||||||
vals.update(kvargs)
|
vals.update(kvargs)
|
||||||
|
|
||||||
|
return string.Formatter().vformat(' '.join(args), args, vals)
|
||||||
|
|
||||||
return string.Formatter().vformat(' '.join(args), args, vals)
|
|
||||||
|
|
||||||
def fformat(s):
|
def fformat(s):
|
||||||
return e(s, frame_index=3)
|
return e(s, frame_index=3)
|
||||||
|
|
||||||
def cprint(*args, color=Fore.RESET, char='*', sep=' ', end='\n', frame_index=1, file=sys.stdout, printmsg=True, verbosity=0, **kvargs):
|
|
||||||
if printmsg and verbosity > config['verbose']:
|
|
||||||
return ''
|
|
||||||
frame = sys._getframe(frame_index)
|
|
||||||
|
|
||||||
vals = {
|
def cprint(*args, color=Fore.RESET, char='*', sep=' ', end='\n', frame_index=1, file=sys.stdout, printmsg=True,
|
||||||
'bgreen': Fore.GREEN + Style.BRIGHT,
|
verbosity=0, **kvargs):
|
||||||
'bred': Fore.RED + Style.BRIGHT,
|
if printmsg and verbosity > config['verbose']:
|
||||||
'bblue': Fore.BLUE + Style.BRIGHT,
|
return ''
|
||||||
'byellow': Fore.YELLOW + Style.BRIGHT,
|
frame = sys._getframe(frame_index)
|
||||||
'bmagenta': Fore.MAGENTA + Style.BRIGHT,
|
|
||||||
|
|
||||||
'green': Fore.GREEN,
|
vals = {
|
||||||
'red': Fore.RED,
|
'bgreen': Fore.GREEN + Style.BRIGHT,
|
||||||
'blue': Fore.BLUE,
|
'bred': Fore.RED + Style.BRIGHT,
|
||||||
'yellow': Fore.YELLOW,
|
'bblue': Fore.BLUE + Style.BRIGHT,
|
||||||
'magenta': Fore.MAGENTA,
|
'byellow': Fore.YELLOW + Style.BRIGHT,
|
||||||
|
'bmagenta': Fore.MAGENTA + Style.BRIGHT,
|
||||||
|
|
||||||
'bright': Style.BRIGHT,
|
'green': Fore.GREEN,
|
||||||
'srst': Style.NORMAL,
|
'red': Fore.RED,
|
||||||
'crst': Fore.RESET,
|
'blue': Fore.BLUE,
|
||||||
'rst': Style.NORMAL + Fore.RESET
|
'yellow': Fore.YELLOW,
|
||||||
}
|
'magenta': Fore.MAGENTA,
|
||||||
|
|
||||||
if config['accessible']:
|
'bright': Style.BRIGHT,
|
||||||
vals = {'bgreen':'', 'bred':'', 'bblue':'', 'byellow':'', 'bmagenta':'', 'green':'', 'red':'', 'blue':'', 'yellow':'', 'magenta':'', 'bright':'', 'srst':'', 'crst':'', 'rst':''}
|
'srst': Style.NORMAL,
|
||||||
|
'crst': Fore.RESET,
|
||||||
|
'rst': Style.NORMAL + Fore.RESET
|
||||||
|
}
|
||||||
|
|
||||||
vals.update(frame.f_globals)
|
if config['accessible']:
|
||||||
vals.update(frame.f_locals)
|
vals = {'bgreen': '', 'bred': '', 'bblue': '', 'byellow': '', 'bmagenta': '', 'green': '', 'red': '',
|
||||||
vals.update(kvargs)
|
'blue': '', 'yellow': '', 'magenta': '', 'bright': '', 'srst': '', 'crst': '', 'rst': ''}
|
||||||
|
|
||||||
unfmt = ''
|
vals.update(frame.f_globals)
|
||||||
if char is not None and not config['accessible']:
|
vals.update(frame.f_locals)
|
||||||
unfmt += color + '[' + Style.BRIGHT + char + Style.NORMAL + ']' + Fore.RESET + sep
|
vals.update(kvargs)
|
||||||
unfmt += sep.join(args)
|
|
||||||
|
|
||||||
fmted = unfmt
|
unfmt = ''
|
||||||
|
if char is not None and not config['accessible']:
|
||||||
|
unfmt += color + '[' + Style.BRIGHT + char + Style.NORMAL + ']' + Fore.RESET + sep
|
||||||
|
unfmt += sep.join(args)
|
||||||
|
|
||||||
for attempt in range(10):
|
fmted = unfmt
|
||||||
try:
|
|
||||||
fmted = string.Formatter().vformat(unfmt, args, vals)
|
for attempt in range(10):
|
||||||
break
|
try:
|
||||||
except KeyError as err:
|
fmted = string.Formatter().vformat(unfmt, args, vals)
|
||||||
key = err.args[0]
|
break
|
||||||
unfmt = unfmt.replace('{' + key + '}', '{{' + key + '}}')
|
except KeyError as err:
|
||||||
|
key = err.args[0]
|
||||||
|
unfmt = unfmt.replace('{' + key + '}', '{{' + key + '}}')
|
||||||
|
|
||||||
|
if printmsg:
|
||||||
|
print(fmted, sep=sep, end=end, file=file)
|
||||||
|
else:
|
||||||
|
return fmted
|
||||||
|
|
||||||
if printmsg:
|
|
||||||
print(fmted, sep=sep, end=end, file=file)
|
|
||||||
else:
|
|
||||||
return fmted
|
|
||||||
|
|
||||||
def debug(*args, color=Fore.GREEN, sep=' ', end='\n', file=sys.stdout, **kvargs):
|
def debug(*args, color=Fore.GREEN, sep=' ', end='\n', file=sys.stdout, **kvargs):
|
||||||
if config['verbose'] >= 2:
|
if config['verbose'] >= 2:
|
||||||
if config['accessible']:
|
if config['accessible']:
|
||||||
args = ('Debug:',) + args
|
args = ('Debug:',) + args
|
||||||
cprint(*args, color=color, char='-', sep=sep, end=end, file=file, frame_index=2, **kvargs)
|
cprint(*args, color=color, char='-', sep=sep, end=end, file=file, frame_index=2, **kvargs)
|
||||||
|
|
||||||
|
|
||||||
def info(*args, sep=' ', end='\n', file=sys.stdout, **kvargs):
|
def info(*args, sep=' ', end='\n', file=sys.stdout, **kvargs):
|
||||||
cprint(*args, color=Fore.BLUE, char='*', sep=sep, end=end, file=file, frame_index=2, **kvargs)
|
cprint(*args, color=Fore.BLUE, char='*', sep=sep, end=end, file=file, frame_index=2, **kvargs)
|
||||||
|
|
||||||
|
|
||||||
|
def warn(*args, sep=' ', end='\n', file=sys.stderr, **kvargs):
|
||||||
|
if config['accessible']:
|
||||||
|
args = ('Warning:',) + args
|
||||||
|
cprint(*args, color=Fore.YELLOW, char='!', sep=sep, end=end, file=file, frame_index=2, **kvargs)
|
||||||
|
|
||||||
def warn(*args, sep=' ', end='\n', file=sys.stderr,**kvargs):
|
|
||||||
if config['accessible']:
|
|
||||||
args = ('Warning:',) + args
|
|
||||||
cprint(*args, color=Fore.YELLOW, char='!', sep=sep, end=end, file=file, frame_index=2, **kvargs)
|
|
||||||
|
|
||||||
def error(*args, sep=' ', end='\n', file=sys.stderr, **kvargs):
|
def error(*args, sep=' ', end='\n', file=sys.stderr, **kvargs):
|
||||||
if config['accessible']:
|
if config['accessible']:
|
||||||
args = ('Error:',) + args
|
args = ('Error:',) + args
|
||||||
cprint(*args, color=Fore.RED, char='!', sep=sep, end=end, file=file, frame_index=2, **kvargs)
|
cprint(*args, color=Fore.RED, char='!', sep=sep, end=end, file=file, frame_index=2, **kvargs)
|
||||||
|
|
||||||
|
|
||||||
def fail(*args, sep=' ', end='\n', file=sys.stderr, **kvargs):
|
def fail(*args, sep=' ', end='\n', file=sys.stderr, **kvargs):
|
||||||
if config['accessible']:
|
if config['accessible']:
|
||||||
args = ('Failure:',) + args
|
args = ('Failure:',) + args
|
||||||
cprint(*args, color=Fore.RED, char='!', sep=sep, end=end, file=file, frame_index=2, **kvargs)
|
cprint(*args, color=Fore.RED, char='!', sep=sep, end=end, file=file, frame_index=2, **kvargs)
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
|
|
||||||
class CommandStreamReader(object):
|
class CommandStreamReader(object):
|
||||||
|
|
||||||
def __init__(self, stream, target, tag, patterns=None, outfile=None, plugin=None):
|
def __init__(self, stream, target, tag, patterns=None, outfile=None, plugin=None):
|
||||||
self.stream = stream
|
self.stream = stream
|
||||||
self.target = target
|
self.target = target
|
||||||
self.tag = tag
|
self.tag = tag
|
||||||
self.lines = []
|
self.lines = []
|
||||||
self.plugin = plugin
|
self.plugin = plugin
|
||||||
self.patterns = patterns or []
|
self.patterns = patterns or []
|
||||||
self.outfile = outfile
|
self.outfile = outfile
|
||||||
self.ended = False
|
self.ended = False
|
||||||
|
|
||||||
# Empty files that already exist.
|
# Empty files that already exist.
|
||||||
if self.outfile != None:
|
if self.outfile != None:
|
||||||
with open(self.outfile, 'w'): pass
|
with open(self.outfile, 'w'): pass
|
||||||
|
|
||||||
# Read lines from the stream until it ends.
|
# Read lines from the stream until it ends.
|
||||||
async def _read(self):
|
async def _read(self):
|
||||||
while True:
|
while True:
|
||||||
if self.stream.at_eof():
|
if self.stream.at_eof():
|
||||||
break
|
break
|
||||||
try:
|
try:
|
||||||
line = (await self.stream.readline()).decode('utf8').rstrip()
|
line = (await self.stream.readline()).decode('utf8').rstrip()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
error('{bright}[{yellow}' + self.target.address + '{crst}/{bgreen}' + self.tag + '{crst}]{rst} A line was longer than 64 KiB and cannot be processed. Ignoring.')
|
error(
|
||||||
continue
|
'{bright}[{yellow}' + self.target.address + '{crst}/{bgreen}' + self.tag + '{crst}]{rst} A line was longer than 64 KiB and cannot be processed. Ignoring.')
|
||||||
|
continue
|
||||||
|
|
||||||
if line != '':
|
if line != '':
|
||||||
info('{bright}[{yellow}' + self.target.address + '{crst}/{bgreen}' + self.tag + '{crst}]{rst} ' + line.replace('{', '{{').replace('}', '}}'), verbosity=3)
|
info(
|
||||||
|
'{bright}[{yellow}' + self.target.address + '{crst}/{bgreen}' + self.tag + '{crst}]{rst} ' + line.replace(
|
||||||
|
'{', '{{').replace('}', '}}'), verbosity=3)
|
||||||
|
|
||||||
# Check lines for pattern matches.
|
# Check lines for pattern matches.
|
||||||
for p in self.patterns:
|
for p in self.patterns:
|
||||||
matches = p.pattern.findall(line)
|
matches = p.pattern.findall(line)
|
||||||
for match in matches:
|
for match in matches:
|
||||||
async with self.target.lock:
|
async with self.target.lock:
|
||||||
with open(os.path.join(self.target.scandir, '_patterns.log'), 'a') as file:
|
with open(os.path.join(self.target.scandir, '_patterns.log'), 'a') as file:
|
||||||
if p.description:
|
if p.description:
|
||||||
info('{bright}[{yellow}' + self.target.address + '{crst}/{bgreen}' + self.tag + '{crst}]{rst} {bmagenta}' + p.description.replace('{match}', match) + '{rst}', verbosity=2)
|
info(
|
||||||
file.writelines(p.description.replace('{match}', match) + '\n\n')
|
'{bright}[{yellow}' + self.target.address + '{crst}/{bgreen}' + self.tag + '{crst}]{rst} {bmagenta}' + p.description.replace(
|
||||||
else:
|
'{match}', match) + '{rst}', verbosity=2)
|
||||||
info('{bright}[{yellow}' + self.target.address + '{crst}/{bgreen}' + self.tag + '{crst}]{rst} {bmagenta}Matched Pattern: ' + match + '{rst}', verbosity=2)
|
file.writelines(p.description.replace('{match}', match) + '\n\n')
|
||||||
file.writelines('Matched Pattern: ' + match + '\n\n')
|
else:
|
||||||
debug(str(self.plugin.__dict__))
|
info(
|
||||||
next_plugins = self.target.autorecon.get_next_service_scan_plugins(self.plugin)
|
'{bright}[{yellow}' + self.target.address + '{crst}/{bgreen}' + self.tag + '{crst}]{rst} {bmagenta}Matched Pattern: ' + match + '{rst}',
|
||||||
info(str(next_plugins))
|
verbosity=2)
|
||||||
for next_plugin in next_plugins:
|
file.writelines('Matched Pattern: ' + match + '\n\n')
|
||||||
info("Dict: %s" % str(self.target.__dict__))
|
next_plugins_to_run = p.get_next_service_scan_plugins(self.target.autorecon)
|
||||||
for service, details in self.target.scans.get('services', {}).items():
|
for next_plugin in next_plugins_to_run:
|
||||||
for key, value in details.items():
|
# ugly way to get the service details somehow
|
||||||
if value.get('plugin') == self.plugin:
|
for service, details in self.target.scans.get('services', {}).items():
|
||||||
info("Value: %s" % str(value))
|
for key, value in details.items():
|
||||||
# info("Value: %s" % str(value))
|
if value.get('plugin') == self.plugin:
|
||||||
#info("Service Details: %s" % str(details))
|
self.target.autorecon.queue_new_service_scan(next_plugin, service)
|
||||||
#new_service = Service()
|
if self.outfile is not None:
|
||||||
self.target.autorecon.queue_new_service_scan(next_plugin, service)
|
with open(self.outfile, 'a') as writer:
|
||||||
#for next_plugin in next_plugins:
|
writer.write(line + '\n')
|
||||||
# async def service_scan(plugin, service, run_from_service_scan=False):
|
self.lines.append(line)
|
||||||
#autorecon_queue_service_scan(next_plugin, run_fr)
|
self.ended = True
|
||||||
|
|
||||||
if self.outfile is not None:
|
# Read a line from the stream cache.
|
||||||
with open(self.outfile, 'a') as writer:
|
async def readline(self):
|
||||||
writer.write(line + '\n')
|
while True:
|
||||||
self.lines.append(line)
|
try:
|
||||||
self.ended = True
|
return self.lines.pop(0)
|
||||||
|
except IndexError:
|
||||||
|
if self.ended:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
await asyncio.sleep(0.1)
|
||||||
|
|
||||||
# Read a line from the stream cache.
|
# Read all lines from the stream cache.
|
||||||
async def readline(self):
|
async def readlines(self):
|
||||||
while True:
|
lines = []
|
||||||
try:
|
while True:
|
||||||
return self.lines.pop(0)
|
line = await self.readline()
|
||||||
except IndexError:
|
if line is not None:
|
||||||
if self.ended:
|
lines.append(line)
|
||||||
return None
|
else:
|
||||||
else:
|
break
|
||||||
await asyncio.sleep(0.1)
|
return lines
|
||||||
|
|
||||||
# Read all lines from the stream cache.
|
|
||||||
async def readlines(self):
|
|
||||||
lines = []
|
|
||||||
while True:
|
|
||||||
line = await self.readline()
|
|
||||||
if line is not None:
|
|
||||||
lines.append(line)
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
return lines
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ async def get_semaphore(autorecon):
|
||||||
|
|
||||||
async def service_scan(plugin, service, run_from_service_scan=False):
|
async def service_scan(plugin, service, run_from_service_scan=False):
|
||||||
# skip running service scan plugins that are meant to be run for specific services
|
# skip running service scan plugins that are meant to be run for specific services
|
||||||
if plugin.has_previous_plugins() and not run_from_service_scan:
|
if not plugin.run_standalone and not run_from_service_scan:
|
||||||
return
|
return
|
||||||
|
|
||||||
semaphore = service.target.autorecon.service_scan_semaphore
|
semaphore = service.target.autorecon.service_scan_semaphore
|
||||||
|
|
@ -159,13 +159,23 @@ async def service_scan(plugin, service, run_from_service_scan=False):
|
||||||
|
|
||||||
|
|
||||||
class Pattern:
|
class Pattern:
|
||||||
def __init__(self, pattern, description=None, plugins=None):
|
def __init__(self, pattern, description=None, plugin_names=None):
|
||||||
self.pattern = pattern
|
self.pattern = pattern
|
||||||
self.description = description
|
self.description = description
|
||||||
if not plugins:
|
if not plugin_names:
|
||||||
self.plugins = []
|
self.plugin_names = []
|
||||||
else:
|
else:
|
||||||
self.plugins = plugins
|
self.plugin_names = plugin_names
|
||||||
|
|
||||||
|
def get_next_service_scan_plugins(self, autorecon):
|
||||||
|
next_plugins = []
|
||||||
|
if not self.plugin_names:
|
||||||
|
return next_plugins
|
||||||
|
for service_plugin in autorecon.plugin_types['service']:
|
||||||
|
for next_plugin in self.plugin_names:
|
||||||
|
if next_plugin == service_plugin.name:
|
||||||
|
next_plugins.append(service_plugin)
|
||||||
|
return next_plugins
|
||||||
|
|
||||||
|
|
||||||
class Plugin(object):
|
class Plugin(object):
|
||||||
|
|
@ -238,13 +248,13 @@ class Plugin(object):
|
||||||
return self.get_global_option(name, default)
|
return self.get_global_option(name, default)
|
||||||
|
|
||||||
@final
|
@final
|
||||||
def add_pattern(self, pattern, description=None, plugins=None):
|
def add_pattern(self, pattern, description=None, plugin_names=None):
|
||||||
try:
|
try:
|
||||||
compiled = re.compile(pattern)
|
compiled = re.compile(pattern)
|
||||||
if description:
|
if description:
|
||||||
self.patterns.append(Pattern(compiled, description=description, plugins=plugins))
|
self.patterns.append(Pattern(compiled, description=description, plugin_names=plugin_names))
|
||||||
else:
|
else:
|
||||||
self.patterns.append(Pattern(compiled, plugins=plugins))
|
self.patterns.append(Pattern(compiled, plugin_names=plugin_names))
|
||||||
except re.error:
|
except re.error:
|
||||||
fail('Error: The pattern "' + pattern + '" in the plugin "' + self.name + '" is invalid regex.')
|
fail('Error: The pattern "' + pattern + '" in the plugin "' + self.name + '" is invalid regex.')
|
||||||
|
|
||||||
|
|
@ -265,6 +275,7 @@ class ServiceScan(Plugin):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.ports = {'tcp': [], 'udp': []}
|
self.ports = {'tcp': [], 'udp': []}
|
||||||
|
self.run_standalone = True
|
||||||
self.ignore_ports = {'tcp': [], 'udp': []}
|
self.ignore_ports = {'tcp': [], 'udp': []}
|
||||||
self.services = []
|
self.services = []
|
||||||
self.service_names = []
|
self.service_names = []
|
||||||
|
|
@ -543,21 +554,6 @@ class AutoRecon(object):
|
||||||
|
|
||||||
return process, cout, cerr
|
return process, cout, cerr
|
||||||
|
|
||||||
def get_plugin_by_name(self, name):
|
|
||||||
for key, value in self.plugins.items():
|
|
||||||
if value.name == name:
|
|
||||||
return self.plugins[key]
|
|
||||||
|
|
||||||
def get_next_service_scan_plugins(self, current_plugin):
|
|
||||||
next_plugins = []
|
|
||||||
for plugin in self.plugin_types['service']:
|
|
||||||
if not plugin.has_previous_plugins():
|
|
||||||
continue
|
|
||||||
for previous_plugin_name in plugin.get_previous_plugin_names():
|
|
||||||
if current_plugin.name == previous_plugin_name:
|
|
||||||
next_plugins.append(plugin)
|
|
||||||
return next_plugins
|
|
||||||
|
|
||||||
def queue_new_service_scan(self, plugin, service):
|
def queue_new_service_scan(self, plugin, service):
|
||||||
# try using append. in the main method "pending" is sometimes set() and sometimes list()
|
# try using append. in the main method "pending" is sometimes set() and sometimes list()
|
||||||
self.pending.append(asyncio.create_task(service_scan(plugin, service, run_from_service_scan=True)))
|
self.pending.append(asyncio.create_task(service_scan(plugin, service, run_from_service_scan=True)))
|
||||||
|
|
|
||||||
|
|
@ -3,36 +3,38 @@ from autorecon.plugins import ServiceScan
|
||||||
|
|
||||||
class DirectoryListing(ServiceScan):
|
class DirectoryListing(ServiceScan):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.name = "Directory Listing"
|
self.name = "Directory Listing"
|
||||||
self.tags = ['default', 'safe', 'http', 'test']
|
self.tags = ['default', 'safe', 'http', 'test']
|
||||||
|
|
||||||
def configure(self):
|
def configure(self):
|
||||||
self.match_service_name('^http')
|
self.match_service_name('^http')
|
||||||
self.match_service_name('^nacn_http$', negative_match=True)
|
self.match_service_name('^nacn_http$', negative_match=True)
|
||||||
self.add_pattern('<h1>Directory listing for', description='Directory Listing enabled',
|
self.add_pattern('<h1>Directory listing for', description='Directory Listing enabled',
|
||||||
plugin_names=["Directory Listing Verify"])
|
plugin_names=["Directory Listing Verify"])
|
||||||
|
|
||||||
async def run(self, service):
|
async def run(self, service):
|
||||||
await service.execute('curl {http_scheme}://{addressv6}:{port}')
|
await service.execute('curl {http_scheme}://{addressv6}:{port}')
|
||||||
|
|
||||||
|
|
||||||
class DirectoryListingVerify(ServiceScan):
|
class DirectoryListingVerify(ServiceScan):
|
||||||
"""
|
"""
|
||||||
this is a useless plugin that is only run, if directory listing was found.
|
this is a useless plugin that is only run, if directory listing was found.
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.name = "Directory Listing verify"
|
|
||||||
self.tags = ['default', 'safe', 'http', 'test']
|
|
||||||
|
|
||||||
def configure(self):
|
def __init__(self):
|
||||||
self.match_service_name('^http')
|
super().__init__()
|
||||||
self.match_service_name('^nacn_http$', negative_match=True)
|
self.run_standalone = False
|
||||||
|
self.name = "Directory Listing Verify"
|
||||||
|
self.tags = ['default', 'safe', 'http', 'test']
|
||||||
|
|
||||||
async def run(self, service):
|
def configure(self):
|
||||||
await service.execute('curl {http_scheme}://{addressv6}:{port}/?id=1')
|
self.match_service_name('^http')
|
||||||
|
self.match_service_name('^nacn_http$', negative_match=True)
|
||||||
|
|
||||||
def get_previous_plugin_names(self):
|
async def run(self, service):
|
||||||
return ["Directory Listing"]
|
await service.execute('curl {http_scheme}://{addressv6}:{port}/?id=1')
|
||||||
|
|
||||||
|
def get_previous_plugin_names(self):
|
||||||
|
return ["Directory Listing"]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue