垃圾桶

EL PSY CONGROO.

Lz1y's avatar Lz1y

Gogs、gitea RCE

漏洞点

下载最新版本的master线的gogs,然后把 github.com/go-macaron/session/ 切到旧版本

0.11.68.1023

由于是session出问题,根据临时补丁

diff

定位到 vendor/github.com/go-macaron/session/session.go 的Read方法:

func (m *Manager) Read(sid string) (RawStore, error) {
    // No slashes or dots "./" should ever occur in the sid and to prevent session file forgery bug.
    // See https://github.com/gogs/gogs/issues/5469
    if strings.ContainsAny(sid, "./") {
        return nil, errors.New("invalid 'sid': " + sid)
    }
     return m.provider.Read(sid)
}

可以看到添加了一个字符黑名单,所以判断此处为漏洞利用点.深入研究漏洞发生处:

可以看到,首先调用了Start函数,从context中获取到了cookie,如果长度大于零,并且文件存在于服务器中,就直接读取session文件.


通过app.ini,可以获取到PROVIDER_CONFIG为相对路径data/sessions并且得知COOKIE_NAMEi_like_gogits,但是此处让我迷惑的是,默认开启的PROVIDER是memory模式,不知道为什么还会使用实体的文件存储session.可能是PROVIDER_CONFIG优先级大于PROVIDER?

接着进入m.provider.Read方法

而filepath函数内容为:

func (p *FileProvider) filepath(sid string) string {
    return path.Join(p.rootPath, string(sid[0]), string(sid[1]), sid)
}

是直接拼接rootPathsid[0]), string(sid[1]), sid字符.而sid是用户可控的,导致了漏洞的发生.

由于此处漏洞,我们可以任意的伪造User name.

我本地gogs管理员账号为test,生成fakesession,然后将其上传到服务器,再通过上面的漏洞读取改文件即可.

利用

可以看到cookie中的i_like_gogits为穿越目录的内容,并且admin路径可以直接请求,也就是过了session检查.

伪造任意用户登录后,即可使用git hook

成功执行touch /tmp/success

修复

回顾官方修复方案.

func (m *Manager) Read(sid string) (RawStore, error) {
    // No slashes or dots "./" should ever occur in the sid and to prevent session file forgery bug.
    // See https://github.com/gogs/gogs/issues/5469
    if strings.ContainsAny(sid, "./") {
        return nil, errors.New("invalid 'sid': " + sid)
    }

    return m.provider.Read(sid)
}

直接在session.Read这个漏洞利用点加了黑名单,而不是在漏洞根源file.Read添加过滤.所以当其他点调用m.provider.Read(sid)的时候还是存在漏洞.而作者修复方式也很暴力

直接将m.provider.Read()都换成了m.Read()方法.

尾声

而gitea使用了同一个三方库,所以漏洞也大同小异,不再啰嗦.而这个第三方库是修改beego中的session模块,这是不是意味着这个洞还有更多的惊喜等待挖掘呢.