cloudflare cdnjs中的任意代码执行漏洞

  • A+
所属分类:安全漏洞
cloudflare cdnjs中的任意代码执行漏洞点击上方蓝字关注我们


概述


cdnjs库更新服务器中存在任意代码执行漏洞,可导致cdnjs被完全破坏。一旦缓存过期,攻击者就可以利用该漏洞篡改互联网上所有使用cdnjs的网站。


CDNJS是Cloudflare旗下的JavaScript/CSS资料库,为数百万网站提供超过4000个JavaScript和CSS文件,在互联网上有12.7%的网站使用了CDNJS,是继Google Hosted Libraries之后第二个使用最广泛的JavaScript CDN。


初始调查


安全研究员RyotaK在浏览cdnjs网站时,发现以下描述:

cloudflare cdnjs中的任意代码执行漏洞


并发现库信息是在GitHub存储库中管理的,于是研究人员检查了cdnjs使用的GitHub Organization的存储库。结果发现,该存储库被用于以下几种方式:

  • cdnjs/packages: 存储cdnjs支持的库信息

  • cdnjs/cdnjs: 存储库文件

  • cdnjs/logs: 存储库的更新日

  • cdnjs/SRIs: 存储库的SRI

  • cdnjs/static-website:cdnjs.com 的源代码

  • cdnjs/origin-worker: 初始cdnjs.cloudflare.com的Cloudflare Worker

  • cdnjs/tools: cdnjs 管理工具

  • cdnjs/bot-ansible: cdnjs库更新服务器的Ansible存储库


从这些存储库中可以看出,大多数cdnjs的基础设施都集中在这个GitHub Organization中。其中,研究人员对cdnjs/bot-ansible和cdnjs/tools比较感兴趣,因为它可以自动更新库。


在浏览了这两个存储库的代码后,研究人员发现cdnjs/bot-ansible会定期执行cdnjs库更新服务器中cdnjs/tools的autoupdate命令,通过下载npm包/Git存储库来检查cdnjs/packages中库的更新。


自动更新调查

自动更新功能通过下载用户管理的Git存储库/npm包,并从中复制目标文件来更新库,且npm注册表会将每个库压缩成.tgz文件以使其可供下载。

由于这个自动更新工具是使用Go语言写的,因此研究人员推测其可能使用了Go的compress/gzip和archive/tar进行解压

Go语言的archive/tar返回文档中包含的文件名而没有进行过滤,因此如果根据从archive/tar返回的文件名,将压缩文件提取到磁盘中,包含../../../../../../tmp/test等文件名的压缩文档可能会覆盖系统上的任意文件。

根据cdnjs/bot-ansible中的信息,可以知道一些脚本正在定期运行,并且运行 autoupdate命令的用户对它们有写权限,所以研究人员专注于通过路径遍历覆盖文件。

cloudflare cdnjs中的任意代码执行漏洞


路径遍历


研究人员开始阅读autoupdate命令的主要函数,以寻找路径遍历:


func main() {        [...]      switch *pckg.Autoupdate.Source {    case "npm":      {        util.Debugf(ctx, "running npm update")        newVersionsToCommit, allVersions = updateNpm(ctx, pckg)      }    case "git":      {        util.Debugf(ctx, "running git update")        newVersionsToCommit, allVersions = updateGit(ctx, pckg)      }    [...]}


从以上代码片段可以看出,如果将npm指定为自动更新的源,它会将包信息传递给 updateNpm函数。


func updateNpm(ctx context.Context, pckg *packages.Package) ([]newVersionToCommit, []version) {    [...]    newVersionsToCommit = doUpdateNpm(ctx, pckg, newNpmVersions)        [...]}


然后,updateNpm将有关新库版本的信息传递给doUpdateNpm函数。


func doUpdateNpm(ctx context.Context, pckg *packages.Package, versions []npm.Version) []newVersionToCommit {    [...]  for _, version := range versions {        [...]    tarballDir := npm.DownloadTar(ctx, version.Tarball)    filesToCopy := pckg.NpmFilesFrom(tarballDir)        [...]}


并且,doUpdateNpm将新版本的.tgz文件的URL传递给npm.DownloadTar函数。


func DownloadTar(ctx context.Context, url string) string {  dest, err := ioutil.TempDir("", "npmtarball")  util.Check(err)
util.Debugf(ctx, "download %s in %s", url, dest)
resp, err := http.Get(url) util.Check(err)
defer resp.Body.Close()
util.Check(Untar(dest, resp.Body)) return dest}


最后,将使用http.Get获取的.tgz文件传递给Untar函数。


func Untar(dst string, r io.Reader) error {  gzr, err := gzip.NewReader(r)  if err != nil {    return err  }  defer gzr.Close()  tr := tar.NewReader(gzr)  for {    header, err := tr.Next()        [...]    // the target location where the dir/file should be created    target := filepath.Join(dst, removePackageDir(header.Name))        [...]    // check the file type    switch header.Typeflag {        [...]    // if it's a file create it    case tar.TypeReg:      {                [...]        f, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode))                [...]        // copy over contents        if _, err := io.Copy(f, tr); err != nil {          return err        }      }    }  }}


和研究人员预期的一样,解压缩函数中使用了compress/gzip和archive/tar来提取 .tgz 文件。起初,研究人员以为它正在清理removePackageDir函数中的路径,但是检查函数内容后,研究人员注意到它只是从路径中删除了package/。


从这些代码片段中,研究人员确认从发布到npm的.tgz文件执行路径遍历并覆盖服务器上定期执行的脚本后,可以执行任意代码。攻击过程如下所示:


  1. 将包含特制文件名的.tgz文件发布到npm

  2. 等待cdnjs库更新服务器处理特制的.tgz文件

  3. 特制的 .tgz 文件内容被写入定期执行的脚本文件,并执行任意代码。


cloudflare cdnjs中的任意代码执行漏洞

END



cloudflare cdnjs中的任意代码执行漏洞


好文!必须在看

本文始发于微信公众号(SecTr安全团队):cloudflare cdnjs中的任意代码执行漏洞

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: