Vulnerabilities > CVE-2014-0130 - Path Traversal vulnerability in multiple products
Attack vector
NETWORK Attack complexity
LOW Privileges required
NONE Confidentiality impact
HIGH Integrity impact
NONE Availability impact
NONE Summary
Directory traversal vulnerability in actionpack/lib/abstract_controller/base.rb in the implicit-render implementation in Ruby on Rails before 3.2.18, 4.0.x before 4.0.5, and 4.1.x before 4.1.1, when certain route globbing configurations are enabled, allows remote attackers to read arbitrary files via a crafted request.
Vulnerable Configurations
Common Weakness Enumeration (CWE)
Common Attack Pattern Enumeration and Classification (CAPEC)
- Relative Path Traversal An attacker exploits a weakness in input validation on the target by supplying a specially constructed path utilizing dot and slash characters for the purpose of obtaining access to arbitrary files or resources. An attacker modifies a known path on the target in order to reach material that is not available through intended channels. These attacks normally involve adding additional path separators (/ or \) and/or dots (.), or encodings thereof, in various combinations in order to reach parent directories or entirely separate trees of the target's directory structure.
- Directory Traversal An attacker with access to file system resources, either directly or via application logic, will use various file path specification or navigation mechanisms such as ".." in path strings and absolute paths to extend their range of access to inappropriate areas of the file system. The attacker attempts to either explore the file system for recon purposes or access directories and files that are intended to be restricted from their access. Exploring the file system can be achieved through constructing paths presented to directory listing programs, such as "ls" and 'dir', or through specially crafted programs that attempt to explore the file system. The attacker engaging in this type of activity is searching for information that can be used later in a more exploitive attack. Access to restricted directories or files can be achieved through modification of path references utilized by system applications.
- File System Function Injection, Content Based An attack of this type exploits the host's trust in executing remote content including binary files. The files are poisoned with a malicious payload (targeting the file systems accessible by the target software) by the attacker and may be passed through standard channels such as via email, and standard web content like PDF and multimedia files. The attacker exploits known vulnerabilities or handling routines in the target processes. Vulnerabilities of this type have been found in a wide variety of commercial applications from Microsoft Office to Adobe Acrobat and Apple Safari web browser. When the attacker knows the standard handling routines and can identify vulnerabilities and entry points they can be exploited by otherwise seemingly normal content. Once the attack is executed, the attackers' program can access relative directories such as C:\Program Files or other standard system directories to launch further attacks. In a worst case scenario, these programs are combined with other propagation logic and work as a virus.
- Using Slashes and URL Encoding Combined to Bypass Validation Logic This attack targets the encoding of the URL combined with the encoding of the slash characters. An attacker can take advantage of the multiple way of encoding an URL and abuse the interpretation of the URL. An URL may contain special character that need special syntax handling in order to be interpreted. Special characters are represented using a percentage character followed by two digits representing the octet code of the original character (%HEX-CODE). For instance US-ASCII space character would be represented with %20. This is often referred as escaped ending or percent-encoding. Since the server decodes the URL from the requests, it may restrict the access to some URL paths by validating and filtering out the URL requests it received. An attacker will try to craft an URL with a sequence of special characters which once interpreted by the server will be equivalent to a forbidden URL. It can be difficult to protect against this attack since the URL can contain other format of encoding such as UTF-8 encoding, Unicode-encoding, etc.
- Manipulating Input to File System Calls An attacker manipulates inputs to the target software which the target software passes to file system calls in the OS. The goal is to gain access to, and perhaps modify, areas of the file system that the target software did not intend to be accessible.
Nessus
NASL family SuSE Local Security Checks NASL id OPENSUSE-2014-396.NASL description - fix CVE-2014-0130: rubygem-actionpack: directory traversal issue (bnc#876714) CVE-2014-0130.patch: contains the fix last seen 2020-06-05 modified 2014-06-13 plugin id 75374 published 2014-06-13 reporter This script is Copyright (C) 2014-2020 and is owned by Tenable, Inc. or an Affiliate thereof. source https://www.tenable.com/plugins/nessus/75374 title openSUSE Security Update : rubygem-actionpack-3_2 (openSUSE-SU-2014:0720-1) code #%NASL_MIN_LEVEL 80502 # # (C) Tenable Network Security, Inc. # # The descriptive text and package checks in this plugin were # extracted from openSUSE Security Update openSUSE-2014-396. # # The text description of this plugin is (C) SUSE LLC. # include("compat.inc"); if (description) { script_id(75374); script_version("1.4"); script_set_attribute(attribute:"plugin_modification_date", value:"2020/06/04"); script_cve_id("CVE-2014-0130"); script_bugtraq_id(67244); script_name(english:"openSUSE Security Update : rubygem-actionpack-3_2 (openSUSE-SU-2014:0720-1)"); script_summary(english:"Check for the openSUSE-2014-396 patch"); script_set_attribute( attribute:"synopsis", value:"The remote openSUSE host is missing a security update." ); script_set_attribute( attribute:"description", value: " - fix CVE-2014-0130: rubygem-actionpack: directory traversal issue (bnc#876714) CVE-2014-0130.patch: contains the fix" ); script_set_attribute( attribute:"see_also", value:"https://bugzilla.novell.com/show_bug.cgi?id=876714" ); script_set_attribute( attribute:"see_also", value:"https://lists.opensuse.org/opensuse-updates/2014-05/msg00080.html" ); script_set_attribute( attribute:"solution", value:"Update the affected rubygem-actionpack-3_2 package." ); script_set_cvss_base_vector("CVSS2#AV:N/AC:M/Au:N/C:P/I:N/A:N"); script_set_cvss_temporal_vector("CVSS2#E:U/RL:OF/RC:C"); script_set_attribute(attribute:"exploitability_ease", value:"No known exploits are available"); script_set_attribute(attribute:"exploit_available", value:"false"); script_set_attribute(attribute:"plugin_type", value:"local"); script_set_attribute(attribute:"cpe", value:"p-cpe:/a:novell:opensuse:rubygem-actionpack-3_2"); script_set_attribute(attribute:"cpe", value:"cpe:/o:novell:opensuse:12.3"); script_set_attribute(attribute:"patch_publication_date", value:"2014/05/20"); script_set_attribute(attribute:"plugin_publication_date", value:"2014/06/13"); script_end_attributes(); script_category(ACT_GATHER_INFO); script_copyright(english:"This script is Copyright (C) 2014-2020 and is owned by Tenable, Inc. or an Affiliate thereof."); script_family(english:"SuSE Local Security Checks"); script_dependencies("ssh_get_info.nasl"); script_require_keys("Host/local_checks_enabled", "Host/SuSE/release", "Host/SuSE/rpm-list", "Host/cpu"); exit(0); } include("audit.inc"); include("global_settings.inc"); include("rpm.inc"); if (!get_kb_item("Host/local_checks_enabled")) audit(AUDIT_LOCAL_CHECKS_NOT_ENABLED); release = get_kb_item("Host/SuSE/release"); if (isnull(release) || release =~ "^(SLED|SLES)") audit(AUDIT_OS_NOT, "openSUSE"); if (release !~ "^(SUSE12\.3)$") audit(AUDIT_OS_RELEASE_NOT, "openSUSE", "12.3", release); if (!get_kb_item("Host/SuSE/rpm-list")) audit(AUDIT_PACKAGE_LIST_MISSING); ourarch = get_kb_item("Host/cpu"); if (!ourarch) audit(AUDIT_UNKNOWN_ARCH); if (ourarch !~ "^(i586|i686|x86_64)$") audit(AUDIT_ARCH_NOT, "i586 / i686 / x86_64", ourarch); flag = 0; if ( rpm_check(release:"SUSE12.3", reference:"rubygem-actionpack-3_2-3.2.12-1.28.1") ) flag++; if (flag) { if (report_verbosity > 0) security_warning(port:0, extra:rpm_report_get()); else security_warning(0); exit(0); } else { tested = pkg_tests_get(); if (tested) audit(AUDIT_PACKAGE_NOT_AFFECTED, tested); else audit(AUDIT_PACKAGE_NOT_INSTALLED, "rubygem-actionpack-3_2"); }
NASL family Debian Local Security Checks NASL id DEBIAN_DSA-2929.NASL description Several vulnerabilities were discovered in Action Pack, a component of Ruby on Rails. - CVE-2014-0081 actionview/lib/action_view/helpers/number_helper.rb contains multiple cross-site scripting vulnerabilities - CVE-2014-0082 actionpack/lib/action_view/template/text.rb performs symbol interning on MIME type strings, allowing remote denial-of-service attacks via increased memory consumption. - CVE-2014-0130 A directory traversal vulnerability in actionpack/lib/abstract_controller/base.rb allows remote attackers to read arbitrary files. last seen 2020-03-17 modified 2014-05-19 plugin id 74043 published 2014-05-19 reporter This script is Copyright (C) 2014-2020 and is owned by Tenable, Inc. or an Affiliate thereof. source https://www.tenable.com/plugins/nessus/74043 title Debian DSA-2929-1 : ruby-actionpack-3.2 - security update code #%NASL_MIN_LEVEL 80502 # # (C) Tenable Network Security, Inc. # # The descriptive text and package checks in this plugin were # extracted from Debian Security Advisory DSA-2929. The text # itself is copyright (C) Software in the Public Interest, Inc. # include("compat.inc"); if (description) { script_id(74043); script_version("1.7"); script_set_attribute(attribute:"plugin_modification_date", value:"2020/03/12"); script_cve_id("CVE-2014-0081", "CVE-2014-0082", "CVE-2014-0130"); script_bugtraq_id(65604, 65647, 67244); script_xref(name:"DSA", value:"2929"); script_name(english:"Debian DSA-2929-1 : ruby-actionpack-3.2 - security update"); script_summary(english:"Checks dpkg output for the updated package"); script_set_attribute( attribute:"synopsis", value:"The remote Debian host is missing a security-related update." ); script_set_attribute( attribute:"description", value: "Several vulnerabilities were discovered in Action Pack, a component of Ruby on Rails. - CVE-2014-0081 actionview/lib/action_view/helpers/number_helper.rb contains multiple cross-site scripting vulnerabilities - CVE-2014-0082 actionpack/lib/action_view/template/text.rb performs symbol interning on MIME type strings, allowing remote denial-of-service attacks via increased memory consumption. - CVE-2014-0130 A directory traversal vulnerability in actionpack/lib/abstract_controller/base.rb allows remote attackers to read arbitrary files." ); script_set_attribute( attribute:"see_also", value:"https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=747382" ); script_set_attribute( attribute:"see_also", value:"https://security-tracker.debian.org/tracker/CVE-2014-0081" ); script_set_attribute( attribute:"see_also", value:"https://security-tracker.debian.org/tracker/CVE-2014-0082" ); script_set_attribute( attribute:"see_also", value:"https://security-tracker.debian.org/tracker/CVE-2014-0130" ); script_set_attribute( attribute:"see_also", value:"https://packages.debian.org/source/wheezy/ruby-actionpack-3.2" ); script_set_attribute( attribute:"see_also", value:"https://www.debian.org/security/2014/dsa-2929" ); script_set_attribute( attribute:"solution", value: "Upgrade the ruby-actionpack-3.2 packages. For the stable distribution (wheezy), these problems have been fixed in version 3.2.6-6+deb7u2." ); script_set_cvss_base_vector("CVSS2#AV:N/AC:L/Au:N/C:N/I:N/A:P"); script_set_cvss_temporal_vector("CVSS2#E:U/RL:OF/RC:C"); script_set_attribute(attribute:"exploitability_ease", value:"No known exploits are available"); script_set_attribute(attribute:"exploit_available", value:"false"); script_set_attribute(attribute:"plugin_type", value:"local"); script_set_attribute(attribute:"cpe", value:"p-cpe:/a:debian:debian_linux:ruby-actionpack-3.2"); script_set_attribute(attribute:"cpe", value:"cpe:/o:debian:debian_linux:7.0"); script_set_attribute(attribute:"patch_publication_date", value:"2014/05/16"); script_set_attribute(attribute:"plugin_publication_date", value:"2014/05/19"); script_end_attributes(); script_category(ACT_GATHER_INFO); script_copyright(english:"This script is Copyright (C) 2014-2020 and is owned by Tenable, Inc. or an Affiliate thereof."); script_family(english:"Debian Local Security Checks"); script_dependencies("ssh_get_info.nasl"); script_require_keys("Host/local_checks_enabled", "Host/Debian/release", "Host/Debian/dpkg-l"); exit(0); } include("audit.inc"); include("debian_package.inc"); if (!get_kb_item("Host/local_checks_enabled")) audit(AUDIT_LOCAL_CHECKS_NOT_ENABLED); if (!get_kb_item("Host/Debian/release")) audit(AUDIT_OS_NOT, "Debian"); if (!get_kb_item("Host/Debian/dpkg-l")) audit(AUDIT_PACKAGE_LIST_MISSING); flag = 0; if (deb_check(release:"7.0", prefix:"ruby-actionpack-3.2", reference:"3.2.6-6+deb7u2")) flag++; if (flag) { if (report_verbosity > 0) security_warning(port:0, extra:deb_report_get()); else security_warning(0); exit(0); } else audit(AUDIT_HOST_NOT, "affected");
NASL family SuSE Local Security Checks NASL id OPENSUSE-2014-397.NASL description - fix CVE-2014-0130: rubygem-actionpack: directory traversal issue (bnc#876714) CVE-2014-0130.patch: contains the fix last seen 2020-06-05 modified 2014-06-13 plugin id 75375 published 2014-06-13 reporter This script is Copyright (C) 2014-2020 and is owned by Tenable, Inc. or an Affiliate thereof. source https://www.tenable.com/plugins/nessus/75375 title openSUSE Security Update : rubygem-actionpack-3_2 (openSUSE-SU-2014:0718-1) NASL family Fedora Local Security Checks NASL id FEDORA_2014-6098.NASL description Fix for CVE-2014-0130 - Avoid directory traversal Note that Tenable Network Security has extracted the preceding description block directly from the Fedora security advisory. Tenable has attempted to automatically clean and format it as much as possible without introducing additional issues. last seen 2020-03-17 modified 2014-05-25 plugin id 74166 published 2014-05-25 reporter This script is Copyright (C) 2014-2020 and is owned by Tenable, Inc. or an Affiliate thereof. source https://www.tenable.com/plugins/nessus/74166 title Fedora 20 : rubygem-actionpack-4.0.0-4.fc20 (2014-6098) NASL family Red Hat Local Security Checks NASL id REDHAT-RHSA-2014-1863.NASL description Updated Subscription Asset Manager 1.4 packages that fix multiple security issues are now available. Red Hat Product Security has rated this update as having Important security impact. Common Vulnerability Scoring System (CVSS) base scores, which give detailed severity ratings, are available for each vulnerability from the CVE links in the References section. Red Hat Subscription Asset Manager acts as a proxy for handling subscription information and software updates on client machines. Red Hat Subscription Asset Manager is built on Ruby on Rails, a model-view-controller (MVC) framework for web application development. Action Pack implements the controller and the view components. A directory traversal flaw was found in the way Ruby on Rails handled wildcard segments in routes with implicit rendering. A remote attacker could use this flaw to retrieve arbitrary local files accessible to a Ruby on Rails application using the aforementioned routes via a specially crafted request. (CVE-2014-0130) A flaw was found in the way Ruby on Rails handled hashes in certain queries. A remote attacker could use this flaw to perform a denial of service (resource consumption) attack by sending specially crafted queries that would result in the creation of Ruby symbols, which were never garbage collected. (CVE-2013-1854) Two cross-site scripting (XSS) flaws were found in Action Pack. A remote attacker could use these flaws to conduct XSS attacks against users of an application using Action Pack. (CVE-2013-1855, CVE-2013-1857) It was discovered that the internationalization component of Ruby on Rails could, under certain circumstances, return a fallback HTML string that contained user input. A remote attacker could possibly use this flaw to perform a reflective cross-site scripting (XSS) attack by providing a specially crafted input to an application using the aforementioned component. (CVE-2013-4491) A denial of service flaw was found in the header handling component of Action View. A remote attacker could send strings in specially crafted headers that would be cached indefinitely, which would result in all available system memory eventually being consumed. (CVE-2013-6414) It was found that the number_to_currency Action View helper did not properly escape the unit parameter. An attacker could use this flaw to perform a cross-site scripting (XSS) attack on an application that uses data submitted by a user in the unit parameter. (CVE-2013-6415) Red Hat would like to thank Ruby on Rails upstream for reporting these issues. Upstream acknowledges Ben Murphy as the original reporter of CVE-2013-1854, Charlie Somerville as the original reporter of CVE-2013-1855, Alan Jenkins as the original reporter of CVE-2013-1857, Peter McLarnan as the original reporter of CVE-2013-4491, Toby Hsieh as the original reporter of CVE-2013-6414, and Ankit Gupta as the original reporter of CVE-2013-6415. All Subscription Asset Manager users are advised to upgrade to these updated packages, which contain backported patches to correct these issues. last seen 2020-06-01 modified 2020-06-02 plugin id 79326 published 2014-11-19 reporter This script is Copyright (C) 2014-2019 and is owned by Tenable, Inc. or an Affiliate thereof. source https://www.tenable.com/plugins/nessus/79326 title RHEL 6 : Subscription Asset Manager (RHSA-2014:1863) NASL family Fedora Local Security Checks NASL id FEDORA_2014-6127.NASL description Fix for CVE-2014-0130 - Avoid directory traversal Note that Tenable Network Security has extracted the preceding description block directly from the Fedora security advisory. Tenable has attempted to automatically clean and format it as much as possible without introducing additional issues. last seen 2020-03-17 modified 2014-05-25 plugin id 74167 published 2014-05-25 reporter This script is Copyright (C) 2014-2020 and is owned by Tenable, Inc. or an Affiliate thereof. source https://www.tenable.com/plugins/nessus/74167 title Fedora 19 : rubygem-actionpack-3.2.13-6.fc19 (2014-6127)
Redhat
advisories |
| ||||
rpms |
|
Seebug
bulletinFamily exploit description 如果你的应用程序使用的动态模版路径 (例如: `render params[:id]`) 那么你的程序将会存在远程代码执行和本地文件包含漏洞. 请把你的 Rails 升级到最新版本, 或者重构你的 `controllers`。 我们将展示如何在特定环境下使用代码执行和本地包含漏洞去攻击 Ruby on Rails 。 Rails的控制器有包含指定渲染文件的功能,举个例子, 当我们调用 show 方法的时候,如果没有定义其他渲染方法,该框架将会隐藏渲染 `show.html.erb` 文件。 > 在绝大多数情况下,开发者会输出不同的格式,例如:文本, JSON, XML 或者其他任何格式,或者查看一个文件, 在这种情况下, 就会使用一个可以动态渲染的模版语言,例如 ERB, HAML, 或者其他的什么. 但是有几种方法可以修改他们展示的内容, 对我们来说,我们只要盯着渲染的方法就好了. The Rails 的文档定义了几种渲染模版和定义内容的方法 , 包括指定模版的路径的 `file:` 参数。 如果你已经阅读过[解决方法的文档](http://guides.rubyonrails.org/layouts_and_rendering.html),但是不确定你需不需要这样的功能——实际上并不止你一个人存在这样的疑惑。那么先让我们看看下面这段代码: ``` def show render params[:template] end ``` 这个代码看起来似乎很简单,但是谁也想不到一个控制器只是为了渲染模版, 他定义了一个 `template` 参数. 但是他没有被过滤过, 然后 Rails 就会去找指定的模版. , 但是这个模版在哪呢?是 views 目录,还是根目录,又或者是其他目录? 难道他是期待一个模板文件名,或者是一个特殊后缀的文件名 ,还是说一个完整的路径? 带着这些未知的问题继续探索下去。 <br> ### 问题解答 **动态渲染机制是用一个函数解决大量问题的最好的例子。这也就是他的问题所在。** 让我们假设渲染机制是从 `app/views/user/#{params[:template]}` 路径读取文件 – 这似乎是一个合理的想法. 如果我们把 template 参数的值设置为 dashboard ,他将加载 `app/views/user/dashboard.{ext}`, .ext 是一个在白名单里的后缀名 (如 .html, .haml, .html.erb, etc.) ![](https://images.seebug.org/1453869000947) 那让我们现在想想,如果把 template 的值设置为: `../admin/dashboard`. 他将会返回什么样的结果给我们呢? 这可能比较难知道, 但是我们经过尝试时候,他提示我们缺少模版。 ![](https://images.seebug.org/1453869010659) 通过分析错误提示,可是看出他试图从 `RAILS_ROOT/app/views`, `RAILS_ROOT` 和系统根目录去寻找文件. 这有点让人蛋疼, 因为他为什么要从系统的根目录去寻找我们需要的模版文件呢? > 通过黑客的本能反应,我把参数的内容设置为 `/etc/passwd` , 并且我们确实读取到了 `passwd` 文件. 这是一个重大的发现. ![](https://images.seebug.org/1453869016778) 既然我们能够读取 `passwd` 文件, 那么我们是不是也能读取应用程序的源码和配置文件呢, 让我们把参数设置为 `config/initializers/secrettoken.rb` 看看。 ![](https://images.seebug.org/1453869023678) > 别忘了是为什么造成了这样的漏洞,是因为你选择了动态设置模版路径导致的。 ``` def show render params[:template] end ``` > 这只是一段片段并且简单的代码,就能造成这样的漏洞,我相信有不少开发者会这么写,但是这还不是最糟糕的问题。 通过 Jeff Jarmoc 的一篇论文 "[The Anatomy of a Rails Vulnerability – CVE-2014-0130: From Directory Traversal to Shell,](http://matasano.com/research/AnatomyOfRailsVuln-CVE-2014-0130.pdf)" 我们得知,可以通过这样的漏洞获取一个远程代码执行. Jeff 的论文介绍了一个在某些版本的 Rails 拥有一个相似的缺陷, Rail’s implicit 渲染机制允许目录遍历, 或者更准确的说, **本地文件包含**, 这是一个因为开发者导致的漏洞. > 在深入挖掘这个漏洞之前我们先思考下,我们现在拥有的是**本地包含**,而不是目录遍历. 不过我们拥有的一个优势就是, 我们可以**加载可执行文件 (ERB)**. 传统意义上来说目录遍历只能返回一些不可执行的文件内容, 比如说 CSV 文件. 所以从本质上来说, 我们不仅可以读取程序的源代码, 还可以读取系统文件, 而且我们还能执行 ruby 代码,是不是屌屌的. 因为我们可以执行 ruby 代码, 所以我们拥有与 web server 同级别的权限去执行系统命令. 从文件包含到代码执行,我们需要采用一种叫日志污染的手法, 会将当前环境的每一个请求,包括参数都会写入日志文件 (比如说 `development.log`). 尽管是纯文本文件,只要是日志,都可以被包含进 ruby 代码. 通过使用有效的 ruby 代码作为参数发起一个请求便可以完成上述过程。 在下面的例子中我们向 web 程序发起一个合法的请求,通过 fake 参数传入一个URL编码的`<%= `ls` %>`。 ![](https://images.seebug.org/1453869034398) 通过对日志文件的审计,我们可以看到日志中存在这么一条 url decode 后的参数条目,这是一个有效的 ruby 代码,当 web 应用渲染了该日志文件,代码就会被执行。 ![](https://images.seebug.org/1453869040890) 然后我们就可以用 ruby 的文件包含漏洞,将包含刚才的请求的日志包含尽量,刚刚的参数就会执行。 ![](https://images.seebug.org/1453869046882) 当请求返回后,我们可以看到,原来的 fake 参数的值已经被 `ls` 命令的值替代。通过如上的方法也可以执行其他的命令了。 <br> ### 结论 如果不去深入地挖掘细节或者积极地尝试 exploit,Rails 的渲染机制将是很神秘很难理解的。很遗憾,Rails 的参考文档在这方面并没有多大帮助。 和 CVE-2014-0130 类似, 使用动态模板渲染造成了目录遍历和代码执行。我已经不止一次地在很多开源 Rails 项目中看到过存在这种漏洞了。如果你还没有读过 Jeff Jarmoc 的那篇论文,我建议最好先阅读一下,这篇文章深入地挖掘了与 CVE-2014-0130 相关的漏洞和危害评估。 这是我写的可以探测和利用本文所述漏洞的 msf module: : https://gist.github.com/forced-request/5158759a6418e6376afb ![](https://images.seebug.org/1453869060160) > 以上中文翻译来自于:https://www.92aq.com/2016/01/27/ruby-on-rails-%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C.html > 英文原文地址:https://nvisium.com/blog/2016/01/26/rails-dynamic-render-to-rce-cve-2016-0752/ <br> ### 时间线 * 2015年2月1日 漏洞被发现 * 2015年2月10日 Rails team 决定修复该漏洞 * 2015年7月13日 漏洞在未公开情况下得到证实(距第一次报告该漏洞已经有 5 个月时间) * 2016年1月25日 针对该漏洞的补丁正式发布,并且该漏洞被 CVE 收录(近 5 个月才证实该漏洞,将近 1 年才修复该漏洞) * 2016年1月27日 Seebug 收录该漏洞 <br/> ### 漏洞证明 **漏洞应用** 测试环境:Rails-4.1.5 (Ruby-2.1.5) 测试系统:Kali Linux 2.0 创建 Rails 应用: ``` rails new cve-2016-0752 cd cve-2016-0752 ``` 使用自带命令创建控制器`vuln`路由`index`,并修改其路由默认处理代码: ``` rails generate controller vuln index ``` 修改`app/controllers/vuln_controller.rb`中`index`函数代码为: ``` class VulnController < ApplicationController def index render params[:q] end end ``` 启动应用访问 `http://192.168.199.205:3000/vuln/index?q=/etc/passwd` 时,代码会将 `/etc/passwd` 做为模版相对使用函数 render 进行渲染,而 render 函数在寻找模版文件时默认包含了系统根路径,在应用默认的模版存储路径中无法找到 `/etc/passwd` 时回去寻找 `//etc/passwd`,这时如果能够访问到 `//etc/passwd` 文件,应用会将其文件内容作为模版进行渲染: ![](https://images.seebug.org/1453880682821) **配合访问日志执行命令** Rails应用文件log/development.log存储的是用户访问日志,根据2.1现在已经能控制渲染的模板文件路径,借助访问日志就可以控制渲染模版的内容。借助Rails的模板引擎,在模板内容中插入模板元素<%= `ifconfig` %>,表示将 ifconfig 系统命令的结果作为渲染内容进行返回。 访问http://192.168.199.205:3000/vuln/index?q=<%25=%20`ifconfig`%20%25>,会在log/development.log中留下记录: ![](https://images.seebug.org/1453880658435) 这时通过控制模版文件渲染为log/development.log,即可将目标主机的网络信息通过页面结果返回,http://192.168.199.205:3000/vuln/index?q=../../log/development.log: ![](https://images.seebug.org/1453880644666) ### 漏洞影响 从 zoomeye.org 上搜索使用了 Rails 框架的站点: ![](https://images.seebug.org/1453880609880) 全球大约有**12w**个使用了Rails的站点**可能**受到该漏洞的影响。 同时也可以在 Github 上搜索 `render params` 来查看潜在受到影响的 项目: ![](https://images.seebug.org/1453882149584) 可以看到也有大量的项目符合这样的代码写法,可能受到该漏洞的影响。 id SSV:90633 last seen 2017-11-19 modified 2016-01-27 published 2016-01-27 reporter Root source https://www.seebug.org/vuldb/ssvid-90633 title Rails Dynamic Render 远程命令执行漏洞 (CVE-2016-0752) bulletinFamily exploit description Impact ------ The implicit render functionality allows controllers to render a template, even if there is no explicit action with the corresponding name. This module does not perform adequate input sanitization which could allow an attacker to use a specially crafted request to retrieve arbitrary files from the rails application server. In order to be vulnerable an application must specifically use globbing routes[1] in combination with the :action parameter. The purpose of the route globbing feature is to allow parameters to contain characters which would otherwise be regarded as separators, for example '/' and '.'. As these characters have semantic meaning within template filenames, it is highly unlikely that applications are deliberately combining these functions. To determine if you are vulnerable, search your application's routes files for '*action' and if you find any, use one of the work arounds below. Releases -------- The 4.1.1, 4.0.5 and 3.2.18 releases are available at the normal locations. Workarounds ----------- The simplest workaround is to simply not use globbing matches for the :action parameter. As action methods cannot contain a '/' character, the simple matching should be sufficient. So replace `get 'my_url/*action', controller: 'asdf'` with ` get 'my_url/:action', controller: 'asdf'` If your application depends on this functionality, you will need to rename the route parameter and add an explicit action: get 'my_url/*template_path', controller: 'asdf', action: 'display' Then add an action which renders explicitly: ``` def display if !params[:template_path].index('.') render file: params[:template_path] end end ``` Note: The path check in this example may not be suitable for your application, take care Patches ------- To aid users who aren't able to upgrade immediately we have provided patches for the two supported release series. They are in git-am format and consist of a single changeset. * 4-1-directory_traversal.patch - Patch for 4.1 series * 4-0-directory_traversal.patch - Patch for 4.0 series * 3-2-directory_traversal.patch - Patch for 3.2 series Please note that only the 4.1.x, 4.0.x and 3.2.x series are supported at present. Users of earlier unsupported releases are advised to upgrade as soon as possible as we cannot guarantee the continued availability of security fixes for unsupported releases. Credits ------- Thanks to Ville Lautanala of Flowdock for reporting the vulnerability to us, and working with us on a fix. [1] http://guides.rubyonrails.org/routing.html#route-globbing-and-wildcard-segments [ CONTENT OF TYPE text/html SKIPPED ] >From 0f3b7d1a319383f743f9938e1eed00f0fba7a367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= <[email protected]> Date: Thu, 17 Apr 2014 16:50:39 -0300 Subject: [PATCH] Only accept actions without File::SEPARATOR in the name. This will avoid directory traversal in implicit render. Fixes: CVE-2014-0130 --- ``` actionpack/lib/abstract_controller/base.rb | 28 +++++++++++++++++++--- .../new_base/render_implicit_action_test.rb | 17 ++++++++++++- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb index fd6a46f..2541125 100644 --- a/actionpack/lib/abstract_controller/base.rb +++ b/actionpack/lib/abstract_controller/base.rb @@ -112,7 +112,7 @@ module AbstractController def process(action, *args) @_action_name = action_name = action.to_s - unless action_name = method_for_action(action_name) + unless action_name = _find_action_name(action_name) raise ActionNotFound, "The action '#{action}' could not be found for #{self.class.name}" end @@ -138,7 +138,7 @@ module AbstractController # available action consider actions that are also available # through other means, for example, implicit render ones. def available_action?(action_name) - method_for_action(action_name).present? + _find_action_name(action_name).present? end private @@ -182,6 +182,23 @@ module AbstractController end # Takes an action name and returns the name of the method that will + # handle the action. + # + # It checks if the action name is valid and returns false otherwise. + # + # See method_for_action for more information. + # + # ==== Parameters + # * <tt>action_name</tt> - An action name to find a method name for + # + # ==== Returns + # * <tt>string</tt> - The name of the method that handles the action + # * false - No valid method name could be found. Raise ActionNotFound. + def _find_action_name(action_name) + _valid_action_name?(action_name) && method_for_action(action_name) + end + + # Takes an action name and returns the name of the method that will # handle the action. In normal cases, this method returns the same # name as it receives. By default, if #method_for_action receives # a name that is not an action, it will look for an #action_missing @@ -203,11 +220,16 @@ module AbstractController # # ==== Returns # * <tt>string</tt> - The name of the method that handles the action - # * <tt>nil</tt> - No method name could be found. Raise ActionNotFound. + # * <tt>nil</tt> - No method name could be found. def method_for_action(action_name) if action_method?(action_name) then action_name elsif respond_to?(:action_missing, true) then "_handle_action_missing" end end + + # Checks if the action name is valid and returns false otherwise. + def _valid_action_name?(action_name) + action_name.to_s !~ Regexp.new(File::SEPARATOR) + end end end ``` ``` diff --git a/actionpack/test/controller/new_base/render_implicit_action_test.rb b/actionpack/test/controller/new_base/render_implicit_action_test.rb index 1e2191d..5b4885f 100644 --- a/actionpack/test/controller/new_base/render_implicit_action_test.rb +++ b/actionpack/test/controller/new_base/render_implicit_action_test.rb @@ -6,7 +6,7 @@ module RenderImplicitAction "render_implicit_action/simple/hello_world.html.erb" => "Hello world!", "render_implicit_action/simple/hyphen-ated.html.erb" => "Hello hyphen-ated!", "render_implicit_action/simple/not_implemented.html.erb" => "Not Implemented" - )] + ), ActionView::FileSystemResolver.new(File.expand_path('../../../controller', __FILE__))] def hello_world() end end @@ -33,10 +33,25 @@ module RenderImplicitAction assert_status 200 end + test "render does not traverse the file system" do + assert_raises(AbstractController::ActionNotFound) do + action_name = %w(.. .. fixtures shared).join(File::SEPARATOR) + SimpleController.action(action_name).call(Rack::MockRequest.env_for("/")) + end + end + test "available_action? returns true for implicit actions" do assert SimpleController.new.available_action?(:hello_world) assert SimpleController.new.available_action?(:"hyphen-ated") assert SimpleController.new.available_action?(:not_implemented) end + + test "available_action? does not allow File::SEPARATOR on the name" do + action_name = %w(evil .. .. path).join(File::SEPARATOR) + assert_equal false, SimpleController.new.available_action?(action_name.to_sym) + + action_name = %w(evil path).join(File::SEPARATOR) + assert_equal false, SimpleController.new.available_action?(action_name.to_sym) + end end end ``` 1.9.1 >From a8ecbfde294a2ec53f034e729d663cb266dc9e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= <[email protected]> Date: Thu, 17 Apr 2014 16:50:39 -0300 Subject: [PATCH] Only accept actions without File::SEPARATOR in the name. This will avoid directory traversal in implicit render. Fixes: CVE-2014-0130 --- ``` actionpack/lib/abstract_controller/base.rb | 28 +++++++++++++++++++--- .../new_base/render_implicit_action_test.rb | 17 ++++++++++++- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb index af5de81..26f8160 100644 --- a/actionpack/lib/abstract_controller/base.rb +++ b/actionpack/lib/abstract_controller/base.rb @@ -127,7 +127,7 @@ module AbstractController def process(action, *args) @_action_name = action_name = action.to_s - unless action_name = method_for_action(action_name) + unless action_name = _find_action_name(action_name) raise ActionNotFound, "The action '#{action}' could not be found for #{self.class.name}" end @@ -160,7 +160,7 @@ module AbstractController # ==== Returns # * <tt>TrueClass</tt>, <tt>FalseClass</tt> def available_action?(action_name) - method_for_action(action_name).present? + _find_action_name(action_name).present? end private @@ -204,6 +204,23 @@ module AbstractController end # Takes an action name and returns the name of the method that will + # handle the action. + # + # It checks if the action name is valid and returns false otherwise. + # + # See method_for_action for more information. + # + # ==== Parameters + # * <tt>action_name</tt> - An action name to find a method name for + # + # ==== Returns + # * <tt>string</tt> - The name of the method that handles the action + # * false - No valid method name could be found. Raise ActionNotFound. + def _find_action_name(action_name) + _valid_action_name?(action_name) && method_for_action(action_name) + end + + # Takes an action name and returns the name of the method that will # handle the action. In normal cases, this method returns the same # name as it receives. By default, if #method_for_action receives # a name that is not an action, it will look for an #action_missing @@ -225,7 +242,7 @@ module AbstractController # # ==== Returns # * <tt>string</tt> - The name of the method that handles the action - # * <tt>nil</tt> - No method name could be found. Raise ActionNotFound. + # * <tt>nil</tt> - No method name could be found. def method_for_action(action_name) if action_method?(action_name) action_name @@ -233,5 +250,10 @@ module AbstractController "_handle_action_missing" end end + + # Checks if the action name is valid and returns false otherwise. + def _valid_action_name?(action_name) + action_name.to_s !~ Regexp.new(File::SEPARATOR) + end end end ``` ``` diff --git a/actionpack/test/controller/new_base/render_implicit_action_test.rb b/actionpack/test/controller/new_base/render_implicit_action_test.rb index 1e2191d..5b4885f 100644 --- a/actionpack/test/controller/new_base/render_implicit_action_test.rb +++ b/actionpack/test/controller/new_base/render_implicit_action_test.rb @@ -6,7 +6,7 @@ module RenderImplicitAction "render_implicit_action/simple/hello_world.html.erb" => "Hello world!", "render_implicit_action/simple/hyphen-ated.html.erb" => "Hello hyphen-ated!", "render_implicit_action/simple/not_implemented.html.erb" => "Not Implemented" - )] + ), ActionView::FileSystemResolver.new(File.expand_path('../../../controller', __FILE__))] def hello_world() end end @@ -33,10 +33,25 @@ module RenderImplicitAction assert_status 200 end + test "render does not traverse the file system" do + assert_raises(AbstractController::ActionNotFound) do + action_name = %w(.. .. fixtures shared).join(File::SEPARATOR) + SimpleController.action(action_name).call(Rack::MockRequest.env_for("/")) + end + end + test "available_action? returns true for implicit actions" do assert SimpleController.new.available_action?(:hello_world) assert SimpleController.new.available_action?(:"hyphen-ated") assert SimpleController.new.available_action?(:not_implemented) end + + test "available_action? does not allow File::SEPARATOR on the name" do + action_name = %w(evil .. .. path).join(File::SEPARATOR) + assert_equal false, SimpleController.new.available_action?(action_name.to_sym) + + action_name = %w(evil path).join(File::SEPARATOR) + assert_equal false, SimpleController.new.available_action?(action_name.to_sym) + end end end ``` 1.9.1 >From 529720df0193991c66350154e8bed5a59dbaacfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= <[email protected]> Date: Thu, 17 Apr 2014 16:50:39 -0300 Subject: [PATCH] Only accept actions without File::SEPARATOR in the name. This will avoid directory traversal in implicit render. Fixes: CVE-2014-0130 --- ``` actionpack/lib/abstract_controller/base.rb | 28 +++++++++++++++++++--- .../new_base/render_implicit_action_test.rb | 17 ++++++++++++- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb index af5de81..26f8160 100644 --- a/actionpack/lib/abstract_controller/base.rb +++ b/actionpack/lib/abstract_controller/base.rb @@ -127,7 +127,7 @@ module AbstractController def process(action, *args) @_action_name = action_name = action.to_s - unless action_name = method_for_action(action_name) + unless action_name = _find_action_name(action_name) raise ActionNotFound, "The action '#{action}' could not be found for #{self.class.name}" end @@ -160,7 +160,7 @@ module AbstractController # ==== Returns # * <tt>TrueClass</tt>, <tt>FalseClass</tt> def available_action?(action_name) - method_for_action(action_name).present? + _find_action_name(action_name).present? end private @@ -204,6 +204,23 @@ module AbstractController end # Takes an action name and returns the name of the method that will + # handle the action. + # + # It checks if the action name is valid and returns false otherwise. + # + # See method_for_action for more information. + # + # ==== Parameters + # * <tt>action_name</tt> - An action name to find a method name for + # + # ==== Returns + # * <tt>string</tt> - The name of the method that handles the action + # * false - No valid method name could be found. Raise ActionNotFound. + def _find_action_name(action_name) + _valid_action_name?(action_name) && method_for_action(action_name) + end + + # Takes an action name and returns the name of the method that will # handle the action. In normal cases, this method returns the same # name as it receives. By default, if #method_for_action receives # a name that is not an action, it will look for an #action_missing @@ -225,7 +242,7 @@ module AbstractController # # ==== Returns # * <tt>string</tt> - The name of the method that handles the action - # * <tt>nil</tt> - No method name could be found. Raise ActionNotFound. + # * <tt>nil</tt> - No method name could be found. def method_for_action(action_name) if action_method?(action_name) action_name @@ -233,5 +250,10 @@ module AbstractController "_handle_action_missing" end end + + # Checks if the action name is valid and returns false otherwise. + def _valid_action_name?(action_name) + action_name.to_s !~ Regexp.new(File::SEPARATOR) + end end end diff --git a/actionpack/test/controller/new_base/render_implicit_action_test.rb b/actionpack/test/controller/new_base/render_implicit_action_test.rb index 1e2191d..5b4885f 100644 --- a/actionpack/test/controller/new_base/render_implicit_action_test.rb +++ b/actionpack/test/controller/new_base/render_implicit_action_test.rb @@ -6,7 +6,7 @@ module RenderImplicitAction "render_implicit_action/simple/hello_world.html.erb" => "Hello world!", "render_implicit_action/simple/hyphen-ated.html.erb" => "Hello hyphen-ated!", "render_implicit_action/simple/not_implemented.html.erb" => "Not Implemented" - )] + ), ActionView::FileSystemResolver.new(File.expand_path('../../../controller', __FILE__))] def hello_world() end end @@ -33,10 +33,25 @@ module RenderImplicitAction assert_status 200 end + test "render does not traverse the file system" do + assert_raises(AbstractController::ActionNotFound) do + action_name = %w(.. .. fixtures shared).join(File::SEPARATOR) + SimpleController.action(action_name).call(Rack::MockRequest.env_for("/")) + end + end + test "available_action? returns true for implicit actions" do assert SimpleController.new.available_action?(:hello_world) assert SimpleController.new.available_action?(:"hyphen-ated") assert SimpleController.new.available_action?(:not_implemented) end + + test "available_action? does not allow File::SEPARATOR on the name" do + action_name = %w(evil .. .. path).join(File::SEPARATOR) + assert_equal false, SimpleController.new.available_action?(action_name.to_sym) + + action_name = %w(evil path).join(File::SEPARATOR) + assert_equal false, SimpleController.new.available_action?(action_name.to_sym) + end end end ``` id SSV:93066 last seen 2017-11-19 modified 2017-04-28 published 2017-04-28 reporter Root source https://www.seebug.org/vuldb/ssvid-93066 title Ruby on Rails 'implicit render' functionality Directory Traversal Vulnerability (CVE-2014-0130)