Skip to content

Commit

Permalink
Merge pull request #76 from BloodHoundAD/adcs
Browse files Browse the repository at this point in the history
ADCS initial MR
  • Loading branch information
elikmiller authored Nov 22, 2023
2 parents 8ac850c + df41c18 commit 6cbc4ed
Show file tree
Hide file tree
Showing 48 changed files with 2,079 additions and 148 deletions.
13 changes: 6 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

## Build

``` powershell
```powershell
dotnet build
```

Expand All @@ -17,31 +17,30 @@ dotnet build
This project is configured to generate test coverage every time tests are run and produces a HTML report at
[./docfx/coverage/report](./docfx/coverage/report).


``` powershell
```powershell
dotnet test
```

## Documentation

Documentation is generated into Html from Markdown using [docfx](https://https://dotnet.github.io/docfx/).
Documentation is generated into HTML from Markdown using [docfx](https://dotnet.github.io/docfx/).

To build the docs:

``` powershell
```powershell
dotnet build docfx
```

To preview the docs:

``` powershell
```powershell
dotnet build docfx
dotnet build docfx -t:Serve
```

To preview the docs with test coverage:

``` powershell
```powershell
dotnet test
dotnet build docfx
dotnet build docfx -t:Serve
Expand Down
7 changes: 7 additions & 0 deletions src/CommonLib/EdgeNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,12 @@ public static class EdgeNames
public const string AddKeyCredentialLink = "AddKeyCredentialLink";
public const string SQLAdmin = "SQLAdmin";
public const string WriteAccountRestrictions = "WriteAccountRestrictions";

//CertAbuse edges
public const string WritePKIEnrollmentFlag = "WritePKIEnrollmentFlag";
public const string WritePKINameFlag = "WritePKINameFlag";
public const string ManageCA = "ManageCA";
public const string ManageCertificates = "ManageCertificates";
public const string Enroll = "Enroll";
}
}
15 changes: 15 additions & 0 deletions src/CommonLib/Enums/CAExtensionTypes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace SharpHoundCommonLib.Enums
{
// From https://learn.microsoft.com/en-us/windows/win32/seccertenroll/supported-extensions
public static class CAExtensionTypes
{
public const string AuthorityInformationAccess = "1.3.6.1.5.5.7.1.1";
public const string AuthorityKeyIdentifier = "2.5.29.35";
public const string BasicConstraints = "2.5.29.19";
public const string NameConstraints = "2.5.29.30";
public const string EnhancedKeyUsage = "2.5.29.37";
public const string KeyUsage = "2.5.29.15";
public const string SubjectAlternativeNames = "2.5.29.17";
public const string SubjectKeyIdentifier = "2.5.29.14";
}
}
15 changes: 15 additions & 0 deletions src/CommonLib/Enums/CertificationAuthorityRights.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;

namespace SharpHoundCommonLib.Enums
{
[Flags]
public enum CertificationAuthorityRights
{
ManageCA = 1, // Administrator
ManageCertificates = 2, // Officer
Auditor = 4,
Operator = 8,
Read = 256,
Enroll = 512
}
}
11 changes: 7 additions & 4 deletions src/CommonLib/Enums/CollectionMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@ public enum ResolvedCollectionMethod
SPNTargets = 1 << 13,
PSRemote = 1 << 14,
UserRights = 1 << 15,
CARegistry = 1 << 16,
DCRegistry = 1 << 17,
CertServices = 1 << 18,
LocalGroups = DCOM | RDP | LocalAdmin | PSRemote,
ComputerOnly = LocalGroups | Session | UserRights,
DCOnly = ACL | Container | Group | ObjectProps | Trusts | GPOLocalGroup,
Default = Group | Session | Trusts | ACL | ObjectProps | LocalGroups | SPNTargets | Container,
All = Default | LoggedOn | GPOLocalGroup | UserRights
ComputerOnly = LocalGroups | Session | UserRights | CARegistry | DCRegistry,
DCOnly = ACL | Container | Group | ObjectProps | Trusts | GPOLocalGroup | CertServices,
Default = Group | Session | Trusts | ACL | ObjectProps | LocalGroups | SPNTargets | Container | CertServices,
All = Default | LoggedOn | GPOLocalGroup | UserRights | CARegistry | DCRegistry
}
}
13 changes: 13 additions & 0 deletions src/CommonLib/Enums/CommonOids.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace SharpHoundCommonLib.Enums
{
// More can be found here: https://www.pkisolutions.com/object-identifiers-oid-in-pki/
public static class CommonOids
{
public static string AnyPurpose = "2.5.29.37.0";
public static string ClientAuthentication = "1.3.6.1.5.5.7.3.2";
public static string PKINITClientAuthentication = "1.3.6.1.5.2.3.4";
public static string SmartcardLogon = "1.3.6.1.4.1.311.20.2.2";
public static string CertificateRequestAgent = "1.3.6.1.4.1.311.20.2.1";
public static string CertificateRequestAgentPolicy = "1.3.6.1.4.1.311.20.2.1";
}
}
5 changes: 5 additions & 0 deletions src/CommonLib/Enums/DataType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,10 @@ public static class DataType
public const string GPOs = "gpos";
public const string OUs = "ous";
public const string Containers = "containers";
public const string RootCAs = "rootcas";
public const string AIACAs = "aiacas";
public const string NTAuthStores = "ntauthstores";
public const string EnterpriseCAs = "enterprisecas";
public const string CertTemplates = "certtemplates";
}
}
13 changes: 13 additions & 0 deletions src/CommonLib/Enums/DirectoryPaths.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace SharpHoundCommonLib.Enums
{
public class DirectoryPaths
{
public const string EnterpriseCALocation = "CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration";
public const string RootCALocation = "CN=Certification Authorities,CN=Public Key Services,CN=Services,CN=Configuration";
public const string AIACALocation = "CN=AIA,CN=Public Key Services,CN=Services,CN=Configuration";
public const string CertTemplateLocation = "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration";
public const string NTAuthStoreLocation = "CN=NTAuthCertificates,CN=Public Key Services,CN=Services,CN=Configuration";
public const string PKILocation = "CN=Public Key Services,CN=Services,CN=Configuration";
public const string ConfigLocation = "CN=Configuration";
}
}
9 changes: 8 additions & 1 deletion src/CommonLib/Enums/Labels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ public enum Label
GPO,
Domain,
OU,
Container
Container,
Configuration,
CertTemplate,
CertAuthority,
RootCA,
AIACA,
EnterpriseCA,
NTAuthStore
}
}
13 changes: 13 additions & 0 deletions src/CommonLib/Enums/PKICertificateAuthorityFlags.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;

namespace SharpHoundCommonLib.Enums
{
[Flags]
public enum PKICertificateAuthorityFlags
{
NO_TEMPLATE_SUPPORT = 0x00000001,
SUPPORTS_NT_AUTHENTICATION = 0x00000002,
CA_SUPPORTS_MANUAL_AUTHENTICATION = 0x00000004,
CA_SERVERTYPE_ADVANCED = 0x00000008
}
}
25 changes: 25 additions & 0 deletions src/CommonLib/Enums/PKICertificateNameFlag.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;

namespace SharpHoundCommonLib.Enums
{
[Flags]
public enum PKICertificateNameFlag : uint
{
ENROLLEE_SUPPLIES_SUBJECT = 0x00000001,
ADD_EMAIL = 0x00000002,
ADD_OBJ_GUID = 0x00000004,
OLD_CERT_SUPPLIES_SUBJECT_AND_ALT_NAME = 0x00000008,
ADD_DIRECTORY_PATH = 0x00000100,
ENROLLEE_SUPPLIES_SUBJECT_ALT_NAME = 0x00010000,
SUBJECT_ALT_REQUIRE_DOMAIN_DNS = 0x00400000,
SUBJECT_ALT_REQUIRE_SPN = 0x00800000,
SUBJECT_ALT_REQUIRE_DIRECTORY_GUID = 0x01000000,
SUBJECT_ALT_REQUIRE_UPN = 0x02000000,
SUBJECT_ALT_REQUIRE_EMAIL = 0x04000000,
SUBJECT_ALT_REQUIRE_DNS = 0x08000000,
SUBJECT_REQUIRE_DNS_AS_CN = 0x10000000,
SUBJECT_REQUIRE_EMAIL = 0x20000000,
SUBJECT_REQUIRE_COMMON_NAME = 0x40000000,
SUBJECT_REQUIRE_DIRECTORY_PATH = 0x80000000
}
}
32 changes: 32 additions & 0 deletions src/CommonLib/Enums/PKIEnrollmentFlag.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;

namespace SharpHoundCommonLib.Enums
{
// from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-crtd/ec71fd43-61c2-407b-83c9-b52272dec8a1
// and from certutil.exe -v -dstemplate
[Flags]
public enum PKIEnrollmentFlag : uint
{
NONE = 0x00000000,
INCLUDE_SYMMETRIC_ALGORITHMS = 0x00000001,
PEND_ALL_REQUESTS = 0x00000002,
PUBLISH_TO_KRA_CONTAINER = 0x00000004,
PUBLISH_TO_DS = 0x00000008,
AUTO_ENROLLMENT_CHECK_USER_DS_CERTIFICATE = 0x00000010,
AUTO_ENROLLMENT = 0x00000020,
CT_FLAG_DOMAIN_AUTHENTICATION_NOT_REQUIRED = 0x80,
PREVIOUS_APPROVAL_VALIDATE_REENROLLMENT = 0x00000040,
USER_INTERACTION_REQUIRED = 0x00000100,
ADD_TEMPLATE_NAME = 0x200,
REMOVE_INVALID_CERTIFICATE_FROM_PERSONAL_STORE = 0x00000400,
ALLOW_ENROLL_ON_BEHALF_OF = 0x00000800,
ADD_OCSP_NOCHECK = 0x00001000,
ENABLE_KEY_REUSE_ON_NT_TOKEN_KEYSET_STORAGE_FULL = 0x00002000,
NOREVOCATIONINFOINISSUEDCERTS = 0x00004000,
INCLUDE_BASIC_CONSTRAINTS_FOR_EE_CERTS = 0x00008000,
ALLOW_PREVIOUS_APPROVAL_KEYBASEDRENEWAL_VALIDATE_REENROLLMENT = 0x00010000,
ISSUANCE_POLICIES_FROM_REQUEST = 0x00020000,
SKIP_AUTO_RENEWAL = 0x00040000,
NO_SECURITY_EXTENSION = 0x00080000
}
}
61 changes: 53 additions & 8 deletions src/CommonLib/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.DirectoryServices;
using System.DirectoryServices.Protocols;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
Expand Down Expand Up @@ -85,11 +86,7 @@ public static string GetSid(this DirectoryEntry result)
/// <returns></returns>
public static bool IsComputerCollectionSet(this ResolvedCollectionMethod methods)
{
return (methods & ResolvedCollectionMethod.LocalAdmin) != 0 ||
(methods & ResolvedCollectionMethod.DCOM) != 0 || (methods & ResolvedCollectionMethod.RDP) != 0 ||
(methods & ResolvedCollectionMethod.PSRemote) != 0 ||
(methods & ResolvedCollectionMethod.Session) != 0 ||
(methods & ResolvedCollectionMethod.LoggedOn) != 0;
return (methods & ResolvedCollectionMethod.ComputerOnly) != 0;
}

/// <summary>
Expand All @@ -99,9 +96,7 @@ public static bool IsComputerCollectionSet(this ResolvedCollectionMethod methods
/// <returns></returns>
public static bool IsLocalGroupCollectionSet(this ResolvedCollectionMethod methods)
{
return (methods & ResolvedCollectionMethod.DCOM) != 0 ||
(methods & ResolvedCollectionMethod.LocalAdmin) != 0 ||
(methods & ResolvedCollectionMethod.PSRemote) != 0 || (methods & ResolvedCollectionMethod.RDP) != 0;
return (methods & ResolvedCollectionMethod.LocalGroups) != 0;
}

/// <summary>
Expand Down Expand Up @@ -252,6 +247,37 @@ public static byte[] GetPropertyAsBytes(this SearchResultEntry searchResultEntry
return bytes;
}

/// <summary>
/// Gets the specified property as an int
/// </summary>
/// <param name="entry"></param>
/// <param name="property"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool GetPropertyAsInt(this SearchResultEntry entry, string property, out int value)
{
var prop = entry.GetProperty(property);
if (prop != null) return int.TryParse(prop, out value);
value = 0;
return false;
}

/// <summary>
/// Gets the specified property as an array of X509 certificates.
/// </summary>
/// <param name="searchResultEntry"></param>
/// <param name="property"></param>
/// <returns></returns>
public static X509Certificate2[] GetPropertyAsArrayOfCertificates(this SearchResultEntry searchResultEntry,
string property)
{
if (!searchResultEntry.Attributes.Contains(property))
return null;

return searchResultEntry.GetPropertyAsArrayOfBytes(property).Select(x => new X509Certificate2(x)).ToArray();
}


/// <summary>
/// Attempts to get the unique object identifier as used by BloodHound for the Search Result Entry. Tries to get
/// objectsid first, and then objectguid next.
Expand Down Expand Up @@ -343,6 +369,21 @@ public static Label GetLabel(this SearchResultEntry entry)
objectType = Label.Domain;
else if (objectClasses.Contains(ContainerClass, StringComparer.InvariantCultureIgnoreCase))
objectType = Label.Container;
else if (objectClasses.Contains(ConfigurationClass, StringComparer.InvariantCultureIgnoreCase))
objectType = Label.Configuration;
else if (objectClasses.Contains(PKICertificateTemplateClass, StringComparer.InvariantCultureIgnoreCase))
objectType = Label.CertTemplate;
else if (objectClasses.Contains(PKIEnrollmentServiceClass, StringComparer.InvariantCultureIgnoreCase))
objectType = Label.EnterpriseCA;
else if (objectClasses.Contains(CertificationAutorityClass, StringComparer.InvariantCultureIgnoreCase))
{
if (entry.DistinguishedName.Contains(DirectoryPaths.RootCALocation))
objectType = Label.RootCA;
else if (entry.DistinguishedName.Contains(DirectoryPaths.AIACALocation))
objectType = Label.AIACA;
else if (entry.DistinguishedName.Contains(DirectoryPaths.NTAuthStoreLocation))
objectType = Label.NTAuthStore;
}
}

Log.LogDebug("GetLabel - Final label for {ObjectID}: {Label}", objectId, objectType);
Expand All @@ -356,6 +397,10 @@ public static Label GetLabel(this SearchResultEntry entry)
private const string OrganizationalUnitClass = "organizationalUnit";
private const string DomainClass = "domain";
private const string ContainerClass = "container";
private const string ConfigurationClass = "configuration";
private const string PKICertificateTemplateClass = "pKICertificateTemplate";
private const string PKIEnrollmentServiceClass = "pKIEnrollmentService";
private const string CertificationAutorityClass = "certificationAuthority";

#endregion
}
Expand Down
Loading

0 comments on commit 6cbc4ed

Please sign in to comment.