Node.js 执行命令
1.2.1 【必须】使用child_process执行系统命令,应限定或校验命令和参数的内容
- 适用场景包括:
child_process.exec
,child_process.execSync
,child_process.spawn
,child_process.spawnSync
,child_process.execFile
,child_process.execFileSync
- 调用上述函数,应首先考虑限定范围,供用户选择。
- 使用
child_process.exec
或child_process.execSync
时,如果可枚举输入的参数内容或者格式,则应限定白名单。如果无法枚举命令或参数,则必须过滤或者转义指定符号,包括:|;&$()><`!
- 使用
child_process.spawn
或child_process.execFile
时,应校验传入的命令和参数在可控列表内。
const Router = require("express").Router();
const validator = require("validator");
const { exec } = require('child_process');
// bad:未限定或过滤,直接执行命令
Router.get("/vul_cmd_inject", (req, res) => {
const txt = req.query.txt || "echo 1";
exec(txt, (err, stdout, stderr) => {
if (err) { res.send({ err: 1 }) }
res.send({stdout, stderr});
});
});
// good:通过白名单,限定外部可执行命令范围
Router.get("/not_vul_cmd_inject", (req, res) => {
const txt = req.query.txt || "echo 1";
const phone = req.query.phone || "";
const cmdList = {
sendmsg: "./sendmsg "
};
if (txt in cmdList && validator.isMobilePhone(phone)) {
exec(cmdList[txt] + phone, (err, stdout, stderr) => {
if (err) { res.send({ err: 1 }) };
res.send({stdout, stderr});
});
} else {
res.send({
err: 1,
tips: `you can use '${Object.keys(cmdList)}'`,
});
}
});
// good:执行命令前,过滤/转义指定符号
Router.get("/not_vul_cmd_inject", (req, res) => {
const txt = req.query.txt || "echo 1";
let phone = req.query.phone || "";
const cmdList = {
sendmsg: "./sendmsg "
};
phone = phone.replace(/(\||;|&|\$\(|\(|\)|>|<|\`|!)/gi,"");
if (txt in cmdList) {
exec(cmdList[txt] + phone, (err, stdout, stderr) => {
if (err) { res.send({ err: 1 }) };
res.send({stdout, stderr});
});
} else {
res.send({
err: 1,
tips: `you can use '${Object.keys(cmdList)}'`,
});
}
});
关联漏洞:高风险 - 任意命令执行