Bug #64884 logins with incorrect password are allowed
Submitted: 6 Apr 2012 7:02 Modified: 29 May 2012 16:21
Reporter: Sergei Golubchik Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Security: Privileges Severity:S1 (Critical)
Version:all OS:Any
Assigned to: CPU Architecture:Any

[6 Apr 2012 7:02] Sergei Golubchik
Description:
symptom: main.connect fails sporadically with

mysqltest: At line 65: query 'connect  fail_con,localhost,test,zorro,' succeeded - should have failed with errno 1045...

or a similar message.

Reason:  in sql/password.c the function

my_bool
check_scramble(const char *scramble_arg, const char *message,
               const uint8 *hash_stage2)
{
 ...
  return memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE);
}

And in 'man memcmp' one can see
       int memcmp(const void *s1, const void *s2, size_t n);
...
       The memcmp() function returns  an  integer  less  than,  equal  to,  or
       greater than zero if the first n bytes of s1 is found, respectively, to
       be less than, to match, or be greater than the first n bytes of s2.

So, memcmp returns an *integer*. It is implicitly casted to my_bool - which is char. If memcmp happen to return a non-zero number that has a zero last byte - check_scramble will return 0 (password was ok), despite the fact that the password was incorrect.

This happens to me (Gentoo, gcc 4.5.3, glibc-2.13) every couple of hundreds logins. Add a loop in connect.test to have a better chance of hitting this bug.

Present in MySQL 5.1 and later, up to the trunk.

How to repeat:
Sapienti sat

Suggested fix:
=== modified file 'sql/password.c'
--- a/sql/password.c    2011-11-21 17:13:14 +0000
+++ b/sql/password.c    2012-04-04 13:34:37 +0000
@@ -503,7 +503,7 @@ check_scramble(const char *scramble_arg,
   mysql_sha1_reset(&sha1_context);
   mysql_sha1_input(&sha1_context, buf, SHA1_HASH_SIZE);
   mysql_sha1_result(&sha1_context, hash_stage2_reassured);
-  return memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE);
+  return test(memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE));
 }
[6 Apr 2012 8:19] Valeriy Kravchuk
Verified just as described (after 100+ runs of the test) with current mysql-trunk on 64-bit FC14:

...
main.connect                             [ pass ]  10199
main.connect                             [ pass ]  10196
main.connect                             [ pass ]  10208
main.connect                             [ fail ]
        Test ended at 2012-04-06 11:15:42

CURRENT_TEST: main.connect
mysqltest: At line 65: query 'connect  fail_con,localhost,test,zorro,' succeeded - should have failed with errno 1045...
[6 Apr 2012 13:29] Paul DuBois
Noted in 5.1.63, 5.5.24, 5.5.6 changelogs.

An incorrect type conversion in password handling permitted clients
to connect with incorrect passwords.
[20 Apr 2012 18:32] Sergei Golubchik
RedHat told us they've requested a CVE id for this bug.
It is CVE-2012-2122.

It would be great to avoid duplicate CVE ids for the same issue, if possible, so we all would appreciate if you could use this number and not request a new one.
[29 May 2012 16:21] Sergei Golubchik
Just FYI,

we're going to disclose publically the details related to the
security bug#64884.

It's fixed both in MariaDB and in MySQL. And it doesn't affect official
MySQL binaries, as far as I know.

But anyway, here's an advance warning that we'll do it in about a week
or two.
[11 Jun 2012 7:50] MySQL Verification Team
https://www.secmaniac.com/blog/2012/06/11/massive-mysql-authentication-bypass-exploit/
http://seclists.org/oss-sec/2012/q2/493
[11 Jun 2012 22:25] James Day
Just to confirm what Sergei wrote earlier, the Oracle-produced MySQL builds do not use the gcc SSE option that exposes this problem.

If you are not using the Oracle builds you should contact your build provider for guidance on how to proceed. If it is needed, it's likely that they will have a recompiled build that includes the code change that eliminates the issue if SSE support is enabled.

Please also remember that in most cases you should have a firewall that prohibits most of the internet and most of an intranet from even being able to send a packet to your MySQL server. If you haven't done this yet, please make it a high priority action item.

If you must have access from the internet, the correct way is usually to use a gateway box that you connect to, which then lets you connect to the server. That way your gateway is the system that can be seen, not your database server. This makes it much harder to cause trouble.

If you haven't done it yet please also read the security section of the MySQL manual: http://dev.mysql.com/doc/refman/5.5/en/security.html . It contains many practical steps that you should take to make it harder to cause trouble.

James Day, MySQL Senior Principal Support Engineer, Oracle.