Plugin Updates
Separated plugins out into separate files to make them easier to understand.
This commit is contained in:
parent
0e27e3b1c4
commit
ae0eb0629a
|
@ -1,18 +1,5 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapFTP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Nmap FTP'
|
||||
self.tags = ['default', 'safe', 'ftp']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^ftp', '^ftp\-data'])
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(ftp* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_ftp_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_ftp_nmap.xml" {address}')
|
||||
|
||||
class BruteforceFTP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
|
@ -0,0 +1,20 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class BruteforceHTTP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Bruteforce HTTP"
|
||||
self.tags = ['default', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
service.add_manual_commands('Credential bruteforcing commands (don\'t run these without modifying them):', [
|
||||
'hydra -L "' + 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') + '" -e nsr -s {port} -o "{scandir}/{protocol}_{port}_{http_scheme}_auth_hydra.txt" {http_scheme}-get://{addressv6}/path/to/auth/area',
|
||||
'medusa -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') + '" -e ns -n {port} -O "{scandir}/{protocol}_{port}_{http_scheme}_auth_medusa.txt" -M http -h {addressv6} -m DIR:/path/to/auth/area',
|
||||
'hydra -L "' + 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') + '" -e nsr -s {port} -o "{scandir}/{protocol}_{port}_{http_scheme}_form_hydra.txt" {http_scheme}-post-form://{addressv6}/path/to/login.php:"username=^USER^&password=^PASS^":"invalid-login-message"',
|
||||
'medusa -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') + '" -e ns -n {port} -O "{scandir}/{protocol}_{port}_{http_scheme}_form_medusa.txt" -M web-form -h {addressv6} -m FORM:/path/to/login.php -m FORM-DATA:"post?username=&password=" -m DENY-SIGNAL:"invalid login message"'
|
||||
])
|
|
@ -1,18 +1,5 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapRDP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap RDP"
|
||||
self.tags = ['default', 'safe', 'rdp']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^rdp', '^ms\-wbt\-server', '^ms\-term\-serv'])
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(rdp* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_rdp_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_rdp_nmap.xml" {address}')
|
||||
|
||||
class BruteforceRDP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
|
@ -1,18 +1,5 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapSSH(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap SSH"
|
||||
self.tags = ['default', 'safe', 'ssh']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^ssh')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,ssh2-enum-algos,ssh-hostkey,ssh-auth-methods" -oN "{scandir}/{protocol}_{port}_ssh_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_ssh_nmap.xml" {address}')
|
||||
|
||||
class BruteforceSSH(ServiceScan):
|
||||
|
||||
def __init__(self):
|
|
@ -0,0 +1,26 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
from autorecon.io import fformat
|
||||
|
||||
class CurlKnownSecurity(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Known Security"
|
||||
self.tags = ['default', 'safe', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
|
||||
async def run(self, service):
|
||||
if service.protocol == 'tcp':
|
||||
process, stdout, _ = await service.execute('curl -sSikf {http_scheme}://{addressv6}:{port}/.well-known/security.txt', future_outfile='{protocol}_{port}_{http_scheme}_known-security.txt')
|
||||
|
||||
lines = await stdout.readlines()
|
||||
|
||||
if process.returncode == 0 and lines:
|
||||
filename = fformat('{scandir}/{protocol}_{port}_{http_scheme}_known-security.txt')
|
||||
with open(filename, mode='wt', encoding='utf8') as robots:
|
||||
robots.write('\n'.join(lines))
|
||||
else:
|
||||
service.info('{bblue}[' + fformat('{tag}') + ']{rst} There did not appear to be a .well-known/security.txt file in the webroot (/).')
|
|
@ -0,0 +1,26 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
from autorecon.io import fformat
|
||||
|
||||
class CurlRobots(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Curl Robots"
|
||||
self.tags = ['default', 'safe', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
|
||||
async def run(self, service):
|
||||
if service.protocol == 'tcp':
|
||||
process, stdout, _ = await service.execute('curl -sSikf {http_scheme}://{addressv6}:{port}/robots.txt', future_outfile='{protocol}_{port}_{http_scheme}_curl-robots.txt')
|
||||
|
||||
lines = await stdout.readlines()
|
||||
|
||||
if process.returncode == 0 and lines:
|
||||
filename = fformat('{scandir}/{protocol}_{port}_{http_scheme}_curl-robots.txt')
|
||||
with open(filename, mode='wt', encoding='utf8') as robots:
|
||||
robots.write('\n'.join(lines))
|
||||
else:
|
||||
service.info('{bblue}[' + fformat('{tag}') + ']{rst} There did not appear to be a robots.txt file in the webroot (/).')
|
|
@ -0,0 +1,18 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class Curl(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Curl"
|
||||
self.tags = ['default', 'safe', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.add_option("path", default="/", help="The path on the web server to curl. Default: %(default)s")
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
self.add_pattern('(?i)powered[ -]by[^\n]+')
|
||||
|
||||
async def run(self, service):
|
||||
if service.protocol == 'tcp':
|
||||
await service.execute('curl -sSik {http_scheme}://{addressv6}:{port}' + self.get_option('path'), outfile='{protocol}_{port}_{http_scheme}_curl.html')
|
|
@ -1,134 +0,0 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
from shutil import which
|
||||
|
||||
class NmapMongoDB(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap MongoDB"
|
||||
self.tags = ['default', 'safe', 'databases']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^mongod')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(mongodb* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_mongodb_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_mongodb_nmap.xml" {address}')
|
||||
|
||||
class NmapMSSQL(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap MSSQL"
|
||||
self.tags = ['default', 'safe', 'databases']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^mssql', '^ms\-sql'])
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
if service.target.ipversion == 'IPv4':
|
||||
service.add_manual_command('(sqsh) interactive database shell:', 'sqsh -U <username> -P <password> -S {address}:{port}')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(ms-sql* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" --script-args="mssql.instance-port={port},mssql.username=sa,mssql.password=sa" -oN "{scandir}/{protocol}_{port}_mssql_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_mssql_nmap.xml" {address}')
|
||||
|
||||
class NmapMYSQL(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap MYSQL"
|
||||
self.tags = ['default', 'safe', 'databases']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^mysql')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
if service.target.ipversion == 'IPv4':
|
||||
service.add_manual_command('(sqsh) interactive database shell:', 'sqsh -U <username> -P <password> -S {address}:{port}')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(mysql* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_mysql_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_mysql_nmap.xml" {address}')
|
||||
|
||||
class NmapOracle(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap Oracle"
|
||||
self.tags = ['default', 'safe', 'databases']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^oracle')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
service.add_manual_command('Brute-force SIDs using Nmap:', 'nmap {nmap_extra} -sV -p {port} --script="banner,oracle-sid-brute" -oN "{scandir}/{protocol}_{port}_oracle_sid-brute_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_oracle_sid-brute_nmap.xml" {address}')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(oracle* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_oracle_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_oracle_nmap.xml" {address}')
|
||||
|
||||
class OracleTNScmd(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Oracle TNScmd"
|
||||
self.tags = ['default', 'safe', 'databases']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^oracle')
|
||||
|
||||
def check(self):
|
||||
if which('tnscmd10g') is None:
|
||||
self.error('The tnscmd10g program could not be found. Make sure it is installed. (On Kali, run: sudo apt install tnscmd10g)')
|
||||
|
||||
async def run(self, service):
|
||||
if service.target.ipversion == 'IPv4':
|
||||
await service.execute('tnscmd10g ping -h {address} -p {port} 2>&1', outfile='{protocol}_{port}_oracle_tnscmd_ping.txt')
|
||||
await service.execute('tnscmd10g version -h {address} -p {port} 2>&1', outfile='{protocol}_{port}_oracle_tnscmd_version.txt')
|
||||
|
||||
class OracleScanner(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Oracle Scanner"
|
||||
self.tags = ['default', 'safe', 'databases']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^oracle')
|
||||
|
||||
def check(self):
|
||||
if which('oscanner') is None:
|
||||
self.error('The oscanner program could not be found. Make sure it is installed. (On Kali, run: sudo apt install oscanner)')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('oscanner -v -s {address} -P {port} 2>&1', outfile='{protocol}_{port}_oracle_scanner.txt')
|
||||
|
||||
class OracleODAT(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Oracle ODAT"
|
||||
self.tags = ['default', 'safe', 'databases']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^oracle')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
service.add_manual_commands('Install ODAT (https://github.com/quentinhardy/odat) and run the following commands:', [
|
||||
'python odat.py tnscmd -s {address} -p {port} --ping',
|
||||
'python odat.py tnscmd -s {address} -p {port} --version',
|
||||
'python odat.py tnscmd -s {address} -p {port} --status',
|
||||
'python odat.py sidguesser -s {address} -p {port}',
|
||||
'python odat.py passwordguesser -s {address} -p {port} -d <sid> --accounts-file accounts/accounts_multiple.txt',
|
||||
'python odat.py tnspoison -s {address} -p {port} -d <sid> --test-module'
|
||||
])
|
||||
|
||||
class OraclePatator(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Oracle Patator"
|
||||
self.tags = ['default', 'databases']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^oracle')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
service.add_manual_command('Install Oracle Instant Client (https://github.com/rapid7/metasploit-framework/wiki/How-to-get-Oracle-Support-working-with-Kali-Linux) and then bruteforce with patator:', 'patator oracle_login host={address} port={port} user=COMBO00 password=COMBO01 0=/usr/share/seclists/Passwords/Default-Credentials/oracle-betterdefaultpasslist.txt -x ignore:code=ORA-01017 -x ignore:code=ORA-28000')
|
|
@ -1,102 +0,0 @@
|
|||
from autorecon.plugins import PortScan
|
||||
from autorecon.config import config
|
||||
import os, re
|
||||
|
||||
class QuickTCPPortScan(PortScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Top TCP Ports'
|
||||
self.description = 'Performs an Nmap scan of the top 1000 TCP ports.'
|
||||
self.type = 'tcp'
|
||||
self.tags = ['default', 'default-port-scan']
|
||||
self.priority = 0
|
||||
|
||||
async def run(self, target):
|
||||
if target.ports: # Don't run this plugin if there are custom ports.
|
||||
return []
|
||||
|
||||
if config['proxychains']:
|
||||
traceroute_os = ''
|
||||
else:
|
||||
traceroute_os = ' -A --osscan-guess'
|
||||
|
||||
process, stdout, stderr = await target.execute('nmap {nmap_extra} -sV -sC --version-all' + traceroute_os + ' -oN "{scandir}/_quick_tcp_nmap.txt" -oX "{scandir}/xml/_quick_tcp_nmap.xml" {address}', blocking=False)
|
||||
services = await target.extract_services(stdout)
|
||||
await process.wait()
|
||||
return services
|
||||
|
||||
class AllTCPPortScan(PortScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'All TCP Ports'
|
||||
self.description = 'Performs an Nmap scan of all TCP ports.'
|
||||
self.type = 'tcp'
|
||||
self.specific_ports = True
|
||||
self.tags = ['default', 'default-port-scan', 'long']
|
||||
|
||||
async def run(self, target):
|
||||
if config['proxychains']:
|
||||
traceroute_os = ''
|
||||
else:
|
||||
traceroute_os = ' -A --osscan-guess'
|
||||
|
||||
if target.ports:
|
||||
if target.ports['tcp']:
|
||||
process, stdout, stderr = await target.execute('nmap {nmap_extra} -sV -sC --version-all' + traceroute_os + ' -p ' + target.ports['tcp'] + ' -oN "{scandir}/_full_tcp_nmap.txt" -oX "{scandir}/xml/_full_tcp_nmap.xml" {address}', blocking=False)
|
||||
else:
|
||||
return []
|
||||
else:
|
||||
process, stdout, stderr = await target.execute('nmap {nmap_extra} -sV -sC --version-all' + traceroute_os + ' -p- -oN "{scandir}/_full_tcp_nmap.txt" -oX "{scandir}/xml/_full_tcp_nmap.xml" {address}', blocking=False)
|
||||
services = []
|
||||
while True:
|
||||
line = await stdout.readline()
|
||||
if line is not None:
|
||||
match = re.search('^Discovered open port ([0-9]+)/tcp', line)
|
||||
if match:
|
||||
target.info('Discovered open port {bmagenta}tcp/' + match.group(1) + '{rst} on {byellow}' + target.address + '{rst}', verbosity=1)
|
||||
service = target.extract_service(line)
|
||||
if service:
|
||||
services.append(service)
|
||||
else:
|
||||
break
|
||||
await process.wait()
|
||||
return services
|
||||
|
||||
class Top100UDPPortScan(PortScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Top 100 UDP Ports'
|
||||
self.description = 'Performs an Nmap scan of the top 100 UDP ports.'
|
||||
self.type = 'udp'
|
||||
self.specific_ports = True
|
||||
self.tags = ['default', 'default-port-scan', 'long']
|
||||
|
||||
async def run(self, target):
|
||||
# Only run UDP scan if user is root.
|
||||
if os.getuid() == 0:
|
||||
if target.ports:
|
||||
if target.ports['udp']:
|
||||
process, stdout, stderr = await target.execute('nmap {nmap_extra} -sU -A --osscan-guess -p ' + target.ports['udp'] + ' -oN "{scandir}/_custom_ports_udp_nmap.txt" -oX "{scandir}/xml/_custom_ports_udp_nmap.xml" {address}', blocking=False)
|
||||
else:
|
||||
return []
|
||||
else:
|
||||
process, stdout, stderr = await target.execute('nmap {nmap_extra} -sU -A --top-ports 100 -oN "{scandir}/_top_100_udp_nmap.txt" -oX "{scandir}/xml/_top_100_udp_nmap.xml" {address}', blocking=False)
|
||||
services = []
|
||||
while True:
|
||||
line = await stdout.readline()
|
||||
if line is not None:
|
||||
match = re.search('^Discovered open port ([0-9]+)/udp', line)
|
||||
if match:
|
||||
target.info('Discovered open port {bmagenta}udp/' + match.group(1) + '{rst} on {byellow}' + target.address + '{rst}', verbosity=1)
|
||||
service = target.extract_service(line)
|
||||
if service:
|
||||
services.append(service)
|
||||
else:
|
||||
break
|
||||
await process.wait()
|
||||
return services
|
||||
else:
|
||||
target.error('UDP scan requires AutoRecon be run with root privileges.')
|
|
@ -0,0 +1,75 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
from autorecon.config import config
|
||||
from shutil import which
|
||||
import os
|
||||
|
||||
class DirBuster(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Directory Buster"
|
||||
self.slug = 'dirbuster'
|
||||
self.priority = 0
|
||||
self.tags = ['default', 'safe', 'long', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.add_choice_option('tool', default='feroxbuster', choices=['feroxbuster', 'gobuster', 'dirsearch', 'ffuf', 'dirb'], help='The tool to use for directory busting. Default: %(default)s')
|
||||
self.add_list_option('wordlist', default=[os.path.join(config['config_dir'], 'wordlists', 'dirbuster.txt')], help='The wordlist(s) to use when directory busting. Separate multiple wordlists with spaces. Default: %(default)s')
|
||||
self.add_option('threads', default=10, help='The number of threads to use when directory busting. Default: %(default)s')
|
||||
self.add_option('ext', default='txt,html,php,asp,aspx,jsp', help='The extensions you wish to fuzz (no dot, comma separated). Default: %(default)s')
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
|
||||
def check(self):
|
||||
tool = self.get_option('tool')
|
||||
if tool == 'feroxbuster':
|
||||
if which('feroxbuster') is None:
|
||||
self.error('The feroxbuster program could not be found. Make sure it is installed. (On Kali, run: sudo apt install feroxbuster)')
|
||||
elif tool == 'gobuster':
|
||||
if which('gobuster') is None:
|
||||
self.error('The gobuster program could not be found. Make sure it is installed. (On Kali, run: sudo apt install gobuster)')
|
||||
elif tool == 'dirsearch':
|
||||
if which('dirsearch') is None:
|
||||
self.error('The dirsearch program could not be found. Make sure it is installed. (On Kali, run: sudo apt install dirsearch)')
|
||||
|
||||
async def run(self, service):
|
||||
dot_extensions = ','.join(['.' + x for x in self.get_option('ext').split(',')])
|
||||
for wordlist in self.get_option('wordlist'):
|
||||
name = os.path.splitext(os.path.basename(wordlist))[0]
|
||||
if self.get_option('tool') == 'feroxbuster':
|
||||
await service.execute('feroxbuster -u {http_scheme}://{addressv6}:{port}/ -t ' + str(self.get_option('threads')) + ' -w ' + wordlist + ' -x "' + self.get_option('ext') + '" -v -k -n -q -e -o "{scandir}/{protocol}_{port}_{http_scheme}_feroxbuster_' + name + '.txt"')
|
||||
elif self.get_option('tool') == 'gobuster':
|
||||
await service.execute('gobuster dir -u {http_scheme}://{addressv6}:{port}/ -t ' + str(self.get_option('threads')) + ' -w ' + wordlist + ' -e -k -x "' + self.get_option('ext') + '" -z -d -o "{scandir}/{protocol}_{port}_{http_scheme}_gobuster_' + name + '.txt"')
|
||||
elif self.get_option('tool') == 'dirsearch':
|
||||
if service.target.ipversion == 'IPv6':
|
||||
service.error('dirsearch does not support IPv6.')
|
||||
else:
|
||||
await service.execute('dirsearch -u {http_scheme}://{address}:{port}/ -t ' + str(self.get_option('threads')) + ' -e "' + self.get_option('ext') + '" -f -q -w ' + wordlist + ' --format=plain -o "{scandir}/{protocol}_{port}_{http_scheme}_dirsearch_' + name + '.txt"')
|
||||
elif self.get_option('tool') == 'ffuf':
|
||||
await service.execute('ffuf -u {http_scheme}://{addressv6}:{port}/FUZZ -t ' + str(self.get_option('threads')) + ' -w ' + wordlist + ' -e "' + dot_extensions + '" -v -noninteractive | tee {scandir}/{protocol}_{port}_{http_scheme}_ffuf_' + name + '.txt')
|
||||
elif self.get_option('tool') == 'dirb':
|
||||
await service.execute('dirb {http_scheme}://{addressv6}:{port}/ ' + wordlist + ' -l -r -S -X ",' + dot_extensions + '" -o "{scandir}/{protocol}_{port}_{http_scheme}_dirb_' + name + '.txt"')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
dot_extensions = ','.join(['.' + x for x in self.get_option('ext').split(',')])
|
||||
if self.get_option('tool') == 'feroxbuster':
|
||||
service.add_manual_command('(feroxbuster) Multi-threaded recursive directory/file enumeration for web servers using various wordlists:', [
|
||||
'feroxbuster -u {http_scheme}://{addressv6}:{port} -t ' + str(self.get_option('threads')) + ' -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x "' + self.get_option('ext') + '" -v -k -n -o {scandir}/{protocol}_{port}_{http_scheme}_feroxbuster_dirbuster.txt'
|
||||
])
|
||||
elif self.get_option('tool') == 'gobuster':
|
||||
service.add_manual_command('(gobuster v3) Multi-threaded directory/file enumeration for web servers using various wordlists:', [
|
||||
'gobuster dir -u {http_scheme}://{addressv6}:{port}/ -t ' + str(self.get_option('threads')) + ' -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -e -k -x "' + self.get_option('ext') + '" -z -o "{scandir}/{protocol}_{port}_{http_scheme}_gobuster_dirbuster.txt"'
|
||||
])
|
||||
elif self.get_option('tool') == 'dirsearch':
|
||||
if service.target.ipversion == 'IPv4':
|
||||
service.add_manual_command('(dirsearch) Multi-threaded recursive directory/file enumeration for web servers using various wordlists:', [
|
||||
'dirsearch -u {http_scheme}://{address}:{port}/ -t ' + str(self.get_option('threads')) + ' -r -e "' + self.get_option('ext') + '" -f -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt --format=plain --output="{scandir}/{protocol}_{port}_{http_scheme}_dirsearch_dirbuster.txt"'
|
||||
])
|
||||
elif self.get_option('tool') == 'ffuf':
|
||||
service.add_manual_command('(ffuf) Multi-threaded recursive directory/file enumeration for web servers using various wordlists:', [
|
||||
'ffuf -u {http_scheme}://{addressv6}:{port}/FUZZ -t ' + str(self.get_option('threads')) + ' -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -e "' + dot_extensions + '" -v -noninteractive | tee {scandir}/{protocol}_{port}_{http_scheme}_ffuf_dirbuster.txt'
|
||||
])
|
||||
elif self.get_option('tool') == 'dirb':
|
||||
service.add_manual_command('(dirb) Recursive directory/file enumeration for web servers using various wordlists:', [
|
||||
'dirb {http_scheme}://{addressv6}:{port}/ /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -l -r -S -X ",' + dot_extensions + '" -o "{scandir}/{protocol}_{port}_{http_scheme}_dirb_dirbuster.txt"'
|
||||
])
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class DNSReverseLookup(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'DNS Reverse Lookup'
|
||||
self.tags = ['default', 'safe', 'dns']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^domain')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('dig -p {port} -x {address} @{address}', outfile='{protocol}_{port}_dns_reverse-lookup.txt')
|
|
@ -0,0 +1,18 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class DNSZoneTransfer(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'DNS Zone Transfer'
|
||||
self.tags = ['default', 'safe', 'dns']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^domain')
|
||||
|
||||
async def run(self, service):
|
||||
if self.get_global('domain'):
|
||||
await service.execute('dig AXFR -p {port} @{address} ' + self.get_global('domain'), outfile='{protocol}_{port}_dns_zone-transfer-domain.txt')
|
||||
if service.target.type == 'hostname':
|
||||
await service.execute('dig AXFR -p {port} @{address} {address}', outfile='{protocol}_{port}_dns_zone-transfer-hostname.txt')
|
||||
await service.execute('dig AXFR -p {port} @{address}', outfile='{protocol}_{port}_dns_zone-transfer.txt')
|
|
@ -1,143 +0,0 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
from shutil import which
|
||||
import os
|
||||
|
||||
class NmapDNS(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Nmap DNS'
|
||||
self.tags = ['default', 'safe', 'dns']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^domain')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(dns* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_dns_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_dns_nmap.xml" {address}')
|
||||
|
||||
class DNSZoneTransfer(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'DNS Zone Transfer'
|
||||
self.tags = ['default', 'safe', 'dns']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^domain')
|
||||
|
||||
async def run(self, service):
|
||||
if self.get_global('domain'):
|
||||
await service.execute('dig AXFR -p {port} @{address} ' + self.get_global('domain'), outfile='{protocol}_{port}_dns_zone-transfer-domain.txt')
|
||||
if service.target.type == 'hostname':
|
||||
await service.execute('dig AXFR -p {port} @{address} {address}', outfile='{protocol}_{port}_dns_zone-transfer-hostname.txt')
|
||||
await service.execute('dig AXFR -p {port} @{address}', outfile='{protocol}_{port}_dns_zone-transfer.txt')
|
||||
|
||||
class DNSReverseLookup(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'DNS Reverse Lookup'
|
||||
self.tags = ['default', 'safe', 'dns']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^domain')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('dig -p {port} -x {address} @{address}', outfile='{protocol}_{port}_dns_reverse-lookup.txt')
|
||||
|
||||
class NmapMulticastDNS(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Nmap Multicast DNS'
|
||||
self.tags = ['default', 'safe', 'dns']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^mdns', '^zeroconf'])
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(dns* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_multicastdns_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_multicastdns_nmap.xml" {address}')
|
||||
|
||||
|
||||
class DnsReconDefault(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "DnsRecon Default Scan"
|
||||
self.slug = 'dnsrecon'
|
||||
self.priority = 0
|
||||
self.tags = ['default', 'safe', 'dns']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^domain')
|
||||
|
||||
def check(self):
|
||||
if which('dnsrecon') is None:
|
||||
self.error('The program dnsrecon could not be found. Make sure it is installed. (On Kali, run: sudo apt install dnsrecon)')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
service.add_manual_command('Use dnsrecon to automatically query data from the DNS server. You must specify the target domain name.', [
|
||||
'dnsrecon -n {address} -d <DOMAIN-NAME> 2>&1 | tee {scandir}/{protocol}_{port}_dnsrecon_default_manual.txt'
|
||||
])
|
||||
|
||||
async def run(self, service):
|
||||
if self.get_global('domain'):
|
||||
await service.execute('dnsrecon -n {address} -d ' + self.get_global('domain') + ' 2>&1', outfile='{protocol}_{port}_dnsrecon_default.txt')
|
||||
else:
|
||||
service.error('A domain name was not specified in the command line options (--global.domain). If you know the domain name, look in the _manual_commands.txt file for the dnsrecon command.')
|
||||
|
||||
class DnsReconSubdomainBruteforce(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "DnsRecon Bruteforce Subdomains"
|
||||
self.slug = 'dnsrecon-brute'
|
||||
self.priority = 0
|
||||
self.tags = ['default', 'safe', 'long', 'dns']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^domain')
|
||||
|
||||
def check(self):
|
||||
if which('dnsrecon') is None:
|
||||
self.error('The program dnsrecon could not be found. Make sure it is installed. (On Kali, run: sudo apt install dnsrecon)')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
domain_name = '<DOMAIN-NAME>'
|
||||
if self.get_global('domain'):
|
||||
domain_name = self.get_global('domain')
|
||||
service.add_manual_command('Use dnsrecon to bruteforce subdomains of a DNS domain.', [
|
||||
'dnsrecon -n {address} -d ' + domain_name + ' -D /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -t brt 2>&1 | tee {scandir}/{protocol}_{port}_dnsrecon_subdomain_bruteforce.txt',
|
||||
])
|
||||
|
||||
class SubdomainEnumeration(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Subdomain Enumeration"
|
||||
self.slug = "subdomain-enum"
|
||||
self.tags = ['default', 'safe', 'long', 'dns']
|
||||
|
||||
def configure(self):
|
||||
self.add_option('domain', help='The domain to use as the base domain (e.g. example.com) for subdomain enumeration. Default: %(default)s')
|
||||
self.add_list_option('wordlist', default=['/usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt'], help='The wordlist(s) to use when enumerating subdomains. Separate multiple wordlists with spaces. Default: %(default)s')
|
||||
self.add_option('threads', default=10, help='The number of threads to use when enumerating subdomains. Default: %(default)s')
|
||||
self.match_service_name('^domain')
|
||||
|
||||
async def run(self, service):
|
||||
domains = []
|
||||
|
||||
if self.get_option('domain'):
|
||||
domains.append(self.get_option('domain'))
|
||||
if service.target.type == 'hostname' and service.target.address not in domains:
|
||||
domains.append(service.target.address)
|
||||
if self.get_global('domain') and self.get_global('domain') not in domains:
|
||||
domains.append(self.get_global('domain'))
|
||||
|
||||
if len(domains) > 0:
|
||||
for wordlist in self.get_option('wordlist'):
|
||||
name = os.path.splitext(os.path.basename(wordlist))[0]
|
||||
for domain in domains:
|
||||
await service.execute('gobuster dns -d ' + domain + ' -r {addressv6} -w ' + wordlist + ' -o "{scandir}/{protocol}_{port}_' + domain + '_subdomains_' + name + '.txt"')
|
||||
else:
|
||||
service.info('The target was not a domain, nor was a domain provided as an option. Skipping subdomain enumeration.')
|
|
@ -0,0 +1,26 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
from shutil import which
|
||||
|
||||
class DnsReconSubdomainBruteforce(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "DnsRecon Bruteforce Subdomains"
|
||||
self.slug = 'dnsrecon-brute'
|
||||
self.priority = 0
|
||||
self.tags = ['default', 'safe', 'long', 'dns']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^domain')
|
||||
|
||||
def check(self):
|
||||
if which('dnsrecon') is None:
|
||||
self.error('The program dnsrecon could not be found. Make sure it is installed. (On Kali, run: sudo apt install dnsrecon)')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
domain_name = '<DOMAIN-NAME>'
|
||||
if self.get_global('domain'):
|
||||
domain_name = self.get_global('domain')
|
||||
service.add_manual_command('Use dnsrecon to bruteforce subdomains of a DNS domain.', [
|
||||
'dnsrecon -n {address} -d ' + domain_name + ' -D /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -t brt 2>&1 | tee {scandir}/{protocol}_{port}_dnsrecon_subdomain_bruteforce.txt',
|
||||
])
|
|
@ -0,0 +1,29 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
from shutil import which
|
||||
|
||||
class DnsRecon(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "DnsRecon Default Scan"
|
||||
self.slug = 'dnsrecon'
|
||||
self.priority = 0
|
||||
self.tags = ['default', 'safe', 'dns']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^domain')
|
||||
|
||||
def check(self):
|
||||
if which('dnsrecon') is None:
|
||||
self.error('The program dnsrecon could not be found. Make sure it is installed. (On Kali, run: sudo apt install dnsrecon)')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
service.add_manual_command('Use dnsrecon to automatically query data from the DNS server. You must specify the target domain name.', [
|
||||
'dnsrecon -n {address} -d <DOMAIN-NAME> 2>&1 | tee {scandir}/{protocol}_{port}_dnsrecon_default_manual.txt'
|
||||
])
|
||||
|
||||
async def run(self, service):
|
||||
if self.get_global('domain'):
|
||||
await service.execute('dnsrecon -n {address} -d ' + self.get_global('domain') + ' 2>&1', outfile='{protocol}_{port}_dnsrecon_default.txt')
|
||||
else:
|
||||
service.error('A domain name was not specified in the command line options (--global.domain). If you know the domain name, look in the _manual_commands.txt file for the dnsrecon command.')
|
|
@ -0,0 +1,18 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class Enum4Linux(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Enum4Linux"
|
||||
self.tags = ['default', 'safe', 'active-directory']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^ldap', '^smb', '^microsoft\-ds', '^netbios'])
|
||||
self.match_port('tcp', [139, 389, 445])
|
||||
self.match_port('udp', 137)
|
||||
self.run_once(True)
|
||||
|
||||
async def run(self, service):
|
||||
if service.target.ipversion == 'IPv4':
|
||||
await service.execute('enum4linux -a -M -l -d {address} 2>&1', outfile='enum4linux.txt')
|
|
@ -0,0 +1,16 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class GetArch(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'get-arch'
|
||||
self.tags = ['default', 'safe', 'rpc']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^msrpc'])
|
||||
self.match_port('tcp', 135)
|
||||
self.add_pattern(' is ((32|64)-bit)', description='Identified Architecture: {match1}')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('getArch.py -target {address}', outfile='{protocol}_{port}_rpc_architecture.txt')
|
|
@ -1,282 +0,0 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
from autorecon.io import fformat
|
||||
from autorecon.config import config
|
||||
from shutil import which
|
||||
import os
|
||||
|
||||
class NmapHTTP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap HTTP"
|
||||
self.tags = ['default', 'safe', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
self.add_pattern('Server: ([^\n]+)', description='Identified HTTP Server: {match1}')
|
||||
self.add_pattern('WebDAV is ENABLED', description='WebDAV is enabled')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(http* or ssl*) and not (brute or broadcast or dos or external or http-slowloris* or fuzzer)" -oN "{scandir}/{protocol}_{port}_{http_scheme}_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_{http_scheme}_nmap.xml" {address}')
|
||||
|
||||
class BruteforceHTTP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Bruteforce HTTP"
|
||||
self.tags = ['default', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
service.add_manual_commands('Credential bruteforcing commands (don\'t run these without modifying them):', [
|
||||
'hydra -L "' + 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') + '" -e nsr -s {port} -o "{scandir}/{protocol}_{port}_{http_scheme}_auth_hydra.txt" {http_scheme}-get://{addressv6}/path/to/auth/area',
|
||||
'medusa -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') + '" -e ns -n {port} -O "{scandir}/{protocol}_{port}_{http_scheme}_auth_medusa.txt" -M http -h {addressv6} -m DIR:/path/to/auth/area',
|
||||
'hydra -L "' + 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') + '" -e nsr -s {port} -o "{scandir}/{protocol}_{port}_{http_scheme}_form_hydra.txt" {http_scheme}-post-form://{addressv6}/path/to/login.php:"username=^USER^&password=^PASS^":"invalid-login-message"',
|
||||
'medusa -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') + '" -e ns -n {port} -O "{scandir}/{protocol}_{port}_{http_scheme}_form_medusa.txt" -M web-form -h {addressv6} -m FORM:/path/to/login.php -m FORM-DATA:"post?username=&password=" -m DENY-SIGNAL:"invalid login message"'
|
||||
])
|
||||
|
||||
class Curl(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Curl"
|
||||
self.tags = ['default', 'safe', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.add_option("path", default="/", help="The path on the web server to curl. Default: %(default)s")
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
self.add_pattern('(?i)powered[ -]by[^\n]+')
|
||||
|
||||
async def run(self, service):
|
||||
if service.protocol == 'tcp':
|
||||
await service.execute('curl -sSik {http_scheme}://{addressv6}:{port}' + self.get_option('path'), outfile='{protocol}_{port}_{http_scheme}_curl.html')
|
||||
|
||||
class CurlRobots(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Curl Robots"
|
||||
self.tags = ['default', 'safe', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
|
||||
async def run(self, service):
|
||||
if service.protocol == 'tcp':
|
||||
process, stdout, _ = await service.execute('curl -sSikf {http_scheme}://{addressv6}:{port}/robots.txt', future_outfile='{protocol}_{port}_{http_scheme}_curl-robots.txt')
|
||||
|
||||
lines = await stdout.readlines()
|
||||
|
||||
if process.returncode == 0 and lines:
|
||||
filename = fformat('{scandir}/{protocol}_{port}_{http_scheme}_curl-robots.txt')
|
||||
with open(filename, mode='wt', encoding='utf8') as robots:
|
||||
robots.write('\n'.join(lines))
|
||||
else:
|
||||
service.info('{bblue}[' + fformat('{tag}') + ']{rst} There did not appear to be a robots.txt file in the webroot (/).')
|
||||
|
||||
class CurlKnownSecurity(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Known Security"
|
||||
self.tags = ['default', 'safe', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
|
||||
async def run(self, service):
|
||||
if service.protocol == 'tcp':
|
||||
process, stdout, _ = await service.execute('curl -sSikf {http_scheme}://{addressv6}:{port}/.well-known/security.txt', future_outfile='{protocol}_{port}_{http_scheme}_known-security.txt')
|
||||
|
||||
lines = await stdout.readlines()
|
||||
|
||||
if process.returncode == 0 and lines:
|
||||
filename = fformat('{scandir}/{protocol}_{port}_{http_scheme}_known-security.txt')
|
||||
with open(filename, mode='wt', encoding='utf8') as robots:
|
||||
robots.write('\n'.join(lines))
|
||||
else:
|
||||
service.info('{bblue}[' + fformat('{tag}') + ']{rst} There did not appear to be a .well-known/security.txt file in the webroot (/).')
|
||||
|
||||
|
||||
class DirBuster(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Directory Buster"
|
||||
self.slug = 'dirbuster'
|
||||
self.priority = 0
|
||||
self.tags = ['default', 'safe', 'long', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.add_choice_option('tool', default='feroxbuster', choices=['feroxbuster', 'gobuster', 'dirsearch', 'ffuf', 'dirb'], help='The tool to use for directory busting. Default: %(default)s')
|
||||
self.add_list_option('wordlist', default=[os.path.join(config['config_dir'], 'wordlists', 'dirbuster.txt')], help='The wordlist(s) to use when directory busting. Separate multiple wordlists with spaces. Default: %(default)s')
|
||||
self.add_option('threads', default=10, help='The number of threads to use when directory busting. Default: %(default)s')
|
||||
self.add_option('ext', default='txt,html,php,asp,aspx,jsp', help='The extensions you wish to fuzz (no dot, comma separated). Default: %(default)s')
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
|
||||
def check(self):
|
||||
tool = self.get_option('tool')
|
||||
if tool == 'feroxbuster':
|
||||
if which('feroxbuster') is None:
|
||||
self.error('The feroxbuster program could not be found. Make sure it is installed. (On Kali, run: sudo apt install feroxbuster)')
|
||||
elif tool == 'gobuster':
|
||||
if which('gobuster') is None:
|
||||
self.error('The gobuster program could not be found. Make sure it is installed. (On Kali, run: sudo apt install gobuster)')
|
||||
elif tool == 'dirsearch':
|
||||
if which('dirsearch') is None:
|
||||
self.error('The dirsearch program could not be found. Make sure it is installed. (On Kali, run: sudo apt install dirsearch)')
|
||||
|
||||
async def run(self, service):
|
||||
dot_extensions = ','.join(['.' + x for x in self.get_option('ext').split(',')])
|
||||
for wordlist in self.get_option('wordlist'):
|
||||
name = os.path.splitext(os.path.basename(wordlist))[0]
|
||||
if self.get_option('tool') == 'feroxbuster':
|
||||
await service.execute('feroxbuster -u {http_scheme}://{addressv6}:{port}/ -t ' + str(self.get_option('threads')) + ' -w ' + wordlist + ' -x "' + self.get_option('ext') + '" -v -k -n -q -e -o "{scandir}/{protocol}_{port}_{http_scheme}_feroxbuster_' + name + '.txt"')
|
||||
elif self.get_option('tool') == 'gobuster':
|
||||
await service.execute('gobuster dir -u {http_scheme}://{addressv6}:{port}/ -t ' + str(self.get_option('threads')) + ' -w ' + wordlist + ' -e -k -x "' + self.get_option('ext') + '" -z -d -o "{scandir}/{protocol}_{port}_{http_scheme}_gobuster_' + name + '.txt"')
|
||||
elif self.get_option('tool') == 'dirsearch':
|
||||
if service.target.ipversion == 'IPv6':
|
||||
service.error('dirsearch does not support IPv6.')
|
||||
else:
|
||||
await service.execute('dirsearch -u {http_scheme}://{address}:{port}/ -t ' + str(self.get_option('threads')) + ' -e "' + self.get_option('ext') + '" -f -q -w ' + wordlist + ' --format=plain -o "{scandir}/{protocol}_{port}_{http_scheme}_dirsearch_' + name + '.txt"')
|
||||
elif self.get_option('tool') == 'ffuf':
|
||||
await service.execute('ffuf -u {http_scheme}://{addressv6}:{port}/FUZZ -t ' + str(self.get_option('threads')) + ' -w ' + wordlist + ' -e "' + dot_extensions + '" -v -noninteractive | tee {scandir}/{protocol}_{port}_{http_scheme}_ffuf_' + name + '.txt')
|
||||
elif self.get_option('tool') == 'dirb':
|
||||
await service.execute('dirb {http_scheme}://{addressv6}:{port}/ ' + wordlist + ' -l -r -S -X ",' + dot_extensions + '" -o "{scandir}/{protocol}_{port}_{http_scheme}_dirb_' + name + '.txt"')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
dot_extensions = ','.join(['.' + x for x in self.get_option('ext').split(',')])
|
||||
if self.get_option('tool') == 'feroxbuster':
|
||||
service.add_manual_command('(feroxbuster) Multi-threaded recursive directory/file enumeration for web servers using various wordlists:', [
|
||||
'feroxbuster -u {http_scheme}://{addressv6}:{port} -t ' + str(self.get_option('threads')) + ' -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x "' + self.get_option('ext') + '" -v -k -n -o {scandir}/{protocol}_{port}_{http_scheme}_feroxbuster_dirbuster.txt'
|
||||
])
|
||||
elif self.get_option('tool') == 'gobuster':
|
||||
service.add_manual_command('(gobuster v3) Multi-threaded directory/file enumeration for web servers using various wordlists:', [
|
||||
'gobuster dir -u {http_scheme}://{addressv6}:{port}/ -t ' + str(self.get_option('threads')) + ' -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -e -k -x "' + self.get_option('ext') + '" -z -o "{scandir}/{protocol}_{port}_{http_scheme}_gobuster_dirbuster.txt"'
|
||||
])
|
||||
elif self.get_option('tool') == 'dirsearch':
|
||||
if service.target.ipversion == 'IPv4':
|
||||
service.add_manual_command('(dirsearch) Multi-threaded recursive directory/file enumeration for web servers using various wordlists:', [
|
||||
'dirsearch -u {http_scheme}://{address}:{port}/ -t ' + str(self.get_option('threads')) + ' -r -e "' + self.get_option('ext') + '" -f -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt --format=plain --output="{scandir}/{protocol}_{port}_{http_scheme}_dirsearch_dirbuster.txt"'
|
||||
])
|
||||
elif self.get_option('tool') == 'ffuf':
|
||||
service.add_manual_command('(ffuf) Multi-threaded recursive directory/file enumeration for web servers using various wordlists:', [
|
||||
'ffuf -u {http_scheme}://{addressv6}:{port}/FUZZ -t ' + str(self.get_option('threads')) + ' -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -e "' + dot_extensions + '" -v -noninteractive | tee {scandir}/{protocol}_{port}_{http_scheme}_ffuf_dirbuster.txt'
|
||||
])
|
||||
elif self.get_option('tool') == 'dirb':
|
||||
service.add_manual_command('(dirb) Recursive directory/file enumeration for web servers using various wordlists:', [
|
||||
'dirb {http_scheme}://{addressv6}:{port}/ /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -l -r -S -X ",' + dot_extensions + '" -o "{scandir}/{protocol}_{port}_{http_scheme}_dirb_dirbuster.txt"'
|
||||
])
|
||||
|
||||
class Nikto(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'nikto'
|
||||
self.tags = ['default', 'safe', 'long', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
if service.target.ipversion == 'IPv4':
|
||||
service.add_manual_command('(nikto) old but generally reliable web server enumeration tool:', 'nikto -ask=no -h {http_scheme}://{address}:{port} 2>&1 | tee "{scandir}/{protocol}_{port}_{http_scheme}_nikto.txt"')
|
||||
|
||||
class VirtualHost(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Virtual Host Enumeration'
|
||||
self.slug = 'vhost-enum'
|
||||
self.tags = ['default', 'safe', 'http', 'long']
|
||||
|
||||
def configure(self):
|
||||
self.add_option('hostname', help='The hostname to use as the base host (e.g. example.com) for virtual host enumeration. Default: %(default)s')
|
||||
self.add_list_option('wordlist', default=['/usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt'], help='The wordlist(s) to use when enumerating virtual hosts. Separate multiple wordlists with spaces. Default: %(default)s')
|
||||
self.add_option('threads', default=10, help='The number of threads to use when enumerating virtual hosts. Default: %(default)s')
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
|
||||
def check(self):
|
||||
if which('gobuster') is None:
|
||||
self.error('The gobuster program could not be found. Make sure it is installed. (On Kali, run: sudo apt install gobuster)')
|
||||
|
||||
async def run(self, service):
|
||||
hostnames = []
|
||||
if self.get_option('hostname'):
|
||||
hostnames.append(self.get_option('hostname'))
|
||||
if service.target.type == 'hostname' and service.target.address not in hostnames:
|
||||
hostnames.append(service.target.address)
|
||||
if self.get_global('domain') and self.get_global('domain') not in hostnames:
|
||||
hostnames.append(self.get_global('domain'))
|
||||
|
||||
if len(hostnames) > 0:
|
||||
for wordlist in self.get_option('wordlist'):
|
||||
name = os.path.splitext(os.path.basename(wordlist))[0]
|
||||
for hostname in hostnames:
|
||||
await service.execute('gobuster vhost -k -u {http_scheme}://' + hostname + ':{port}/ -t ' + str(self.get_option('threads')) + ' -w ' + wordlist + ' -r -o "{scandir}/{protocol}_{port}_{http_scheme}_' + hostname + '_vhosts_' + name + '.txt"')
|
||||
else:
|
||||
service.info('The target was not a hostname, nor was a hostname provided as an option. Skipping virtual host enumeration.')
|
||||
|
||||
class WhatWeb(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "whatweb"
|
||||
self.tags = ['default', 'safe', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
|
||||
async def run(self, service):
|
||||
if service.protocol == 'tcp' and service.target.ipversion == 'IPv4':
|
||||
await service.execute('whatweb --color=never --no-errors -a 3 -v {http_scheme}://{address}:{port} 2>&1', outfile='{protocol}_{port}_{http_scheme}_whatweb.txt')
|
||||
|
||||
class WkHTMLToImage(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "wkhtmltoimage"
|
||||
self.tags = ['default', 'safe', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
|
||||
def check(self):
|
||||
if which('wkhtmltoimage') is None:
|
||||
self.error('The wkhtmltoimage program could not be found. Make sure it is installed. (On Kali, run: sudo apt install wkhtmltopdf)')
|
||||
|
||||
async def run(self, service):
|
||||
if which('wkhtmltoimage') is not None:
|
||||
if service.protocol == 'tcp':
|
||||
await service.execute('wkhtmltoimage --format png {http_scheme}://{addressv6}:{port}/ {scandir}/{protocol}_{port}_{http_scheme}_screenshot.png')
|
||||
|
||||
class WPScan(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'WPScan'
|
||||
self.tags = ['default', 'safe', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.add_option('api-token', help='An API Token from wpvulndb.com to help search for more vulnerabilities.')
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
api_token = ''
|
||||
if self.get_option('api-token'):
|
||||
api_token = ' --api-token ' + self.get_option('api-token')
|
||||
|
||||
service.add_manual_command('(wpscan) WordPress Security Scanner (useful if WordPress is found):', 'wpscan --url {http_scheme}://{addressv6}:{port}/ --no-update -e vp,vt,tt,cb,dbe,u,m --plugins-detection aggressive --plugins-version-detection aggressive -f cli-no-color' + api_token + ' 2>&1 | tee "{scandir}/{protocol}_{port}_{http_scheme}_wpscan.txt"')
|
|
@ -1,18 +1,5 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapLDAP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap LDAP"
|
||||
self.tags = ['default', 'safe', 'ldap', 'active-directory']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^ldap')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(ldap* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_ldap_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_ldap_nmap.xml" {address}')
|
||||
|
||||
class LDAPSearch(ServiceScan):
|
||||
|
||||
def __init__(self):
|
|
@ -0,0 +1,16 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class LookupSID(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'lookupsid'
|
||||
self.tags = ['default', 'safe', 'active-directory']
|
||||
|
||||
def configure(self):
|
||||
self.match_service('tcp', 445, '^microsoft\-ds')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
service.add_manual_command('Lookup SIDs', [
|
||||
'lookupsid.py [username]:[password]@{address}'
|
||||
])
|
|
@ -1,201 +0,0 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
from autorecon.io import fformat
|
||||
|
||||
class NmapCassandra(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap Cassandra"
|
||||
self.tags = ['default', 'safe', 'cassandra']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^apani1')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(cassandra* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_cassandra_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_cassandra_nmap.xml" {address}')
|
||||
|
||||
class NmapCUPS(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap CUPS"
|
||||
self.tags = ['default', 'safe', 'cups']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^ipp')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(cups* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_cups_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_cups_nmap.xml" {address}')
|
||||
|
||||
class NmapDistccd(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap distccd"
|
||||
self.tags = ['default', 'safe', 'distccd']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^distccd')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,distcc-cve2004-2687" --script-args="distcc-cve2004-2687.cmd=id" -oN "{scandir}/{protocol}_{port}_distcc_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_distcc_nmap.xml" {address}')
|
||||
|
||||
class NmapFinger(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap finger"
|
||||
self.tags = ['default', 'safe', 'finger']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^finger')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,finger" -oN "{scandir}/{protocol}_{port}_finger_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_finger_nmap.xml" {address}')
|
||||
|
||||
class NmapIMAP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap IMAP"
|
||||
self.tags = ['default', 'safe', 'imap', 'email']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^imap')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(imap* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_imap_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_imap_nmap.xml" {address}')
|
||||
|
||||
class NmapIrc(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Nmap IRC'
|
||||
self.tags = ['default', 'safe', 'irc']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^irc')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV --script irc-botnet-channels,irc-info,irc-unrealircd-backdoor -oN "{scandir}/{protocol}_{port}_irc_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_irc_nmap.xml" -p {port} {address}')
|
||||
|
||||
class NmapNNTP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap NNTP"
|
||||
self.tags = ['default', 'safe', 'nntp']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^nntp')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,nntp-ntlm-info" -oN "{scandir}/{protocol}_{port}_nntp_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_nntp_nmap.xml" {address}')
|
||||
|
||||
class NmapNTP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap NTP"
|
||||
self.tags = ['default', 'safe', 'ntp']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^ntp')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(ntp* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_ntp_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_ntp_nmap.xml" {address}')
|
||||
|
||||
class NmapPOP3(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap POP3"
|
||||
self.tags = ['default', 'safe', 'pop3', 'email']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^pop3')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(pop3* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_pop3_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_pop3_nmap.xml" {address}')
|
||||
|
||||
class NmapRMI(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap RMI"
|
||||
self.tags = ['default', 'safe', 'rmi']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^java\-rmi', '^rmiregistry'])
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,rmi-vuln-classloader,rmi-dumpregistry" -oN "{scandir}/{protocol}_{port}_rmi_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_rmi_nmap.xml" {address}')
|
||||
|
||||
class NmapTelnet(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Nmap Telnet'
|
||||
self.tags = ['default', 'safe', 'telnet']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^telnet')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,telnet-encryption,telnet-ntlm-info" -oN "{scandir}/{protocol}_{port}_telnet-nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_telnet_nmap.xml" {address}')
|
||||
|
||||
class NmapTFTP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Nmap TFTP'
|
||||
self.tags = ['default', 'safe', 'tftp']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^tftp')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,tftp-enum" -oN "{scandir}/{protocol}_{port}_tftp-nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_tftp_nmap.xml" {address}')
|
||||
|
||||
class NmapVNC(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Nmap VNC'
|
||||
self.tags = ['default', 'safe', 'vnc']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^vnc')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(vnc* or realvnc* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" --script-args="unsafe=1" -oN "{scandir}/{protocol}_{port}_vnc_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_vnc_nmap.xml" {address}')
|
||||
|
||||
class WinRMDetection(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'WinRM Detection'
|
||||
self.tags = ['default', 'safe', 'winrm']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^wsman')
|
||||
self.match_service('tcp', [5985, 5986], '^http')
|
||||
|
||||
async def run(self, service):
|
||||
filename = fformat('{scandir}/{protocol}_{port}_winrm-detection.txt')
|
||||
with open(filename, mode='wt', encoding='utf8') as winrm:
|
||||
winrm.write('WinRM was possibly detected running on ' + service.protocol + ' port ' + str(service.port) + '.\nCheck _manual_commands.txt for manual commands you can run against this service.')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
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')
|
||||
])
|
||||
|
||||
service.add_manual_commands('Check login (requires credentials):', [
|
||||
'crackmapexec winrm {address} -d ' + self.get_global('domain', default='<domain>') + ' -u <username> -p <password> -x "whoami"'
|
||||
])
|
||||
|
||||
service.add_manual_commands('Evil WinRM (gem install evil-winrm):', [
|
||||
'evil-winrm -u <user> -p <password> -i {address}',
|
||||
'evil-winrm -u <user> -H <hash> -i {address}'
|
||||
])
|
|
@ -0,0 +1,17 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NBTScan(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'nbtscan'
|
||||
self.tags = ['default', 'safe', 'netbios', 'active-directory']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^smb', '^microsoft\-ds', '^netbios'])
|
||||
self.match_port('udp', 137)
|
||||
self.run_once(True)
|
||||
|
||||
async def run(self, service):
|
||||
if service.target.ipversion == 'IPv4':
|
||||
await service.execute('nbtscan -rvh {address} 2>&1', outfile='nbtscan.txt')
|
|
@ -1,40 +0,0 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapNFS(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap NFS"
|
||||
self.tags = ['default', 'safe', 'nfs']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^nfs', '^rpcbind'])
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(rpcinfo or nfs*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_nfs_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_nfs_nmap.xml" {address}')
|
||||
|
||||
class Showmount(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "showmount"
|
||||
self.tags = ['default', 'safe', 'nfs']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^nfs', '^rpcbind'])
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('showmount -e {address} 2>&1', outfile='{protocol}_{port}_showmount.txt')
|
||||
|
||||
class NmapMountd(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap Mountd"
|
||||
self.tags = ['default', 'safe', 'nfs']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^mountd')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,nfs* and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_mountd_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_mountd_nmap.xml" {address}')
|
|
@ -0,0 +1,16 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class Nikto(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'nikto'
|
||||
self.tags = ['default', 'safe', 'long', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
if service.target.ipversion == 'IPv4':
|
||||
service.add_manual_command('(nikto) old but generally reliable web server enumeration tool:', 'nikto -ask=no -h {http_scheme}://{address}:{port} 2>&1 | tee "{scandir}/{protocol}_{port}_{http_scheme}_nikto.txt"')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapCassandra(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap Cassandra"
|
||||
self.tags = ['default', 'safe', 'cassandra']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^apani1')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(cassandra* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_cassandra_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_cassandra_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapCUPS(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap CUPS"
|
||||
self.tags = ['default', 'safe', 'cups']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^ipp')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(cups* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_cups_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_cups_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapDistccd(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap distccd"
|
||||
self.tags = ['default', 'safe', 'distccd']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^distccd')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,distcc-cve2004-2687" --script-args="distcc-cve2004-2687.cmd=id" -oN "{scandir}/{protocol}_{port}_distcc_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_distcc_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapDNS(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Nmap DNS'
|
||||
self.tags = ['default', 'safe', 'dns']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^domain')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(dns* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_dns_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_dns_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapFinger(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap finger"
|
||||
self.tags = ['default', 'safe', 'finger']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^finger')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,finger" -oN "{scandir}/{protocol}_{port}_finger_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_finger_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapFTP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Nmap FTP'
|
||||
self.tags = ['default', 'safe', 'ftp']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^ftp', '^ftp\-data'])
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(ftp* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_ftp_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_ftp_nmap.xml" {address}')
|
|
@ -0,0 +1,17 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapHTTP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap HTTP"
|
||||
self.tags = ['default', 'safe', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
self.add_pattern('Server: ([^\n]+)', description='Identified HTTP Server: {match1}')
|
||||
self.add_pattern('WebDAV is ENABLED', description='WebDAV is enabled')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(http* or ssl*) and not (brute or broadcast or dos or external or http-slowloris* or fuzzer)" -oN "{scandir}/{protocol}_{port}_{http_scheme}_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_{http_scheme}_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapIMAP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap IMAP"
|
||||
self.tags = ['default', 'safe', 'imap', 'email']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^imap')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(imap* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_imap_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_imap_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapIrc(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Nmap IRC'
|
||||
self.tags = ['default', 'safe', 'irc']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^irc')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV --script irc-botnet-channels,irc-info,irc-unrealircd-backdoor -oN "{scandir}/{protocol}_{port}_irc_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_irc_nmap.xml" -p {port} {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapLDAP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap LDAP"
|
||||
self.tags = ['default', 'safe', 'ldap', 'active-directory']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^ldap')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(ldap* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_ldap_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_ldap_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapMongoDB(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap MongoDB"
|
||||
self.tags = ['default', 'safe', 'databases']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^mongod')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(mongodb* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_mongodb_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_mongodb_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapMountd(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap Mountd"
|
||||
self.tags = ['default', 'safe', 'nfs']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^mountd')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,nfs* and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_mountd_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_mountd_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapRPC(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap MSRPC"
|
||||
self.tags = ['default', 'rpc']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^msrpc', '^rpcbind', '^erpc'])
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,msrpc-enum,rpc-grind,rpcinfo" -oN "{scandir}/{protocol}_{port}_rpc_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_rpc_nmap.xml" {address}')
|
|
@ -0,0 +1,18 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapMSSQL(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap MSSQL"
|
||||
self.tags = ['default', 'safe', 'databases']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^mssql', '^ms\-sql'])
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
if service.target.ipversion == 'IPv4':
|
||||
service.add_manual_command('(sqsh) interactive database shell:', 'sqsh -U <username> -P <password> -S {address}:{port}')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(ms-sql* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" --script-args="mssql.instance-port={port},mssql.username=sa,mssql.password=sa" -oN "{scandir}/{protocol}_{port}_mssql_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_mssql_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapMulticastDNS(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Nmap Multicast DNS'
|
||||
self.tags = ['default', 'safe', 'dns']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^mdns', '^zeroconf'])
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(dns* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_multicastdns_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_multicastdns_nmap.xml" {address}')
|
|
@ -0,0 +1,18 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapMYSQL(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap MYSQL"
|
||||
self.tags = ['default', 'safe', 'databases']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^mysql')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
if service.target.ipversion == 'IPv4':
|
||||
service.add_manual_command('(sqsh) interactive database shell:', 'sqsh -U <username> -P <password> -S {address}:{port}')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(mysql* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_mysql_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_mysql_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapNFS(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap NFS"
|
||||
self.tags = ['default', 'safe', 'nfs']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^nfs', '^rpcbind'])
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(rpcinfo or nfs*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_nfs_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_nfs_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapNNTP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap NNTP"
|
||||
self.tags = ['default', 'safe', 'nntp']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^nntp')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,nntp-ntlm-info" -oN "{scandir}/{protocol}_{port}_nntp_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_nntp_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapNTP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap NTP"
|
||||
self.tags = ['default', 'safe', 'ntp']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^ntp')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(ntp* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_ntp_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_ntp_nmap.xml" {address}')
|
|
@ -0,0 +1,17 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapOracle(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap Oracle"
|
||||
self.tags = ['default', 'safe', 'databases']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^oracle')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
service.add_manual_command('Brute-force SIDs using Nmap:', 'nmap {nmap_extra} -sV -p {port} --script="banner,oracle-sid-brute" -oN "{scandir}/{protocol}_{port}_oracle_sid-brute_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_oracle_sid-brute_nmap.xml" {address}')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(oracle* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_oracle_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_oracle_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapPOP3(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap POP3"
|
||||
self.tags = ['default', 'safe', 'pop3', 'email']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^pop3')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(pop3* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_pop3_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_pop3_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapRDP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap RDP"
|
||||
self.tags = ['default', 'safe', 'rdp']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^rdp', '^ms\-wbt\-server', '^ms\-term\-serv'])
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(rdp* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_rdp_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_rdp_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapRedis(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Nmap Redis'
|
||||
self.tags = ['default', 'safe', 'redis']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^redis$')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,redis-info" -oN "{scandir}/{protocol}_{port}_redis_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_redis_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapRMI(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap RMI"
|
||||
self.tags = ['default', 'safe', 'rmi']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^java\-rmi', '^rmiregistry'])
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,rmi-vuln-classloader,rmi-dumpregistry" -oN "{scandir}/{protocol}_{port}_rmi_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_rmi_nmap.xml" {address}')
|
|
@ -12,16 +12,3 @@ class NmapRsync(ServiceScan):
|
|||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(rsync* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_rsync_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_rsync_nmap.xml" {address}')
|
||||
|
||||
class RsyncList(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Rsync List Files'
|
||||
self.tags = ['default', 'safe', 'rsync']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^rsync')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('rsync -av --list-only rsync://{addressv6}:{port}', outfile='{protocol}_{port}_rsync_file_list.txt')
|
|
@ -12,17 +12,3 @@ class NmapSIP(ServiceScan):
|
|||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,sip-enum-users,sip-methods" -oN "{scandir}/{protocol}_{port}_sip_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_sip_nmap.xml" {address}')
|
||||
|
||||
class SIPVicious(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "SIPVicious"
|
||||
self.tags = ['default', 'safe', 'sip']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^asterisk', '^sip'])
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
if service.target.ipversion == 'IPv4':
|
||||
service.add_manual_command('svwar:', 'svwar -D -m INVITE -p {port} {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapSMB(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap SMB"
|
||||
self.tags = ['default', 'safe', 'smb', 'active-directory']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^smb', '^microsoft\-ds', '^netbios'])
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(nbstat or smb* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_smb_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_smb_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapSMTP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap SMTP"
|
||||
self.tags = ['default', 'safe', 'smtp', 'email']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^smtp')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(smtp* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_smtp_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_smtp_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapSNMP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap SNMP"
|
||||
self.tags = ['default', 'safe', 'snmp']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^snmp')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(snmp* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_snmp-nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_snmp_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapSSH(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap SSH"
|
||||
self.tags = ['default', 'safe', 'ssh']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^ssh')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,ssh2-enum-algos,ssh-hostkey,ssh-auth-methods" -oN "{scandir}/{protocol}_{port}_ssh_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_ssh_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapTelnet(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Nmap Telnet'
|
||||
self.tags = ['default', 'safe', 'telnet']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^telnet')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,telnet-encryption,telnet-ntlm-info" -oN "{scandir}/{protocol}_{port}_telnet-nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_telnet_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapTFTP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Nmap TFTP'
|
||||
self.tags = ['default', 'safe', 'tftp']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^tftp')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,tftp-enum" -oN "{scandir}/{protocol}_{port}_tftp-nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_tftp_nmap.xml" {address}')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapVNC(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Nmap VNC'
|
||||
self.tags = ['default', 'safe', 'vnc']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^vnc')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(vnc* or realvnc* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" --script-args="unsafe=1" -oN "{scandir}/{protocol}_{port}_vnc_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_vnc_nmap.xml" {address}')
|
|
@ -0,0 +1,18 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class OneSixtyOne(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "OneSixtyOne"
|
||||
self.tags = ['default', 'safe', 'snmp']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^snmp')
|
||||
self.match_port('udp', 161)
|
||||
self.run_once(True)
|
||||
self.add_option('community-strings', default='/usr/share/seclists/Discovery/SNMP/common-snmp-community-strings-onesixtyone.txt', help='The file containing a list of community strings to try. Default: %(default)s')
|
||||
|
||||
async def run(self, service):
|
||||
if service.target.ipversion == 'IPv4':
|
||||
await service.execute('onesixtyone -c ' + service.get_option('community-strings') + ' -dd {address} 2>&1', outfile='{protocol}_{port}_snmp_onesixtyone.txt')
|
|
@ -0,0 +1,21 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class OracleODAT(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Oracle ODAT"
|
||||
self.tags = ['default', 'safe', 'databases']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^oracle')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
service.add_manual_commands('Install ODAT (https://github.com/quentinhardy/odat) and run the following commands:', [
|
||||
'python odat.py tnscmd -s {address} -p {port} --ping',
|
||||
'python odat.py tnscmd -s {address} -p {port} --version',
|
||||
'python odat.py tnscmd -s {address} -p {port} --status',
|
||||
'python odat.py sidguesser -s {address} -p {port}',
|
||||
'python odat.py passwordguesser -s {address} -p {port} -d <sid> --accounts-file accounts/accounts_multiple.txt',
|
||||
'python odat.py tnspoison -s {address} -p {port} -d <sid> --test-module'
|
||||
])
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class OraclePatator(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Oracle Patator"
|
||||
self.tags = ['default', 'databases']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^oracle')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
service.add_manual_command('Install Oracle Instant Client (https://github.com/rapid7/metasploit-framework/wiki/How-to-get-Oracle-Support-working-with-Kali-Linux) and then bruteforce with patator:', 'patator oracle_login host={address} port={port} user=COMBO00 password=COMBO01 0=/usr/share/seclists/Passwords/Default-Credentials/oracle-betterdefaultpasslist.txt -x ignore:code=ORA-01017 -x ignore:code=ORA-28000')
|
|
@ -0,0 +1,19 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
from shutil import which
|
||||
|
||||
class OracleScanner(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Oracle Scanner"
|
||||
self.tags = ['default', 'safe', 'databases']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^oracle')
|
||||
|
||||
def check(self):
|
||||
if which('oscanner') is None:
|
||||
self.error('The oscanner program could not be found. Make sure it is installed. (On Kali, run: sudo apt install oscanner)')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('oscanner -v -s {address} -P {port} 2>&1', outfile='{protocol}_{port}_oracle_scanner.txt')
|
|
@ -0,0 +1,21 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
from shutil import which
|
||||
|
||||
class OracleTNScmd(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Oracle TNScmd"
|
||||
self.tags = ['default', 'safe', 'databases']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^oracle')
|
||||
|
||||
def check(self):
|
||||
if which('tnscmd10g') is None:
|
||||
self.error('The tnscmd10g program could not be found. Make sure it is installed. (On Kali, run: sudo apt install tnscmd10g)')
|
||||
|
||||
async def run(self, service):
|
||||
if service.target.ipversion == 'IPv4':
|
||||
await service.execute('tnscmd10g ping -h {address} -p {port} 2>&1', outfile='{protocol}_{port}_oracle_tnscmd_ping.txt')
|
||||
await service.execute('tnscmd10g version -h {address} -p {port} 2>&1', outfile='{protocol}_{port}_oracle_tnscmd_version.txt')
|
|
@ -0,0 +1,41 @@
|
|||
from autorecon.plugins import PortScan
|
||||
from autorecon.config import config
|
||||
import re
|
||||
|
||||
class AllTCPPortScan(PortScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'All TCP Ports'
|
||||
self.description = 'Performs an Nmap scan of all TCP ports.'
|
||||
self.type = 'tcp'
|
||||
self.specific_ports = True
|
||||
self.tags = ['default', 'default-port-scan', 'long']
|
||||
|
||||
async def run(self, target):
|
||||
if config['proxychains']:
|
||||
traceroute_os = ''
|
||||
else:
|
||||
traceroute_os = ' -A --osscan-guess'
|
||||
|
||||
if target.ports:
|
||||
if target.ports['tcp']:
|
||||
process, stdout, stderr = await target.execute('nmap {nmap_extra} -sV -sC --version-all' + traceroute_os + ' -p ' + target.ports['tcp'] + ' -oN "{scandir}/_full_tcp_nmap.txt" -oX "{scandir}/xml/_full_tcp_nmap.xml" {address}', blocking=False)
|
||||
else:
|
||||
return []
|
||||
else:
|
||||
process, stdout, stderr = await target.execute('nmap {nmap_extra} -sV -sC --version-all' + traceroute_os + ' -p- -oN "{scandir}/_full_tcp_nmap.txt" -oX "{scandir}/xml/_full_tcp_nmap.xml" {address}', blocking=False)
|
||||
services = []
|
||||
while True:
|
||||
line = await stdout.readline()
|
||||
if line is not None:
|
||||
match = re.search('^Discovered open port ([0-9]+)/tcp', line)
|
||||
if match:
|
||||
target.info('Discovered open port {bmagenta}tcp/' + match.group(1) + '{rst} on {byellow}' + target.address + '{rst}', verbosity=1)
|
||||
service = target.extract_service(line)
|
||||
if service:
|
||||
services.append(service)
|
||||
else:
|
||||
break
|
||||
await process.wait()
|
||||
return services
|
|
@ -0,0 +1,40 @@
|
|||
from autorecon.plugins import PortScan
|
||||
from autorecon.config import config
|
||||
import os, re
|
||||
|
||||
class Top100UDPPortScan(PortScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Top 100 UDP Ports'
|
||||
self.description = 'Performs an Nmap scan of the top 100 UDP ports.'
|
||||
self.type = 'udp'
|
||||
self.specific_ports = True
|
||||
self.tags = ['default', 'default-port-scan', 'long']
|
||||
|
||||
async def run(self, target):
|
||||
# Only run UDP scan if user is root.
|
||||
if os.getuid() == 0:
|
||||
if target.ports:
|
||||
if target.ports['udp']:
|
||||
process, stdout, stderr = await target.execute('nmap {nmap_extra} -sU -A --osscan-guess -p ' + target.ports['udp'] + ' -oN "{scandir}/_custom_ports_udp_nmap.txt" -oX "{scandir}/xml/_custom_ports_udp_nmap.xml" {address}', blocking=False)
|
||||
else:
|
||||
return []
|
||||
else:
|
||||
process, stdout, stderr = await target.execute('nmap {nmap_extra} -sU -A --top-ports 100 -oN "{scandir}/_top_100_udp_nmap.txt" -oX "{scandir}/xml/_top_100_udp_nmap.xml" {address}', blocking=False)
|
||||
services = []
|
||||
while True:
|
||||
line = await stdout.readline()
|
||||
if line is not None:
|
||||
match = re.search('^Discovered open port ([0-9]+)/udp', line)
|
||||
if match:
|
||||
target.info('Discovered open port {bmagenta}udp/' + match.group(1) + '{rst} on {byellow}' + target.address + '{rst}', verbosity=1)
|
||||
service = target.extract_service(line)
|
||||
if service:
|
||||
services.append(service)
|
||||
else:
|
||||
break
|
||||
await process.wait()
|
||||
return services
|
||||
else:
|
||||
target.error('UDP scan requires AutoRecon be run with root privileges.')
|
|
@ -0,0 +1,26 @@
|
|||
from autorecon.plugins import PortScan
|
||||
from autorecon.config import config
|
||||
|
||||
class QuickTCPPortScan(PortScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Top TCP Ports'
|
||||
self.description = 'Performs an Nmap scan of the top 1000 TCP ports.'
|
||||
self.type = 'tcp'
|
||||
self.tags = ['default', 'default-port-scan']
|
||||
self.priority = 0
|
||||
|
||||
async def run(self, target):
|
||||
if target.ports: # Don't run this plugin if there are custom ports.
|
||||
return []
|
||||
|
||||
if config['proxychains']:
|
||||
traceroute_os = ''
|
||||
else:
|
||||
traceroute_os = ' -A --osscan-guess'
|
||||
|
||||
process, stdout, stderr = await target.execute('nmap {nmap_extra} -sV -sC --version-all' + traceroute_os + ' -oN "{scandir}/_quick_tcp_nmap.txt" -oX "{scandir}/xml/_quick_tcp_nmap.xml" {address}', blocking=False)
|
||||
services = await target.extract_services(stdout)
|
||||
await process.wait()
|
||||
return services
|
|
@ -1,19 +1,6 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
from shutil import which
|
||||
|
||||
class NmapRedis(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Nmap Redis'
|
||||
self.tags = ['default', 'safe', 'redis']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^redis$')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,redis-info" -oN "{scandir}/{protocol}_{port}_redis_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_redis_nmap.xml" {address}')
|
||||
|
||||
class RedisCli(ServiceScan):
|
||||
|
||||
def __init__(self):
|
|
@ -89,75 +89,3 @@ class CherryTree(Report):
|
|||
output.writelines('</node>\n')
|
||||
|
||||
output.writelines('</cherrytree>')
|
||||
|
||||
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['output'], '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```')
|
|
@ -0,0 +1,75 @@
|
|||
from autorecon.plugins import Report
|
||||
from autorecon.config import config
|
||||
import os, glob
|
||||
|
||||
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['output'], '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```')
|
|
@ -1,57 +0,0 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapRPC(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap MSRPC"
|
||||
self.tags = ['default', 'rpc']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^msrpc', '^rpcbind', '^erpc'])
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,msrpc-enum,rpc-grind,rpcinfo" -oN "{scandir}/{protocol}_{port}_rpc_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_rpc_nmap.xml" {address}')
|
||||
|
||||
class RPCClient(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "rpcclient"
|
||||
self.tags = ['default', 'safe', 'rpc']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^msrpc', '^rpcbind', '^erpc'])
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
service.add_manual_command('RPC Client:', 'rpcclient -p {port} -U "" {address}')
|
||||
|
||||
class RPCDump(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'rpcdump'
|
||||
self.tags = ['default', 'safe', 'rpc']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^msrpc', '^rpcbind', '^erpc', '^ncacn_http$'])
|
||||
self.match_port('tcp', [135, 139, 443, 445, 593])
|
||||
|
||||
async def run(self, service):
|
||||
if service.protocol == 'tcp':
|
||||
await service.execute('impacket-rpcdump -port {port} {address}', outfile='{protocol}_{port}_rpc_rpcdump.txt')
|
||||
|
||||
class GetArch(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'get-arch'
|
||||
self.tags = ['default', 'safe', 'rpc']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^msrpc'])
|
||||
self.match_port('tcp', 135)
|
||||
self.add_pattern(' is ((32|64)-bit)', description='Identified Architecture: {match1}')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('getArch.py -target {address}', outfile='{protocol}_{port}_rpc_architecture.txt')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class RPCClient(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "rpcclient"
|
||||
self.tags = ['default', 'safe', 'rpc']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^msrpc', '^rpcbind', '^erpc'])
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
service.add_manual_command('RPC Client:', 'rpcclient -p {port} -U "" {address}')
|
|
@ -0,0 +1,16 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class RPCDump(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'rpcdump'
|
||||
self.tags = ['default', 'safe', 'rpc']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^msrpc', '^rpcbind', '^erpc', '^ncacn_http$'])
|
||||
self.match_port('tcp', [135, 139, 443, 445, 593])
|
||||
|
||||
async def run(self, service):
|
||||
if service.protocol == 'tcp':
|
||||
await service.execute('impacket-rpcdump -port {port} {address}', outfile='{protocol}_{port}_rpc_rpcdump.txt')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class RsyncList(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Rsync List Files'
|
||||
self.tags = ['default', 'safe', 'rsync']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^rsync')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('rsync -av --list-only rsync://{addressv6}:{port}', outfile='{protocol}_{port}_rsync_file_list.txt')
|
|
@ -0,0 +1,14 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class Showmount(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "showmount"
|
||||
self.tags = ['default', 'safe', 'nfs']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^nfs', '^rpcbind'])
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('showmount -e {address} 2>&1', outfile='{protocol}_{port}_showmount.txt')
|
|
@ -0,0 +1,15 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class SIPVicious(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "SIPVicious"
|
||||
self.tags = ['default', 'safe', 'sip']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^asterisk', '^sip'])
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
if service.target.ipversion == 'IPv4':
|
||||
service.add_manual_command('svwar:', 'svwar -D -m INVITE -p {port} {address}')
|
|
@ -0,0 +1,24 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class SMBVuln(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "SMB Vulnerabilities"
|
||||
self.tags = ['unsafe', 'smb', 'active-directory']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^smb', '^microsoft\-ds', '^netbios'])
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="smb-vuln-ms06-025" --script-args="unsafe=1" -oN "{scandir}/{protocol}_{port}_smb_ms06-025.txt" -oX "{scandir}/xml/{protocol}_{port}_smb_ms06-025.xml" {address}')
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="smb-vuln-ms07-029" --script-args="unsafe=1" -oN "{scandir}/{protocol}_{port}_smb_ms07-029.txt" -oX "{scandir}/xml/{protocol}_{port}_smb_ms07-029.xml" {address}')
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="smb-vuln-ms08-067" --script-args="unsafe=1" -oN "{scandir}/{protocol}_{port}_smb_ms08-067.txt" -oX "{scandir}/xml/{protocol}_{port}_smb_ms08-067.xml" {address}')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
if not plugin_was_run: # Only suggest these if they weren't run.
|
||||
service.add_manual_commands('Nmap scans for SMB vulnerabilities that could potentially cause a DoS if scanned (according to Nmap). Be careful:', [
|
||||
'nmap {nmap_extra} -sV -p {port} --script="smb-vuln-ms06-025" --script-args="unsafe=1" -oN "{scandir}/{protocol}_{port}_smb_ms06-025.txt" -oX "{scandir}/xml/{protocol}_{port}_smb_ms06-025.xml" {address}',
|
||||
'nmap {nmap_extra} -sV -p {port} --script="smb-vuln-ms07-029" --script-args="unsafe=1" -oN "{scandir}/{protocol}_{port}_smb_ms07-029.txt" -oX "{scandir}/xml/{protocol}_{port}_smb_ms07-029.xml" {address}',
|
||||
'nmap {nmap_extra} -sV -p {port} --script="smb-vuln-ms08-067" --script-args="unsafe=1" -oN "{scandir}/{protocol}_{port}_smb_ms08-067.txt" -oX "{scandir}/xml/{protocol}_{port}_smb_ms08-067.xml" {address}'
|
||||
])
|
|
@ -1,119 +0,0 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapSMB(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap SMB"
|
||||
self.tags = ['default', 'safe', 'smb', 'active-directory']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^smb', '^microsoft\-ds', '^netbios'])
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(nbstat or smb* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_smb_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_smb_nmap.xml" {address}')
|
||||
|
||||
class SMBVuln(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "SMB Vulnerabilities"
|
||||
self.tags = ['unsafe', 'smb', 'active-directory']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^smb', '^microsoft\-ds', '^netbios'])
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="smb-vuln-ms06-025" --script-args="unsafe=1" -oN "{scandir}/{protocol}_{port}_smb_ms06-025.txt" -oX "{scandir}/xml/{protocol}_{port}_smb_ms06-025.xml" {address}')
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="smb-vuln-ms07-029" --script-args="unsafe=1" -oN "{scandir}/{protocol}_{port}_smb_ms07-029.txt" -oX "{scandir}/xml/{protocol}_{port}_smb_ms07-029.xml" {address}')
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="smb-vuln-ms08-067" --script-args="unsafe=1" -oN "{scandir}/{protocol}_{port}_smb_ms08-067.txt" -oX "{scandir}/xml/{protocol}_{port}_smb_ms08-067.xml" {address}')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
if not plugin_was_run: # Only suggest these if they weren't run.
|
||||
service.add_manual_commands('Nmap scans for SMB vulnerabilities that could potentially cause a DoS if scanned (according to Nmap). Be careful:', [
|
||||
'nmap {nmap_extra} -sV -p {port} --script="smb-vuln-ms06-025" --script-args="unsafe=1" -oN "{scandir}/{protocol}_{port}_smb_ms06-025.txt" -oX "{scandir}/xml/{protocol}_{port}_smb_ms06-025.xml" {address}',
|
||||
'nmap {nmap_extra} -sV -p {port} --script="smb-vuln-ms07-029" --script-args="unsafe=1" -oN "{scandir}/{protocol}_{port}_smb_ms07-029.txt" -oX "{scandir}/xml/{protocol}_{port}_smb_ms07-029.xml" {address}',
|
||||
'nmap {nmap_extra} -sV -p {port} --script="smb-vuln-ms08-067" --script-args="unsafe=1" -oN "{scandir}/{protocol}_{port}_smb_ms08-067.txt" -oX "{scandir}/xml/{protocol}_{port}_smb_ms08-067.xml" {address}'
|
||||
])
|
||||
|
||||
class Enum4Linux(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Enum4Linux"
|
||||
self.tags = ['default', 'safe', 'active-directory']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^ldap', '^smb', '^microsoft\-ds', '^netbios'])
|
||||
self.match_port('tcp', [139, 389, 445])
|
||||
self.match_port('udp', 137)
|
||||
self.run_once(True)
|
||||
|
||||
async def run(self, service):
|
||||
if service.target.ipversion == 'IPv4':
|
||||
await service.execute('enum4linux -a -M -l -d {address} 2>&1', outfile='enum4linux.txt')
|
||||
|
||||
class LookupSID(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'lookupsid'
|
||||
self.tags = ['default', 'safe', 'active-directory']
|
||||
|
||||
def configure(self):
|
||||
self.match_service('tcp', 445, '^microsoft\-ds')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
service.add_manual_command('Lookup SIDs', [
|
||||
'lookupsid.py [username]:[password]@{address}'
|
||||
])
|
||||
|
||||
class NBTScan(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'nbtscan'
|
||||
self.tags = ['default', 'safe', 'netbios', 'active-directory']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^smb', '^microsoft\-ds', '^netbios'])
|
||||
self.match_port('udp', 137)
|
||||
self.run_once(True)
|
||||
|
||||
async def run(self, service):
|
||||
if service.target.ipversion == 'IPv4':
|
||||
await service.execute('nbtscan -rvh {address} 2>&1', outfile='nbtscan.txt')
|
||||
|
||||
class SMBClient(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "SMBClient"
|
||||
self.tags = ['default', 'safe', 'smb', 'active-directory']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^smb', '^microsoft\-ds', '^netbios'])
|
||||
self.match_port('tcp', [139, 445])
|
||||
self.run_once(True)
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('smbclient -L //{address} -N -I {address} 2>&1', outfile='smbclient.txt')
|
||||
|
||||
class SMBMap(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "SMBMap"
|
||||
self.tags = ['default', 'safe', 'smb', 'active-directory']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^smb', '^microsoft\-ds', '^netbios'])
|
||||
|
||||
async def run(self, service):
|
||||
if service.target.ipversion == 'IPv4':
|
||||
await service.execute('smbmap -H {address} -P {port} 2>&1', outfile='smbmap-share-permissions.txt')
|
||||
await service.execute('smbmap -u null -p "" -H {address} -P {port} 2>&1', outfile='smbmap-share-permissions.txt')
|
||||
await service.execute('smbmap -H {address} -P {port} -R 2>&1', outfile='smbmap-list-contents.txt')
|
||||
await service.execute('smbmap -u null -p "" -H {address} -P {port} -R 2>&1', outfile='smbmap-list-contents.txt')
|
||||
await service.execute('smbmap -H {address} -P {port} -x "ipconfig /all" 2>&1', outfile='smbmap-execute-command.txt')
|
||||
await service.execute('smbmap -u null -p "" -H {address} -P {port} -x "ipconfig /all" 2>&1', outfile='smbmap-execute-command.txt')
|
|
@ -0,0 +1,16 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class SMBClient(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "SMBClient"
|
||||
self.tags = ['default', 'safe', 'smb', 'active-directory']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^smb', '^microsoft\-ds', '^netbios'])
|
||||
self.match_port('tcp', [139, 445])
|
||||
self.run_once(True)
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('smbclient -L //{address} -N -I {address} 2>&1', outfile='smbclient.txt')
|
|
@ -0,0 +1,20 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class SMBMap(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "SMBMap"
|
||||
self.tags = ['default', 'safe', 'smb', 'active-directory']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name(['^smb', '^microsoft\-ds', '^netbios'])
|
||||
|
||||
async def run(self, service):
|
||||
if service.target.ipversion == 'IPv4':
|
||||
await service.execute('smbmap -H {address} -P {port} 2>&1', outfile='smbmap-share-permissions.txt')
|
||||
await service.execute('smbmap -u null -p "" -H {address} -P {port} 2>&1', outfile='smbmap-share-permissions.txt')
|
||||
await service.execute('smbmap -H {address} -P {port} -R 2>&1', outfile='smbmap-list-contents.txt')
|
||||
await service.execute('smbmap -u null -p "" -H {address} -P {port} -R 2>&1', outfile='smbmap-list-contents.txt')
|
||||
await service.execute('smbmap -H {address} -P {port} -x "ipconfig /all" 2>&1', outfile='smbmap-execute-command.txt')
|
||||
await service.execute('smbmap -u null -p "" -H {address} -P {port} -x "ipconfig /all" 2>&1', outfile='smbmap-execute-command.txt')
|
|
@ -1,18 +1,5 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapSMTP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap SMTP"
|
||||
self.tags = ['default', 'safe', 'smtp', 'email']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^smtp')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(smtp* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_smtp_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_smtp_nmap.xml" {address}')
|
||||
|
||||
class SMTPUserEnum(ServiceScan):
|
||||
|
||||
def __init__(self):
|
|
@ -1,35 +1,5 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class NmapSNMP(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Nmap SNMP"
|
||||
self.tags = ['default', 'safe', 'snmp']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^snmp')
|
||||
|
||||
async def run(self, service):
|
||||
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(snmp* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oN "{scandir}/{protocol}_{port}_snmp-nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_snmp_nmap.xml" {address}')
|
||||
|
||||
class OneSixtyOne(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "OneSixtyOne"
|
||||
self.tags = ['default', 'safe', 'snmp']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^snmp')
|
||||
self.match_port('udp', 161)
|
||||
self.run_once(True)
|
||||
self.add_option('community-strings', default='/usr/share/seclists/Discovery/SNMP/common-snmp-community-strings-onesixtyone.txt', help='The file containing a list of community strings to try. Default: %(default)s')
|
||||
|
||||
async def run(self, service):
|
||||
if service.target.ipversion == 'IPv4':
|
||||
await service.execute('onesixtyone -c ' + service.get_option('community-strings') + ' -dd {address} 2>&1', outfile='{protocol}_{port}_snmp_onesixtyone.txt')
|
||||
|
||||
class SNMPWalk(ServiceScan):
|
||||
|
||||
def __init__(self):
|
|
@ -0,0 +1,34 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
import os
|
||||
|
||||
class SubdomainEnumeration(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Subdomain Enumeration"
|
||||
self.slug = "subdomain-enum"
|
||||
self.tags = ['default', 'safe', 'long', 'dns']
|
||||
|
||||
def configure(self):
|
||||
self.add_option('domain', help='The domain to use as the base domain (e.g. example.com) for subdomain enumeration. Default: %(default)s')
|
||||
self.add_list_option('wordlist', default=['/usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt'], help='The wordlist(s) to use when enumerating subdomains. Separate multiple wordlists with spaces. Default: %(default)s')
|
||||
self.add_option('threads', default=10, help='The number of threads to use when enumerating subdomains. Default: %(default)s')
|
||||
self.match_service_name('^domain')
|
||||
|
||||
async def run(self, service):
|
||||
domains = []
|
||||
|
||||
if self.get_option('domain'):
|
||||
domains.append(self.get_option('domain'))
|
||||
if service.target.type == 'hostname' and service.target.address not in domains:
|
||||
domains.append(service.target.address)
|
||||
if self.get_global('domain') and self.get_global('domain') not in domains:
|
||||
domains.append(self.get_global('domain'))
|
||||
|
||||
if len(domains) > 0:
|
||||
for wordlist in self.get_option('wordlist'):
|
||||
name = os.path.splitext(os.path.basename(wordlist))[0]
|
||||
for domain in domains:
|
||||
await service.execute('gobuster dns -d ' + domain + ' -r {addressv6} -w ' + wordlist + ' -o "{scandir}/{protocol}_{port}_' + domain + '_subdomains_' + name + '.txt"')
|
||||
else:
|
||||
service.info('The target was not a domain, nor was a domain provided as an option. Skipping subdomain enumeration.')
|
|
@ -0,0 +1,39 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
from shutil import which
|
||||
import os
|
||||
|
||||
class VirtualHost(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'Virtual Host Enumeration'
|
||||
self.slug = 'vhost-enum'
|
||||
self.tags = ['default', 'safe', 'http', 'long']
|
||||
|
||||
def configure(self):
|
||||
self.add_option('hostname', help='The hostname to use as the base host (e.g. example.com) for virtual host enumeration. Default: %(default)s')
|
||||
self.add_list_option('wordlist', default=['/usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt'], help='The wordlist(s) to use when enumerating virtual hosts. Separate multiple wordlists with spaces. Default: %(default)s')
|
||||
self.add_option('threads', default=10, help='The number of threads to use when enumerating virtual hosts. Default: %(default)s')
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
|
||||
def check(self):
|
||||
if which('gobuster') is None:
|
||||
self.error('The gobuster program could not be found. Make sure it is installed. (On Kali, run: sudo apt install gobuster)')
|
||||
|
||||
async def run(self, service):
|
||||
hostnames = []
|
||||
if self.get_option('hostname'):
|
||||
hostnames.append(self.get_option('hostname'))
|
||||
if service.target.type == 'hostname' and service.target.address not in hostnames:
|
||||
hostnames.append(service.target.address)
|
||||
if self.get_global('domain') and self.get_global('domain') not in hostnames:
|
||||
hostnames.append(self.get_global('domain'))
|
||||
|
||||
if len(hostnames) > 0:
|
||||
for wordlist in self.get_option('wordlist'):
|
||||
name = os.path.splitext(os.path.basename(wordlist))[0]
|
||||
for hostname in hostnames:
|
||||
await service.execute('gobuster vhost -k -u {http_scheme}://' + hostname + ':{port}/ -t ' + str(self.get_option('threads')) + ' -w ' + wordlist + ' -r -o "{scandir}/{protocol}_{port}_{http_scheme}_' + hostname + '_vhosts_' + name + '.txt"')
|
||||
else:
|
||||
service.info('The target was not a hostname, nor was a hostname provided as an option. Skipping virtual host enumeration.')
|
|
@ -0,0 +1,16 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class WhatWeb(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "whatweb"
|
||||
self.tags = ['default', 'safe', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
|
||||
async def run(self, service):
|
||||
if service.protocol == 'tcp' and service.target.ipversion == 'IPv4':
|
||||
await service.execute('whatweb --color=never --no-errors -a 3 -v {http_scheme}://{address}:{port} 2>&1', outfile='{protocol}_{port}_{http_scheme}_whatweb.txt')
|
|
@ -0,0 +1,32 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
from autorecon.io import fformat
|
||||
|
||||
class WinRMDetection(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'WinRM Detection'
|
||||
self.tags = ['default', 'safe', 'winrm']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^wsman')
|
||||
self.match_service('tcp', [5985, 5986], '^http')
|
||||
|
||||
async def run(self, service):
|
||||
filename = fformat('{scandir}/{protocol}_{port}_winrm-detection.txt')
|
||||
with open(filename, mode='wt', encoding='utf8') as winrm:
|
||||
winrm.write('WinRM was possibly detected running on ' + service.protocol + ' port ' + str(service.port) + '.\nCheck _manual_commands.txt for manual commands you can run against this service.')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
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')
|
||||
])
|
||||
|
||||
service.add_manual_commands('Check login (requires credentials):', [
|
||||
'crackmapexec winrm {address} -d ' + self.get_global('domain', default='<domain>') + ' -u <username> -p <password> -x "whoami"'
|
||||
])
|
||||
|
||||
service.add_manual_commands('Evil WinRM (gem install evil-winrm):', [
|
||||
'evil-winrm -u <user> -p <password> -i {address}',
|
||||
'evil-winrm -u <user> -H <hash> -i {address}'
|
||||
])
|
|
@ -0,0 +1,22 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
from shutil import which
|
||||
|
||||
class WkHTMLToImage(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "wkhtmltoimage"
|
||||
self.tags = ['default', 'safe', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
|
||||
def check(self):
|
||||
if which('wkhtmltoimage') is None:
|
||||
self.error('The wkhtmltoimage program could not be found. Make sure it is installed. (On Kali, run: sudo apt install wkhtmltopdf)')
|
||||
|
||||
async def run(self, service):
|
||||
if which('wkhtmltoimage') is not None:
|
||||
if service.protocol == 'tcp':
|
||||
await service.execute('wkhtmltoimage --format png {http_scheme}://{addressv6}:{port}/ {scandir}/{protocol}_{port}_{http_scheme}_screenshot.png')
|
|
@ -0,0 +1,20 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
|
||||
class WPScan(ServiceScan):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = 'WPScan'
|
||||
self.tags = ['default', 'safe', 'http']
|
||||
|
||||
def configure(self):
|
||||
self.add_option('api-token', help='An API Token from wpvulndb.com to help search for more vulnerabilities.')
|
||||
self.match_service_name('^http')
|
||||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
api_token = ''
|
||||
if self.get_option('api-token'):
|
||||
api_token = ' --api-token ' + self.get_option('api-token')
|
||||
|
||||
service.add_manual_command('(wpscan) WordPress Security Scanner (useful if WordPress is found):', 'wpscan --url {http_scheme}://{addressv6}:{port}/ --no-update -e vp,vt,tt,cb,dbe,u,m --plugins-detection aggressive --plugins-version-detection aggressive -f cli-no-color' + api_token + ' 2>&1 | tee "{scandir}/{protocol}_{port}_{http_scheme}_wpscan.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.targets import Target, Service
|
||||
|
||||
VERSION = "2.0.15"
|
||||
VERSION = "2.0.16"
|
||||
|
||||
if not os.path.exists(config['config_dir']):
|
||||
shutil.rmtree(config['config_dir'], ignore_errors=True, onerror=None)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "autorecon"
|
||||
version = "2.0.15"
|
||||
version = "2.0.16"
|
||||
description = "A multi-threaded network reconnaissance tool which performs automated enumeration of services."
|
||||
authors = ["Tib3rius"]
|
||||
license = "GNU GPL v3"
|
||||
|
|
Loading…
Reference in New Issue