Ejemplo n.º 1
0
        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));
                }
        }
Ejemplo n.º 2
0
        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());
                }
        }
Ejemplo n.º 3
0
        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);
        }