• Mysql 协议嗅探


    需求

    监听通过网卡的所有mysql流量,进行解析,可在不影响现有业务情况下,进行入侵检测(IDS)或数据集成

    协议要点

    起初发现 用mysql-front访问数据库和mysql 的客户端访问时数据包格式不同,纠结很久,不明白,mysql-front源码看了眼,delphi,不懂,弃

    压缩解析

    当链接mysql时,若启用-C参数表示,对于连接数据启用压缩,压缩格式为zlib

    mysql的压缩函数为:

     1 // mysql-source/mysys/my_compress.c
     2 
     3 my_bool my_compress(uchar *packet, size_t *len, size_t *complen)
     4 {
     5   DBUG_ENTER("my_compress");
     6   if (*len < MIN_COMPRESS_LENGTH)
     7   {
     8     *complen=0;
     9     DBUG_PRINT("note",("Packet too short: Not compressed"));
    10   }
    11   else
    12   {
    13     uchar *compbuf=my_compress_alloc(packet,len,complen);
    14     if (!compbuf)
    15       DBUG_RETURN(*complen ? 0 : 1);
    16     memcpy(packet,compbuf,*len);
    17     my_free(compbuf);
    18   }
    19   DBUG_RETURN(0);
    20 }
    21 
    22 
    23 uchar *my_compress_alloc(const uchar *packet, size_t *len, size_t *complen)
    24 {
    25   uchar *compbuf;
    26   uLongf tmp_complen;
    27   int res;
    28   *complen=  *len * 120 / 100 + 12;
    29 
    30   if (!(compbuf= (uchar *) my_malloc(key_memory_my_compress_alloc,
    31                                      *complen, MYF(MY_WME))))
    32     return 0;                    /* Not enough memory */
    33 
    34   tmp_complen= (uint) *complen;
    35   res= compress((Bytef*) compbuf, &tmp_complen, (Bytef*) packet, (uLong) *len);
    36   *complen=    tmp_complen;
    37 
    38   if (res != Z_OK)
    39   {
    40     my_free(compbuf);
    41     return 0;
    42   }
    43 
    44   if (*complen >= *len)
    45   {
    46     *complen= 0;
    47     my_free(compbuf);
    48     DBUG_PRINT("note",("Packet got longer on compression; Not compressed"));
    49     return 0;
    50   }
    51   /* Store length of compressed packet in *len */
    52   swap_variables(size_t, *len, *complen);
    53   return compbuf;
    54 }

     其中第35行调用了zlib中的compress()函数,但是该处仅对compress()进行了封装,并没有协议解析部分,我们继续往下看。

    整个项目寻找目标代码比较费劲,可以先在头文件中寻找关键信息,于是找到了下面的代码

    // mysql-source/include/sql_state.h
    { ER_NET_UNCOMPRESS_ERROR                 ,"08S01", "" }

    这是在mysql在解析压缩的数据时如果出错的提示信息和错误码,依次可以查找其引用,发现了真正的数据包压缩代码

     1 // mysql-source/sql/net_serv.cc
     2 
     3 static uchar *
     4 compress_packet(NET *net, const uchar *packet, size_t *length)
     5 {
     6   uchar *compr_packet;
     7   size_t compr_length;
     8   const uint header_length= NET_HEADER_SIZE + COMP_HEADER_SIZE;
     9 
    10   compr_packet= (uchar *) my_malloc(key_memory_NET_compress_packet,
    11                                     *length + header_length, MYF(MY_WME));
    12 
    13   if (compr_packet == NULL)
    14     return NULL;
    15 
    16   memcpy(compr_packet + header_length, packet, *length);
    17 
    18   /* Compress the encapsulated packet. */
    19   if (my_compress(compr_packet + header_length, length, &compr_length))
    20   {
    21     /*
    22       If the length of the compressed packet is larger than the
    23       original packet, the original packet is sent uncompressed.
    24     */
    25     compr_length= 0;
    26   }
    27 
    28   /* Length of the compressed (original) packet. */
    29   int3store(&compr_packet[NET_HEADER_SIZE], static_cast<uint>(compr_length));
    30   /* Length of this packet. */
    31   int3store(compr_packet, static_cast<uint>(*length));
    32   /* Packet number. */
    33   compr_packet[3]= (uchar) (net->compress_pkt_nr++);
    34 
    35   *length+= header_length;
    36 
    37   return compr_packet;
    38 }

     从8-19行可以看到,压缩数据的组包过程,前面分别加了NET_HEADER_SIZE + COMP_HEADER_SIZE 长的控制字段

    查找该宏,发现其定义如下

    1 // mysql-source/include/mysql_com.h
    2 
    3   /* Constants when using compression */
    4 #define NET_HEADER_SIZE 4        /* standard header size */
    5 #define COMP_HEADER_SIZE 3        /* compression header extra size */

    NET_HEADER_SIZE 字段中 长度字段存储 数据部分 未解压时的长度

    COMP_HEADER_SIZE 字段是用来存储  解压后的 数据的长度,我们可以依次申请内存,然后调用zlib对压缩内容进行解析即可。

     如果不分析直接进行对wireshark抓到的数据进行zlib解析的话,由于控制字段的存在会解压缩失败,在python中的报错如下

    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    zlib.error: Error -3 while decompressing data: incorrect data check

     起初看到这个错误很头痛也不想看zlib解析细节,才有了从mysql找原因的本文,现在可以记录zlib 压缩字符串的开头常常是x78x9c,出现同样错误的可以看看是否正确

  • 相关阅读:
    redis相关
    Ubuntu安装之python开发
    Shell编程实战
    saltstack高效运维
    docker网络
    docker入门
    python学习博客地址集合。。。
    vue+uwsgi+nginx部署路飞学城
    部署你的CRM程序
    Java Netty教程(目录)
  • 原文地址:https://www.cnblogs.com/the-owl/p/7650690.html
Copyright © 2020-2023  润新知