/// <summary> /// Creates an instance of an RPCServer which is used for making SharpHound specific API calls for computers /// </summary> /// <param name="name">The name of the computer to connect too. This should be the network name of the computer</param> /// <param name="domain">The domain name of the computer</param> /// <param name="samAccountName">The samaccountname of the computer</param> /// <param name="computerSid">The security identifier for the computer</param> /// <exception cref="APIException">An exception if the an API fails to connect initially. Generally indicates the server is unavailable or permissions aren't available.</exception> internal RPCServer(string name, string domain, string samAccountName, string computerSid) { _computerDomain = domain; _computerSAN = samAccountName; _computerSID = computerSid; var sid = new SecurityIdentifier("S-1-5-32"); var sidBytes = new byte[sid.BinaryLength]; sid.GetBinaryForm(sidBytes, 0); var us = new NativeMethods.UNICODE_STRING(name); //Every API call we make relies on both SamConnect and SamOpenDomain //Make these calls immediately and save the handles. If either fails, nothing else is going to work var status = SamConnect(ref us, out _serverHandle, SamAccessMasks.SamServerLookupDomain | SamAccessMasks.SamServerConnect, ref _obj); if (status != NativeMethods.NtStatus.StatusSuccess) { SamCloseHandle(_serverHandle); throw new APIException { Status = status.ToString(), APICall = "SamConnect" }; } status = SamOpenDomain(_serverHandle, DomainAccessMask.Lookup, sidBytes, out _domainHandle); if (status != NativeMethods.NtStatus.StatusSuccess) { throw new APIException { Status = status.ToString(), APICall = "SamOpenDomain" }; } }
private static extern NativeMethods.NtStatus SamLookupDomainInSamServer( IntPtr serverHandle, ref NativeMethods.UNICODE_STRING name, out IntPtr sid);
private static extern NativeMethods.NtStatus SamConnect( ref NativeMethods.UNICODE_STRING serverName, out IntPtr serverHandle, SamAccessMasks desiredAccess, ref NativeMethods.OBJECT_ATTRIBUTES objectAttributes );
internal string GetMachineSid() { if (Cache.GetMachineSid(_computerSID, out var machineSid)) { return(machineSid); } NativeMethods.NtStatus status; //Try the simplest method first, getting the SID directly using samaccountname try { var san = new NativeMethods.UNICODE_STRING(_computerSAN); status = SamLookupDomainInSamServer(_serverHandle, ref san, out var temp); if (status == NativeMethods.NtStatus.StatusSuccess) { machineSid = new SecurityIdentifier(temp).Value; SamFreeMemory(temp); Cache.AddMachineSid(_computerSID, machineSid); return(machineSid); } } catch { //pass } machineSid = "DUMMYSTRING"; //As a fallback, try and retrieve the local administrators group and get the first account with a rid of 500 //If at any time we encounter a failure, just return a dummy sid that wont match anything status = SamOpenAlias(_domainHandle, AliasOpenFlags.ListMembers, (int)LocalGroupRids.Administrators, out var aliasHandle); if (status != NativeMethods.NtStatus.StatusSuccess) { SamCloseHandle(aliasHandle); return(machineSid); } status = SamGetMembersInAlias(aliasHandle, out var members, out var count); if (status != NativeMethods.NtStatus.StatusSuccess) { SamCloseHandle(aliasHandle); return(machineSid); } SamCloseHandle(aliasHandle); if (count == 0) { SamFreeMemory(members); return(machineSid); } var sids = new List <string>(); for (var i = 0; i < count; i++) { try { var ptr = Marshal.ReadIntPtr(members, Marshal.SizeOf(typeof(IntPtr)) * i); var sid = new SecurityIdentifier(ptr).Value; sids.Add(sid); } catch (Exception e) { Logging.Debug($"Exception converting sid: {e}"); } } var domainSid = new SecurityIdentifier(_computerSID).AccountDomainSid.Value.ToUpper(); machineSid = sids.Select(x => { try { return(new SecurityIdentifier(x).Value); } catch { return(null); } }).Where(x => x != null).DefaultIfEmpty(null).FirstOrDefault(x => x.EndsWith("-500") && !x.ToUpper().StartsWith(domainSid)); if (machineSid == null) { return("DUMMYSTRING"); } machineSid = new SecurityIdentifier(machineSid).AccountDomainSid.Value; Cache.AddMachineSid(_computerSID, machineSid); return(machineSid); }