rubygems.org远程命令执行漏洞分析 - 嘶吼 RoarTalk – 网络安全行业综合服务平台,4hou.com

rubygems.org远程命令执行漏洞分析

xiaohui 漏洞 2017-10-12 09:45:49
108896
收藏

导语:

1507713618957888.jpg

通过rubygems.org上的反序列化漏洞执行远程代码, 是 Ruby 社区的一个非常受欢迎的托管服务。不过目前该漏洞的补丁已经发布,请点此升级到最新的版本。这个漏洞已被官方命名为CVE-2017-0903,关于该漏洞的详细官方介绍请点此

如果你曾经编写过ruby应用程序,那么很可能你已经和rubygems.org进行过交互了。甚至你可能已经把该网站设置为信任,以允许它在你的计算机上运行任意程序,例如,当用gem命令安装rails时,gem程序就会从rubygems.org获取rails gem及其所有依赖项,并将所有内容安装到相应的位置,这样任何拥有账户的人都可以在后台发布gem命令了。

Rubygems.org本身就是一个rails应用程序,它有着清楚地信息披露条例。

远程命令执行漏洞分析

Ruby gems实际上只是tar文件,所以运行tar -xvf foo.gem通常会留给你三个文件:

metadata.gz
data.tar.gz
checksums.yaml.gz

这三个文件都是以.gz结尾,属于被压缩的文件。 metadata.gz包含一个YAML文件,包含有关gem的信息,如名称,作者,版本等。 data.tar.gz包含了另一个tar文件,该文件包含所有源代码。 checksums.yaml.gz包含一个YAML文件,其中包含gem命令的一些哈希加密。

不过我发现,解析不信任的YAML是危险的。原来,我一直认为它是一种类似JSON的良性交换格式,但事实上,YAML允许任意对象的编码,就像利用Python pickle可以实现任意代码执行。

当你将gem上传到rubygems.org时,应用程序将调用Gem::Package.new(body).spec。该方法所用的rubygems gem使用了不安全的YAML.load调用来加载gem中的YAML文件。

不过,rubygems.org的作者是知道该方法的安全隐患的,在2013年以前,开发者利用给内置对象扩展方法(Monkey Patching)修补了YAML和gem解析库,仅允许对白名单里的对象进行反序列化。到2015年则完全采用了Psych.safe_load。

不幸的是,monkey-patching的修复还是遗留了一些漏洞,因为它只修补了Gem::Specification#from_yaml方法。如果我来看看在调用到#spec时所发生的一些情况,我就会明白#verify的调用,下面是调用中的一些关键部分:

# ...
  @gem.with_read_io do |io|
    Gem::Package::TarReader.new io do |reader|
    read_checksums reader
    verify_files reader
    end
  end
  verify_checksums @digests, @checksums
# ...

然后,在#read_checksums中会发生以下进程:

# ...
  Gem.load_yaml
  @checksums = gem.seek 'checksums.yaml.gz' do |entry|
    Zlib::GzipReader.wrap entry do |gz_io|
      YAML.load gz_io.read # oops
    end
  end
# ...

现在,我就可以用我控制的输入调用YAML.load。最初,我试图在YAML.load调用时运行漏洞利用代码。但事实比我想得更复杂,虽然我可以反序列化任意对象,但其实对这些对象进行调用的方法却非常有限。是我可以对这些对象做出的唯一实际方法是非常有限的。 这时,就要在python上使用yaml解析库库,这可以让我多一些调用方法的选择,比如#[]=, #init_with,和#marshal_load(请注意不是Marshal.load)。但是对于大多数对象来说,这些方法并不会给攻击带来什么灵活性,因为他们通常的做法只是初始化几个变量并返回。在一些标准的rails库中存在一些危险的#[]=方法(如过去一样),但目前,我还没有找到一个能够攻击的对象。

于是,我又重新检查了rubygems.org应用程序,对其中的@checksums变量的作用进行重新评估,发现可以将其设置为任何类实例变量,在#verify_checksums中的情况如下:

# ...
  checksums.sort.each do |algorithm, gem_digests|
    gem_digests.sort.each do |file_name, gem_hexdigest|
      computed_digest = digests[algorithm][file_name]
# ...

如果我可以构建一个调用#sort的对象,那就可以实施一些攻击,触发漏洞。这样,我就有了以下的POC。实际得到评估的有效载荷包含在底层64位编码的DEFLATE压缩的编组部分,在本例中,它只是负责运行echo "oops"。

SHA1: !ruby/object:Gem::Package::TarReader
  io: !ruby/object:Gem::Package::TarReader::Entry
    closed: false
    header: 'foo'
    read: 0
    io: !ruby/object:ActiveSupport::Cache::MemoryStore
      options: {}
      monitor: !ruby/object:ActiveSupport::Cache::Strategy::LocalCache::LocalStore
        registry: {}
      key_access: {}
      data:
        '3': !ruby/object:ActiveSupport::Cache::Entry
          compressed: true
          value: !binary '
          eJx1jrsKAjEQRbeQNT4QwQ9Q8hlTRXGL7UTFemMysIGYCZNZ0b/XYsHK8nIO
          nDtRBGbvJDzxMuRMLABHzIzOSqD0G+jbVMQmhzfLwd4jnphebwUrE0ZAoJrz
          YQpLE0PCRKGCmSnsWr3p0PW000S56G5eQ91cv9oDpScPC8YyRIG18WOMmGD7
          /1X1AV+XPlQ='

可以看出,从最后一步才开始逆向进行#sort调用。

在底部,我有一个ActiveSupport::Cache::Entry对象。这个对象的重要之处在于,当#value方法被调用并且@compressed为true时,它将在攻击者提供的DEFLATE压缩的数据上调用Marshal.load。解组的对象的构造方式是这样的,只要调用其上的任何方法就可以执行攻击者的代码。该方法是我以前写的,工作原理请点击这里。不幸的是,我不能在实现代码执行时,只用YAML来反序列化这个对象,因为它几乎对所有的方法都进行了undef,包括允许我设置实例变量的方法。因此,在使用时,要对Marshal.load进行加载才可以。

我会利用ActiveSupport::Cache::MemoryStore对象在@data哈希中解组我的恶意对象。它的父类ActiveSupport::Cache::Store定义了一个在MemoryStore中调用#read_entry的#read方法,#read_entry基本上只是抓取@data中的条目并将其返回。

由于MemoryStore以反序列化后的数组或者序列化后的字节缓存(ByteBuffer)形式将代码块存储到内存中,所以对MemoryStore#read的调用来自对Gem::Package::TarReader::Entry#read的调用,而Gem::Package::TarReader::Entry#read本身是由Gem::Package::TarReader#each调用的。读取返回后,对返回的值调用#size,由于我的恶意解组对象未定义,所以这会导致我的有效载荷开始执行。

最后,因为Gem::Package::TarReader对可枚举性(enumerable)进行了指定,所以调用其#sort方法将会调用其#each方法,这样整个攻击链就被启动了。

总结

在本文中,我介绍了 YAML的强大功能,有时它也可以在表现力较弱但很安全的交换格式(如JSON)中使用。也许在将来,YAML.load可以被修改为将类的白名单作为可选参数,使复杂对象的反序列化成为选择性行为。其实,目前的YAML.load实际上应该被命名为类似YAML.unsafe_load这样的名称,这样用户就知道他们何时用YAML.safe_load了。 

  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论

 
本站4hou.com,所使用的字体和图片文字等素材部分来源于原作者或互联网共享平台。如使用任何字体和图片文字有侵犯其版权所有方的,嘶吼将配合联系原作者核实,并做出删除处理。
©2022 北京嘶吼文化传媒有限公司 京ICP备16063439号-1 本站由 提供云计算服务