Our Blog

Let me store that for you

Reading time ~8 min

A while ago Jonas Lykkegaard disclosed a zeroday that could be used to create files in the SYSTEM folder. CVE-2020-16885 got assigned for this vulnerability, and was since patched with KB4580346. This vulnerability was very convenient for Dynamic-link library (DLL) side-loading, which I will show in this blog post. Below you can find his original Twitter message.

Twitter message of Jonas Lykkegaard

The screenshot he posted shows everything that is needed to exploit and I wanted to verify this.

So what is NtCreateFile?

NtCreateFile is a function within NTDLL.dll and is used to either create a new file or directory, or open an existing file, device, directory, or volume. Microsoft has documented this function quite well too.

And what is STORVSP?

Hyper-V STORVSP stands for ‘Storage Virtual Service Provider’ and is a paravirtualised device hosted in the Kernel. There are some good BlackHat presentations available on Hyper-V where one of them shows the flow for STORVSP. Note that STORVSP operates in Kernel mode on the I/O stack.

Overview of Hyper-V and storVSP

Verifying the vulnerability

But does the exploit work? For a quick test you can download FileTest. The image below shows the values Jonas used in his Twitter message where the expected outcome is that a file called test.txt is created in the C:\Windows\System32 folder.

FileTest and NtCreateFile to create a file in ‘c:\Windows\System32’ folder

After the ‘NtCreateFile’ button is pressed, the file was indeed created, and as a low privileged user I also had full control over it.

Test file is created
Low privileged user had full control on the created file

This meant that the vulnerability found by Jonas worked (Microsoft has since patched the vulnerability before this blog post was made public). I validated this vulnerability against multiple Windows features that make use of Hyper-V too, namely:

  • Hyper-V
  • Windows Sandbox
  • Windows Credential Guard

Windows Subsystem for Linux does not seem to be vulnerable, but Windows Credential Guard seems to enable all the Hyper-V features.

Root cause

Low privileged users were allowed to create files with NtCreateFile using \Device\STORVSP\vSMB\??\C:\Windows\System32\ as filename. Since STORVSP is in Kernel mode and there was no check on privileges, it was possible to place files in protected folders like the SYSTEM folder.

Chaining with DLL side-loading

This arbitrary write vulnerability was all you needed to perform a DLL side-loading attack. DLL side-loading is a popular attack method that takes advantage of how Microsoft Windows handles loading DLL’s.

If your program doesn’t specify the absolute path to a DLL, a search is conducted by Windows to try to find that DLL and load it. If SafeDllSearchMode is enabled, the search order is as follows:

  • The directory from which the application was loaded.
  • The system directory. Use the GetSystemDirectory function to get the path of this directory.
  • The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
  • The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  • The current directory.
  • The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key. The App Paths key is not used when computing the DLL search path.

For this attack a spoofed (malicious) DLL file is (most commonly) placed in a Windows ‘SYSTEM’ directory so that the operating system loads it instead of the legitimate file.

Let’s chain Jonas’ finding with DLL side-loading.


For testing purposes, the following things are necessary to prepare:

  • VM with Windows 10 x64 with low privileged user;
  • Hyper-V enabled;
  • Defender disabled (just easier for working with msfvenom payloads);
  • File Test;
  • SysInternals – Procmon.

Finding a missing DLL to load

You do not want to create files randomly, but instead create one that you know your target searches for. The first step is to determine if the target tries to load DLL files (hopefully as AUTHORITY\SYSTEM) that cannot be found. This can be done with Procmon which is part of the SysInternals suite.

The filters I used in Procmon were:

Filters in Procmon to find missing DLL’s

The result would be different per target, but in this example you see that webio.dll is searched for by UpdateNotificationMgr.exe as NT AUTHORITY\SYSTEM, but cannot be found.

DLL file ‘webio.dll’ cannot be found

UpdateNotificationMgr.exe runs when the RunUpdateNotificationMgr task is started. This is a task that can be started as a low privileged user, but runs as ‘SYSTEM’ user.

Task that runs the UpdateNotificationMgr.exe

We can now use the arbitrary write vulnerability to create the missing DLL file. Start FileTest as a restricted user and place the correct parameters according to the screenshot of Jonas to create webio.dll in the C:\Windows\System32\UNP\ folder.

FileTest is used to create ‘webio.dll’

That looks good as the status is STATUS_SUCCESS. Let’s validate if the file was created:

webio.dll is created

Great. The file is created, but do we have permissions to edit this file as a restricted user?

low privileged user has full control over webio.dll

Oh yeah baby, Full control!

Creating the payload

You may have noticed that the created file is empty. This is ok. Since we have full control over the file we can modify it after creation. For the contents of the malicious DLL file, I used MSFvenom for a quick payload. MSFvenom is part of MetaSploit and can be used to create and encode payloads. The steps below show how a payload could be created. Keep in mind that payloads created by MSFvenom are often found by endpoint security solutions.

Creating a payload and saving it to dll_payload.txt using msfvenom may look something like this for a simple command that adds a new local administrator:

msfvenom -p windows/x64/exec -a x64 cmd='cmd.exe /k "net user /add ntcreatefile OCDyear2020! && net localgroup administrators ntcreatefile /add"' Exitfunc=thread -f dll -o dll_payload.txt

Placing the content of the payload in the DLL, we can type it to our file in System32:

type c:\tmp\dll_payload.txt > C:\Windows\System32\UNP\webio.dll

A quick recap

We have found a way to load a DLL file with the NT AUTHORITY\SYSTEM user rights. We used the vulnerability to create the file and we used MSFvenom to create the payload. Let’s run the task now to see what happens.

webio.dll is now found and loaded

Running net users in the command prompt verifies that the user is created and is a member of the local administrators group.

‘Net users’ shows that a new user is created
The newly created user is a member of the local administrators group


An official patch for this vulnerability exists as KB4580346. For the period that this vulnerability did not have a patch though, detection was the next best thing. While testing, Microsoft Defender did not detect the creation of a file in a ‘SYSTEM’ folder by a profile that was not in an administrators group. Firing up the Event Viewer and looking for Hyper-V STORVSP events also did not show any results either. None of the Hyper-V logs were showing events that might lead to detection.

What you could do was to monitor ‘SYSTEM’ folders for the creation of files by a profile that was not in an administrator group. This would not be a perfect detection since DLL files can be loaded from locations other than the ‘SYSTEM’ folder, but perhaps this would be an interesting case to try.

Overall, this was fun :) Thank you Jonas for your time to chat about this finding.