[SAFE-ID: JIWO-2021-2938] 作者: 大猪 发表于: [2021-09-30]
本文共  位读者顶过
Days ago, as usual I was reading some google project zero bugs. Then I found this one by James Forshaw about an EoP in dos device when a privileged process impersonate the user to load libraries. You can read the article here , My only problem was the PoC file as it seems look like james submitted 2 attachment to MSRC, the first one was with the actual PoC compiled and a dll, the second attachment seems to be password protected
And after some research trying to find the original PoC source code, I didn't found something useful so the only way to answer my questions is to reverse the actual PoC.
I really had some questions like, how did he managed the override the original link ? how did he get the login session \Sessions\0\DosDevices\X-Y <- how did he manage to get those numbers ?
Nothing special the dll will just call "RevertToSelf()" and then create notepad as a child process.
But for the actual PoC, some ops are done. I will only cover the code which has impact on our research area.
The PoC will first check the current OS architecture if it match x86 it will continue otherwise it will exit. I still don't know why did he do that but maybe to get ride off the annoying Wow64 redirections.
And after doing some reverse I finally answered my question, in order to get the current DosDevice path is to call GetTokenInformation
Then simply it will redirect the dos device symlink to the PoC's current directory by calling NtCreateSymbolicLinkObject, of course it make sure to recreate C:\Windows\System32 and place the dll described previously to system32 with the name PrintFilterPipelinePrxy.dll, after that the PoC will simply call "OpenPrinterW" "StartDocPrinterW" "EndDocPrinter" then the dll will be loaded as the spooler service. Microsoft has released the advisory for the bug as CVE-2015-1644
After taking a look on how Microsoft patched the bug, Microsoft implemented a mitigation to make sure that the dll load behaviour won't be redirected because of a DosDevice link, by using the OBJ_IGNORE_IMPERSONATED_DEVICEMAP. But any other file system operation will follow the link if it’s not using the flag described above.
The following Diagram will explain how things are done
You won't need to create the actual DosDevice link, overriding C:\ will do the job for the current user.
I was firstly inspired by sandbox escaper arbitrary file read PoC, which was dropped as a 0day vulnerability 2018. The bug existed in MsiAdvertiseProduct function, calling it will trigger a file copy from windows installer service running as SYSTEM privileges.
In this vulnerability I will be attacking the MsiInstallProduct which takes two arguments.
The first one is szPackagePath which can be either an URL or a local file. The second parameter is szCommandLine.
After calling the function, I had the following output from process monitor
Phase 1: Windows installer service will impersonate the user and call OpenAndValidateMsiStorageRec which will first check if the package valid.
Phase 2: Windows installer service will reverse to itself and create a new file in C:\Windows\Installer\*.msi
Phase 3: It will make sure that the opened file match the expected file to be opened by calling GetFinalPathNameByHandleW if it match the file will be copied if it doesn’t the installer service will impersonate the user and try to copy the file.
The flaw exist exactly in msi.dll!CopyTempDatabase() when it call CElevate::CElevate((CElevate *)&X, 1); to elevate privileges instead of staying in impersonation mode
There’s some checks in CopyTempDatabase such as CMsiFileCopy::VerifySource which check the source if it valid for for copy or not but it can be defeated if the user impersonation is done incorrectly.
Since the package sanitization will run while impersonating the user, we can redirect it with the trick mentioned above to a valid package which will trick OpenAndValidateMsiStorage and mark it as a valid package. Then the installer will check if the target file is the one expected to be opened in our case yes it is so it will proceed copying the file to C:\Windodws\Installer\*.msi
I succeeded implementing the exploit but I had one more issue, when the file is copied to C:\Windows\installer it’s probably not the only file there so fetching the newly created file is like a programming quiz, I took a while to see my options, the first one was ReadDirectoryChangesW which wait and fetch any newly created file, this sounds great but wasn’t useful. Since windows installer service tamper with certain parameters of the directory and remove the newly created MSI package as soon as it’s written. The second option was to use FindFirstFileW, FindNextFileW which has solved a bit of the problem, the technique I used here is to find newest file created and pick it as the our target, for some unknow reasons the technique failed and always pick the wrong file. So I moved away to another technique (and it was my last hope), This snippet of code will explain the process of finding the newly created file
We will first begin by deprecating “C:\” path and we will use the windows GUI path so we won’t issues with redirection, to retrieve the GUI path of drive you can use GetVolumeNameForVolumeMountPoint, then it will be used primary in the next api calls. Next our PoC will search \Windows\Installer\*.msi and will store it in an array “first_srch” and then you might notice there’s two calls of FindFirstChangeNotification and according to Microsoft documentation
“Creates a change notification handle and sets up initial change notification filter conditions. A wait on a notification handle succeeds when a change matching the filter conditions occurs in the specified directory or subtree. The function does not report changes to the specified directory itself. “
The PoC will set 2 events, one for the file creation and the second one for file write, When the first event trigger the PoC will restart the search of MSI files and will store to an array, the PoC will take those arrays and compare every file name if there’s something that doesn’t match at certain index then it’s the newly created file. After that we will just wait the second event to trigger then simply copy our file.
How exploitable a windows read-file ?
When windows crash it automatically generate a windows kernel memory dump in C:\Windows\memory.dmp and restrict it’s DACL to administrators only
You can read the file with the PoC :)