Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into attribute_error_fix
Browse files Browse the repository at this point in the history
  • Loading branch information
nurfed1 committed Jun 21, 2023
2 parents f95af28 + 6eb4f4e commit 10b062f
Show file tree
Hide file tree
Showing 14 changed files with 113 additions and 29 deletions.
1 change: 1 addition & 0 deletions certipy/commands/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ def ldap_authentication(
sasl_credentials=sasl_credentials,
auto_bind=ldap3.AUTO_BIND_TLS_BEFORE_BIND,
raise_exceptions=True,
receive_timeout=self.target.timeout * 10
)
except ldap3.core.exceptions.LDAPUnavailableResult as e:
logging.error("LDAP not configured for SSL/TLS connections")
Expand Down
12 changes: 8 additions & 4 deletions certipy/commands/find.py
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,10 @@ def security_to_bloodhound_aces(self, security: ActiveDirectorySecurity) -> List
is_inherited = rights["inherited"]
principal = self.connection.lookup_sid(sid)

standard_rights = rights["rights"].to_list()
try:
standard_rights = list(rights["rights"])
except:
standard_rights = rights["rights"].to_list()

for right in standard_rights:
aces.append(
Expand Down Expand Up @@ -857,7 +860,6 @@ def get_template_permissions(self, template: LDAPEntry):

if (
EXTENDED_RIGHTS_NAME_MAP["Enroll"] in rights["extended_rights"]
or EXTENDED_RIGHTS_NAME_MAP["AutoEnroll"] in rights["extended_rights"]
):
enrollment_rights.append(self.connection.lookup_sid(sid).get("name"))
if (
Expand Down Expand Up @@ -1029,7 +1031,6 @@ def can_user_enroll_in_template(self, template: LDAPEntry):
EXTENDED_RIGHTS_NAME_MAP["All-Extended-Rights"]
in rights["extended_rights"]
or EXTENDED_RIGHTS_NAME_MAP["Enroll"] in rights["extended_rights"]
or EXTENDED_RIGHTS_NAME_MAP["AutoEnroll"] in rights["extended_rights"]
or CERTIFICATE_RIGHTS.GENERIC_ALL in rights["rights"]
):
enrollable_sids.append(sid)
Expand Down Expand Up @@ -1076,7 +1077,10 @@ def get_ca_permissions(self, ca: LDAPEntry):
for sid, rights in security.aces.items():
if self.hide_admins and is_admin_sid(sid):
continue
ca_rights = rights["rights"].to_list()
try:
ca_rights = list(rights["rights"])
except:
ca_rights = rights["rights"].to_list()
for ca_right in ca_rights:
if ca_right not in access_rights:
access_rights[ca_right] = [
Expand Down
30 changes: 29 additions & 1 deletion certipy/commands/forge.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

from certipy.lib.certificate import (
PRINCIPAL_NAME,
NameOID,
UTF8String,
cert_id_to_parts,
create_pfx,
Expand All @@ -13,6 +12,9 @@
get_subject_from_str,
load_pfx,
x509,
asn1x509,
NTDS_CA_SECURITY_EXT,
szOID_NTDS_OBJECTSID
)
from certipy.lib.logger import logging

Expand All @@ -23,6 +25,7 @@ def __init__(
ca_pfx: str = None,
upn: str = None,
dns: str = None,
sid: str = None,
template: str = None,
subject: str = None,
issuer: str = None,
Expand All @@ -35,6 +38,7 @@ def __init__(
self.ca_pfx = ca_pfx
self.alt_upn = upn
self.alt_dns = dns
self.alt_sid = sid
self.template = template
self.subject = subject
self.issuer = issuer
Expand Down Expand Up @@ -200,6 +204,30 @@ def forge(self):
False,
)

alt_sid = self.alt_sid
if alt_sid:
if type(alt_sid) == str:
alt_sid = alt_sid.encode()

sid_extension = asn1x509.GeneralNames([asn1x509.GeneralName(
{
"other_name": asn1x509.AnotherName(
{
"type_id": szOID_NTDS_OBJECTSID,
"value": asn1x509.OctetString(alt_sid).retag(
{"explicit": 0}
),
}
)
}
)]
)

cert = cert.add_extension(
x509.UnrecognizedExtension(NTDS_CA_SECURITY_EXT, sid_extension.dump()),
False,
)

cert = cert.sign(ca_key, signature_hash_algorithm())

pfx = create_pfx(key, cert)
Expand Down
1 change: 1 addition & 0 deletions certipy/commands/parsers/forge.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def add_subparser(subparsers: argparse._SubParsersAction) -> Tuple[str, Callable
)
subparser.add_argument("-upn", action="store", metavar="alternative UPN")
subparser.add_argument("-dns", action="store", metavar="alternative DNS")
subparser.add_argument("-sid", action="store", metavar="alternative Object SID")
subparser.add_argument(
"-template",
action="store",
Expand Down
1 change: 1 addition & 0 deletions certipy/commands/parsers/relay.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def add_subparser(subparsers: argparse._SubParsersAction) -> Tuple[str, Callable

group.add_argument("-upn", action="store", metavar="alternative UPN")
group.add_argument("-dns", action="store", metavar="alternative DNS")
group.add_argument("-sid", action="store", metavar="alternative Object SID")
group.add_argument(
"-retrieve",
action="store",
Expand Down
1 change: 1 addition & 0 deletions certipy/commands/parsers/req.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def add_subparser(subparsers: argparse._SubParsersAction) -> Tuple[str, Callable
)
group.add_argument("-upn", action="store", metavar="alternative UPN")
group.add_argument("-dns", action="store", metavar="alternative DNS")
group.add_argument("-sid", action="store", metavar="alternative Object SID")
group.add_argument(
"-subject",
action="store",
Expand Down
3 changes: 3 additions & 0 deletions certipy/commands/relay.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ def _run(self):
self.username,
alt_dns=self.adcs_relay.dns,
alt_upn=self.adcs_relay.upn,
alt_sid=self.adcs_relay.sid,
key_size=self.adcs_relay.key_size,
)

Expand Down Expand Up @@ -374,6 +375,7 @@ def __init__(
template=None,
upn=None,
dns=None,
sid=None,
retrieve=None,
key_size: int = 2048,
out=None,
Expand All @@ -389,6 +391,7 @@ def __init__(
self.template = template
self.upn = upn
self.dns = dns
self.sid = sid
self.request_id = int(retrieve)
self.key_size = key_size
self.out = out
Expand Down
3 changes: 3 additions & 0 deletions certipy/commands/req.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,7 @@ def __init__(
template: str = None,
upn: str = None,
dns: str = None,
sid: str = None,
subject: str = None,
retrieve: int = 0,
on_behalf_of: str = None,
Expand All @@ -545,6 +546,7 @@ def __init__(
self.template = template
self.alt_upn = upn
self.alt_dns = dns
self.alt_sid = sid
self.subject = subject
self.request_id = int(retrieve)
self.on_behalf_of = on_behalf_of
Expand Down Expand Up @@ -669,6 +671,7 @@ def request(self) -> bool:
username,
alt_dns=self.alt_dns,
alt_upn=self.alt_upn,
alt_sid=self.alt_sid,
key=self.key,
key_size=self.key_size,
subject=self.subject,
Expand Down
51 changes: 45 additions & 6 deletions certipy/lib/certificate.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import os
import struct
import sys
from typing import Callable, List, Tuple
from typing import List, Tuple

from asn1crypto import cms as asn1cms
from asn1crypto import core as asn1core
Expand Down Expand Up @@ -50,17 +50,29 @@
"DC": NameOID.DOMAIN_COMPONENT,
}

PRINCIPAL_NAME = x509.ObjectIdentifier("1.3.6.1.4.1.311.20.2.3")
asn1x509.ExtensionId._map.update(
{
"1.3.6.1.4.1.311.25.2": "security_ext",
}
)

NTDS_CA_SECURITY_EXT = x509.ObjectIdentifier("1.3.6.1.4.1.311.25.2")
asn1x509.Extension._oid_specs.update(
{
"security_ext": asn1x509.GeneralNames,
}
)

PRINCIPAL_NAME = x509.ObjectIdentifier("1.3.6.1.4.1.311.20.2.3")
NTDS_CA_SECURITY_EXT = x509.ObjectIdentifier("1.3.6.1.4.1.311.25.2")
NTDS_OBJECTSID = x509.ObjectIdentifier("1.3.6.1.4.1.311.25.2.1")

szOID_RENEWAL_CERTIFICATE = asn1cms.ObjectIdentifier("1.3.6.1.4.1.311.13.1")
szOID_ENCRYPTED_KEY_HASH = asn1cms.ObjectIdentifier("1.3.6.1.4.1.311.21.21")
szOID_PRINCIPAL_NAME = asn1cms.ObjectIdentifier("1.3.6.1.4.1.311.20.2.3")
szOID_ENCRYPTED_KEY_HASH = asn1cms.ObjectIdentifier("1.3.6.1.4.1.311.21.21")
szOID_CMC_ADD_ATTRIBUTES = asn1cms.ObjectIdentifier("1.3.6.1.4.1.311.10.10.1")

szOID_NTDS_CA_SECURITY_EXT = asn1cms.ObjectIdentifier("1.3.6.1.4.1.311.25.2")
szOID_NTDS_OBJECTSID = asn1cms.ObjectIdentifier("1.3.6.1.4.1.311.25.2.1")

class TaggedCertificationRequest(asn1core.Sequence):
_fields = [
Expand Down Expand Up @@ -317,6 +329,7 @@ def create_csr(
username: str,
alt_dns: bytes = None,
alt_upn: bytes = None,
alt_sid: bytes = None,
key: rsa.RSAPrivateKey = None,
key_size: int = 2048,
subject: str = None,
Expand Down Expand Up @@ -360,8 +373,6 @@ def create_csr(
alt_dns = alt_dns.decode()
general_names.append(asn1x509.GeneralName({"dns_name": alt_dns}))

# sans.append(x509.DNSName(alt_dns))

if alt_upn:
if type(alt_upn) == bytes:
alt_upn = alt_upn.decode()
Expand Down Expand Up @@ -393,6 +404,34 @@ def create_csr(

cri_attributes.append(cri_attribute)

if alt_sid:
if type(alt_sid) == str:
alt_sid = alt_sid.encode()


san_extension = asn1x509.Extension(
{"extn_id": "security_ext", "extn_value": [asn1x509.GeneralName(
{
"other_name": asn1x509.AnotherName(
{
"type_id": szOID_NTDS_OBJECTSID,
"value": asn1x509.OctetString(alt_sid).retag(
{"explicit": 0}
),
}
)
}
)]}
)

set_of_extensions = asn1csr.SetOfExtensions([[san_extension]])

cri_attribute = asn1csr.CRIAttribute(
{"type": "extension_request", "values": set_of_extensions}
)

cri_attributes.append(cri_attribute)

if renewal_cert:
cri_attributes.append(
asn1csr.CRIAttribute(
Expand Down
2 changes: 1 addition & 1 deletion certipy/lib/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ class MS_PKI_CERTIFICATE_AUTHORITY_FLAG(IntFlag):
"1.3.6.1.4.1.311.10.3.2": "Microsoft Time Stamping",
"1.3.6.1.4.1.311.76.8.1": "Microsoft Publishe",
"1.3.6.1.5.5.7.3.2": "Client Authentication",
"1.3.6.1.5.2.3.4": "PKIINIT Client Authentication",
"1.3.6.1.5.2.3.4": "PKINIT Client Authentication",
"1.3.6.1.4.1.311.10.3.13": "Lifetime Signing",
"2.5.29.37.0": "Any Purpose",
"1.3.6.1.4.1.311.64.1.1": "Server Trust",
Expand Down
14 changes: 6 additions & 8 deletions certipy/lib/ldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ def machine_account_quota(self):
],
)
if len(results) != 1:
return None
return 0

result = results[0]
machine_account_quota = result.get("ms-DS-MachineAccountQuota")
Expand Down Expand Up @@ -354,13 +354,11 @@ def get_user_sids(self, username: str):
if primary_group_id is not None:
sids.add("%s-%d" % (self.domain_sid, primary_group_id))

# Add Domain Computers group if Machine Account Quota > 0
if self.machine_account_quota > 0:
logging.debug(
"Adding Domain Computers to list of current user's SIDs (Machine Account Quota: %d > 0)"
% self.machine_account_quota
)
sids.add("%s-515" % self.domain_sid)
# Add Domain Computers group
logging.debug(
"Adding Domain Computers to list of current user's SIDs"
)
sids.add("%s-515" % self.domain_sid)

dns = [user.get("distinguishedName")]
for sid in sids:
Expand Down
5 changes: 4 additions & 1 deletion certipy/lib/structs.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ def to_list(self):
return members

def to_str_list(self):
return list(map(lambda x: str(x), self.to_list()))
try:
return list(map(lambda x: str(x), list(self)))
except:
return list(map(lambda x: str(x), self.to_list()))

def __str__(self):
cls = self.__class__
Expand Down
10 changes: 5 additions & 5 deletions customqueries.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
"queryList": [
{
"final": true,
"query": "MATCH (n:GPO) WHERE n.type = 'Certificate Template' and n.`Enabled` = true and (n.`Extended Key Usage` = [] or 'Any Purpose' IN n.`Extended Key Usage`) RETURN n"
"query": "MATCH (n:GPO) WHERE n.type = 'Certificate Template' and n.`Enabled` = true and (n.`Extended Key Usage` = [] or 'Any Purpose' IN n.`Extended Key Usage` or n.`Any Purpose` = True) RETURN n"
}
]
},
Expand All @@ -98,7 +98,7 @@
"queryList": [
{
"final": true,
"query": "MATCH p=allShortestPaths((g {owned:true})-[*1..]->(n:GPO)) WHERE g<>n and n.type = 'Certificate Template' and n.`Enabled` = true and (n.`Extended Key Usage` = [] or 'Any Purpose' IN n.`Extended Key Usage`) return p"
"query": "MATCH p=allShortestPaths((g {owned:true})-[*1..]->(n:GPO)) WHERE g<>n and n.type = 'Certificate Template' and n.`Enabled` = true and (n.`Extended Key Usage` = [] or 'Any Purpose' IN n.`Extended Key Usage` or n.`Any Purpose` = True) RETURN p"
}
]
},
Expand All @@ -108,7 +108,7 @@
"queryList": [
{
"final": true,
"query": "MATCH (n:GPO) WHERE n.type = 'Certificate Template' and n.`Enabled` = true and (n.`Extended Key Usage` = [] or 'Any Purpose' IN n.`Extended Key Usage` or 'Certificate Request Agent' IN n.`Extended Key Usage`) RETURN n"
"query": "MATCH (n:GPO) WHERE n.type = 'Certificate Template' and n.`Enabled` = true and (n.`Extended Key Usage` = [] or 'Any Purpose' IN n.`Extended Key Usage` or 'Certificate Request Agent' IN n.`Extended Key Usage` or n.`Any Purpose` = True) RETURN n"
}
]
},
Expand All @@ -118,7 +118,7 @@
"queryList": [
{
"final": true,
"query": "MATCH p=allShortestPaths((g {owned:true})-[*1..]->(n:GPO)) WHERE g<>n and n.type = 'Certificate Template' and n.`Enabled` = true and (n.`Extended Key Usage` = [] or 'Any Purpose' IN n.`Extended Key Usage` or 'Certificate Request Agent' IN n.`Extended Key Usage`) return p"
"query": "MATCH p=allShortestPaths((g {owned:true})-[*1..]->(n:GPO)) WHERE g<>n and n.type = 'Certificate Template' and n.`Enabled` = true and (n.`Extended Key Usage` = [] or 'Any Purpose' IN n.`Extended Key Usage` or n.`Any Purpose` = True or 'Certificate Request Agent' IN n.`Extended Key Usage`) RETURN p"
}
]
},
Expand Down Expand Up @@ -213,4 +213,4 @@
]
}
]
}
}
Loading

0 comments on commit 10b062f

Please sign in to comment.