Closed SAERXCIT closed 2 years ago
HI! I took a quick look at your PR. Your code looks really great! :astonished: This will be a really nice addition to PrivescCheck. I'll just have to do some tests this weekend but I'm sure it will be fine. 🙂
Thanks! To be honest most of it is strongly inspired from the links in Get-ShadowCopies
comments, so thanks to them.
Just a heads up, the code does not work in PSv2 as [IO.File]::Open
does not accept paths starting with \\?\GLOBALROOT
. I'm currently trying to rewrite it using CreateFile
and GetFileAttributesEx
.
Pushed a hopefully fixed version, it now works in my powershell -version 2
shell.
The check is now performed using CreateFile
with ReadData
access, and I consider that access is possible if the handle returned is not -1
. Let me know if this might generate false positives.
Additionally, the last write time is now retrieved using GetFileAttributesEx
. I had to add some more Win32 stuff, so if this is not wanted, ditch it, it's not the most important part :upside_down_face:
In the end, I could not use the code of your PR as is. I had to do a lot of modifications. So I didn't merge it but I used your code as a solid base for my own commit.
Main & Win32
GetFileAttributesEx
and the associated structures as the last write time wasn't that relevant IMHO.-SetLastError
flag in the definition of the NT functions as they do not set the last error code. They are native functions, not Win32 functions. Their error code is directly returned (NTSTATUS
).NtQueryDirectoryObject
. The last argument is a pointer.RtlNtStatusToDosError
to convert an NTSTATUS
to a Win32 error code.Get-ShadowCopies
GetLastError
(as explained previously).$odi
as $ObjectDirectoryInformation
, it's a convention I try to follow in the code.Helpers
Get-NamePipeDacl
as Get-FileDacl
as its code was rather generic and could be used to retrieve the DACL of any file, not only named pipes.Credentials
Invoke-SensitiveHiveShadowCopyCheck
to query and parse the DACL of the files. This yields a cleaner output IMHO.PS C:\> Invoke-SensitiveHiveShadowCopyCheck | fl
Volume : HarddiskVolumeShadowCopy3
Path : \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy3\Windows\System32\config\SAM
IdentityReference : BUILTIN\Users
AccessRights : ReadData, ReadExtendedAttributes, Execute, ReadAttributes, ReadControl, Synchronize
Volume : HarddiskVolumeShadowCopy3
Path : \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy3\Windows\System32\config\SECURITY
IdentityReference : BUILTIN\Users
AccessRights : ReadData, ReadExtendedAttributes, Execute, ReadAttributes, ReadControl, Synchronize
Volume : HarddiskVolumeShadowCopy3
Path : \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy3\Windows\System32\config\SYSTEM
IdentityReference : BUILTIN\Users
AccessRights : ReadData, ReadExtendedAttributes, Execute, ReadAttributes, ReadControl, Synchronize
Great! Thanks a lot for your work, the detailed changelog, and the shout out :) I'm glad PrivescCheck now checks for that.
There was a lot of issues with my code haha, as you could see I had never programmed for Windows anything more advanced than a dumb DLL with commands in a WinExec
, so I got confused :upside_down_face: For that I greatly appreciate your explanations!
Regarding the last write time info, it was quickly determine the most recent copy containing the most up-to-date data, in the edge case where multiple shadow copies exist and the last one is not for some reason the most recent one. I don't even know if this is possible so as you said this is probably irrelevant.
Closing the PR, cheers!
Hi Clément!
This PR adds a new helper function (
Get-ShadowCopies
) and a new check (Invoke-SensitiveHiveShadowCopyCheck
). It will check if the user has read access on the SAM/SECURITY/SYSTEM hives in all existing shadow copies.Why
Microsoft has patched this August CVE-2021-36934, but as noted in the advisory:
To avoid deleting data without users' consent, we have opted to allow users to delete their shadow copies themselves
. Since manual intervention is required to remove/regenerate shadow copies after applying this update, this vuln might stay with us for a long time. As such, I felt a check for it was a good addition to PrivescCheck.How
Get-ShadowCopies
uses the Win32 functionsNtOpenDirectoryObject
andNtQueryDirectoryObject
fromntdll.dll
to list all existing shadow copies. I had to add their definition tosrc/01_Win32.ps1
since they were not present there.Invoke-SensitiveHiveShadowCopyCheck
calls[IO.File]::Open
on each hive file usingRead
access, asGet-Acl
does not work on the type of paths used (\\?\GLOBALROOT\...
). If this call succeeds, I consider that the user has read access on the hive file. I don't know of any scenario where that would not be the case. Additionally, the fileLastWriteTime
is printed to help find the most recent copy available.Example
Here,
HarddiskVolumeShadowCopy1
was created before applying the update/mitigation (icacls $env:windir\system32\config\*.* /inheritance:e
), andHarddiskVolumeShadowCopy2
after, so as expectedHarddiskVolumeShadowCopy1
is still vulnerable.This has only been tested on one VM so further testing is welcome :upside_down_face:
Cheers!