欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

Go代码审计:Gitea远程命令执行漏洞链

来源:本站整理 作者:佚名 时间:2018-07-18 TAG: 我要投稿

这是一个非常漂亮的漏洞链,很久没见过了。我用docker来复现并学习这个漏洞,官方提供了docker镜像,vulhub也会上线这个环境。
漏洞一、逻辑错误导致权限绕过
这是本漏洞链的导火索,其出现在Git LFS的处理逻辑中。
Git LFS是Git为大文件设置的存储容器,我们可以理解为,他将真正的文件存储在git仓库外,而git仓库中只存储了这个文件的索引(一个哈希值)。这样,git objects和.git文件夹下其实是没有这个文件的,这个文件储存在git服务器上。gitea作为一个git服务器,也提供了LFS功能。
在 modules/lfs/server.go 文件中,PostHandler是POST请求的处理函数:

可见,其中间部分包含对权限的检查:
if !authenticate(ctx, repository, rv.Authorization, true) {
    requireAuth(ctx)}
在没有权限的情况下,仅执行了requireAuth函数:这个函数做了两件事,一是写入WWW-Authenticate头,二是设置状态码为401。也就是说,在没有权限的情况下,并没有停止执行PostHandler函数。
所以,这里存在一处权限绕过漏洞。
漏洞二、目录穿越漏洞
这个权限绕过漏洞导致的后果是,未授权的任意用户都可以为某个项目(后面都以vulhub/repo为例)创建一个Git LFS对象。
这个LFS对象可以通过http://example.com/vulhub/repo.git/info/lfs/objects/[oid]这样的接口来访问,比如下载、写入内容等。其中[oid]是LFS对象的ID,通常来说是一个哈希,但gitea中并没有限制这个ID允许包含的字符,这也是导致第二个漏洞的根本原因。
我们利用第一个漏洞,先发送一个数据包,创建一个Oid为……/../../etc/passwd的LFS对象:
POST /vulhub/repo.git/info/lfs/objects HTTP/1.1Host: your-ip:3000Accept-Encoding: gzip, deflateAccept: application/vnd.git-lfs+jsonAccept-Language: enUser-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)Connection: closeContent-Type: application/jsonContent-Length: 151{
    "Oid": "....../../../etc/passwd",
    "Size": 1000000,
    "User" : "a",
    "Password" : "a",
    "Repo" : "a",
    "Authorization" : "a"}
其中,vulhub/repo是一个公开的项目。
也就是说,这个漏洞的利用是有条件的,第一个条件就是需要有一个公开项目。为什么呢?虽然“创建LFS对象”接口有权限绕过漏洞,但是“读取这个对象所代表的文件”接口没有漏洞,会先检查你是否有权限访问这个LFS对象所在的项目。只有公开项目才有权限读取。
见下图,发送数据包后,虽然返回了401状态码,但实际上这个LFS对象已经创建成功,且其Oid为……/../../etc/passwd。

第二步,就是访问这个对象。访问方法就是GET请求http://example.com/vulhub/repo.git/info/lfs/objects/[oid]/sth,oid就是刚才指定的,这里要用url编码一下。
见下图,/etc/passwd已被成功读取:

那么,我们来看看为什么读取到了/etc/passwd文件。
代码 modules/lfs/content_store.go :

可见,meta.Oid被传入transformKey函数,这个函数里,将Oid转换成了key[0:2]/key[2:4]/key[4:]这样的形式,前两个、中间两个字符做为目录名,第四个字符以后的内容作为文件名。
那么,我创建的Oid为……/../../etc/passwd,在经过transformKey函数后就变成了../../../../../etc/passwd,s.BasePath是LFS对象的基础目录,二者拼接后自然就读取到了/etc/passwd文件。
这就是第二个漏洞:目录穿越。
漏洞三、读取配置文件,构造JWT密文
vulhub/repo虽然是一个公开项目,但默认只有读权限。我们需要进一步利用。
我们利用目录穿越漏洞,可以读取到gitea的配置文件。这个文件在$GITEA_CUSTOM/conf/app.ini,$GITEA_CUSTOM是gitea的根目录,默认是/var/lib/gitea/,在vulhub里是/data/gitea。
所以,要从LFS的目录跨越到$GITEA_CUSTOM/conf/app.ini,需要构造出的Oid是….gitea/conf/app.ini(经过转换后就变成了/data/gitea/lfs/../../gitea/conf/app.ini,也就是/data/gitea/conf/app.ini。原漏洞作者给出的POC这一块是有坑的,这个Oid需要根据不同$GITEA_CUSTOM的设置进行调整。)
成功读取到配置文件(仍需先发送POST包创建Oid为….gitea/conf/app.ini的LFS对象):

配置文件中有很多敏感信息,如数据库账号密码、一些Token等。如果是sqlite数据库,我们甚至能直接下载之。当然,密码加了salt。
Gitea中,LFS的接口是使用JWT认证,其加密密钥就是配置文件中的LFS_JWT_SECRET。所以,这里我们就可以用来构造JWT认证,进而获取LFS完整的读写权限。

[1] [2] [3]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载