public Sid LookupSid(string name, out SidNameUse nameUse, out string domainName) { NtStatus status; UnicodeString nameStr; IntPtr referencedDomains; IntPtr sids; nameStr = new UnicodeString(name); try { if ((status = Win32.LsaLookupNames2( this, 0, 1, new UnicodeString[] { nameStr }, out referencedDomains, out sids )) >= NtStatus.Error) { Win32.ThrowLastError(status); } } finally { nameStr.Dispose(); } using (var referencedDomainsAlloc = new LsaMemoryAlloc(referencedDomains)) using (var sidsAlloc = new LsaMemoryAlloc(sids)) { LsaTranslatedSid2 translatedSid = sidsAlloc.ReadStruct <LsaTranslatedSid2>(); nameUse = translatedSid.Use; if (nameUse == SidNameUse.Invalid || nameUse == SidNameUse.Unknown) { domainName = null; return(null); } if (translatedSid.DomainIndex != -1) { LsaReferencedDomainList domains = referencedDomainsAlloc.ReadStruct <LsaReferencedDomainList>(); MemoryRegion trustArray = new MemoryRegion(domains.Domains); LsaTrustInformation trustInfo = trustArray.ReadStruct <LsaTrustInformation>(translatedSid.DomainIndex); domainName = trustInfo.Name.Read(); } else { domainName = null; } return(new Sid(translatedSid.Sid)); } }
public string LookupName(Sid sid, out SidNameUse nameUse, out string domainName) { NtStatus status; IntPtr referencedDomains; IntPtr names; if ((status = Win32.LsaLookupSids( this, 1, new IntPtr[] { sid }, out referencedDomains, out names )) >= NtStatus.Error) { if (status == NtStatus.NoneMapped) { nameUse = SidNameUse.Unknown; domainName = null; return(null); } Win32.Throw(status); } using (var referencedDomainsAlloc = new LsaMemoryAlloc(referencedDomains)) using (var namesAlloc = new LsaMemoryAlloc(names)) { LsaTranslatedName translatedName = namesAlloc.ReadStruct <LsaTranslatedName>(); nameUse = translatedName.Use; if (nameUse == SidNameUse.Invalid || nameUse == SidNameUse.Unknown) { domainName = null; return(null); } if (translatedName.DomainIndex != -1) { LsaReferencedDomainList domains = referencedDomainsAlloc.ReadStruct <LsaReferencedDomainList>(); MemoryRegion trustArray = new MemoryRegion(domains.Domains); LsaTrustInformation trustInfo = trustArray.ReadStruct <LsaTrustInformation>(translatedName.DomainIndex); domainName = trustInfo.Name.Read(); } else { domainName = null; } return(translatedName.Name.Read()); } }
private static SamEnumerationObject[] NetLocalGroupGetMembers(ResolvedEntry entry, out string machineSid) { Utils.Debug("Starting NetLocalGroupGetMembers"); var server = new UNICODE_STRING(entry.BloodHoundDisplay); //Connect to the server with the proper access maskes. This gives us our server handle var obj = default(OBJECT_ATTRIBUTES); Utils.Debug($"Starting SamConnect"); var status = SamConnect(ref server, out var serverHandle, SamAccessMasks.SamServerLookupDomain | SamAccessMasks.SamServerConnect, ref obj); Utils.Debug($"SamConnect returned {status}"); switch (status) { case NtStatus.StatusRpcServerUnavailable: throw new SystemDownException(); case NtStatus.StatusSuccess: break; default: throw new ApiFailedException(); } Utils.Debug($"Starting SamLookupDomainInSamServer"); //Use SamLookupDomainInServer with the hostname to find the machine sid if possible try { var san = new UNICODE_STRING(entry.ComputerSamAccountName); SamLookupDomainInSamServer(serverHandle, ref san, out var temp); //This will throw an exception if we didn't actually find the alias machineSid = new SecurityIdentifier(temp).Value; SamFreeMemory(temp); } catch { machineSid = "DUMMYSTRINGSHOULDNOTMATCH"; } Utils.Debug($"Resolved Machine Sid {machineSid}"); Utils.Debug($"Starting SamOpenDomain"); //Open the domain for the S-1-5-32 (BUILTIN) alias status = SamOpenDomain(serverHandle, DomainAccessMask.Lookup, _sidbytes, out var domainHandle); Utils.Debug($"SamOpenDomain returned {status}"); if (!status.Equals(NtStatus.StatusSuccess)) { SamCloseHandle(serverHandle); throw new ApiFailedException(); } Utils.Debug($"Starting SamOpenAlias"); //Open the alias for Local Administrators (always RID 544) status = SamOpenAlias(domainHandle, AliasOpenFlags.ListMembers, 544, out var aliasHandle); Utils.Debug($"SamOpenAlias returned {status}"); if (!status.Equals(NtStatus.StatusSuccess)) { SamCloseHandle(domainHandle); SamCloseHandle(serverHandle); throw new ApiFailedException(); } Utils.Debug($"Starting SamGetMembersInAlias"); //Get the members in the alias. This returns a list of SIDs status = SamGetMembersInAlias(aliasHandle, out var members, out var count); Utils.Debug($"SamGetMembersInAlias returned {status}"); if (!status.Equals(NtStatus.StatusSuccess)) { SamCloseHandle(aliasHandle); SamCloseHandle(domainHandle); SamCloseHandle(serverHandle); throw new ApiFailedException(); } Utils.Debug($"Cleaning up handles"); SamCloseHandle(aliasHandle); SamCloseHandle(domainHandle); SamCloseHandle(serverHandle); if (count == 0) { SamFreeMemory(members); return(new SamEnumerationObject[0]); } Utils.Debug($"Copying data"); //Copy the data of our sids to a new array so it doesn't get eaten var grabbedSids = new IntPtr[count]; Marshal.Copy(members, grabbedSids, 0, count); var sids = new string[count]; //Convert the bytes to strings for usage for (var i = 0; i < count; i++) { try { sids[i] = new SecurityIdentifier(grabbedSids[i]).Value; } catch { sids[i] = null; } } Utils.Debug($"Starting LsaOpenPolicy"); //Open the LSA policy on the target machine var obja = default(OBJECT_ATTRIBUTES); status = LsaOpenPolicy(ref server, ref obja, LsaOpenMask.ViewLocalInfo | LsaOpenMask.LookupNames, out var policyHandle); Utils.Debug($"LSAOpenPolicy returned {status}"); if (!status.Equals(NtStatus.StatusSuccess)) { LsaClose(policyHandle); SamFreeMemory(members); throw new ApiFailedException(); } Utils.Debug($"Starting LSALookupSids"); var nameList = IntPtr.Zero; var domainList = IntPtr.Zero; //Call LsaLookupSids using the sids we got from SamGetMembersInAlias status = LsaLookupSids(policyHandle, count, members, ref domainList, ref nameList); Utils.Debug($"LSALookupSids returned {status}"); if (!status.Equals(NtStatus.StatusSuccess) && !status.Equals(NtStatus.StatusSomeMapped)) { LsaClose(policyHandle); LsaFreeMemory(domainList); LsaFreeMemory(nameList); SamFreeMemory(members); throw new ApiFailedException(); } Utils.Debug($"Finished API calls"); //Convert the returned names into structures var iter = nameList; var translatedNames = new LsaTranslatedNames[count]; Utils.Debug($"Resolving names"); for (var i = 0; i < count; i++) { translatedNames[i] = (LsaTranslatedNames)Marshal.PtrToStructure(iter, typeof(LsaTranslatedNames)); iter = (IntPtr)(iter.ToInt64() + Marshal.SizeOf(typeof(LsaTranslatedNames))); } Utils.Debug($"Resolving domains"); //Convert the returned domain list to a structure var lsaDomainList = (LsaReferencedDomainList)(Marshal.PtrToStructure(domainList, typeof(LsaReferencedDomainList))); //Convert the domain list to individual structures var trustInfos = new LsaTrustInformation[lsaDomainList.count]; iter = lsaDomainList.domains; for (var i = 0; i < lsaDomainList.count; i++) { trustInfos[i] = (LsaTrustInformation)Marshal.PtrToStructure(iter, typeof(LsaTrustInformation)); iter = (IntPtr)(iter.ToInt64() + Marshal.SizeOf(typeof(LsaTrustInformation))); } Utils.Debug($"Matching up data"); var resolvedObjects = new SamEnumerationObject[translatedNames.Length]; //Match up sids, domain names, and account names for (var i = 0; i < translatedNames.Length; i++) { var x = translatedNames[i]; if (x.DomainIndex > trustInfos.Length || x.DomainIndex < 0 || trustInfos.Length == 0) { continue; } resolvedObjects[i] = new SamEnumerationObject { AccountDomain = trustInfos[x.DomainIndex].name.ToString(), AccountName = x.Name.ToString(), AccountSid = sids[i], SidUsage = x.Use }; } Utils.Debug($"Cleaning up"); //Cleanup SamFreeMemory(members); LsaFreeMemory(domainList); LsaFreeMemory(nameList); LsaClose(policyHandle); Utils.Debug($"Done NetLocalGroupGetMembers"); return(resolvedObjects); }