googleprojectzero / sandbox-attacksurface-analysis-tools Goto Github PK
View Code? Open in Web Editor NEWSet of tools to analyze Windows sandboxes for exposed attack surface.
License: Apache License 2.0
Set of tools to analyze Windows sandboxes for exposed attack surface.
License: Apache License 2.0
Hi James,
I was checking the function HcsRpc_ShutdownSystem
(from vmcompute.exe
- HCS service):
PS> $a = Get-RpcServer "C:\windows\system32\vmcompute.exe" -DbgHelpPath "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\dbghelp.dll"
PS> $a.Procedures[4]
Name : HcsRpc_ShutdownSystem
Params : {FC_SUPPLEMENT - NdrSupplementTypeReference - IsIn, , FC_UP - NdrPointerTypeReference - MustSize, MustFree, IsIn, FC_HYPER - NdrSimpleTypeReference - IsIn,
IsBasetype...}
l saw it has 4 arguments (there is a fifth without a Name
so I don't know if I should include it):
PS> $a.Procedures[4].Params
Attributes : IsIn
Type : FC_SUPPLEMENT - NdrSupplementTypeReference
ServerAllocSize : 0
Offset : 0
Name : p0
IsIn : True
IsOut : False
IsInOut : False
IsSimpleRef : False
Explicit : True
Generic : False
Attributes : 0
Type : FC_BIND_CONTEXT - NdrSimpleTypeReference
ServerAllocSize : 0
Offset : 0
Name :
IsIn : False
IsOut : False
IsInOut : False
IsSimpleRef : False
Attributes : MustSize, MustFree, IsIn
Type : FC_UP - NdrPointerTypeReference
ServerAllocSize : 0
Offset : 8
Name : p1
IsIn : True
IsOut : False
IsInOut : False
IsSimpleRef : False
Attributes : IsIn, IsBasetype
Type : FC_HYPER - NdrSimpleTypeReference
ServerAllocSize : 0
Offset : 16
Name : p2
IsIn : True
IsOut : False
IsInOut : False
IsSimpleRef : False
Attributes : MustSize, MustFree, IsOut
Type : FC_RP - NdrPointerTypeReference
ServerAllocSize : 8
Offset : 24
Name : p3
IsIn : False
IsOut : True
IsInOut : False
IsSimpleRef : False
I connected the client:
PS> $a.Endpoints
UUID Version Protocol Endpoint Annotation
e7a216af-1ec1-447f-8d3f-a87278db564d 1.0 ncalrpc LRPC-6981a149a72e0ebb3e
PS> $client = Get-RpcClient $rpc
PS> Connect-RpcClient $c -EndpointPath "LRPC-6981a149a72e0ebb3e"
PS> $c.Connected
True
But when I tried to call it with 4 parameters (p0,p1,p2 and p3
) it didn't accept it:
PS> $c.HcsRpc_ShutdownSystem([NullString]::Value, [NullString]::Value, [NullString]::Value, [NullString]::Value)
Cannot find an overload for "HcsRpc_ShutdownSystem" and the argument count: "4".
But with 3 parameters it didn't throw the "Cannot find an overload" error.
It throw other error about using the wrong type but this is a different issue.
I am currently want to understand why the Params
shows me 4 (maybe 5) parameters when the client can send only 3.
I reversed the vmcompute.exe
and vmcompute.dll
, it seems that in both (server and client) it receives 4 parameters and not 3:
Why I am getting the overload error when using 4 parameters?
I am using NtFileOpen
on named pipes, sometimes some fields are throwing an exception while others are not:
Is there a way to check if a field threw an exception without using try..catch
for every field?
For example, in the following code, we can get an object with fields that threw an exception:
namedPipeFileObject = (NtNamedPipeFileBase)NtFile.Open(obj_attributes, i_Access, i_ShareMode, i_Options);
row.Cells[0].Value = namedPipeObject.NumberOfLinks;
row.Cells[1].Value = namedPipeObject.DirectoryGrantedAccess;
row.Cells[2].Value = namedPipeObject.GrantedAccess;
row.Cells[3].Value = namedPipeObject.GrantedAccessGeneric;
But using try..catch
for every field can be overkill, especially if we will go over all the fields.
Any suggestion how to handle it?
Hello,
I was searching for RTL_USER_PROCESS_PARAMETERS in your project but can't find it. You did not implement it ?
The current release show 1.1.33 as latest
https://github.com/googleprojectzero/sandbox-attacksurface-analysis-tools/releases
The PS Gallery has 2.0 published with an alpha as well..
https://www.powershellgallery.com/packages/NtObjectManager/2.0.0
In Windows 11 24H2, BindFlt now has public APIs for creation and removal of bind links, as described in https://learn.microsoft.com/en-us/windows/win32/bindlink/bindlink-overview.
It would be useful for NtObjectManager to have wrappers for these APIs, since overwriting file or directory paths or introducing merges would certainly have security implications in many scenarios.
When I am calling RpcServer.ParsePeFile
like that:
string name = @"C:\Windows\winsxs\x86_wcf-system.identitymodel_b03f5f7f11d50a3a_10.0.19041.1_none_e690fdc7d17e3f70\System.IdentityModel.dll";
string symbolsPath = @"srv*c:\symbols*http://msdl.microsoft.com/download/symbols";
string dbgHelp = @"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\dbghelp.dll";
NtApiDotNet.Win32.RpcServer.ParsePeFile(name, dbgHelp , symbolsPath , NtApiDotNet.Win32.RpcServerParserFlags.None);
I am getting the following error:
C:\Windows\winsxs\x86_wcf-system.identitymodel_b03f5f7f11d50a3a_10.0.19041.1_none_e690fdc7d17e3f70\System.IdentityModel.dll is either not designed to run on Windows or it contains an error. Try installing the program again using the original installation media or contact your system administator or the software vendor for support. Error status: 0xc000012f.
The problem is that I when I tried to use try...catch
it doesn't work on these kind of errors.
Any idea how to solve\workaround it?
I noticed that the DLL PE magic starts with DCS
which is related to Delta Compression Application.
More reference from this answer.
I think I can workaround it by checking the magic of the file by reading it first before moving it to the function but it might affect the performance a bit.
The problem can also repeat if you run it like that:
rpcFile = @"C:\Windows\winsxs\x86_wcf-system.identitymodel_b03f5f7f11d50a3a_10.0.19041.1_none_e690fdc7d17e3f70\System.IdentityModel.dll";
using (var result = SafeLoadLibraryHandle.LoadLibrary(rpcFile, LoadLibraryFlags.DontResolveDllReferences, false))
{
}
I noticed that it won't help to check for MZ
as magic file because there are files like:
C:\Windows\winsxs\x86_microsoft-windows-n..nd-syswow64-payload_31bf3856ad364e35_1.0.19041.1_none_beac3411b23832d5\compobj.dll
Which starts with MZ
but still have bad image.
Thanks
Hi,
With PowerShell we can run:
PS C:\WINDOWS\system32> Get-NtNamedPipeFile("\Device\NamedPipe\initShutdown")
Handle Name NtTypeName Inherit ProtectFromClose
------ ---- ---------- ------- ----------------
2988 InitShutdown File False False
I want to do it programmatically with C#. I found how it is being called with C#:
I made the below function but I don't know how to initialize NtObject root
:
FileShareMode ShareMode = FileShareMode.Read | FileShareMode.Write;
FileOpenOptions Options = FileOpenOptions.SynchronousIoNonAlert;
FileAccessRights Access = FileAccessRights.GenericRead | FileAccessRights.GenericWrite | FileAccessRights.Synchronize;
using (ObjectAttributes obj_attributes = new ObjectAttributes(i_NamedPipe, AttributeFlags.CaseInsensitive, root))
{
var a = NtFile.CreateNamedPipe(obj_attributes, Access, ShareMode, Options, FileDisposition.Open, NamedPipeType.Bytestream,
NamedPipeReadMode.ByteStream, NamedPipeCompletionMode.CompleteOperation, 0, 0, 0, NtWaitTimeout.FromMilliseconds(0));
}
Does it make sense to have a GitHub Actions Workflow to automatically build the source and respective Release.7z artifact of this repository? If you want that, I can probably do a PR.
Hi James,
Amazing project :)
I am using the NtObjectManager
and for now it helps me a lot.
I had an idea I wanted to share.
The Problem
Today, as far as I know, when I want to export RpcServer functions, I can use such command:
Get-RpcServer 'C:\windows\system32\combase.dll' -DbgHelpPath "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\dbghelp.dll"
But when I used RPCView, you can see that svchost.exe
also exports RPC functions but when trying to export it like that:
Get-RpcServer 'C:\windows\system32\svchost.exe'
It won't work. The reason is that it uses DLLs that have the RPC functions.
For example this svchost
:
C:\Windows\system32\svchost.exe C:\Windows\system32\svchost.exe -k LocalServiceNetworkRestricted -p -s TimeBrokerSvc
According to RPCView, it uses:
C:\Windows\system32\combase.dll
C:\Windows\system32\BrokerLib.dll
C:\Windows\system32\TimeBrokerServer.dll
They export the functions of the DLLs.
The Idea
A new function, maybe Get-RpcServerByPid.
It will know to export processes like svchost.exe
.
I don't know how they did it, but I suppose they listed the modules of the process and checked each of its modules.
Example:
Get-RpcServerByPid <pid_of_svchost>
It will run Get-RpcServer
on svchost.exe
and list all its loaded modules and run it on them.
I spoke about svchost.exe
but of course it should be generic and the logic will run on each process PID that you will decide.
Forgive me for not knowing all of the proper terminology to use here, I'll do my best to describe what I'm observing. I've been using Get-NtApiSet to resolve ApiSet names to their implementation DLL. Recently, I was analyzing kernel32!OpenProcess to use as a demonstration in a workshop and noticed what I suspect is a looping issue. As I'm sure you're aware, kernel32!OpenProcess is a simple wrapper that calls an imported function. On the version of Windows that I am using (), it is calling api-ms-win-core-processthreads-l1-1-2!OpenProcess
. Now I know that the implementation is in kernelbase.dll, but because this is for a workshop I want to show my work. To do this, I've been relying on Get-NtApiSet as it seems to be the best solution for this type of resolution. However, this particular time I noticed an issue with the resolution. Here is the command and output:
Get-NtApiSet -Name api-ms-win-core-processthreads-l1-1-2
Name HostModule Flags
---- ---------- -----
api-ms-win-core-processthreads-l1-1-3 kernel32.dll Sealed
Now I think I only noticed this because I knew that the resulting HostModule should have been kernelbase.dll, but also notice that I requested version l1-1-2
and it returned version l1-1-3
. I decided to just list all ApiSets that were known to the tool and found a pattern that when the final number in the version (the minor version maybe) is non zero, the results will only include the largest value. For example, here is the output for the example mentioned above:
api-ms-win-core-processsecurity-l1-1-0 kernel32.dll Sealed
api-ms-win-core-processsnapshot-l1-1-0 kernelbase.dll Sealed
api-ms-win-core-processthreads-l1-1-3 kernel32.dll Sealed
I did however notice that in cases where the 2nd to last number in the version (the major number?) is non zero, it includes both versions:
api-ms-win-core-processtopology-l1-1-0 kernelbase.dll Sealed
api-ms-win-core-processtopology-l1-2-0 kernelbase.dll Sealed
This leads me to suspect that maybe there is some issue with the looping where the results being aren't being added to the list at the lowest level? I looked through the code to see if I could spot anything, but haven't found it yet. I'll keep looking, but thought I'd put this on your radar in case you can think of a quick solution or know something that I don't about ApiSets and their versions.
I have a named pipe with the following name:
PS C:\WINDOWS\system32> $pipes = [System.IO.Directory]::GetFiles("\\.\\pipe\\")
PS C:\WINDOWS\system32> $pipes[5]
\\.\\pipe\\Winsock2\CatalogChangeListener-5f4-0
When I run Get-NtNamedPipeFile
it fails:
PS C:\WINDOWS\system32> $b = Get-NtNamedPipeFile("\\Device\\NamedPipe\\Winsock2\\CatalogChangeListener-5f4-0")
Get-NtNamedPipeFile : (0xC0000033) - Object Name invalid.
At line:1 char:6
+ $b = Get-NtNamedPipeFile("\\Device\\NamedPipe\\Winsock2\\CatalogChang ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-NtNamedPipeFile], NtException
+ FullyQualifiedErrorId : NtApiDotNet.NtException,NtObjectManager.Cmdlets.Object.GetNtNamedPipeFileCmdlet
What can be the reason for that and is it possible to solve it?
Hi James,
The RPC functions from PowerShell works good:
PS C:\WINDOWS\system32> Get-RpcServer "C:\tmp\CExecSvc.exe" -DbgHelpPath "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\dbghelp.dll"
Name UUID Ver Procs EPs Service Running
---- ---- --- ----- --- ------- -------
CExecSvc.exe 75ef42c7-22f4-44a0-8200-9351cd316e01 1.0 4 0 False
I wanted to use the Get-RpcServer
from C# code. I searched in the PowerShell script and found that you are using [NtApiDotNet.Win32.RpcServer]::ParsePeFile
to do it:
sandbox-attacksurface-analysis-tools/NtObjectManager/RpcFunctions.ps1
Lines 311 to 318 in 067c758
I wrote it in C#:
// string symbols = @"srv*c:\symbols*http://msdl.microsoft.com/download/symbols";
string dbg = @"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\dbghelp.dll";
string rpcFile = @"C:\tmp\CExecSvc.exe";
var rpcServer = NtApiDotNet.Win32.RpcServer.ParsePeFile(rpcFile, dbg, "", NtApiDotNet.Win32.RpcServerParserFlags.None);
But the rpcServer
variable is empty (Count=0
). Any idea what I am missing here?
Notice that I also tried with symbols without success.
I am using NtApiDoNet.dll
version 1.1.33
Windows Defender is reporting the module as Trojan:Win32/Tiggre!rfn
:NtApiDotNet.Forms.dll
and Trojan:Win32/Wacatac.B!ml
:ViewSecurityDescriptor.exe
Hi James, Thanks for the great work.
When I run the work on Win10 22H2 (19045.2728) with the command $allrpc = ls "C:\Windows\system32\*" -Include "*.dll","*.exe" | Get-RpcServer
, it has the following errors:
Get-RpcServer : Exception calling "ParsePeFile" with "4" argument(s): "Value cannot be null.
Parameter name: key"
At line:1 char:65
+ ... = ls "C:\Windows\system32\*" -Include "*.dll","*.exe" | Get-RpcServer
+ ~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-RpcServer
This error just keep happening and it cannot parse any server. I guess this happens because Windows has changed its APIs? or because some kind of new Windows security policies?
btw, when I run the same command on Win10 1909, it has no problem.
0:026> !dumpstack
OS Thread Id: 0x2ae4 (26)
Current frame: VCRUNTIME140_CLR0400!memcpy+0xff
Child-SP RetAddr Caller, Callee
000000fbf164ce10 00007ffb89cbab46 clr!SafeBuffer::PtrToStructure+0x16, calling VCRUNTIME140_CLR0400!memcpy
000000fbf164ce20 00007ffb89cbab13 clr!SafeBuffer::SizeOfType+0x43, calling clr!MethodTable::GetClass
000000fbf164ce40 00007ffb2a66cc9c (MethodDesc 00007ffb2aa03620 +0x2c System.Runtime.InteropServices.SafeBuffer.GenericPtrToStructure[[System.Byte, mscorlib]](Byte*, Byte ByRef, UInt32)), calling 00007ffb89cbab30 (stub for System.Runtime.InteropServices.SafeBuffer.PtrToStructureNative(Byte*, TypedReference, UInt32))
000000fbf164ce58 00007ffb89b56c5f clr!SafeHandle::DangerousAddRef+0x6f, calling clr!LazyMachStateCaptureState
000000fbf164ce80 00007ffb2a66ca22 (MethodDesc 00007ffb2aa035c0 +0x112 System.Runtime.InteropServices.SafeBuffer.ReadArray[[System.Byte, mscorlib]](UInt64, Byte[], Int32, Int32)), calling (MethodDesc 00007ffb2aa03620 +0 System.Runtime.InteropServices.SafeBuffer.GenericPtrToStructure[[System.Byte, mscorlib]](Byte*, Byte ByRef, UInt32))
000000fbf164cf00 00007ffb2a66c8e8 (MethodDesc 00007ffb2a9e4738 +0x48 NtApiDotNet.Win32.ImageSection.ToArray()), calling (MethodDesc 00007ffb2aa035c0 +0 System.Runtime.InteropServices.SafeBuffer.ReadArray[[System.Byte, mscorlib]](UInt64, Byte[], Int32, Int32))
000000fbf164cf10 00007ffb70abdb8a (MethodDesc 00007ffb706e6918 +0x1a System.Guid.ToByteArray()), calling clr!JIT_NewArr1VC_MP_InlineGetThread
000000fbf164cf40 00007ffb2a66c646 (MethodDesc 00007ffb2a9ec490 +0x56 NtApiDotNet.Win32.RpcServer+<FindRpcServerInterfaces>d__60.MoveNext()), calling (MethodDesc 00007ffb2a9e4738 +0 NtApiDotNet.Win32.ImageSection.ToArray())
000000fbf164cf60 00007ffb2a66c5c1 (MethodDesc 00007ffb2a9ec500 +0x51 NtApiDotNet.Win32.RpcServer+<FindRpcServerInterfaces>d__60.System.Collections.Generic.IEnumerable<NtApiDotNet.Win32.RpcServer.RpcOffset>.GetEnumerator()), calling clr!JIT_WriteBarrier
000000fbf164cf70 00007ffb2a66c445 (MethodDesc 00007ffb2a9e3988 +0x15 NtApiDotNet.Win32.RpcServer+<>c__DisplayClass51_0.<ParsePeFile>b__0(NtApiDotNet.Win32.ImageSection)), calling (MethodDesc 00007ffb2a9e59c8 +0 NtApiDotNet.NtObjectUtils.HasFlagSet[[NtApiDotNet.Win32.RpcServerParserFlags, NtApiDotNet]](NtApiDotNet.Win32.RpcServerParserFlags, NtApiDotNet.Win32.RpcServerParserFlags))
000000fbf164cfa0 00007ffb2a66c2c5 (MethodDesc 00007ffb2a9ebec0 +0x155 System.Linq.Enumerable+<SelectManyIterator>d__17`2[[System.__Canon, mscorlib],[NtApiDotNet.Win32.RpcServer+RpcOffset, NtApiDotNet]].MoveNext()), calling 00007ffb2a53d760
000000fbf164cfc0 00007ffb2a66c14c (MethodDesc 00007ffb2a9ebf30 +0x5c System.Linq.Enumerable+<SelectManyIterator>d__17`2[[System.__Canon, mscorlib],[NtApiDotNet.Win32.RpcServer+RpcOffset, NtApiDotNet]].System.Collections.Generic.IEnumerable<TResult>.GetEnumerator()), calling clr!JIT_WriteBarrier
000000fbf164cfd0 00007ffb89b5b319 clr!JIT_GetCurrentManagedThreadId+0x9, calling clr!GetThread
000000fbf164d000 00007ffb2a66c015 (MethodDesc 00007ffb2a9e5720 +0x45 System.Linq.Enumerable.Any[[NtApiDotNet.Win32.RpcServer+RpcOffset, NtApiDotNet]](System.Collections.Generic.IEnumerable`1<RpcOffset>)), calling 00007ffb2a53d8a0
000000fbf164d050 00007ffb2a6695ae (MethodDesc 00007ffb2a9e14f8 +0x15e NtApiDotNet.Win32.RpcServer.ParsePeFile(System.String, System.String, System.String, NtApiDotNet.Win32.RpcServerParserFlags)), calling (MethodDesc 00007ffb2a9e5720 +0 System.Linq.Enumerable.Any[[NtApiDotNet.Win32.RpcServer+RpcOffset, NtApiDotNet]](System.Collections.Generic.IEnumerable`1<RpcOffset>))
000000fbf164d080 00007ffb89b769ef clr!GCInterface::SuppressFinalize+0x3f
The issue is reproduced with latest chrome.dll, presumably caused by the presence of .retplne
section with zero attributes, which is mapped as PAGE_NOACCESS
:
0:026> !vprot rdx
BaseAddress: 00007ffb36665000
AllocationBase: 00007ffb2d5b0000
AllocationProtect: 00000080 PAGE_EXECUTE_WRITECOPY
RegionSize: 0000000000001000
State: 00001000 MEM_COMMIT
Protect: 00000001 PAGE_NOACCESS
Type: 01000000 MEM_IMAGE
Suggested fix is to check Characteristics in SafeLoadLibraryHandle.SetupValues
:
for (int i = 0; i < header.FileHeader.NumberOfSections; ++i)
{
ImageSectionHeader section = (ImageSectionHeader)Marshal.PtrToStructure(buffer + i * header_size, typeof(ImageSectionHeader));
ImageSection sect = new ImageSection(section, MappedAsImage, base_ptr);
_image_sections.Add(sect);
}
I am not sure if this is possible but I have a svchost.exe
process that I want to see its procedures.
I used the following commands to get all the servers:
$a = Get-RpcAlpcServer | where-object {$_.ProcessName -eq "svchost.exe"}
I see the endpoints of each process but is there a way to find what procedures it has?
For example, in RPCView, I can see svchost.exe
with PID 2288 and it has two endpoints and two interfaces that shows the procedures:
I tried to check of the Endpoints
object has a way to get it but didn't see something:
This is more of a question (I'd be curious to understand roughly why this happens, even if there's no workaround):
I'm trying the following on Windows 10 (22H2): I start TokenViewer.exe elevated as a user that posseses "act as operating system" privileges. In the logon user tab I create a new processes (with Services4Users, i.e. without password). TokenViewer opens a new Windows in which displays the token of the new processes (which is Impersonation
level, as expected). Now in the Operations tab I try to create a cmd.exe
process (with Interactive
enabled). This works, a process is started and a window appears. However the resulting Window is black/blank, with a blue (but also blank) title bar. (See screenshot below). Things that I type in the cmd.exe shell aren't visible, but are being accepted (i.e. typing exit
+ ENTER closes the window/process).
I've also tried things like conhost.exe
, conhost.exe cmd.exe
, conemu.exe
, but this produced the same. This is also the case when trying to start other GUI apps like notepad.exe
.
If anyone could point me in the direction of an explanation, I'd highly appreciate it. Thanks in advance!
Does Get-RpcAlpcServer
can get the RpcAlpcServer from a process inside a container?
I had a container running with process CExecSvc.exe
(PID 4880) but when I tried to get it with the above function it didn't find it:
PS C:\Windows\system32> Get-RpcAlpcServer| where {$_.ProcessName -eq "cexecsvc.exe"}
PS C:\Windows\system32> Get-RpcAlpcServer -ProcessId 4880
PS C:\Windows\system32>
I noticed that RPCView also can't get this information.
This is not critical for me because I used the workaround with Get-RpcServer
on the file itself, just wondering if this is a bug or currently not possible.
Reference:
sandbox-attacksurface-analysis-tools/NtApiDotNet/Win32/RpcAlpcServer.cs
Lines 91 to 112 in c02ed8b
I updated the .NET framework to 4.8 for the other projects, and while building NtObjectManager, it failed. So I downgraded it to .NET framework 4.7.2. And compiled both NtApiDotNet and NtObjectManager. Buid Succeeds
It would be excellent if you could publish symbols for the nuget package, and adding sourcelink metadata would also be appreciated :)
I was going to submit a PR for it, but the contribution guidelines mention signing a copyright transfer thingie, which seems like too much work for this. Just adding a few lines to the csproj is all that's needed.
<PropertyGroup>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
</ItemGroup>
That should be all that's needed to add the sourcelink info and publish a symbol package to the nuget symbol server :)
Code to Reproduce:
foreach (var computer in computers)
{
var potentialString = $"ncacn_ip_tcp:{computer}";
var results = RpcEndpointMapper.QueryEndpoints(potentialString);
foreach (var result in results)
{
if (result.ProtocolSequence == "ncacn_ip_tcp")
{
Console.WriteLine($"Got result: {result}");
}
}
}
Result:
Multiple results are returned but fails when pinvoking RpcMgmtEpEltInqNext. authlogics02.authlogics.com is running Windows Server 2022, we don't see this behavior on other machines.
Got result: [50abc2a4-574d-40b3-9d66-ee4fd5fba076, 5.0] ncacn_ip_tcp:authlogics02.authlogics.com[58522]
Got result: [6bffd098-a112-3610-9833-46c3f874532d, 1.0] ncacn_ip_tcp:authlogics02.authlogics.com[58502]
Got result: [5b821720-f63b-11d0-aad2-00c04fc324db, 1.0] ncacn_ip_tcp:authlogics02.authlogics.com[58502]
Got result: [897e2e5f-93f3-4376-9c9c-fd2277495c27, 1.0] ncacn_ip_tcp:authlogics02.authlogics.com[58483]
Got result: [367abb81-9844-35f1-ad32-98f038001003, 2.0] ncacn_ip_tcp:authlogics02.authlogics.com[58464]
Got result: [12345678-1234-abcd-ef00-0123456789ab, 1.0] ncacn_ip_tcp:authlogics02.authlogics.com[49676]
Got result: [0b6edbfa-4a24-4fc6-8a23-942b1eca65d1, 1.0] ncacn_ip_tcp:authlogics02.authlogics.com[49676]
Got result: [ae33069b-a2a8-46ee-a235-ddfd339be281, 1.0] ncacn_ip_tcp:authlogics02.authlogics.com[49676]
Got result: [4a452661-8290-4b36-8fbe-7f4093a94978, 1.0] ncacn_ip_tcp:authlogics02.authlogics.com[49676]
Got result: [76f03f96-cdfd-44fc-a22c-64950a001209, 1.0] ncacn_ip_tcp:authlogics02.authlogics.com[49676]
Got result: [29770a8f-829b-4158-90a2-78cd488501f7, 1.0] ncacn_ip_tcp:authlogics02.authlogics.com[49671]
Got result: [86d35949-83c9-4044-b424-db363231fd0c, 1.0] ncacn_ip_tcp:authlogics02.authlogics.com[49668]
Got result: [3a9ef155-691d-4449-8d05-09ad57031823, 1.0] ncacn_ip_tcp:authlogics02.authlogics.com[49668]
Got result: [f6beaff7-1e19-4fbb-9f8f-b89e2018337c, 1.0] ncacn_ip_tcp:authlogics02.authlogics.com[49666]Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at NtApiDotNet.Win32.Win32NativeMethods.RpcMgmtEpEltInqNext(SafeRpcInquiryHandle InquiryContext, RPC_IF_ID IfId, SafeRpcBindingHandle& Binding, UUID ObjectUuid, SafeRpcStringHandle& Annotation)
at NtApiDotNet.Win32.RpcEndpointMapper.d__0.MoveNext() in D:\Github\sandbox-attacksurface-analysis-tools\NtApiDotNet\Win32\RpcEndpointMapper.cs:line 88
错误 CS0165 使用了未赋值的局部变量“ticket” NtApiDotNet D:\sandbox-attacksurface-analysis-tools\NtApiDotNet\Win32\Security\Authentication\Kerberos\Builder\KerberosTicketBuilder.cs 208 活动
I encountered the following bug in FromByteArray while executing DumpReparsePoints with the handling of the IO_REPARSE_TAG_AF_UNIX tag.
filename: "C:\Users\xxxx\AppData\Local\Packages\TheDebianProject.DebianGNULinux_76v4gfsz19hv4\LocalState\fsserver" ends up with the bytestream: 230000800000000000000000000000000000000000000000
BinaryReader reader = new BinaryReader(new MemoryStream(ba), Encoding.Unicode); // results in IO_REPARSE_TAG_AF_UNIX (0x80000023)
ReparseTag tag = (ReparseTag)reader.ReadUInt32(); // results in IO_REPARSE_TAG_AF_UNIX (0x80000023)
int data_length = reader.ReadUInt16(); // results in 0
// Reserved
reader.ReadUInt16(); // obsolete
long remaining_length = reader.RemainingLength(); // results in 16 (Remaining null bytes)
long expected_length = data_length; // results in 0
if (!NtFileUtils.IsReparseTagMicrosoft(tag)) // returns false, doesn't enter the if statement
{
expected_length += 16; // obsolete
}
if (remaining_length != expected_length) // 16 != 0, enters the if statement
{
// Corrupted buffer. Return an opaque buffer with all the data until the end.
return new OpaqueReparseBuffer(tag, reader.ReadToEnd()); // reader.ReadToEnd() ends with a System.OutOfMemoryException
}
I propose you to implement binary encoding for CLAIM_SECURITY_ATTRIBUTE_V1 data type. It is required for making "resource attribute" in security descriptor. The binary encoding is not officially documented, but you can find an example here.
Get-AccessibleFile -Recurse currently doesn't follow symlink and junction directories and I suppose this makes sense. However, I can see some cases where it's useful to follow such directories.
Could it be considered implementing an additional flag for this, that can be used in combination with the recurse flag?
Hi,
is it possible you provide Nuget packages targeting .net standard?
I saw the NtApiDotNet.Core.csproj but couldn't find a corresponding nuget package.
Hi James,
I am creating the following dummy named pipe without Dacl in Powershell:
function CreateDummyPipeForTesting {
$pipeSecurity = New-Object System.IO.Pipes.PipeSecurity
$pipeSecurity.SetAccessRuleProtection($true, $true)
$pipeServer = New-Object System.IO.Pipes.NamedPipeServerStream("myPipe", [System.IO.Pipes.PipeDirection]::InOut, -1, [System.IO.Pipes.PipeTransmissionMode]::Byte, [System.IO.Pipes.PipeOptions]::None, 4096, 4096, $pipeSecurity)
Write-Output "Waiting for client connection..."
$pipeServer.WaitForConnection()
Write-Output "Client connected."
$reader = New-Object System.IO.StreamReader($pipeServer)
$writer = New-Object System.IO.StreamWriter($pipeServer)
while ($true) {
$message = $reader.ReadLine()
Write-Output "Received message: $message"
$writer.WriteLine("Hello from the server!")
$writer.Flush()
}
}
CreateDummyPipeForTesting
When I run the PowerShell GetNtFile
, everything works fine:
PS C:\Users\eviatar> $b = Get-NtFile("\Device\NamedPipe\myPipe")
PS C:\Users\eviatar> $b.SecurityDescriptor | fl
Dacl : {}
Sacl :
But when I am trying to use the C# parallel function (NtFile.Open()
) like that:
public static NtNamedPipeFileBase GetNamedPipeObjectClient2()
{
NtNamedPipeFileBase namedPipeFileObject = null;
string i_NamedPipe = @"\Device\NamedPipe\myPipe";
//i_NamedPipe = @"\Device\NamedPipe\InitShutdown";
FileShareMode ShareMode = FileShareMode.Read | FileShareMode.Write;
FileOpenOptions Options = FileOpenOptions.SynchronousIoNonAlert;
FileAccessRights Access = FileAccessRights.GenericRead | FileAccessRights.GenericWrite | FileAccessRights.Synchronize;
using (ObjectAttributes obj_attributes = new ObjectAttributes(i_NamedPipe))
{
try
{
namedPipeFileObject = (NtNamedPipeFileBase)NtFile.Open(obj_attributes, Access, ShareMode, Options);
// namedPipeFileObject = NtFile.CreateNamedPipe(obj_attributes, Access, ShareMode, Options, FileDisposition.Open, NamedPipeType.Bytestream,
// NamedPipeReadMode.ByteStream, NamedPipeCompletionMode.CompleteOperation, 0, 0, 0, NtWaitTimeout.FromMilliseconds(0));
}
catch (Exception e)
{
//
}
};
return namedPipeFileObject;
}
I am getting an exception:
{"(0xC0000022) - {Access Denied}
A process has requested access to an object, but has not been granted those access rights."}
I also tried to run it with admin permissions with no success.
I used Get-NtFile
with standard permissions (not admin) and it worked, and I used the same user with the C# function, so I am not sure why it doesn't work.
Maybe my FileAccessRights
is wrong?
I tried to follow the source code but didn't see the use of the default permissions:
James, I was just testing out some of the new features introduced with the most recent 1.1.29 release and I came across some spelling mistakes in the code. Particularly, I've got a lot of interest in Added proper enumeration of AppContainer profiles and support creating with capabilities. So when I was digging into that code, I came across the spelling mistakes which I believe date back further in time.
Quick search: https://github.com/googleprojectzero/sandbox-attacksurface-analysis-tools/search?q=%22CreateSecuityCapabilities%22
Incorrect: Win32Utils.CreateSecuityCapabilities
Correct: Win32Utils.CreateSecurityCapabilities
I don't know if this would cause any functional issues or whether it is just a benign spelling typo in the code, but figured I should mention it to you. Cheers!
Running Get-AccessibleWnf
results in an access denied error when running as a lower-privileged user:
Get-AccessibleWnf : (0xC0000022) - {Access Denied}
A process has requested access to an object, but has not been granted those access rights.
The exception's stacktrace shows the following:
PS C:\> error[0].Exception.StackTrace
at NtApiDotNet.NtObjectUtils.CreateResult[T](NtStatus status, Boolean throw_on_error, Func`2 create_func, Action`1 error_func) in C:\code\sandbox-attacksurface-analysis-tools\NtApiDotNet\NtObjectUtils.cs:line 566
at NtApiDotNet.NtObjectUtils.CreateResult[T](NtStatus status, Boolean throw_on_error, Func`1 create_func) in C:\code\sandbox-attacksurface-analysis-tools\NtApiDotNet\NtObjectUtils.cs:line 533
at NtApiDotNet.NtWnf.Query[T](UInt64 state_name, WnfStateNameInformation info_class, Boolean throw_on_error) in C:\code\sandbox-attacksurface-analysis-tools\NtApiDotNet\NtWnf.cs:line 0
at NtApiDotNet.NtWnf.get_SubscribersPresent() in C:\code\sandbox-attacksurface-analysis-tools\NtApiDotNet\NtWnf.cs:line 310
at NtObjectManager.Cmdlets.Accessible.WnfAccessCheckResult..ctor(NtWnf wnf, AccessMask granted_access, SecurityDescriptor sd, TokenInformation token_info) in C:\code\sandbox-attacksurface-analysis-tools\NtObjectManager\Cmdlets\Accessible\WnfAccessCheckResult.cs:line 42
at NtObjectManager.Cmdlets.Accessible.GetAccessibleWnfCmdlet.RunAccessCheck(IEnumerable`1 tokens) in C:\code\sandbox-attacksurface-analysis-tools\NtObjectManager\Cmdlets\Accessible\GetAccessibleWnfCmdlet.cs:line 74
at NtObjectManager.Cmdlets.Accessible.CommonAccessBaseCmdlet.ProcessRecord() in C:\code\sandbox-attacksurface-analysis-tools\NtObjectManager\Cmdlets\Accessible\CommonAccessBaseCmdlet.cs:line 282
at System.Management.Automation.CommandProcessor.ProcessRecord()
I worked around it temporarily by setting this code to not throw errors, but don't know how much that changes expected behavior elsewhere:
public bool SubscribersPresent => Query<int>(StateName, WnfStateNameInformation.SubscribersPresent, false).Result != 0;
This issue was automatically created by Allstar.
Security Policy Violation
Project is out of compliance with Binary Artifacts policy: binaries present in source code
Rule Description
Binary Artifacts are an increased security risk in your repository. Binary artifacts cannot be reviewed, allowing the introduction of possibly obsolete or maliciously subverted executables. For more information see the Security Scorecards Documentation for Binary Artifacts.
Remediation Steps
To remediate, remove the generated executable artifacts from the repository.
Artifacts Found
Additional Information
This policy is drawn from Security Scorecards, which is a tool that scores a project's adherence to security best practices. You may wish to run a Scorecards scan directly on this repository for more details.
Allstar has been installed on all Google managed GitHub orgs. Policies are gradually being rolled out and enforced by the GOSST and OSPO teams. Learn more at http://go/allstar
This issue will auto resolve when the policy is in compliance.
Issue created by Allstar. See https://github.com/ossf/allstar/ for more information. For questions specific to the repository, please contact the owner or maintainer.
Observation:
When symbols fail to resolve for a binary, Get-RpcServer
appears to assign RPC procedure names incorrectly:
Tested with the latest code on Github as well as the version of NtObjectManager in the PSGallery. Confirmed that the symbol does not exist with symchk as well (can't grab it via winbindex either).
Expected outcome:
If symbol resolution fails, assign an out-generated procedure name (e.g., Proc0
, Proc1
, Proc2
, etc.). Might also throw a warning if symbols are configured but no symbols were found.
Link to example binary (hash C391E5024F1B8FAB6DCD88BBE3B36F71FAE02DD815EA9273D9ACB247781955FB
): spoolsv.exe.txt
Token viewer is a very nice tool which is useful in wide variety of use cases w.r.t analysis of a process's security. It would be great if the below use cases are supported
The need of second one arose when I was analyzing a store app where I was not able to access a file from one of the process running in a container. But a command prompt launched in the same security context with the tool called Hover (as per the documentation) was able to access it. I wanted to see how the privilege of command prompt launched from Hover is different from the actual process which failed to access a file. A comparison view which would result in showing the difference between these two processes would help in easier analysis.
Love the module. Thanks for all the work. I like to open my WindowsTerminal.exe
and/or ssms.exe
( e.g. _SQL Server Management Studio ) with Network Credentials. When I have a few windows open it would be nice to run a command to check if the current process has negotiated the network credentials and what credentials did it negotiate with.
I'm essentially using Get-NtlogonSession
to get the LogonId
where the LogonType
is NewCredentials
. Then I can pass the LogonSession
into Get-KerberosTicket
to view the potential negotiated credential name. Now in order to map the LogonId
to a process, I was using get-NtProcess -access QueryLimitedInformation
to grab all the ProcessId
s. Then I was using get-NttokenfromProcess
to grab the AuthenticationId
to map back to the LogonId
from Get-NtLogonSession
.
Is this the ideal way to do it or is there a more straightforward approach?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.