Ruby on Rails 曝路径穿越与任意文件读取漏洞

释放双眼,带上耳机,听听看~!

文章转载开源中国

开发者 John Hawthorn 公开了 Ruby on Rails 上的一个路径穿越与任意文件读取漏洞

Ruby on Rails 曝路径穿越与任意文件读取漏洞

John 指出,Action View 中可能存在文件内容泄露漏洞。特制的 accept headers 并调用 render file,可以导致目标服务器上的任意文件被渲染,从而泄露文件内容。控制器中受影响的代码如上图所示。

漏洞分析

在控制器中通过

1
render file

形式来渲染应用之外的视图,因此在 actionview-5.2.1/lib/action_view/renderer/template_renderer.rb:22 中会根据 

1
options.key?(:file)

,调用

1
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

1
find_file

代码如下:

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

用于生成查找文件参数的

1
args_for_lookup

函数,最终返回时会把 payload 保存在

1
details[formats]

中:

Ruby on Rails 曝路径穿越与任意文件读取漏洞

它会执行位于 actionview-5.2.1/lib/action_view/path_set.rb 中的 

1
@view_paths.find_file

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

因为视图在应用之外,所以 outside_app equals == True,并调用 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

跳过

1
cached

部分,

1
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 后的值如下:
Ruby on Rails 曝路径穿越与任意文件读取漏洞

利用

1
../

与前缀组合造成路径穿越,利用最后的

1
{{

完成闭合,经过 File.expand_path 解析后组成的 query 如下:


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

最后

1
/etc/passwd

被当成模板文件进行渲染,造成了任意文件读取。

该漏洞已被 CVE 收录,编号 CVE-2019-5418、CVE-2019-5419,目前补丁已经跟进:https://github.com/rails/rails/commit/f4c70c2222180b8d9d924f00af0c7fd632e26715

禁止接受未注册的 mime types:Ruby on Rails 曝路径穿越与任意文件读取漏洞

详情查看漏洞报告:https://github.com/mpgn/CVE-2019-5418

给TA打赏
共{{data.count}}人
人已打赏
安全漏洞

SAP 开源 SCA 工具,扫描软件包依赖漏洞

2019-3-19 11:12:22

安全漏洞

NSA 的软件逆向工程框架 Ghidra 曝出漏洞

2019-3-23 11:12:22

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索