Ruby on Rails 路径穿越与任意文件读取漏洞分析 -【CVE-2018-3760】
漏洞公告
该漏洞由安全研究人员 Orange Tsai发现。漏洞公告来自 https://groups.google.com/forum/#!topic/rubyonrails-security/ft_J--l55fM
影响面: development servers,且开启了 config.assets.compile
漏洞复现
本地安装好ruby和rails。以ruby 2.4.4 ,rails v5.0.7为例:
此时blog这个rails项目使用的sprockets版本是3.7.2(fixed)。修改blog目录下的Gemfile.lock第122行:
修改配置文件 config/environments/production.rb
:
在blog目录下执行
payload:
win平台:
linux平台
漏洞分析
注:为明白起见,许多分析直接写在代码注释部分,请留意。
问题出在sprockets
,它用来检查 JavaScript 文件的相互依赖关系,用以优化网页中引入的js文件,以避免加载不必要的js文件。当访问如http://127.0.0.1:3000/assets/foo.js
时,会进入server.rb:
forbidden_request
用来对path进行检查,是否包含..
以防止路径穿越,是否是绝对路径:
如果请求中包含..
即返回真,然后返回forbidden_response(env)信息。
回到call函数,进入find_asset(path, options)
,在 lib/ruby/gems/2.4.0/gems/sprockets-3.7.1/lib/sprockets/base.rb:63:
跟进load
,在 lib/ruby/gems/2.4.0/gems/sprockets-3.7.1/lib/sprockets/loader.rb:32 。以请求GET /assets/file:%2f%2f//C:/chybeta/blog/app/assets/config/%252e%252e%2f%252e%2e%2f%252e%2e%2f%252e%2e%2f%252e%2e%2f%252e%2e%2f%252e%2e%2fWindows/win.ini
为例,其一步步的解析过程见下注释:
跟入UnloadedAsset.new
跟入URIUtils.parse_asset_uri
主要是进行了两个检查:文件是否存在和是否在合规目录里。主要关注第二个检测。其中config[:paths]
是允许的路径,而unloaded.filename
是请求的路径文件名。跟入 lib/ruby/gems/2.4.0/gems/sprockets-3.7.2/lib/sprockets/path_utils.rb:120:
继续跟入split_subpath
, lib/ruby/gems/2.4.0/gems/sprockets-3.7.2/lib/sprockets/path_utils.rb:103。假设上面传入的path参数是``。
通过检查后,在load_from_unloaded
末尾即进行了读取等操作,从而通过路径穿越造成任意文件读取。
如果文件以.erb
结尾,则会直接执行:
补丁
在server.rb中,增加关键字过滤://
。