Published on
Tue 04 June 2019
by
@clavoillotte
Edited on
Thu 13 June 2019
Product: osquery for Windows
Type: Local Privilege Escalation
Summary: An access right misconfiguration in Osquery for Windows can be abused to run arbitrary programs or load arbitrary DLLs. This can be used by an unprivileged user to obtain SYSTEM privileges on the local machine.
This vulnerability is patched in version 3.4.0.
Updated with some additional details.
Description
The main executable of Osquery for Windows, osqueryd.exe
, runs with SYSTEM
privileges and starts automatically at boot. It is installed in C:\ProgramData\osquery\osqueryd
with hardened access rights to prevent binary modification and DLL planting.
However, the parent directory C:\ProgramData\osquery
does not have specific access rights, thus inherits the standard ACL from C:\ProgramData
which allows unprivileged users to create files and directories (but not modify existing ones). So unprivileged users can create files & directories in C:\ProgramData\osquery
.
This is an issue because there are at least 2 items that are not created by osquery's installer but are used by osqueryd.exe if present: the extensions.load
file (used to load osquery extensions) and the osquery.conf.d
directory (used to load additional configuration files).
Creating an extensions.load
file with arbitrary content allows unprivileged users to make the osqueryd.exe
service run arbitrary executables with SYSTEM
privileges as osquery extentions.
A check performed on the permissions & owner of the extension's executable file, and the permissions of its parent directory to (attempt to) prevent running a user-modifiable executable.
There are several ways to bypass this check, one of which is creating a hard link to osqueryd.exe itself (as it is owned by SYSTEM
) in a user-owned directory in which we can drop a DLL to perform a standard DLL hijacking, as illustrated below:
osqueryd.exe
attempts to load the following DLLs from its own directory: wevtapi.dll
, NETAPI32.dll
, WTSAPI32.dll
, Secur32.dll
, dbgeng.dll
, IPHLPAPI.DLL
, bcrypt.dll
, VERSION.dll
, dbgmodel.dll
, dbghelp.dll
, XmlLite.dll
, USERENV.dll
, NETUTILS.DLL
, SAMCLI.DLL
, SSPICLI.DLL
.
The one with the least imported functions is USERENV.dll
, from which only GetUserProfileDirectoryW
is imported, so we can make a DLL that only exports this function and runs the desired payload when loaded.
As an unprivileged user we can't write into the C:\ProgramData\osquery\osqueryd
directory, but we can create our own directory, put the malicious USERENV.dll
in it, and create a hard link to osqueryd.exe
in order to obtain the desired owner/ACL. (The hardlink is created using James Forshaw's technique & tool, for more on this you can read a general explanation on privileged file operation bugs here.)
A check is also performed on the directory's ACL, so we'll also need to remove the write access entry of our own user from the directory's ACL to pass this check.
Finally, we can create C:\ProgramData\osquery\extensions.load
(because of the default ACL) and write the path of the hardlink in it. At the next run, osqueryd will run itself (through the hardlink) from our directory, load our DLL and execute its code with SYSTEM
privileges.
Note: in our DLL we also need to exit the process (just after starting the payload) to avoid infinite recursive spawning of osqueryd.exe
processes that would DoS the machine, since every instance will read the extensions.load
file and attempt to execute the extension.
To sum up this exploitation procedure, from an unprivileged user session:
- Create a directory (somewhere the user has write access), e.g.
C:\temp_dir
- Drop a malicious
USERENV.dll
inC:\temp_dir
- Create a hard link, e.g.
C:\temp_dir\osq.exe
, toC:\ProgramData\osquery\osqueryd\osqueryd.exe
- Remove the user's write access to
C:\temp_dir
- Create file
C:\ProgramData\osquery\extensions.load
with content:C:\temp_dir\osq.exe
- Wait for the next run of the osquery service (e.g. next reboot)
The final state is illustrated below:
Proof of Concept
The following video shows a PoC script performing the above steps to load an arbitrary DLL that that adds the unprivileged
user to the administrators
group:
Fix
The vendor has released a patch and an advisory. The fix moves the installation directory to C:\Program Files\osquery
, which restricts unprivileged write access.
Users should update to Osquery version 3.4.0 or above.
Update: osql users can track this issue.
References
https://www.facebook.com/security/advisories/cve-2019-3567
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-3567
Timeline
2019-04-21: Initial report sent to vendor
2019-04-23: Vendor acknowledges reception of report
2019-05-23: Follow-up message sent to vendor
2019-06-04: Vendor response confirming the release of a fixed version
2019-06-04: Mail from vendor informing the bug has been granted a reward through their VRP
2019-06-04: Publication of this advisory