> For the complete documentation index, see [llms.txt](https://gitbook-88.gitbook.io/ctf-writeup/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://gitbook-88.gitbook.io/ctf-writeup/2021/2021-yang-cheng-bei/checkin_go.md).

# checkin\_go

开头是一个提交用户名、密码和MD5的登录框，这里的md5属于老生常谈的爆破不提，用户名需要admin登录，否则无法获得admin的cookie来进行一个金钱的修改。正解是在本地删掉用户认证和302跳转来获得一个admin的cookie进行一个32位的整型溢出。

当然由于go本身不支持session，这里的session是源自于gin，于是我查了一下资料，得知在gin框架中有多种session的存储方式，例如cookie-based或者redis-based等，其中基于Redis肯定是较为安全的一种存储，基于cookie虽然减轻了服务器的存储负担，但是显而易见的增加了不安全性，从这里可以大概猜测这里使用的存储方式是基于cookie类型的一个存储。这题在main.go中进行了设置：

```
	storage := cookie.NewStore(randomChar(16)) // 使用cookie-based存储类型
	r.Use(sessions.Sessions("o", storage)) // 设置o作为存储session的cookie
```

这里初始化之后直接进入sessions.go中的func Sessions，会基于name和store进行一个初始化。

```
func Sessions(name string, store Store) gin.HandlerFunc {
	return func(c *gin.Context) {
		s := &session{name, c.Request, store, nil, false, c.Writer}
		c.Set(DefaultKey, s)
		defer context.Clear(c.Request)
		c.Next()
	}
}
```

初始化后这里的session本身是没有存储意义的（没有存储uname），于是尝试提交uname=admin，删除其他waf，观察调用情况。

首先在gin.go的445行断点，观察这里的c.Keys是nil

```
	engine.handleHTTPRequest(c)
```

进入之后会对c进行一个处理，也就是一种set操作，到最后到c.Next()

![](https://1298837596-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUlxElCQcjylbSFsJycU3%2Fuploads%2FQCkBtwKVokLdvM6GsSY6%2F1.png?alt=media\&token=65b6d0b5-eb04-4c40-8bdb-845c639a5aad)

context.go在go中自带，这里的context.go是gin框架下的文件，进入Next函数，这里对c的index进行了一个自增操作，然后判断c.handlers的长度并一一执行，也就是会一一执行handlers中的所有函数，观察到第三个函数是session的处理，也就是框架刚开始的处理函数。

<figure><img src="https://1298837596-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUlxElCQcjylbSFsJycU3%2Fuploads%2FT1RSufQOW8wAFLcIeptg%2F1.png?alt=media&amp;token=366aac9c-4b03-45e1-88ed-dad71263cfee" alt=""><figcaption></figcaption></figure>

这里的name和store没有传入，于是获得了r最开始设置的name和store，也就是cookie-based的方式，最后进入set，设置了Keys

```
func (c *Context) Set(key string, value interface{}) {
	c.mu.Lock()
	if c.Keys == nil {
		c.Keys = make(map[string]interface{})
	}

	c.Keys[key] = value
	c.mu.Unlock()
}
```

到这里设置好了store后，到了也就是表单提交数据之后的处理，进入s.Set()后会对uname=admin进行处理，也就是`session.Values['uname']='admin'`

```
func (s *session) Set(key interface{}, val interface{}) {
	s.Session().Values[key] = val
	s.written = true
}
```

最后在s.Save()中调用http.SetCookie，返回set-cookie，实现对cookie的设置。

题目本身不难，主要还是对框架的分析花了比较久的时间，毕竟比较少做到Goweb，总体来说还是学到了不少东西的。
