xorl %eax, %eax

CVE-2009-2446: MySQL Log Messages Format String

with one comment

This is a nice bug discovered and disclosed by kingcope on 9 July 2009. The issue affects MySQL 4.0.0 through 5.0.83 releases. Even though kingcope provided complete documentation of the vulnerbility I’m going to write about it too. Here is the vulnerable code as seen in 5.0.82 release of MySQL database.

/*
   Perform one connection-level (COM_XXXX) command.

  SYNOPSIS
    dispatch_command()
    thd             connection handle
    command         type of command to perform
    packet          data for the command, packet is always null-terminated
    packet_length   length of packet + 1 (to show that data is
                    null-terminated) except for COM_SLEEP, where it
                    can be zero.
  RETURN VALUE
    0   ok
    1   request of thread shutdown, i. e. if command is
        COM_QUIT/COM_SHUTDOWN
*/

bool dispatch_command(enum enum_server_command command, THD *thd,
                      char* packet, uint packet_length)
{
        ...
  case COM_CREATE_DB:                           // QQ: To be removed
    {
      char *db=thd->strdup(packet), *alias;
      HA_CREATE_INFO create_info;

      statistic_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB],
                          &LOCK_status);
      // null test to handle EOM
      if (!db || !(alias= thd->strdup(db)) || check_db_name(db))
        ...
      if (check_access(thd,CREATE_ACL,db,0,1,0,is_schema_db(db)))
        break;
      mysql_log.write(thd,command,packet);
      bzero(&create_info, sizeof(create_info));
      mysql_create_db(thd, (lower_case_table_names == 2 ? alias : db),
                      &create_info, 0);
      break;
    }

What kingcope noticed, was that our command is directly passed to mysql_log.write() without any format string specifier as you can see from the above snippet. Because of this, an authenticated user (either local or remote) could trigger this format string and of course, execute code in the context of MySQL application. The exact same vulnerability was also present in the equivalent drop operation like that:

  case COM_DROP_DB:                             // QQ: To be removed
    {
      statistic_increment(thd->status_var.com_stat[SQLCOM_DROP_DB],
                          &LOCK_status);
      char *db=thd->strdup(packet);
      /*  null test to handle EOM */
      if (!db || check_db_name(db))
      {
        my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL");
        break;
      }
      if (check_access(thd,DROP_ACL,db,0,1,0,is_schema_db(db)))
        break;
      if (thd->locked_tables || thd->active_transaction())
      {
        my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                   ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
        break;
      }
      mysql_log.write(thd,command,db);
      mysql_rm_db(thd, db, 0, 0);
      break;
    }

The above code can be found at libmysqld/sql_parse.cc. kingcope also provided a simple PoC code that allows you to play with that bug.

Written by xorl

July 15, 2009 at 20:18

Posted in bugs

One Response

Subscribe to comments with RSS.

  1. This bug is not as straight forward to exploit as people might think. The mysql_log.write function utilizes the, by MySQL implemented, function my_b_vprintf() which only supports %s, %d, %u and %b. This makes exploitation of this bug for anything other than a DoS extremely hard, if not impossible.

    ghalen

    July 17, 2009 at 17:30


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s