A simple (not stealth) method utilizing
Arbitrary Write NULLvulnerabilities
Today, we’re going to have a deep looking through an interesting exploitation technique using
NtQuerySystemInformationsystem call in order to achieve a
LPE - (Local Privilege Escalation) through
HEVD - (Hacksys Extreme Vulnerable Driver). The follow content will only show about possibilities (but unreliable) techniques and methodologies on how to exploit a specify vulnerability typed
Arbitrary Write NULL in most of vulnerable
x86drivers (in case you doesn’t have certain tools in order to exploit them). Also, we’ll not cover how to install and configure kernel debugging or
HEVD IOCLT communication, and all content from this write-up lies behind what should be done to work around with a view to get a
LPE.Hope everyone enjoy! =)
First of all, we need to talk about what is
Arbitrary Write NULL vulnerability, and at kernel perspective, what should be possible to do with it in order to achieve
LPE in our simple
cmd.exe session from
Arbitrary Write NULL is most like
Arbitrary Write vulnerabilities, the difference behind them, is that the first one allows you to be able to
write->[0x00000000] in whatever address/pointer you looking for, and the second one, allows you to define explicitly
Write-What-Where, allowing things like
write->[0xdeadbeef], meaning that you have control over value of an address/pointer which will be overflowed with
0xdeadbeef, instead only
0x00000000. At below we are going to have a looking deep in to
HEVD driver vulnerable function, dissect and understand what is happening.
As you can see here,
ifdef SECURE (which is not),
probeForWrite() function should verify and confirm that our user input buffer is located at
ring3, otherwise our input buffer with be nullified without properly security checks.
[edi] register is been overflowed with
[ebx] register as occurs when compiled code wasn’t defined with
#ifdef SECURE bit set.
IOCTLdrive connection is predefined, we can test it and see that our first
4 bytes from user-buffer
(shellcode_ptr), is about to be
After script run, and hit break-point, we can clearly notice that
[edi] value contains our address to the pointer of user-buffer address
shellcode_ptr -> 0x00500000.
As an example, the content of our
shellcode is storing a piece of
x86 assemblycode to
LPE our permissions. At your first
4 bytes, you can see that have the initial parts of our
shellcode start. Now ignoring the code located there, we’re only looking into
The problem here is obvious, as a simple user
(ring3), if we send a whatever address, it will be nullified, no matter what or how, just it will stay
Said all that, we know from here that we actually only can write
NULL bytes to our defined
address/pointer, and do some magic to achieve
LPE from there, but… how can we do that? Let’s talk about
DACL & Security Description.
DACL & Security Description
First of all, what is
Security Description? how them can be exploited using
Arbitrary Write NULL vulnerabilities?
What is DACL (Discretionary Access Control List)?
DACLstands for Discretionary
Access Control List, in Microsoft Windows family, is an internal list attached to an object in
Active Directorythat specifies which
groupscan access the object and what kinds of operations they can perform on the object. In
Windows NT, an internal list attached to a file or folder on a volume formatted using the
NTFSthat has a similar function.
How DACL works?
Windows, each object in
Active Directoryor a local
NTFSvolume has an attribute called
Security Descriptorthat stores information about
The object’s owner (the security identifier or the owner) and the groups to which the owner belongs.
The discretionary access control list
(DACL)of the object, which lists the security principals
(users, groups, and computers)that have access to the object and their level of access.
system access control list (SACL), which lists the security principals that should trigger audit events when accessing the list.
DACL is a list that contains features, one of them are called
Security Description (we will take deep soon). This list are configured to handle calls and filter what object (
threads, etc), should be
not for specific (
computers). Hard to understand? Let me show up it as
Window UI. =)
Maybe this image should be familiar to you right?. This area is one of various that you can manage
DACL & Security Descriptions easily (without knowing that they actually exists).
As we can see, isn’t hard to understand what it is and why it was created, the thing is, what defines internally what permissions an user can have on it? What objects are configured in
DACL to be filtered? let’s have a deep look into
Windows Internals and his structs.
First of all, let’s take a look at
WinDBG process list.
When we do list our windows processes in
WinDBG, we can see that every process have the same patterns, only with different values or addresses ranges. In the image above, you can notice a marked address
0x856117c8, this address represents a windows object, and this object have some important properties which defines: process name, permissions, process ID’s, handles, etc. (i’ll not extend this, so let it just as a simple recap).
A interesting thing that we can explore at moment, isn’t any else then
nt!_OBJECT_HEADER struct. This struct have literally what tools we need to work and start our attack.
As an image above says, we simply dissect our process utilizing
nt!_OBJECT_HEADER struct, which gave us information about what is located in our object. Also it’s important to notice that
nt!_OBJECT_HEADER only look for addresses offsets before
nt!_EPROCESS, which means that
nt!_EPROCESS range, should stay after those offsets.
But what happens to SecurityDescription?
Another interesting thing is that our
(0x856117b0+0x014) is pointing to
0x8c005e1f address, meaning that something is happening here, and this address have some interaction to
DACL & Security Description implementations.
Now, let’s have a deep look in this specific address
Utilizing previous target
!sd, with simple bit calculation, we now are able to understand much better how it’s implementation are configured on
Windows Internals. So, those marked value, remember you something? Yes, that’s right, this marks are the users information stored in the process. At image below, we can compare these two
As we can compared these two images, we notice that
DAML users, are related to another image about
SecurityDescription(Windows Internals). It’s a example (not legit), that how we can compare this two values.
Knowing that, and understanding the concepts that we actually can nullify any address from
ring0 (kernel) only as an simple user, let’s try to make
(0x856117b0+0x014) point to
(0x00000000), and see what happens!
System.exe (PID:4) process have SecurityDescriptor pointer nullified. Now let’s try to continue our
Wait, what happened? we closed [
System.exe] process manually? and without user permissions for it? using task manager?
nt authority/SYSTEM should have permissions to close this process, but how could be possible a simple user
BSOD'ed whole system? There’s, the magic behind this exploitation is a well-know exploitation technique which nullify
SecurityDescription behaviors from
SYSTEM processes, it technique is very used for
LPE exploits since it applies
no permissions bit for those target processes. In short, from
WinDBG we manually nullified the pointer which contains those permissions information in
SecurityDescription meaning that
anyone now can
write/read/execute in this process. =)
But there’s a problem here, we now understand what we need to do in order to elaborate our exploit but i ask you, how we can identify
SYSTEM process objects from a simple
In the image above, since we’re looking those addresses from
ring0 (kernel mode), we clearly see the object there, but also we need to know that those values are not accessible (also unpredictable), to our simple user from
ring3 (user-land). The randomization of these addresses are implemented every time since
Windows 7 is rebooted
(Address Space Layout Randomization or ASLR), these mitigations deny every try to work with static address. Lastly, another important thing is that the randomization by self are unpredictable (in most of my tests), these objects only randomize through
0x85xxxxxx to 0x87xxxxxx, which means i actually don’t know if a bypass of this randomization (from
ring3), actually exists.
So, what to do next?
NtQuerySystemInformation - Handle Leaking Attack
As mentioned before, isn’t possible to exploit from
ring3 (user-land) due to a lot of permissions restrictions placed by our target “Operation System
(windows 7)so what kind of things can we do to bypass these restrictions? the answer is
NtQuerySystemInformation WinAPI call.
NtQuerySystemInformation by design is one of various security flaws that for
Microsoft only represents a
feature to an user perspective. The biggest problem about it
WinAPI call, is that it’s configured by default to accept user calls (from
undocumented behaviors), which should be parsed and queried together
ring0 (kernel mode) information, as resulting in an leak of
SYSTEM addresses/pointers. This
WinAPI Call, is a
well-know method for
memory leaking attacks, since it’s allow an
attacker to know exactly what pointers are important, and elaborate a better methodology for explore his target vulnerability (in our case
But how could it be possible to leak information from ring3?
Before we start to looking deep into vulnerable (features) calls, we should look at first to the definition of
handles, and why we need to get focus on it.
It’s an abstract reference value to a resource, often memory or an open file, or a pipe.
Properly, in Windows, (and generally in computing) a handle is an abstraction which hides a real memory address from the API user, allowing the system to reorganize physical memory transparently to the program. Resolving a handle into a pointer locks the memory, and releasing the handle invalidates the pointer. In this case think of it as an index into a table of pointers… you use the index for the system API calls, and the system can change the pointer in the table at will.
Alternatively a real pointer may be given as the handle when the API writer intends that the user of the API be insulated from the specifics of what the address returned points to; in this case it must be considered that what the handle points to may change at any time (from API version to version or even from call to call of the API that returns the handle) — the handle should therefore be treated as simply an opaque value meaningful only to the API.
handles have properties to create and configure communications through objects (
open files I/O,
pipes, etc), on
Operation System (OS). These handles are carrying a bunch of information about these objects, one of them are pointers. Basically,
handles loads pointers, but do you know the best part of it? is the possibility to
leak these pointer from
ring3 (user-land), and that’s what we need to deep our look.
NtQuerySystemInformation afford a lot interesting calls, on top of that, we have an undocumented call named
SystemExtendedHandleInformation, which supports the follow structs.
These structs, should help us to leak
handle pointers, and that’s how the magic starts.
designed flaw calls, let me fuzz some handle data from
ring3 (user-mode) perspective and see what happens.
As you can see, from a simple user we actually can
leak a lot of pointers and data. The best part of it, is that one of those pointers are correlated to our
PROCESS object, did you remember?
This is it, that’s the trick! But there’s a problem. Assuming that many restrictions such as:
ASLR, are configured by default, how we knows what
Handle values are correct in order to predict that one who contains our
PROCESS object pointer?
The answer for this question is: “I don’t know, but there’s a method (really not stealth), which work as well!”. This method was discovered after tests assuming
ASLR randomization and what processes (who contains useful pointers), should crash after been
nullified through exploitation technique.
After some tests, it was noticed that if we define
lsass.exe PID, as the only target to have his handles nullified, the
Operation System OS doesn’t crashes (I assume that because
lsass.exe isn’t a process that contains so many handles for
SYSTEM internals, only to hold permissions and things related on this). After all, with
lsass.exe handle pointers nullified, it’s clearly that not only 1 process will have
write/read/execute permission, but also a lot. That’s why i don’t recommend this technique for a real world exploitation because isn’t safe (also not stealthy), nullifying
handles could make the Operation System crash and reboot.
The things is, once
SYSTEM processes do have access permissions for
Anyone, the final part should be a
Shellcode Injection in a
SYSTEM target process, and that’s what we do in
winlogon.exe. This process is running with
SYSTEM permissions (and now after
So, putting all together, this is how it looks like. =D
After exploit runs, we finally got our
nt authority/SYSTEMshell, nothing was crashed and processes work as well without any issues.
The final consideration for this write-up, is that i didn’t found any reliable solution for
WriteNULL challenge, only one which uses another driver vulnerability in order to leak pointer address (on references), meaning that this exploit should be the only one existing in internet utilizing this technique (really no one want to do this). =(
So, it was kind fun and hope everyone enjoyed this write-up. =P
Final Exploit link: