前言

赛后自学了nodejs原型链污染后来尝试做这个题,难度不算太大,但是绕过姿势非常奇怪没见过,写一篇总结记录一下做法

wp

首先打开环境发现是一个登录框,题目有附件我们下载查看附件

最关键的就是controller.js和main.js两个文件,index.html是前端代码用处不大

代码审计

controller.js

 const fs = require("fs");//引入js模块,为flag1和flag2提供读文件操作
const SECRET_COOKIE = process.env.SECRET_COOKIE || "this_is_testing_cookie"
//设置SECRET_COOKIE的值,如果环境变量process.env中存在SECRET.COOKIE就把这个常量赋值为环境变量中的值,如果环境变量中没有则设置为"this_is_testing_cookie"
const flag1 = fs.readFileSync("/flag1")//读flag1中的值
const flag2 = fs.readFileSync("/flag2")//读flag2中的值

//merge函数,nodejs原型链污染的关键函数,文章后面会放我对这个函数在nodejs原型链污染作用上的理解
function merge(target, source) {
for (let key in source) {
if (key == "__proto__") {
continue;//过滤了__proto__键,本题不能用__proto__来进行原型链污染,但prototype仍然可以使用
}
if (key in target && key in source) {
merge(target[key], source[key])
} else {
target[key] = source[key]
}
}
}

//设置一个LoginController函数,描述登录逻辑
function LoginController(req, res) {
try {
let user = {}//设置一个空对象user
merge(user, req.body)//req.body是一个属性,通常用于存储与请求相关的主体内容,尤其是在POST请求中。当客户端向服务器发送数据(例如,通过表单提交或JSON数据),这些数据将被解析并存储在req.body中

if (user.username !== "admin" || user.password !== Math.random().toString()) {
res.status(401).type("text/html").send("Login Failed")//判断用户名或者密码的逻辑
} else {
//登录成功的逻辑,这里是本题nodejs原型链污染的重要利用点
res.cookie("user", SECRET_COOKIE)
req.user = "admin"
res.redirect("/flag1")
}
} catch (e) {
console.log(e)
res.status(401).type("text/html").send("What the heck")
}
}

//设置一个Flag1Controller函数,描述flag1的获得逻辑
function Flag1Controller(req, res) {
try {
if (req.cookies.user === SECRET_COOKIE || req.user == "admin") {
//这个判断使用逻辑或,只要两者有一个判断为true,整个判断为true,所以只要满足req.user == "admin"即可
res.setHeader("This_Is_The_Flag1", flag1.toString().trim())
//把flag1的内容放在相应包中
res.status(200).type("text/html").send("Login success. Welcome,admin!")
} else {
res.status(401).type("text/html").send("Unauthorized")
}
} catch (__) { }
}

//设置一个Flag2Controller函数,描述flag2的获得逻辑
function Flag2Controller(req, res) {
//三元运算符,如果req.body.checkcode的值存在则保留原有的值,如果不存在则复制为1234
let checkcode = req.body.checkcode ? req.body.checkcode : 1234;
console.log(req.body)
if (checkcode.length === 16) { //判断checkcode的长度要等于16
try {
checkcode = checkcode.toLowerCase() //把checkcode的值中的大写字母变成小写字母
if (checkcode !== "aGr5AtSp55dRacer") { //很明显经过前面的操作这里无法直接满足,所以可以通过触发 toLowerCase() 的错误来绕过条件判断,可以通过传递一个非字符串类型且长度为16的值(比如数组),这样执行checkcode时会抛出错误(因为非字符串无法调用该方法),错误被catch捕获后,代码会继续执行catch后面的内容
res.status(403).json({ "msg": "Invalid Checkcode1:" + checkcode })
}
} catch (__) { }
//得到flag2
res.status(200).type("text/html").json({ "msg": "You Got Another Part Of Flag: " + flag2.toString().trim() })
} else {
res.status(403).type("text/html").json({ "msg": "Invalid Checkcode2:" + checkcode })
}
}

module.exports = {
LoginController,
Flag1Controller,
Flag2Controller
}

main.js

 const express = require("express")
const fs = require("fs")
const cookieParser = require("cookie-parser");
const controller = require("./controller")

const app = express();
const PORT = Number(process.env.PORT) || 80
const HOST = '0.0.0.0'


app.use(express.urlencoded({ extended: false }))
app.use(cookieParser())
app.use(express.json())

app.use(express.static('static'))

//登陆页面
app.get("/", (res) => {
res.sendFile(__dirname, "static/index.html")
})

//传值使用post方式
app.post("/", (req, res) => {
controller.LoginController(req, res)
})

//flag1要发送get请求
app.get("/flag1", (req, res) => {
controller.Flag1Controller(req, res)
})

//flag2要发送post请求,可以在登录成功页面抓包post方式在flag2路由下传值
app.post("/flag2", (req, res) => {
controller.Flag2Controller(req, res)
})

app.listen(PORT, HOST, () => {
console.log(`Server is listening on Host ${HOST} Port ${PORT}.`)
})

解题

代码审计后本题的思路就非常明显了,首先绕过登录判断成功登录后访问flag1拿到前半段flag,然后访问flag2绕过判断拿到后半段flag

登录

首先我们随便输入用户名密码,抓包,因为源代码中假如登录成功会执行

 res.cookie("user", SECRET_COOKIE)
req.user = "admin"
res.redirect("/flag1")

所以我们要利用nodejs原型链污染把req.user设置为admin

payload

 {
"username":"admin",
"password":"123",
"constructor":{
"user":"admin"
}
}

把content-type改成application/json后发送请求包

flag1

执行了catch(e)中的内容,看起来登录好像已经绕过了,我们尝试手动访问flag1

成功访问,我们修改请求包为get访问flag1

成功拿到前半段flag1

flag2

接下来就是第二段flag

我做的时候竟然纳闷flag2这段代码是哪个页面的逻辑,想了半天才想到去main.js里面去看看,真服了我这脑子

flag2是post传值,这里需要绕过的关键判断是

 if (checkcode.length === 16) { //判断checkcode的长度要等于16
try {
checkcode = checkcode.toLowerCase() //把checkcode的值中的大写字母变成小写字母
if (checkcode !== "aGr5AtSp55dRacer")

很明显如果我们的字符串大写字母转为小写字母后肯定不能满足这个判断的字符串,因为里面还有大写字母。代码审计中提到了这里的绕过方式,我们利用数组绕过

 {
"checkcode":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
}

成功拿到第二段flag,拼起来就是完整的flag。

[nodejs原型链污染及绕过]校赛第四次纳新赛 bypass WP的更多相关文章

  1. 【web安全】Nodejs原型链污染分析

    Nodejs原型链污染分析 什么是js原型? 可以将js原型理解为其他OOP语言中的类,但还是有细微区别. 1. function F(){...} 2. var f = new F(); 分析: 1 ...

  2. redpwnctf-web-blueprint-javascript 原型链污染学习总结

    前几天看了redpwn的一道web题,node.js的web,涉及知识点是javascript 原型链污染,以前没咋接触过js,并且这个洞貌似也比较新,因此记录一下学习过程 1.本机node.js环境 ...

  3. 原型链污染(Node.js污染,javasrcipt原型链污染的)

    学习链接: https://www.jianshu.com/p/6e623e9debe3 关于NJS  https://xz.aliyun.com/t/7184 相关题是 GYCTF  ez_expr ...

  4. javascript 原型链污染

    原理①javascript中构造函数就相当于类,并且可以将其实例化 ②javascript的每一个函数都有一个prototype属性,用来指向该构造函数的原型同样的javascript的每一个实例对象 ...

  5. 初探JavaScript原型链污染

    18年p师傅在知识星球出了一些代码审计题目,其中就有一道难度为hard的js题目(Thejs)为原型链污染攻击,而当时我因为太忙了(其实是太菜了,流下了没技术的泪水)并没有认真看过,后续在p师傅写出w ...

  6. js原型链污染详解

    前言 之前打某湖论剑,两道js的题,给我整懵逼了,发现以前都没对js做过多少研究,趁着被毒打了,先研究一波js原型链,未雨绸缪. 基础 protype 首先我们研究js原型链,得搞明白原型是什么,这里 ...

  7. JavaScript原型链及其污染

    JavaScript原型链及其污染 一.什么是原型链? 1.JavaScript中,我们如果要define一个类,需要以define"构造函数"的方式来define: functi ...

  8. Nodejs-原型链污染

    原型链污染 javascript 原型链 在javascript中,继承的整个过程就称为该类的原型链. 每个对象的都有一个指向他的原型(prototype)的内部链接,这个原型对象又有它自己的原型,一 ...

  9. js中的原型,原型链和继承

    在传统的基于Class的语言如Java.C++中,继承的本质是扩展一个已有的Class,并生成新的Subclass. 由于这类语言严格区分类和实例,继承实际上是类型的扩展.但是,JavaScript最 ...

  10. Javascript之其实我觉得原型链没有难的那么夸张!

    原型链.闭包.事件循环等,可以说是js中比较复杂的知识了,复杂的不是因为它的概念,而是因为它们本身都涉及到很多的知识体系.所以很难串联起来,有一个完整的思路.我最近想把js中有点意思的知识都总结整理一 ...

随机推荐

  1. 记一次QT的QSS多个控件设置同一个样式的问题

    文章目录 Qt样式表的格式问题 问题的引入 qss 选择器 问题所在 Reference Qt样式表的格式问题 问题的引入 最近在进行样式设计的时候,发现了一个问题,具体如下: 我是将所有样式写到.q ...

  2. tsconfig.json 报错问题解决

    tsconfig.json 报错问题解决 报错如图所示: 创建tsconfig.json配置文件时,VSCode会自动检测当前项目当中是否有ts文件,若没有则报错,提示用户需要创建一个ts文件后,再去 ...

  3. Escalate_Linux靶机提权学习

    靶机下载 https://www.vulnhub.com/entry/escalate_linux-1,323/ 用VMware打开 扫描端口 nmap -sS -sV -n -T4 -p- 192. ...

  4. Ubuntu截屏工具推荐

    Ubuntu截屏工具推荐 本篇博文推荐Ubuntu下的截屏工具Flameshot,可以作为Windows下Snipaste截图工具的平替. GitHub地址:https://github.com/fl ...

  5. [每日算法 - 华为机试] leetcode53 :最大子数组和 「算法中的哲学」

    入口 53. 最大子数组和https://leetcode.cn/problems/maximum-subarray/ 题目描述 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数 ...

  6. AI 应用思考

    之前看到过一个理论,创新技术的三个阶段:新技术创造-精英服务-平民化 技术扩散的三阶段理论模型 1. 创新垄断期(精英创造阶段)技术革命初期,创新活动高度依赖知识密集型投入.AI发展呈现"分 ...

  7. MySqlDataAdapter.Fill() 报异常‘给定关键字不在字典中’的解决方案

    MySqlDataAdapter.Fill() 报异常'给定关键字不在字典中'的解决方案 解决办法 升级依赖库 后来发现居然是MySql.Data.dll文件版本问题,我开始使用的是6.2.1.0版本 ...

  8. Golang高性能引擎:ZKmall开源商城支撑百万级日活交易流畅运行

    在电商业务高并发.低延迟的严苛场景下,技术栈的选择直接决定系统上限.ZKmall开源商城基于Golang技术生态,以协程级并发.毫秒级响应为核心优势,为百万级日活电商平台提供高性能解决方案.本文从架构 ...

  9. MQTT协议发布和订阅的实现,一步步带你实现发布订阅服务。

    MQTT协议 MQTT协议是基于TCP传输协议之上的应用层协议,全程Message Queuing Telemetry Transport.主要用于物联网设备间的通信,在低带宽.不稳定网络环境下的优势 ...

  10. public boolean add(E e)的源码分析

    public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess ...