BadPotato/RPC/nullsession.cs

231 lines
9.8 KiB
C#

//
// Copyright (c) Ping Castle. All rights reserved.
// https://www.pingcastle.com
//
// Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
//
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Security.Principal;
using System.Text;
namespace PingCastle.RPC
{
public enum TypeOfEnumeration
{
Samr,
Lsa,
}
public class NullSessionTester
{
public delegate void Enumerate(NTAccount account);
public Enumerate EnumerateCallback { get; set; }
public string Server { get; set; }
public uint RPCTimeOut { get; set; }
public NullSessionTester(string server, Enumerate enumerateCallback = null)
{
Server = server;
EnumerateCallback = enumerateCallback;
}
public bool EnumerateAccount(int MaximumNumber = int.MaxValue)
{
if (EnumerateAccount(TypeOfEnumeration.Samr, MaximumNumber))
return true;
return EnumerateAccount(TypeOfEnumeration.Lsa, MaximumNumber);
}
public bool EnumerateAccount(TypeOfEnumeration method, int MaximumNumber = int.MaxValue)
{
if (method == TypeOfEnumeration.Samr)
{
return EnumerateAccountUsingSamr(method, MaximumNumber);
}
else if (method == TypeOfEnumeration.Lsa)
{
return EnumerateAccountUsingLsa(method, MaximumNumber);
}
return false;
}
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
private bool EnumerateAccountUsingLsa(TypeOfEnumeration method, int MaximumNumber)
{
Trace.WriteLine("EnumerateAccountUsingLsa");
int UserEnumerated = 0;
Int32 returnCode;
IntPtr PolicyHandle = IntPtr.Zero;
lsa lsa = new lsa();
lsa.RPCTimeOut = this.RPCTimeOut;
returnCode = lsa.LsarOpenPolicy(Server, 0x00000801, out PolicyHandle);
if (returnCode != 0)
{
Trace.WriteLine("LsarOpenPolicy " + returnCode);
return false;
}
try
{
LSA_DOMAIN_INFORMATION PolicyInformation;
returnCode = lsa.LsarQueryInformationPolicy(PolicyHandle, 5, out PolicyInformation);
if (returnCode != 0)
{
Trace.WriteLine("LsarQueryInformationPolicy " + returnCode);
return false;
}
uint currentRid = 500;
int iteration = 0;
// allows 10*1000 sid non resolved
int retrycount = 0;
while ((returnCode == 0 || returnCode == 0x00000107 || (retrycount < 10 && returnCode == -1073741709)) && UserEnumerated < MaximumNumber)
{
Trace.WriteLine("LsarLookupSids iteration " + iteration++);
SecurityIdentifier[] enumBuffer = new SecurityIdentifier[1000];
for (int i = 0; i < enumBuffer.Length; i++)
{
enumBuffer[i] = BuildSIDFromDomainSidAndRid(PolicyInformation.DomainSid, currentRid++);
}
UInt32 MappedCount;
LSA_LOOKUP_RESULT[] LookupResult;
returnCode = lsa.LsarLookupSids(PolicyHandle, enumBuffer, out LookupResult, 2, out MappedCount);
if (returnCode == 0 || returnCode == 0x00000107)
{
retrycount = 0;
for (int i = 0; i < enumBuffer.Length && UserEnumerated < MaximumNumber; i++)
{
if (LookupResult[i].Use == SID_NAME_USE.SidTypeUser && !String.IsNullOrEmpty(LookupResult[i].TranslatedName))
{
UserEnumerated++;
Trace.WriteLine("User:" + LookupResult[i].TranslatedName);
if (EnumerateCallback != null)
{
EnumerateCallback(new NTAccount(LookupResult[i].DomainName, LookupResult[i].TranslatedName));
}
}
}
}
else
{
retrycount++;
Trace.WriteLine("LsarLookupSids " + returnCode);
}
}
}
finally
{
returnCode = lsa.LsarClose(ref PolicyHandle);
}
Trace.WriteLine("EnumerateAccountUsingLsa done");
return UserEnumerated > 0;
}
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
private bool EnumerateAccountUsingSamr(TypeOfEnumeration method, int MaximumNumber)
{
Trace.WriteLine("EnumerateAccountUsingSamr");
int UserEnumerated = 0;
IntPtr ServerHandle = IntPtr.Zero;
samr sam = new samr();
sam.RPCTimeOut = this.RPCTimeOut;
Int32 returnCode;
returnCode = sam.SamrConnect(Server, out ServerHandle, 0x20030);
if (returnCode != 0)
{
Trace.WriteLine("SamrConnect " + returnCode);
return false;
}
try
{
IntPtr enumerationContext = IntPtr.Zero;
SAMR_ENUMERATION_ENTRY[] Buffer = null;
UInt32 CountReturned = 0;
returnCode = sam.SamrEnumerateDomainsInSamServer(ServerHandle, ref enumerationContext, out Buffer, 10000, out CountReturned);
if (returnCode != 0)
{
Trace.WriteLine("SamrEnumerateDomainsInSamServer " + returnCode);
return false;
}
for (ulong i = 0; i < CountReturned; i++)
{
Trace.WriteLine("Domain:" + Buffer[i].Name);
SecurityIdentifier DomainId;
IntPtr DomainHandle = IntPtr.Zero;
IntPtr enumerationContextUser = IntPtr.Zero;
SAMR_ENUMERATION_ENTRY[] EnumerationBuffer = null;
UInt32 UserCount = 0;
returnCode = sam.SamrLookupDomainInSamServer(ServerHandle, Buffer[i].Name, out DomainId);
if (returnCode < 0)
{
Trace.WriteLine("SamrLookupDomainInSamServer " + returnCode);
continue;
}
returnCode = sam.SamrOpenDomain(ServerHandle, 0x100, DomainId, out DomainHandle);
if (returnCode < 0)
{
Trace.WriteLine("SamrOpenDomain " + returnCode);
continue;
}
try
{
int iteration = 0;
returnCode = 0x00000105;
while (returnCode == 0x00000105 && UserEnumerated < MaximumNumber)
{
Trace.WriteLine("SamrEnumerateUsersInDomain iteration " + iteration++);
returnCode = sam.SamrEnumerateUsersInDomain(DomainHandle, ref enumerationContextUser, 0, out EnumerationBuffer, 10000, out UserCount);
if ((returnCode == 0 || returnCode == 0x00000105) && EnumerationBuffer != null)
{
for (int j = 0; j < EnumerationBuffer.Length && UserEnumerated++ < MaximumNumber; j++)
{
Trace.WriteLine("User:" + EnumerationBuffer[j].Name);
if (EnumerateCallback != null)
{
EnumerateCallback(new NTAccount(Buffer[i].Name, EnumerationBuffer[j].Name));
}
}
}
}
Trace.WriteLine("SamrEnumerateUsersInDomain " + returnCode);
}
finally
{
sam.SamrCloseHandle(ref DomainHandle);
}
}
}
finally
{
sam.SamrCloseHandle(ref ServerHandle);
}
Trace.WriteLine("EnumerateAccountUsingSamr done");
return UserEnumerated > 0;
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static SecurityIdentifier BuildSIDFromDomainSidAndRid(SecurityIdentifier DomainSid, UInt32 Rid)
{
byte[] sidByteForm = new byte[SecurityIdentifier.MaxBinaryLength];
DomainSid.GetBinaryForm(sidByteForm, 0);
GCHandle handle = GCHandle.Alloc(sidByteForm, GCHandleType.Pinned);
IntPtr sidIntPtr = handle.AddrOfPinnedObject();
IntPtr SubAuthorityCountIntPtr = NativeMethods.GetSidSubAuthorityCount(sidIntPtr);
byte SubAuthorityCount = Marshal.ReadByte(SubAuthorityCountIntPtr);
Marshal.WriteByte(SubAuthorityCountIntPtr, ++SubAuthorityCount);
IntPtr SubAuthorityIntPtr = NativeMethods.GetSidSubAuthority(sidIntPtr, (uint)SubAuthorityCount - 1);
Marshal.WriteInt32(SubAuthorityIntPtr, (int)Rid);
SecurityIdentifier output = new SecurityIdentifier(sidIntPtr);
handle.Free();
return output;
}
}
}