diff --git a/README.md b/README.md
index 8fc8d3d..794c3ee 100644
--- a/README.md
+++ b/README.md
@@ -56,6 +56,8 @@ Enumeration:
Writing:
--rbcd source Operation to write or remove RBCD. Also used to pass in the source computer account used
for the attack.
+ --altsecid value Operation to write the altSecurityIdentities attribute value, writes by default unless "
+ --remove" is specified
--spn value Operation to write the servicePrincipalName attribute value, writes by default unless "
--remove" is specified
--asrep Operation to write the DONT_REQ_PREAUTH (0x400000) userAccountControl flag on a target
diff --git a/src/adws.py b/src/adws.py
index 2b5fe82..8964c02 100644
--- a/src/adws.py
+++ b/src/adws.py
@@ -1,6 +1,7 @@
import datetime
import logging
import socket
+import re
from base64 import b64decode
from enum import IntFlag
from typing import Self, Type
@@ -426,6 +427,13 @@ def _handle_str_to_xml(self, xmlstr: str) -> ElementTree.Element | None:
soap message return by the server
"""
+ # handling of unescaped XML special characters in
+ # responses to ensure smooth parsing
+ m = re.search(r']*>(X509:<[^>]+>(.*?))', xmlstr)
+ if m:
+ unescaped = m.groups()[0]
+ xmlstr = xmlstr.replace(unescaped, '' % unescaped)
+
if ":Fault>" and ":Reason>" not in xmlstr:
return ElementTree.fromstring(xmlstr)
diff --git a/src/soa.py b/src/soa.py
index e091db8..2414a6b 100644
--- a/src/soa.py
+++ b/src/soa.py
@@ -85,8 +85,9 @@ def getAccountDN(
return dn
-def set_spn(
+def set_array_attribute(
target: str,
+ attr: str,
value: str,
username: str,
ip: str,
@@ -94,32 +95,34 @@ def set_spn(
auth: NTLMAuth,
remove: bool = False,
):
- """Set a value in servicePrincipalName. Appends value to the
- attribute rather than replacing.
+ """Set a value in AD attribute that has isSingleValued=False
+ (e.g. servicePrincipalName, altSecurityIdentities).
+ Appends value to the attribute rather than replacing.
Args:
target (str): target samAccountName
- value (str): value to append to the targets servicePrincipalName
+ attr (str): name of attribute to modify
+ value (str): value to append to the target's attribute
username (str): user to authenticate as
ip (str): the ip of the domain controller
auth (NTLMAuth): authentication method
remove (bool): Whether to remove the value
"""
- dn = getAccountDN(target=target,username=username,ip=ip,domain=domain,auth=auth)
+ dn = getAccountDN(target=target, username=username, ip=ip, domain=domain, auth=auth)
put_client = ADWSConnect.put_client(ip, domain, username, auth)
put_client.put(
object_ref=dn,
operation="add" if not remove else "delete",
- attribute="addata:servicePrincipalName",
+ attribute=f"addata:{attr}",
data_type="string",
value=value,
)
print(
- f"[+] servicePrincipalName {value} {'removed' if remove else 'written'} successfully on {target}!"
+ f"[+] {attr} {value} {'removed' if remove else 'written'} successfully on {target}!"
)
def set_asrep(
@@ -412,6 +415,12 @@ def run_cli():
metavar="source",
help="Operation to write or remove RBCD. Also used to pass in the source computer account used for the attack.",
)
+ writing.add_argument(
+ "--altsecid",
+ action="store",
+ metavar="value",
+ help='Operation to write the altSecurityIdentities attribute value, writes by default unless "--remove" is specified',
+ )
writing.add_argument(
"--spn",
action="store",
@@ -503,6 +512,23 @@ def run_cli():
auth=auth,
remove=options.remove,
)
+ elif options.altsecid != None:
+ if not options.account:
+ logging.critical(
+ 'Please specify an account with "--account"'
+ )
+ raise SystemExit()
+
+ set_array_attribute(
+ ip=remoteName,
+ domain=domain,
+ target=options.account,
+ attr='altSecurityIdentities',
+ value=options.altsecid,
+ username=username,
+ auth=auth,
+ remove=options.remove
+ )
elif options.spn != None:
if not options.account:
logging.critical(
@@ -510,10 +536,11 @@ def run_cli():
)
raise SystemExit()
- set_spn(
+ set_array_attribute(
ip=remoteName,
domain=domain,
target=options.account,
+ attr='servicePrincipalName',
value=options.spn,
username=username,
auth=auth,
diff --git a/src/soap_templates.py b/src/soap_templates.py
index eda1b0d..52a9681 100644
--- a/src/soap_templates.py
+++ b/src/soap_templates.py
@@ -100,9 +100,9 @@
{attribute}
- {value}
+
- """
\ No newline at end of file
+ """