Skip to content
This repository has been archived by the owner on Sep 2, 2022. It is now read-only.

Commit

Permalink
More documentation updates
Browse files Browse the repository at this point in the history
  • Loading branch information
rvazarkar committed Jan 28, 2020
1 parent 70a0757 commit 15733d7
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 3 deletions.
50 changes: 49 additions & 1 deletion SharpHound3/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@ internal static DirectorySearch GetDirectorySearcher(string domain)
return searcher;
}

/// <summary>
/// Strips a serviceprincipalname entry down to just its hostname
/// </summary>
/// <param name="target"></param>
/// <returns></returns>
internal static string StripSPN(string target)
{
return SPNRegex.IsMatch(target) ? target.Split('/')[1].Split(':')[0] : target;
Expand Down Expand Up @@ -223,6 +228,12 @@ internal static LookupClient GetDNSResolver(string domain)
DNSResolverCache.TryAdd(key, resolver);
return resolver;
}

/// <summary>
/// Finds a domain controller serving DNS in the target domain
/// </summary>
/// <param name="domain"></param>
/// <returns></returns>
private static string FindDomainDNSServer(string domain)
{
var searcher = GetDirectorySearcher(domain);
Expand All @@ -248,6 +259,10 @@ private static string FindDomainDNSServer(string domain)
return target;
}

/// <summary>
/// Does throttle and jitter for computer requests
/// </summary>
/// <returns></returns>
internal static async Task DoDelay()
{
var opts = Options.Instance;
Expand All @@ -265,6 +280,12 @@ internal static async Task DoDelay()
await Task.Delay(delay);
}

/// <summary>
/// Wrapper for the port scan function that checks caching and other options
/// </summary>
/// <param name="hostname"></param>
/// <param name="port"></param>
/// <returns></returns>
internal static bool CheckPort(string hostname, int port)
{
if (Options.Instance.SkipPortScan)
Expand All @@ -278,6 +299,12 @@ internal static bool CheckPort(string hostname, int port)
return portOpen;
}

/// <summary>
/// Checks if a specified port is available on the hostname
/// </summary>
/// <param name="hostname"></param>
/// <param name="port"></param>
/// <returns></returns>
private static bool CheckHostPort(string hostname, int port)
{
using (var client = new TcpClient())
Expand All @@ -299,6 +326,11 @@ private static bool CheckHostPort(string hostname, int port)
}
}

/// <summary>
/// Normalizes a domain name to its full DNS name
/// </summary>
/// <param name="domain"></param>
/// <returns></returns>
internal static string NormalizeDomainName(string domain)
{
var resolved = domain;
Expand All @@ -311,6 +343,10 @@ internal static string NormalizeDomainName(string domain)
return resolved.ToUpper();
}

/// <summary>
/// Creates a filename for the looped results which will contain the results of all loops
/// </summary>
/// <returns></returns>
internal static string GetLoopFileName()
{
var options = Options.Instance;
Expand All @@ -333,6 +369,13 @@ internal static string GetLoopFileName()
return finalPath;
}

/// <summary>
/// Uses specified options to determine the final filename of the given file
/// </summary>
/// <param name="filename"></param>
/// <param name="extension"></param>
/// <param name="addTime"></param>
/// <returns></returns>
internal static string ResolveFileName(string filename, string extension, bool addTime)
{
var finalFilename = filename;
Expand All @@ -359,9 +402,14 @@ internal static string ResolveFileName(string filename, string extension, bool a
return finalPath;
}

/// <summary>
/// Converts a string to its base64 representation
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
internal static string Base64(string input)
{
var plainBytes = System.Text.Encoding.UTF8.GetBytes(input);
var plainBytes = Encoding.UTF8.GetBytes(input);
return Convert.ToBase64String(plainBytes);
}

Expand Down
17 changes: 16 additions & 1 deletion SharpHound3/LdapBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ namespace SharpHound3
{
internal class LdapBuilder
{
/// <summary>
/// Builds the necessary attributes and ldap query for the specified set of options
/// </summary>
/// <param name="methods"></param>
/// <returns></returns>
internal static LdapQueryData BuildLdapQuery(CollectionMethodResolved methods)
{
var ldapFilterParts = new List<string>();
Expand Down Expand Up @@ -39,6 +44,7 @@ internal static LdapQueryData BuildLdapQuery(CollectionMethodResolved methods)
ldapFilterParts.Add("(&(sAMAccountType=805306369)(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))");
}

//ACL Collection
if (methods.HasFlag(CollectionMethodResolved.ACL))
{
ldapFilterParts.Add("(|(samAccountType=805306368)(samAccountType=805306369)(samAccountType=268435456)(samAccountType=268435457)(samAccountType=536870912)(samAccountType=536870913)(objectClass=domain)(&(objectcategory=groupPolicyContainer)(flags=*))(objectcategory=organizationalUnit))");
Expand All @@ -48,11 +54,13 @@ internal static LdapQueryData BuildLdapQuery(CollectionMethodResolved methods)
});
}

//Trust enumeration
if (methods.HasFlag(CollectionMethodResolved.Trusts))
{
ldapFilterParts.Add("(objectclass=domain)");
}

//Object Properties
if (methods.HasFlag(CollectionMethodResolved.ObjectProps))
{
ldapFilterParts.Add("(|(samaccounttype=268435456)(samaccounttype=268435457)(samaccounttype=536870912)(samaccounttype=536870913)(samaccounttype=805306368)(samaccounttype=805306369)(objectclass=domain)(objectclass=organizationalUnit)(&(objectcategory=groupPolicyContainer)(flags=*)))");
Expand All @@ -67,20 +75,23 @@ internal static LdapQueryData BuildLdapQuery(CollectionMethodResolved methods)
});
}

//Container enumeration
if (methods.HasFlag(CollectionMethodResolved.Container))
{
ldapFilterParts.Add("(|(&(&(objectcategory=groupPolicyContainer)(flags=*))(name=*)(gpcfilesyspath=*))(objectcategory=organizationalUnit)(objectClass=domain))");
ldapProperties.AddRange(new[] { "gplink", "gpoptions", "name", "displayname" });
}

//GPO Local group enumeration
if (methods.HasFlag(CollectionMethodResolved.GPOLocalGroup))
{
//ldapFilterParts.Add("(&(&(objectcategory=groupPolicyContainer)(flags=*))(name=*)(gpcfilesyspath=*))");
//ldapProperties.AddRange(new[] {"gpcfilesyspath", "displayname"});
ldapFilterParts.Add("(&(|(objectcategory=organizationalUnit)(objectclass=domain))(gplink=*))");
ldapFilterParts.Add("(&(|(objectcategory=organizationalUnit)(objectclass=domain))(gplink=*)(flags=*))");
ldapProperties.AddRange(new[] { "gplink", "name" });
}

//SPN Target Enumeration
if (methods.HasFlag(CollectionMethodResolved.SPNTargets))
{
ldapFilterParts.Add("(&(samaccounttype=805306368)(serviceprincipalname=*))");
Expand All @@ -90,15 +101,19 @@ internal static LdapQueryData BuildLdapQuery(CollectionMethodResolved methods)
});
}

//Take our query parts, and join them together
var finalFilter = string.Join("", ldapFilterParts.ToArray());
//Surround the filters with (|), which will OR them together
finalFilter = ldapFilterParts.Count == 1 ? ldapFilterParts[0] : $"(|{finalFilter})";

//Add the user specified filter if it exists
var userFilter = Options.Instance.LdapFilter;
if (userFilter != null)
{
finalFilter = $"(&({finalFilter})({userFilter}))";
}

//Distinct the attributes
return new LdapQueryData
{
LdapFilter = finalFilter,
Expand Down
73 changes: 72 additions & 1 deletion SharpHound3/ResolutionHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,11 @@ internal static async Task<string> ResolveHostToSid(string hostname, string doma
return tempName;
}

/// <summary>
/// Turns a domain Netbios name into its FQDN using the DsGetDcName function (TESTLAB -> TESTLAB.LOCAL)
/// </summary>
/// <param name="domainName"></param>
/// <returns></returns>
internal static string ResolveDomainNetbiosToDns(string domainName)
{
var key = domainName.ToUpper();
Expand Down Expand Up @@ -210,7 +215,11 @@ internal static string ResolveDomainNetbiosToDns(string domainName)
return flatName;
}


/// <summary>
/// Finds a domain controller for the specified domain using DsGetDcName
/// </summary>
/// <param name="domainName"></param>
/// <returns></returns>
private static string GetDomainControllerForDomain(string domainName)
{
var key = domainName.ToUpper();
Expand Down Expand Up @@ -239,6 +248,12 @@ private static string GetDomainControllerForDomain(string domainName)
return domainController;
}

/// <summary>
/// Attempts to turn an account name into its corresponding SID as well as determine the type of the object
/// </summary>
/// <param name="accountName"></param>
/// <param name="accountDomain"></param>
/// <returns></returns>
internal static async Task<(bool success, string sid, LdapTypeEnum type)> ResolveAccountNameToSidAndType(string accountName,
string accountDomain)
{
Expand Down Expand Up @@ -277,6 +292,11 @@ private static string GetDomainControllerForDomain(string domainName)
return (sid != null, sid, type);
}

/// <summary>
/// Attempts to turn an OU's distinguished name into its corresponding objectguid
/// </summary>
/// <param name="distinguishedName"></param>
/// <returns></returns>
internal static async Task<(bool success, string guid)> OUDistinguishedNameToGuid(string distinguishedName)
{
if (AppCache.GetResolvedDistinguishedName(distinguishedName, out var resolved))
Expand All @@ -303,6 +323,11 @@ private static string GetDomainControllerForDomain(string domainName)
return (true, guid);
}

/// <summary>
/// Attempts to resolve a distinguishedname to its corresponding sid. Checks for ForeignSecurityPrincipals
/// </summary>
/// <param name="distinguishedName"></param>
/// <returns></returns>
internal static async Task<(string sid, LdapTypeEnum type)> ResolveDistinguishedName(string distinguishedName)
{
//Check cache to see if we have the item in there first.
Expand All @@ -311,10 +336,12 @@ private static string GetDomainControllerForDomain(string domainName)
return (resolved.ObjectIdentifier, resolved.ObjectType);
}

//Get the domain name from the DN
var domain = Helpers.DistinguishedNameToDomain(distinguishedName);

if (distinguishedName.Contains("ForeignSecurityPrincipals"))
{
//ForeignSecurityPrincipals generally contain the SID of the object, so we'll extract it and try resolving the SID type
var sid = distinguishedName.Split(',')[0].Substring(3);

if (!sid.Contains("S-1-5"))
Expand All @@ -340,6 +367,11 @@ private static string GetDomainControllerForDomain(string domainName)
return (resolvedSid, resolvedType);
}

/// <summary>
/// Uses LDAP to find the SID associated with the distinguishedname
/// </summary>
/// <param name="distinguishedName"></param>
/// <returns></returns>
private static async Task<(string sid, LdapTypeEnum type)> ResolveDistinguishedNameLdap(
string distinguishedName)
{
Expand All @@ -358,6 +390,12 @@ private static string GetDomainControllerForDomain(string domainName)
return (sid, type);
}

/// <summary>
/// Does some common checks on a SID, and attempts to find the type of the object
/// </summary>
/// <param name="sid"></param>
/// <param name="domain"></param>
/// <returns></returns>
internal static async Task<(string finalSid, LdapTypeEnum type)> ResolveSidAndGetType(string sid, string domain)
{
if (sid.Contains("0ACNF"))
Expand All @@ -378,6 +416,12 @@ private static string GetDomainControllerForDomain(string domainName)
return (sid, type);
}

/// <summary>
/// Looks up the object type of a specified SID
/// </summary>
/// <param name="sid"></param>
/// <param name="domain"></param>
/// <returns></returns>
internal static async Task<LdapTypeEnum> LookupSidType(string sid, string domain)
{
var hexSid = ConvertSidToHexSid(sid);
Expand All @@ -392,6 +436,11 @@ internal static async Task<LdapTypeEnum> LookupSidType(string sid, string domain
return result?.GetLdapType() ?? LdapTypeEnum.Unknown;
}

/// <summary>
/// Converts a string sid to its hex representation for LDAP searches
/// </summary>
/// <param name="sid"></param>
/// <returns></returns>
private static string ConvertSidToHexSid(string sid)
{
try
Expand All @@ -408,6 +457,11 @@ private static string ConvertSidToHexSid(string sid)
}
}

/// <summary>
/// Attempts to find the corresponding domain for a security identifier
/// </summary>
/// <param name="sid"></param>
/// <returns></returns>
private static async Task<string> GetDomainNameFromSid(string sid)
{
try
Expand All @@ -433,6 +487,11 @@ private static async Task<string> GetDomainNameFromSid(string sid)
}
}

/// <summary>
/// Uses LDAP to find the domain name associated with a SID
/// </summary>
/// <param name="sid"></param>
/// <returns></returns>
private static async Task<string> GetDomainNameFromSidLdap(string sid)
{
var searcher = Helpers.GetDirectorySearcher(Options.Instance.Domain);
Expand Down Expand Up @@ -464,6 +523,11 @@ private static async Task<string> GetDomainNameFromSidLdap(string sid)
return null;
}

/// <summary>
/// Calls the NetWkstaGetInfo API on a hostname
/// </summary>
/// <param name="hostname"></param>
/// <returns></returns>
private static async Task<(bool success, WorkstationInfo100 info)> CallNetWkstaGetInfo(string hostname)
{
if (!Helpers.CheckPort(hostname, 445))
Expand All @@ -489,6 +553,13 @@ private static async Task<string> GetDomainNameFromSidLdap(string sid)
}
}

/// <summary>
/// Uses a socket and a set of bytes to request the NETBIOS name from a remote computer
/// </summary>
/// <param name="server"></param>
/// <param name="domain"></param>
/// <param name="netbios"></param>
/// <returns></returns>
private static bool RequestNetbiosNameFromComputer(string server, string domain, out string netbios)
{
var receiveBuffer = new byte[1024];
Expand Down

0 comments on commit 15733d7

Please sign in to comment.