Blogs & Stories

SpiderLabs Blog

Attracting more than a half-million annual readers, this is the security community's go-to destination for technical breakdowns of the latest threats, critical vulnerability disclosures and cutting-edge research.

ModSecurity Mitigations for Ruby on Rails XML Exploits

There is big trouble in Ruby on Rails (RoR) land... The issue is related to XML parsing of YAML document elements or Symbols and results in remote code execution. The vulnerabilities have been confirmed by multiple sources and proof of concept code is available: Rails PoC Exploits by Postmortem.

ModSecurity Mitigations

The primary recommendation is of course to update your Ruby on Rails code to the latest patched version. If, however, you are unable to do so in a timely manner or at all, then here are some options to use ModSecurity to help prevent these attacks.

Activating the XML Request Body Parser (libxml2)

ModSecurity has the ability to inspect XML request bodies using libxml2 however it will not do so automatically. You must use rules to activate the XML request body parser. The OWASP ModSecurity CRS has the following example rule withn the 10 setup file:

## -- [[ Enable XML Body Parsing ]] -------------------------------------------------------## The rules in this file will trigger the XML parser upon an XML request## Initiate XML Processor in case of xml content-type#SecRule REQUEST_HEADERS:Content-Type "text/xml" \  "id:'900017', \  phase:1, \  t:none,t:lowercase, \  nolog, \  pass, \  chain" SecRule REQBODY_PROCESSOR "!@streq XML" \   "ctl:requestBodyProcessor=XML"

With this rule in place, ModSecurity will parse XML request bodies and populate the XML variable with the element payloads.

XML Schema Validation

ModSecurity has the ability to analyze XML request bodies for proper formating and construction. If libxml2 finds any errors it will generate alerts. While this is good for catching many poorly written XML exploit scripts, it does not catch everything. In this case, the problem is not formatting or syntax problems but rather the presence of rogue XML elements that attempt to utilize the yaml/symbol types.

A good defense against these attacks would be to enforce a specific XML Schema definition for the resource you are protecting. ModSecurity has the ability to enforce XML Schema compliance by using the @validateSchema operator. An example rule would look like this:

SecRule XML "@validateSchema /path/to/apache2/conf/xml.xsd" \ "id:'2',phase:2,log,block,msg:'Failed to validate XML payload against schema'"

If your xml.xsd file properly specifies all allowed XML elements, then the presence of this RoR exploit code would be caught. As an example, here is a test using the following Apache XMLBeans XSD file that defines the XML data accepted by the resource:

Screen shot 2013-01-10 at 1.07.03 PM

We can then send the following PoC attack:

Screen shot 2013-01-10 at 1.10.14 PM

ModSecurity would then validate this payload agains the XSD file using the @validateSchema operator and alerts similar to the following would be generated:

Message: Element '{http://xmlbeans.apache.org/samples/validation/todolist}item', attribute 'type': The attribute 'type' is not allowed.Message: Element '{http://xmlbeans.apache.org/samples/validation/todolist}item': Character content other than whitespace is not allowed because the content type is 'element-only'.Message: Element '{http://xmlbeans.apache.org/samples/validation/todolist}item': Character content other than whitespace is not allowed because the content type is 'element-only'.Message: Warning. XML: Schema validation failed. [file "/usr/local/apache/conf/crs/base_rules/modsecurity_crs_15_custom.conf"] [line "6"] [id "200"] [msg "Failed to validate XML payload against schema"]

As you can see, if a proper XSD Schema file is specified, then injection of this data is prevented.

Identify Injection of Ruby Code

Based on the various PoC data available, we can use the following rule to identify if any Ruby code is being submitted within the XML data:

SecRule REQUEST_HEADERS:Content-Type "@contains text/xml" "chain,id:'999010',phase:2,t:none,block,msg:'Ruby on Rails XML Exploit Attempt,',logdata:'%{matched_var}',tag:'CVE-2013-0156'"  SecRule XML:/* "@pm !ruby/"

To test out this rule, we have added some regression tests to the OWASP ModSecurity CRS:

%timeout 10%requestPOST / HTTP/1.1Host: $hostnameUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5Accept-Language: en-us,en;q=0.5Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7Keep-Alive: 300Proxy-Connection: keep-aliveReferer: text/xmlContent-Length: $CONTENT_LENGTH<xml version="1.0" encoding="UTF-8"><boom type="yaml"><![CDATA[$sig]]></boom></xml>%test Ruby on Rails Vuln - CVE-2013-0156 - 1 ########################################%event 999010 %output 999010%var sig=--- !ruby/object:UnsafeObject attribute1: value1%var sig=--- !ruby/string:Arel::Nodes::SqlLiteral \"' OR '2' < '6';--\"%var type=yaml%endtest

When we run these tests using the rulestest.pl regression test tool, this rule will trigger and generate the following debug log output:

Recipe: Invoking rule 1009bb160; [file "/usr/local/apache/conf/crs/base_rules/modsecurity_crs_15_custom.conf"] [line "9"] [id "999010"].Rule 1009bb160: SecRule "REQUEST_HEADERS:Content-Type" "@contains text/xml" "phase:2,log,chain,id:999010,t:none,block,msg:'Ruby on Rails XML Exploit Attempt,',logdata:%{matched_var},tag:CVE-2013-0156"Transformation completed in 2 usec.Executing operator "contains" with param "text/xml" against REQUEST_HEADERS:Content-Type.Target value: "text/xml"Operator completed in 4 usec.Rule returned 1.Match -> mode NEXT_RULE.Recipe: Invoking rule 1009c61c0; [file "/usr/local/apache/conf/crs/base_rules/modsecurity_crs_15_custom.conf"] [line "10"].Rule 1009c61c0: SecRule "XML:/*" "@pm !ruby/"Transformation completed in 1 usec.Executing operator "pm" with param "!ruby/" against XML:/*.Target value: "\n--- !ruby/object:UnsafeObject attribute1: value1\n"Operator completed in 40 usec.Resolved macro %{matched_var} to: \n--- !ruby/object:UnsafeObject attribute1: value1\nWarning. Matched phrase "!ruby/" at XML. [file "/usr/local/apache/conf/crs/base_rules/modsecurity_crs_15_custom.conf"] [line "9"] [id "999010"] [msg "Ruby on Rails XML Exploit Attempt,"] [data "\x0a--- !ruby/object:UnsafeObject attribute1: value1\x0a"] [tag "CVE-2013-0156"]