Slashdot Mirror


Drupal Fixes Highly Critical SQL Injection Flaw

An anonymous reader writes Drupal has patched a critical SQL injection vulnerability in version 7.x of the content management system that can allow arbitrary code execution. The flaw lies in an API that is specifically designed to help prevent against SQL injection attacks. "Drupal 7 includes a database abstraction API to ensure that queries executed against the database are sanitized to prevent SQL injection attacks," the Drupal advisory says. "A vulnerability in this API allows an attacker to send specially crafted requests resulting in arbitrary SQL execution. Depending on the content of the requests this can lead to privilege escalation, arbitrary PHP execution, or other attacks."

11 of 54 comments (clear)

  1. Heh by bunratty · · Score: 5, Funny

    The flaw lies in an API that is specifically designed to help prevent against SQL injection attacks.

    You had one job!

    --
    What a fool believes, he sees, no wise man has the power to reason away.
    1. Re:Heh by Anonymous Coward · · Score: 2, Insightful

      So were they "sanitizing" full-text queries instead of using prepared statements? That's like polishing a turd. No mater how hard you polish, you still have a turd.

    2. Re:Heh by Hewligan · · Score: 2

      No, it's more like they were enforcing parametrised queries on top of an API that allows non-parametrised queries.

      --

      "If God created us in his own image, we have more than reciprocated"

    3. Re:Heh by amicusNYCL · · Score: 5, Informative

      It looks like a feature where you could supply one placeholder in a prepared statement, but give it an array of values, and it would expand the placeholders to fit the array. So if the query was like this:

      SELECT * FROM table WHERE id IN (:idlist)

      and you passed an array with 3 values for idlist, it would replace the query like this:

      SELECT * FROM table WHERE id IN (:idlist_1, :idlist_2, :idlist_3) ... then use the values in the array as the three values for those placeholders. It looks like the old code was using the keys from the data array, so instead of appending someting like "_1", it would append the actual key. So an attacker could put SQL code into the array keys and it would stick those (unchanged) into the query.

      Here is the old code (without comments):

      foreach (array_filter($args, 'is_array') as $key => $data) {
                  $new_keys = array();
                  foreach ($data as $i => $value) {
                      $new_keys[$key . '_' . $i] = $value;
                  }
                  $query = preg_replace('#' . $key . '\b#', implode(', ', array_keys($new_keys)), $query);

      And the new code:

      foreach (array_filter($args, 'is_array') as $key => $data) {
                  $new_keys = array();
                  foreach (array_values($data) as $i => $value) {
                      $new_keys[$key . '_' . $i] = $value;
                  }
                  $query = preg_replace('#' . $key . '\b#', implode(', ', array_keys($new_keys)), $query);

      array_values will return an array with numeric indexes, which is what removes the vulnerability.

      --
      "Our two-party system is like a bowl of shit looking at itself in a mirror." - Lewis Black
  2. Re:Is Drupal 6.x Affected? by Hewligan · · Score: 3, Informative

    I've seen no mention of whether or not Drupal 6.x is vulnerable; are they?

    No, it won't be affected, as the API involved was introduced in Drupal 7.

    --

    "If God created us in his own image, we have more than reciprocated"

  3. Re:Is Drupal 6.x Affected? by amicusNYCL · · Score: 2

    Considering that the API is to help protect against SQL injection though, it's probably fair to say that version 6 is affected by other issues.

    --
    "Our two-party system is like a bowl of shit looking at itself in a mirror." - Lewis Black
  4. Re:Is Drupal 6.x Affected? by fluffy99 · · Score: 2

    I've seen no mention of whether or not Drupal 6.x is vulnerable; are they?

    No, it won't be affected, as the API involved was introduced in Drupal 7.

    No, but it's certainly an indicator of the quality of code. Don't be surprised if other vulnerabilities are discovered as everyone shifts their attention and starts scrutinizing the rest of the code. The code diff is below. It's a pretty amateurish mistake, and had someone reviewed or tested the original code, they'd have seen it didn't do what it was supposed to. The comments even give you a big hint what the next vulnerability is going could be.

    diff --git a/includes/database/database.inc b/includes/database/database.inc
    index f78098b..01b6385 100644
    --- a/includes/database/database.inc
    +++ b/includes/database/database.inc
    @@ -736,7 +736,7 @@ abstract class DatabaseConnection extends PDO { // to expand it out into a comma-delimited set of placeholders.
              foreach (array_filter($args, 'is_array') as $key => $data) {
                  $new_keys = array();
    - foreach ($data as $i => $value) {
    + foreach (array_values($data) as $i => $value) { // This assumes that there are no other placeholders that use the same // name. For example, if the array placeholder is defined as :example // and there is already an :example_2 placeholder, this will generate

  5. It's not that hard to do it right by Art3x · · Score: 5, Interesting

    I understand database abstration layers that let you write:

    db_query('select * from table where id = 3')

    instead of:

    mysql_query('select * from table where id = 3')
    or
    pgsql_query('select * from table where id = 3')

    But I'm not sure I understand why you would want even more abstraction that lets you write:

    db_select('*').from('table').where({ id: 3 })

    ---

    Sealing against SQL injection isn't that hard. Don't ever write:

    select * from table where id = $id

    If you see a dollar sign in an SQL string, it should catch your eye. Instead use parametric queries whenever you can:

    select * from table where id = ? or
    select * from table where id = $1 or
    select * from table where id = :id or
    whatever your programming language's syntax is.

    Maybe variables in queries are unavoidable, if you have some kind of query building code:

    if ($x) {
        $table = 'x';
    } else {
        $table = 'y';
    }

    $q = db_prepare("select * from $table where id = ?");

    Does anyone have a better way to build up queries?

    1. Re:It's not that hard to do it right by dotancohen · · Score: 2

      Go google for "php prepared statements in clause" and see how the very first result is a "solution" that is vulerable to SQL injection.

      --
      It is dangerous to be right when the government is wrong.
    2. Re:It's not that hard to do it right by Alioth · · Score: 2

      People can write equally vulnerable code in Python or Java or Ruby. The root cause is building SQL queries out of strings instead of using prepared parameterized statements (which I believe PHP has supported for a while -- not as long as Python or Perl or Java or Ruby, after all PHP has those god awful mysql_something functions instead of having something like perl's DBI from the get-go).

      I think if you're building queries out of strings you're doing it wrong and asking for an SQL injection vulnerability. From looking at the thread it seems that it was a query that used a list, I think it would have been better to find some other method.

  6. Re:Stored procs? by Elminster+Aumar · · Score: 2

    I know how to use parameterized inputs (I also know how to spell it). Oh, I also use PHP... So I think you need to reconsider using blanket statements that stress your impulse assumptions.