Exemplo n.º 1
0
        public static IEnumerable <Session> GetNetSessions(ResolvedEntry target, string computerDomain)
        {
            if (!Utils.IsMethodSet(ResolvedCollectionMethod.Session) &&
                !Utils.IsMethodSet(ResolvedCollectionMethod.SessionLoop))
            {
                yield break;
            }

            var resumeHandle = IntPtr.Zero;
            var si10         = typeof(SESSION_INFO_10);

            var entriesRead = 0;
            var ptrInfo     = IntPtr.Zero;

            var t = Task <int> .Factory.StartNew(() => NetSessionEnum(target.BloodHoundDisplay, null, null, 10,
                                                                      out ptrInfo, -1, out entriesRead,
                                                                      out _, ref resumeHandle));

            var success = t.Wait(Timeout);

            if (!success)
            {
                throw new TimeoutException();
            }

            var returnValue = t.Result;

            Utils.Debug($"EntriesRead from NetSessionEnum: {entriesRead}");
            Utils.Debug($"ReturnValue from NetSessionEnum: {returnValue}");

            //If we don't get a success, just break
            if (returnValue != (int)NERR.NERR_Success)
            {
                yield break;
            }

            var results = new SESSION_INFO_10[entriesRead];
            var iter    = ptrInfo;

            //Loop over the data and store it into an array
            for (var i = 0; i < entriesRead; i++)
            {
                results[i] = (SESSION_INFO_10)Marshal.PtrToStructure(iter, si10);
                iter       = (IntPtr)(iter.ToInt64() + Marshal.SizeOf(si10));
            }

            //Free the IntPtr
            NetApiBufferFree(ptrInfo);

            foreach (var result in results)
            {
                var username = result.sesi10_username;
                var cname    = result.sesi10_cname;
                Utils.Debug($"Result Username: {username}");
                Utils.Debug($"Result cname: {cname}");

                if (cname == null || username.EndsWith("$") || username.Trim() == "" || username == "$" ||
                    username == _options.CurrentUser)
                {
                    continue;
                }

                if (cname.StartsWith("\\", StringComparison.CurrentCulture))
                {
                    cname = cname.TrimStart('\\');
                }

                if (cname.Equals("[::1]") || cname.Equals("127.0.0.1"))
                {
                    cname = target.BloodHoundDisplay;
                }

                var dnsHostName = _utils.ResolveHost(cname);
                Utils.Debug($"Result cname: {dnsHostName}");
                if (dnsHostName == null)
                {
                    continue;
                }

                //If we're skipping Global Catalog deconfliction, just return a session
                if (_options.SkipGcDeconfliction)
                {
                    yield return(new Session {
                        ComputerName = dnsHostName, UserName = username, Weight = 2
                    });
                }
                else
                {
                    //Check our cache first
                    if (!_cache.GetGcMap(username, out var possible) || possible == null)
                    {
                        //If we didn't get a cache hit, search the global catalog
                        var temp = new List <string>();
                        foreach (var entry in _utils.DoSearch(
                                     $"(&(samAccountType=805306368)(samaccountname={username}))", SearchScope.Subtree,
                                     new[] { "distinguishedname" }, computerDomain, "", true))
                        {
                            temp.Add(Utils.ConvertDnToDomain(entry.DistinguishedName).ToUpper());
                        }

                        possible = temp.ToArray();
                        _cache.AddGcMap(username, possible);
                    }

                    switch (possible.Length)
                    {
                    case 0:
                        //Object isn't in GC, so we'll default to the computer's domain
                        yield return(new Session
                        {
                            UserName = $"{username}@{computerDomain}",
                            ComputerName = dnsHostName,
                            Weight = 2
                        });

                        break;

                    case 1:
                        //Exactly one instance of this samaccountname, the best scenario
                        yield return(new Session
                        {
                            UserName = $"{username}@{possible.First()}",
                            ComputerName = dnsHostName,
                            Weight = 2
                        });

                        break;

                    default:
                        //Multiple possibilities (whyyyyy)
                        //Add a weight of 1 for same domain as computer, 2 for others
                        foreach (var possibility in possible)
                        {
                            var weight = possibility.Equals(computerDomain, StringComparison.CurrentCultureIgnoreCase) ? 1 : 2;

                            yield return(new Session
                            {
                                Weight = weight,
                                ComputerName = dnsHostName.ToUpper(),
                                UserName = $"{username}@{possibility}"
                            });
                        }
                        break;
                    }
                }
            }

            Utils.DoJitter();
        }