阅读(4661) (0)

Node.js 执行命令

2021-06-01 09:50:09 更新

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.execchild_process.execSync时,如果可枚举输入的参数内容或者格式,则应限定白名单。如果无法枚举命令或参数,则必须过滤或者转义指定符号,包括:|;&$()><`!

  • 使用child_process.spawnchild_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)}'`,
        });
    }
});

关联漏洞:高风险 - 任意命令执行