From 4f75a7f55b280c0f528922b8d84984a73c2a6373 Mon Sep 17 00:00:00 2001 From: azoxlpf <213314124+azoxlpf@users.noreply.github.com> Date: Thu, 18 Jun 2026 14:30:43 +0200 Subject: [PATCH 1/3] replace ldap3 with impacket in daclread module --- nxc/modules/daclread.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/nxc/modules/daclread.py b/nxc/modules/daclread.py index f639b29e..6bd53e25 100644 --- a/nxc/modules/daclread.py +++ b/nxc/modules/daclread.py @@ -3,16 +3,30 @@ import json import datetime from enum import Enum from impacket.ldap import ldaptypes +from impacket.ldap.ldapasn1 import SDFlagsControl from impacket.uuid import bin_to_string from nxc.helpers.misc import CATEGORY from nxc.helpers.msada_guids import SCHEMA_OBJECTS, EXTENDED_RIGHTS from nxc.parsers.ldap_results import parse_result_attributes -from ldap3.utils.conv import escape_filter_chars -from ldap3.protocol.microsoft import security_descriptor_control import sys import traceback from os.path import isfile + +def escape_filter_chars(text, encoding="utf-8"): + """Escape special characters in an LDAP search filter assertion value (RFC 4515).""" + if isinstance(text, (bytes, bytearray)): + try: + text = text.decode(encoding) + except Exception: + return "".join(f"\\{b:02x}" for b in text) + escaped = text.replace("\\", "\\5c") + escaped = escaped.replace("*", "\\2a") + escaped = escaped.replace("(", "\\28") + escaped = escaped.replace(")", "\\29") + return escaped.replace("\x00", "\\00") + + OBJECT_TYPES_GUID = {} OBJECT_TYPES_GUID.update(SCHEMA_OBJECTS) OBJECT_TYPES_GUID.update(EXTENDED_RIGHTS) @@ -306,7 +320,7 @@ class NXCModule: resp = connection.search( searchFilter=search_filter(target), attributes=["distinguishedName", "nTSecurityDescriptor"], - searchControls=security_descriptor_control(sdflags=0x04), + searchControls=[SDFlagsControl(criticality=False, flags=0x04)], ) resp_parsed = parse_result_attributes(resp)[0] From e1c99c9387239b15888608386ba49a097a97b773 Mon Sep 17 00:00:00 2001 From: azoxlpf <213314124+azoxlpf@users.noreply.github.com> Date: Thu, 18 Jun 2026 14:39:34 +0200 Subject: [PATCH 2/3] update comment --- nxc/modules/daclread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nxc/modules/daclread.py b/nxc/modules/daclread.py index 6bd53e25..390dab73 100644 --- a/nxc/modules/daclread.py +++ b/nxc/modules/daclread.py @@ -214,7 +214,7 @@ class NXCModule: This module is essentially inspired from the dacledit.py script of Impacket that we have coauthored, @_nwodtuhs and me. It has been converted to an LDAPConnection session, and improvements on the filtering and the ability to specify multiple targets have been added. - It could be interesting to implement the write/remove functions here, but a ldap3 session instead of a LDAPConnection one is required to write. + It could be interesting to implement the write/remove functions here. """ name = "daclread" From 2a3fb7a1685ea11b5cb6572bc37232848329afcf Mon Sep 17 00:00:00 2001 From: Alexander Neff Date: Sun, 12 Jul 2026 08:47:45 -0400 Subject: [PATCH 3/3] Remove custom ldap filtering --- nxc/modules/daclread.py | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/nxc/modules/daclread.py b/nxc/modules/daclread.py index 390dab73..32ea0f25 100644 --- a/nxc/modules/daclread.py +++ b/nxc/modules/daclread.py @@ -13,20 +13,6 @@ import traceback from os.path import isfile -def escape_filter_chars(text, encoding="utf-8"): - """Escape special characters in an LDAP search filter assertion value (RFC 4515).""" - if isinstance(text, (bytes, bytearray)): - try: - text = text.decode(encoding) - except Exception: - return "".join(f"\\{b:02x}" for b in text) - escaped = text.replace("\\", "\\5c") - escaped = escaped.replace("*", "\\2a") - escaped = escaped.replace("(", "\\28") - escaped = escaped.replace(")", "\\29") - return escaped.replace("\x00", "\\00") - - OBJECT_TYPES_GUID = {} OBJECT_TYPES_GUID.update(SCHEMA_OBJECTS) OBJECT_TYPES_GUID.update(EXTENDED_RIGHTS) @@ -204,8 +190,8 @@ class ALLOWED_OBJECT_ACE_MASK_FLAGS(Enum): SEARCH_FILTERS = { - "TARGET": lambda target: f"(sAMAccountName={escape_filter_chars(target)})", - "TARGET_DN": lambda target: f"(distinguishedName={escape_filter_chars(target)})" + "TARGET": lambda target: f"(sAMAccountName={target})", + "TARGET_DN": lambda target: f"(distinguishedName={target})" } @@ -302,7 +288,7 @@ class NXCModule: if self.principal_sAMAccountName is not None: try: resp = connection.search( - searchFilter=f"(sAMAccountName={escape_filter_chars(self.principal_sAMAccountName)})", + searchFilter=f"(sAMAccountName={self.principal_sAMAccountName})", attributes=["objectSid"], ) resp_parsed = parse_result_attributes(resp)[0]