While I was testing a XML Injection vulnerability, I became interested in the W3Schools DTD Validator example that can only work in IE: http://www.w3schools.com/dtd/dtd_validation.asp ([updated 24/10/2016] – link mirror: https://web.archive.org/web/20130424001426/http://w3schools.com/dtd/dtd_validation.asp). As a result, after I finished my testing, I started playing with this Microsoft XMLDOM object to see if it is vulnerable.
I created the following test case to manipulate the “$target$” value and validate it to see the results:
validateXML('<?xml version="1.0" ?><!DOCTYPE anything SYSTEM "$target$">') function validateXML(txt) { // code for IE if (window.ActiveXObject) { var xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async = true; try { xmlDoc.loadXML(txt); if (xmlDoc.parseError.errorCode != 0) { var err; err = "Error Code: " + xmlDoc.parseError.errorCode + "\n"; err += "Error Reason: " + xmlDoc.parseError.reason; err += "Error Line: " + xmlDoc.parseError.line; alert(err); var errReason = xmlDoc.parseError.reason.toLowerCase(); alert(errReason); } else { alert('No Error? Unknown!') } } catch (e) { alert(e); } } else { alert('you need to use IE') } }
You can see this JS in action via this link in IE: http://jsfiddle.net/ubqug/
Detecting files in the C drive:
I tried different local file paths to see if I can include a file from the local file system. The results of the following test cases are the same – “Access is denied.”:
$target$=file://c:/windows/system32/calc.exe
$target$=file://c:/windows/system32/invalid.exe
See this link: http://jsfiddle.net/ubqug/1/
I thought I might be able to use “\\localhost” or “\\127.0.0.1” instead of using “file” protocol:
$target$ = \\127.0.0.1\c$\windows\system32\calc.exe
$target$ = \\127.0.0.1\c$\windows\system32\invalid.exe
The result was the same again; however, I did not receive an “access denied” error this time! See this link: http://jsfiddle.net/ubqug/2/
At this point, I used Sysinternals Suite Process Monitor to monitor the file system and I realised that in the previous example, it was looking for “c$” folder in the C drive!
Therefore, I removed “c$” from my targets and ran the test again:
$target$ = \\127.0.0.1\windows\system32\calc.exe
$target$ = \\127.0.0.1\windows\system32\invalid.exe
The result was promising as I received “Unspecified error” for the file that was available on my file system. See this: http://jsfiddle.net/ubqug/3/
So, I found my first bypass to detect available files on the C drive.
I also found more vectors to find files on the C drive and it turned out that I can get the same result by using “file:\” and “file:\\localhost\” instead of “file:\\”! See this link: http://jsfiddle.net/ubqug/4/
Detecting valid folders in C drive:
It was possible to find the valid folders on C drive by using the same technique as the error messages were a little bit different in case of having a valid or an invalid folder:
$target$ = \\localhost\windows\
$target$ = \\localhost\invalidfolder\
Try it in: http://jsfiddle.net/ubqug/6/ – in case of an invalid folder the message will be: “the system cannot locate the object …”. When a folder is valid we will have: “the system cannot find the path …”
I also found out if I use NTFS ADS (Alternate Data Streams) that are related to files and not the directories such as “::$DATA” I would receive different error messages to detect the valid folders (“access denied” versus the “the system cannot locate the object …”):
$target$ = \\localhost\windows::$DATA
$target$ = \\localhost\invalidfolder::$DATA
See the result in this link: http://jsfiddle.net/ubqug/7/
Detecting files and directories in all drives:
At this point during my testing, I had a limitation and I could not detect my files in any drive other than the C drive by using the previous vectors. Vectors like “file:/e:/” or “\\localhost\e$” did not work.
I solved this problem by using “res://” protocol (http://msdn.microsoft.com/en-us/library/aa767740(v=vs.85).aspx) and I received different error messages by pointing to the files or folders.
$target$ = res://d:\validfile.txt
$target$ = res://d:\invalidfile.txt
See the results here (you need to create the “validfile.txt” file in your D drive or change the path): http://jsfiddle.net/ubqug/5/
Detecting available drives:
In order to make the results more accurate, I had to find the available drive letters on the box. Unfortunately “res://” protocol was not helpful in this case and I had to use another solution. The solution that I found was in fact very easy. I could use the drive letters directly; if the drive letter is available, the error message would be “access denied” and when it is not available, the error message changes to “the system cannot find the path specified”:
$target$ = c:\
$target$ = invalid:\
See the results in http://jsfiddle.net/ubqug/8/
Detecting available Windows internal network addresses or internal websites:
During my tests, I realised that I can send http request to local sites or IP addresses, and I can point to network shares as well. In this case, it would give me an error immediately if the target was valid. However, it could take between 10 to 60 seconds to come back with an error when it could not receive a response from the target! I used this technique to detect valid local IP/Name addresses. However, as it does take a long time to identify an invalid target, it is not appropriate for scanning.
Denial of Service:
Like many other DTD parsers, XMLDOM object was also vulnerable to denial of service. I did not even try hard to find the issue and I used an example in the following link from MSDN Magazine:
http://msdn.microsoft.com/en-us/magazine/ee335713.aspx
Summary:
I have created a PoC page to test the above techniques in one page which can be found via: http://0me.me/demo/IE/dtdTest.html
I also searched in Google and I found out that the general topic of these issues have been mentioned in the following link from Microsoft:
http://msdn.microsoft.com/en-gb/library/windows/desktop/ms754611(v=vs.85).aspx
See the “Threats and Mitigation” section in the link above.
At the moment this issue is a client side issue and only works in IE. I published it as the impacts are low (limited information disclosure vulnerability) and you cannot read the file contents with the vectors that I have found (only worthless local DTD files are partially readable). However, this research can be very valuable to people who are looking for the new vectors in finding/exploiting XML vulnerabilities (for example in Java – I do not have time to test this at the moment) – obviously in legal and legitimate research/pentest projects ;)
Once again, the PoC page is: http://0me.me/demo/IE/dtdTest.html