[LineCTF2022]gotm
题目给出了go的源码(不熟)
我们主要来看main.go的代码
有个Account结构体,主要四个属性
1 | type Account struct { |
有四个路由
1 | func main() { |
我们一个一个来审
我们先来看”/“路由
1 | func root_handler(w http.ResponseWriter, r *http.Request) { |
先获取Token,如果有Token则用jwt解密,如果解密成功则显示用户的id,如果没有token直接返回空白
然后审’/auth’
1 | uid := r.FormValue("id") |
获取用户传入的id和pw
1 | user_acc := get_account(uid) |
如果输入了正确的id和pw(get_account有匹配的正确结果),返回一个TokenResp的对象(json形式),里面存储了状态status,和jwt token,内容是id和是否为admin
1 | type TokenResp struct { |
然后我们审计“/flag”路由
1 | func flag_handler(w http.ResponseWriter, r *http.Request) { |
通过对传入的X-Token进行jwt解码,然后判断is_admin,如果为true就给flag
最后来看/regist路由
1 | func regist_handler(w http.ResponseWriter, r *http.Request) { |
路由中默认给is_admin为false,所以我们要想办法给is_admin为true
由于jwt编码过程中需要用到secret_key作签名密钥,secret_key是环境变量,就需要通过SSTI漏洞把secret_key
现在我们要利用go ssti注入获取key然后伪造jwt
https://forum.butian.net/share/1286
先说一下go的ssti,和jinja2的ssti类似,都是因为直接渲染拼接的字符导致插入了模板语言后执行
Go 语言内置了 text/template 和 html/template 两个模板库。如果开发人员没有正确使用这些库,可能会导致 SSTI 注入。例如,如果使用 text/template 处理用户输入,并且未对输入进行转义,攻击者可以插入恶意模板代码。
这里ssti漏洞产生的位置在
http.HandleFunc(“/“, root_handler)
1 | func root_handler(w http.ResponseWriter, r *http.Request) { |
常规思路可以注入{{.}}
或{{.secret_key}}
来读secret_key属性,但此处由于root_handler()
函数得到的acc是数组中的地址,也就是get_account函数通过在全局变量acc数组中查找我们的用户,这种情况下直接注入{{.secret_key}}
会返回空,所以此处只能用{{.}}
来返回全部属性
我们在/regist页面进行注册
1 | ?id={{.}}&pw=pass |
然后我们访问auth进行登录,得到token
我们再回到最开始的页面,将token值传入X-Token头部,成功读到secret_key
得到secret_key
1 | this_is_f4Ke_key |
我们修改jwt,将is_admin修改为true.
再到/flag页面,将修改后的jwt传入token中
得到flag