MySQL Allows Password Bypass

 
MySQL Allows Password Bypass

Reported Feburary 9, 2000 by
Robert van der Meulen/Emphyrio and Willem Pinckaers

VERSIONS AFFECTED
MySQL 3.22.26a and later, and possibly earlier versions

DESCRIPTION

The MySQL database server contains a vulnerability within the password checking routines that allow a person to easily access restricted databases.

To exploit this bug, a valid username is needed where that user must have access to the database server.

The authentication concepts used in MySQL dictate that no passwords are sent between client & server upon connection and that no passwords are stoerd within MySQL in any decodable form.

Upon connection to the server, the server sends to the client where the client generates a new string with a random generator initiated with the hash values from the password along with the string received by the client.

This client-developed check string is then sent to the server where it is compared with a string generated from the stored hash_value of the password along with the random string.

The problem is that there are bugs in the code used to perform the comparison between the check string and the string generated from the hash_value of the password and random string,

Here is the code is used as extracted from mysql-3.22.26a/sql/password.c :

while (*scrambled)
\{
   if (*scrambled++ != (char) (*to++ ^ extra))
   return 1; /* Wrong password */
\}


The value "scrambled" represents the check value while  the code snipet (*to++ ^ extra) parses the hash_value.

Now suppose a client sends a single character to the server as the check string. With the code written the way it is, a single character string would cause a comparison of only the first character of the actual password to the single character check string. In other words, if you can determine the first character of the server-side check string (based on the actual password) then an unauthorized user could gain authentication.

The string that"s used for the comparison is generated using some random data, so two following authenticate-actions will probably use different check-strings.

After looking at the algorithm that generates the check string it is clear that there are actually only 32 possibilities for each character.

Hosts in the access list (by default any host, on a lot of distributions and servers) can connect to the MySQL server, without a password, and access data as long as the attacker has a valid username for the database server.

To correct this matter change the routine "check_scramble" in the MySQL code file password.c so that performs a string length check BEFORE starting the comparison routine.

This should be as easy as using the following code:

if (strlen(scrambled)!=strlen(to)) \{
return 1;
\}

while (*scrambled)
\{
   if (*scrambled++ != (char) (*to++ ^ extra))
   return 1; /* Wrong password */
\}


WARNING: This is NOT an official fix. You may use this as a temporary solution to the problem, however no guarantees are expressed or implied. Alternatively, you may use the patch snippet provided below:

Patch:
*** /my/monty/master/mysql-3.23.10-alpha/sql/sql_parse.cc Sun Jan 30
10:42:42 2000
--- ./sql_parse.cc Wed Feb  9 16:05:49 2000
***************
*** 17,22 ****
--- 17,24 ----
  #include
  #include

+ #define SCRAMBLE_LENGTH 8
+
  extern int yyparse(void);
  extern "C" pthread_mutex_t THR_LOCK_keycache;

***************
*** 188,195 ****
      end=strmov(buff,server_version)+1;
      int4store((uchar*) end,thd->thread_id);
      end+=4;
!     memcpy(end,thd->scramble,9);
!     end+=9;
  #ifdef HAVE_COMPRESS
      client_flags |= CLIENT_COMPRESS;
  #endif /* HAVE_COMPRESS */
--- 190,197 ----
      end=strmov(buff,server_version)+1;
      int4store((uchar*) end,thd->thread_id);
      end+=4;
!     memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1);
!     end+=SCRAMBLE_LENGTH +1;
  #ifdef HAVE_COMPRESS
      client_flags |= CLIENT_COMPRESS;
  #endif /* HAVE_COMPRESS */
***************
*** 268,273 ****
--- 270,277 ----
    char *user=   (char*) net->read_pos+5;
    char *passwd= strend(user)+1;
    char *db=0;
+   if (passwd\[0\] && strlen(passwd) != SCRAMBLE_LENGTH)
+     return ER_HANDSHAKE_ERROR;
    if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
      db=strend(passwd)+1;
    if (thd->client_capabilities & CLIENT_INTERACTIVE)

RPMs:
New RPMs should arrive shortly to http://www.mysql.org and all its mirrors.

VENDOR RESPONSE

The developers of MySQL have been notified of this issue, however no fix information was known at the time of this writing.

CREDITS
Discovered by Robert van der Meulen/Emphyrio and Willem Pinckaers

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish