Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/utils_rewrite' into utils_rewrite
Browse files Browse the repository at this point in the history
  • Loading branch information
rvazarkar committed Jul 8, 2024
2 parents cda27fd + 12a3357 commit ab6f0fd
Show file tree
Hide file tree
Showing 3 changed files with 354 additions and 348 deletions.
203 changes: 102 additions & 101 deletions src/CommonLib/DirectoryEntryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,127 +7,128 @@
using SharpHoundCommonLib.LDAPQueries;
using SharpHoundCommonLib.OutputTypes;

namespace SharpHoundCommonLib;
namespace SharpHoundCommonLib {

public static class DirectoryEntryExtensions {
public static string GetProperty(this DirectoryEntry entry, string propertyName) {
try {
if (!entry.Properties.Contains(propertyName))
entry.RefreshCache(new[] { propertyName });

if (!entry.Properties.Contains(propertyName))
public static class DirectoryEntryExtensions {
public static string GetProperty(this DirectoryEntry entry, string propertyName) {
try {
if (!entry.Properties.Contains(propertyName))
entry.RefreshCache(new[] { propertyName });

if (!entry.Properties.Contains(propertyName))
return null;
}
catch {
return null;
}
catch {
return null;
}
}

var s = entry.Properties[propertyName][0];
return s switch
{
string st => st,
_ => null
};
}
var s = entry.Properties[propertyName][0];
return s switch
{
string st => st,
_ => null
};
}

public static string[] GetPropertyAsArray(this DirectoryEntry entry, string propertyName) {
try {
if (!entry.Properties.Contains(propertyName))
entry.RefreshCache(new[] { propertyName });

if (!entry.Properties.Contains(propertyName))
public static string[] GetPropertyAsArray(this DirectoryEntry entry, string propertyName) {
try {
if (!entry.Properties.Contains(propertyName))
entry.RefreshCache(new[] { propertyName });

if (!entry.Properties.Contains(propertyName))
return null;
}
catch {
return null;
}
catch {
return null;
}
}

var dest = new List<string>();
foreach (var val in entry.Properties[propertyName]) {
if (val is string s) {
dest.Add(s);
var dest = new List<string>();
foreach (var val in entry.Properties[propertyName]) {
if (val is string s) {
dest.Add(s);
}
}
}

return dest.ToArray();
}
return dest.ToArray();
}

public static bool GetTypedPrincipal(this DirectoryEntry entry, out TypedPrincipal principal) {
var identifier = entry.GetObjectIdentifier();
var success = entry.GetLabel(out var label);
principal = new TypedPrincipal(identifier, label);
return (success && !string.IsNullOrWhiteSpace(identifier));
}
public static bool GetTypedPrincipal(this DirectoryEntry entry, out TypedPrincipal principal) {
var identifier = entry.GetObjectIdentifier();
var success = entry.GetLabel(out var label);
principal = new TypedPrincipal(identifier, label);
return (success && !string.IsNullOrWhiteSpace(identifier));
}

public static string GetObjectIdentifier(this DirectoryEntry entry) {
return entry.GetSid() ?? entry.GetGuid();
}
public static string GetObjectIdentifier(this DirectoryEntry entry) {
return entry.GetSid() ?? entry.GetGuid();
}

public static string GetSid(this DirectoryEntry entry)
{
try
public static string GetSid(this DirectoryEntry entry)
{
if (!entry.Properties.Contains(LDAPProperties.ObjectSID))
entry.RefreshCache(new[] { LDAPProperties.ObjectSID });
try
{
if (!entry.Properties.Contains(LDAPProperties.ObjectSID))
entry.RefreshCache(new[] { LDAPProperties.ObjectSID });

if (!entry.Properties.Contains(LDAPProperties.ObjectSID))
if (!entry.Properties.Contains(LDAPProperties.ObjectSID))
return null;
}
catch
{
return null;
}
catch
{
return null;
}
}

var s = entry.Properties[LDAPProperties.ObjectSID][0];
return s switch
{
byte[] b => new SecurityIdentifier(b, 0).ToString(),
string st => new SecurityIdentifier(Encoding.ASCII.GetBytes(st), 0).ToString(),
_ => null
};
}

public static string GetGuid(this DirectoryEntry entry)
{
try
var s = entry.Properties[LDAPProperties.ObjectSID][0];
return s switch
{
byte[] b => new SecurityIdentifier(b, 0).ToString(),
string st => new SecurityIdentifier(Encoding.ASCII.GetBytes(st), 0).ToString(),
_ => null
};
}

public static string GetGuid(this DirectoryEntry entry)
{
//Attempt to refresh the props first
if (!entry.Properties.Contains(LDAPProperties.ObjectGUID))
entry.RefreshCache(new[] { LDAPProperties.ObjectGUID });
try
{
//Attempt to refresh the props first
if (!entry.Properties.Contains(LDAPProperties.ObjectGUID))
entry.RefreshCache(new[] { LDAPProperties.ObjectGUID });

if (!entry.Properties.Contains(LDAPProperties.ObjectGUID))
if (!entry.Properties.Contains(LDAPProperties.ObjectGUID))
return null;
}
catch
{
return null;
}
catch
{
return null;
}
}

var s = entry.Properties[LDAPProperties.ObjectGUID][0];
return s switch
{
byte[] b => new Guid(b).ToString(),
string st => st,
_ => null
};
}


public static bool GetLabel(this DirectoryEntry entry, out Label type) {
try {
entry.RefreshCache(CommonProperties.TypeResolutionProps);
}
catch {
//pass
var s = entry.Properties[LDAPProperties.ObjectGUID][0];
return s switch
{
byte[] b => new Guid(b).ToString(),
string st => st,
_ => null
};
}


public static bool GetLabel(this DirectoryEntry entry, out Label type) {
try {
entry.RefreshCache(CommonProperties.TypeResolutionProps);
}
catch {
//pass
}

var flagString = entry.GetProperty(LDAPProperties.Flags);
if (!int.TryParse(flagString, out var flags)) {
flags = 0;
}
var flagString = entry.GetProperty(LDAPProperties.Flags);
if (!int.TryParse(flagString, out var flags)) {
flags = 0;
}

return LdapUtils.ResolveLabel(entry.GetObjectIdentifier(), entry.GetProperty(LDAPProperties.DistinguishedName),
entry.GetProperty(LDAPProperties.SAMAccountType),
entry.GetPropertyAsArray(LDAPProperties.SAMAccountType), flags, out type);
}
return LdapUtils.ResolveLabel(entry.GetObjectIdentifier(), entry.GetProperty(LDAPProperties.DistinguishedName),
entry.GetProperty(LDAPProperties.SAMAccountType),
entry.GetPropertyAsArray(LDAPProperties.SAMAccountType), flags, out type);
}
}
}
128 changes: 66 additions & 62 deletions src/CommonLib/LdapConnectionPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,80 +103,84 @@ public void Dispose() {
}

private async Task<(bool Success, LdapConnectionWrapper Connection, string Message)> CreateNewConnection(bool globalCatalog = false) {
if (!string.IsNullOrWhiteSpace(_ldapConfig.Server)) {
return CreateNewConnectionForServer(_ldapConfig.Server, globalCatalog);
}

if (CreateLdapConnection(_identifier.ToUpper().Trim(), globalCatalog, out var connectionWrapper)) {
_log.LogDebug("Successfully created ldap connection for domain: {Domain} using strategy 1. SSL: {SSl}", _identifier, connectionWrapper.Connection.SessionOptions.SecureSocketLayer);
return (true, connectionWrapper, "");
}

string tempDomainName;

var dsGetDcNameResult = _nativeMethods.CallDsGetDcName(null, _identifier,
(uint)(NetAPIEnums.DSGETDCNAME_FLAGS.DS_FORCE_REDISCOVERY |
NetAPIEnums.DSGETDCNAME_FLAGS.DS_RETURN_DNS_NAME |
NetAPIEnums.DSGETDCNAME_FLAGS.DS_DIRECTORY_SERVICE_REQUIRED));
if (dsGetDcNameResult.IsSuccess) {
tempDomainName = dsGetDcNameResult.Value.DomainName;
try {
if (!string.IsNullOrWhiteSpace(_ldapConfig.Server)) {
return CreateNewConnectionForServer(_ldapConfig.Server, globalCatalog);
}

if (CreateLdapConnection(_identifier.ToUpper().Trim(), globalCatalog, out var connectionWrapper)) {
_log.LogDebug("Successfully created ldap connection for domain: {Domain} using strategy 1. SSL: {SSl}", _identifier, connectionWrapper.Connection.SessionOptions.SecureSocketLayer);
return (true, connectionWrapper, "");
}

string tempDomainName;

var dsGetDcNameResult = _nativeMethods.CallDsGetDcName(null, _identifier,
(uint)(NetAPIEnums.DSGETDCNAME_FLAGS.DS_FORCE_REDISCOVERY |
NetAPIEnums.DSGETDCNAME_FLAGS.DS_RETURN_DNS_NAME |
NetAPIEnums.DSGETDCNAME_FLAGS.DS_DIRECTORY_SERVICE_REQUIRED));
if (dsGetDcNameResult.IsSuccess) {
tempDomainName = dsGetDcNameResult.Value.DomainName;

if (!tempDomainName.Equals(_identifier, StringComparison.OrdinalIgnoreCase) &&
CreateLdapConnection(tempDomainName, globalCatalog, out connectionWrapper)) {
_log.LogDebug(
"Successfully created ldap connection for domain: {Domain} using strategy 2 with name {NewName}",
_identifier, tempDomainName);
return (true, connectionWrapper, "");
}

var server = dsGetDcNameResult.Value.DomainControllerName.TrimStart('\\');

var result =
await CreateLDAPConnectionWithPortCheck(server, globalCatalog);
if (result.success) {
_log.LogDebug(
"Successfully created ldap connection for domain: {Domain} using strategy 3 to server {Server}",
_identifier, server);
return (true, result.connection, "");
}
}

if (!LdapUtils.GetDomain(_identifier, _ldapConfig, out var domainObject) || domainObject.Name == null) {
//If we don't get a result here, we effectively have no other ways to resolve this domain, so we'll just have to exit out
_log.LogDebug(
"Could not get domain object from GetDomain, unable to create ldap connection for domain {Domain}",
_identifier);
return (false, null, "Unable to get domain object for further strategies");
}
tempDomainName = domainObject.Name.ToUpper().Trim();

if (!tempDomainName.Equals(_identifier, StringComparison.OrdinalIgnoreCase) &&
CreateLdapConnection(tempDomainName, globalCatalog, out connectionWrapper)) {
_log.LogDebug(
"Successfully created ldap connection for domain: {Domain} using strategy 2 with name {NewName}",
"Successfully created ldap connection for domain: {Domain} using strategy 4 with name {NewName}",
_identifier, tempDomainName);
return (true, connectionWrapper, "");
}

var server = dsGetDcNameResult.Value.DomainControllerName.TrimStart('\\');

var result =
await CreateLDAPConnectionWithPortCheck(server, globalCatalog);
if (result.success) {
_log.LogDebug(
"Successfully created ldap connection for domain: {Domain} using strategy 3 to server {Server}",
_identifier, server);
return (true, result.connection, "");
}
}

if (!LdapUtils.GetDomain(_identifier, _ldapConfig, out var domainObject) || domainObject.Name == null) {
//If we don't get a result here, we effectively have no other ways to resolve this domain, so we'll just have to exit out
_log.LogDebug(
"Could not get domain object from GetDomain, unable to create ldap connection for domain {Domain}",
_identifier);
return (false, null, "Unable to get domain object for further strategies");
}
tempDomainName = domainObject.Name.ToUpper().Trim();

if (!tempDomainName.Equals(_identifier, StringComparison.OrdinalIgnoreCase) &&
CreateLdapConnection(tempDomainName, globalCatalog, out connectionWrapper)) {
_log.LogDebug(
"Successfully created ldap connection for domain: {Domain} using strategy 4 with name {NewName}",
_identifier, tempDomainName);
return (true, connectionWrapper, "");
}

var primaryDomainController = domainObject.PdcRoleOwner.Name;
var portConnectionResult =
await CreateLDAPConnectionWithPortCheck(primaryDomainController, globalCatalog);
if (portConnectionResult.success) {
_log.LogDebug(
"Successfully created ldap connection for domain: {Domain} using strategy 5 with to pdc {Server}",
_identifier, primaryDomainController);
return (true, connectionWrapper, "");
}

foreach (DomainController dc in domainObject.DomainControllers) {
portConnectionResult =
await CreateLDAPConnectionWithPortCheck(dc.Name, globalCatalog);
var primaryDomainController = domainObject.PdcRoleOwner.Name;
var portConnectionResult =
await CreateLDAPConnectionWithPortCheck(primaryDomainController, globalCatalog);
if (portConnectionResult.success) {
_log.LogDebug(
"Successfully created ldap connection for domain: {Domain} using strategy 6 with to pdc {Server}",
"Successfully created ldap connection for domain: {Domain} using strategy 5 with to pdc {Server}",
_identifier, primaryDomainController);
return (true, connectionWrapper, "");
return (true, portConnectionResult.connection, "");
}

foreach (DomainController dc in domainObject.DomainControllers) {
portConnectionResult =
await CreateLDAPConnectionWithPortCheck(dc.Name, globalCatalog);
if (portConnectionResult.success) {
_log.LogDebug(
"Successfully created ldap connection for domain: {Domain} using strategy 6 with to pdc {Server}",
_identifier, primaryDomainController);
return (true, portConnectionResult.connection, "");
}
}
} catch (Exception e) {
_log.LogInformation(e, "We will not be able to connect to domain {Domain} by any strategy, leaving it.", _identifier);
}

return (false, null, "All attempted connections failed");
Expand Down
Loading

0 comments on commit ab6f0fd

Please sign in to comment.