Windows: NPFS Symlink Security Feature Bypass/Elevation of Privilege/Dangerous Behavior
Platform: Windows 10 1709 (functionality not present prior to this version)
Class: Security Feature Bypass/Elevation of Privilege/Dangerous Behavior
Summary: It’s possible to create NPFS symlinks as a low IL or normal user and the implementation doesn’t behave in a similar manner to other types of Windows symlinks leading to dangerous behavior or EoP.
Description:
Windows 10 1709 introduced a new symlink feature to NPFS which is accessible from a FSCTL. From what I can see the implementation has a number of security issues which concern me:
The fact that you can create the symlink as a lower privileged user is bad enough, although I don’t believe it can be done from an AC so maybe you don’t care about it. But the other two issues are examples of dangerous behavior which _will_ come
back to bite you at some point in the future.
Let’s take point 2 as an example, up to this point NPFS hasn’t had the concept of symbolic links. Sure you could drop an appropriate object manager symlink somewhere and get a caller to follow it but you’d need to be able to influence the callers path or their DOS device directory. With this if a privileged caller is expecting to open a named pipe, say \.\pipe\ABC then ABC could actually be a symbolic link to a normal file. If the caller then just writes data to the pipe expecting it to be a stream they could actually be writing data into a file which might result in EoP. Basically I see it’s a case of when not if that a EoP bug is found which abuses this behavior.
Also, there’s no way I know of for detecting you’re opening a symbolic link. For example if you open the target with the FILE_OPEN_REPARSE_POINT flag it continues to do the reparse operation. Due to creating a normal NTFS symbolic link this might also have weird behavior when a remote system accessed a named pipe, although I’ve not tested that.
Overall I think the behavior of the implementation has the potential for malicious use and should be limited to privileged users. I don’t know it’s original purpose, perhaps it’s related to Silos (there is a flag to make a global symlink) or it’s to make it easier to implement named pipes in WSL, I don’t know. If the purpose is just to symlink between named pipes then perhaps only allow a caller to specify the name relative to the NPFS device rather than allowing a full object path.
Proof of Concept:
I’ve provided a PoC as a C# project. The PoC will create a symlink called ABC which points to notepad.exe. It will check the file file it opens via the symlink matches the file opened directly.
Expected Result:
The creation of the symlink should fail with an error.
Observed Result:
The symlink is created, is valid and the poc printed ‘Success’ as it’s opened the copy of notepad.exe via the symlink.