• 【Python】pcap抓MySQL网络包


    pcap
    # -*- coding:utf-8 -*-
    # yum install libpcap-devel python-devel
    # pip install pypcap hexdump -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
    
    import pcap, hexdump, zlib
    import re, threading, requests
    
    INFO = """## SRC %s:%s
    ## DST %s:%s
    ## TYPE %d
    ## QUERY:
        %s
    
    """
    
    
    class Pkt:
        def __init__(self, pkt, dloff):
            """
    
            :param pkt:
            :param dloff: IP层数据开始位置,成员函数的offset以此为准
            """
            self.pkt = pkt
            self.dloff = dloff
            self.src = self.__addr__()
            self.dst = self.__addr__(src=False)
            self.ipv, self.ip_header_length = self.__l3_base_info__()
            self.l4type, self.l4_header_length = self.__l4__()
    
        def __l4__(self):
            """
                4层协议类型 1:ICMP 6:TCP 7:UDP
                TCP Header 长度位置 = dloff + ip_header_length + 12 的高四位
            :return: ICMP/TCP/UDP
            """
            d = {1: "ICMP", 6: "TCP", 7: "UDP"}
            l, null = self.__split_bin__(bin(ord(self.pkt[self.dloff + self.ip_header_length + 12])))
            # print "tcp length", ord(self.pkt[self.dloff + self.ip_header_length + 12])
            # print "tcp length", bin(ord(self.pkt[self.dloff + self.ip_header_length + 12]))
            # print "tcp length", l * 4, null, self.ip_header_length
            return d[ord(self.pkt[self.dloff + 9])], l * 4
    
        def __port__(self, src=True):
            offset, s = 0 if src else 2, ""
            for h in [hex(ord(self.pkt[self.dloff + self.ip_header_length + offset])), hex(ord(self.pkt[self.dloff + self.ip_header_length + 1 + offset]))]:
                s = s + h[2:]
            return int(s, 16)
    
        def __split_bin__(self, s):
            """
    
            :param s: 8位bit,例如'0b1000101'
            :return: 高位(0-15),低位(0-15)
            """
            pass
            if not s.startswith("0b"):
                raise TypeError
            if len(s[2:]) < 8:
                s = (8-len(s[2:])) * "0" + s[2:]
            else:
                s = s[2:]
            return int(s[0:4], 2), int(s[4:], 2)
    
        def __addr__(self, src=True):
            """
                src addr offset 12
                dst addr offset 16
            :param src: True 源,False 目的
            :return: ip
            """
            if src:
                return '.'.join(str(ord(self.pkt[i])) for i in range(self.dloff + 12, self.dloff + 16))
            else:
                return '.'.join(str(ord(self.pkt[i])) for i in range(self.dloff + 16, self.dloff + 20))
    
        def __l3_base_info__(self):
            """
                ip协议信息(协议版本和头长度) offset 0
            :return: 协议版本号(4,6),头部长度
            """
            s = bin(ord(self.pkt[self.dloff]))
            v, l = self.__split_bin__(s)
            return v, l * 4
    
        def __mysql_protocol__(self):
            """
                mysql protocol offset: ip_header_length + l4_header_length - 1
                5层内容,包含:
                Packet Length 3字节
                Packet Number 1字节
                Command Type 1字节 https://dev.mysql.com/doc/internals/en/command-phase.html
                    3 -> query
                    22 -> Prepare DML 预编译语句
                    23 -> Execute DML 预编译的Value
                    25 -> Close
                5字节后是实际内容
            :return:
            """
            offset = self.dloff + self.ip_header_length + self.l4_header_length
            # length = self.pkt[offset: offset+3]
            if not self.pkt[offset: offset+3]:
                return None, None
            command = ord(self.pkt[offset+4])
            # print type(self.pkt[self.dloff + self.ip_header_length + self.l4_header_length:])
            # print dir(self.pkt[self.dloff + self.ip_header_length + self.l4_header_length:])
            return command, self.pkt[offset+5:]
            # print zlib.decompress(self.pkt[self.dloff + self.ip_header_length + self.l4_header_length:])
            # print zlib.decompress(self.pkt[self.dloff + self.ip_header_length + self.l4_header_length+6:])
            # return hexdump.hexdump(self.pkt[self.dloff + self.ip_header_length + self.l4_header_length:])
    
        def format(self):
            src_port, dst_port = self.__port__(), self.__port__(False)
            command, query = self.__mysql_protocol__()
            if not command:
                return None
            global INFO
            # return self.dloff, self.src, self.dst, "IPv%s" % str(self.ipv), self.__l4__()
            return INFO % (self.src, src_port, self.dst, dst_port, command, query)
    
    
    if __name__ == "__main__":
        # catch_pack("eth0", 1)
        sniffer = pcap.pcap(name="en0", immediate=True, timeout_ms=10)
        sniffer.setfilter("dst port 3306")  # 只抓取TCP包
        # addr = lambda pkt, offset: '.'.join(str(ord(pkt[i])) for i in range(offset, offset + 4))
        for ts, pkt in sniffer:
            # print ts, sniffer.dloff
            # print '%d\tSRC %-16s\tDST %-16s' % (ts, addr(pkt, sniffer.dloff + 12), addr(pkt, sniffer.dloff + 16))
            msg = Pkt(pkt, sniffer.dloff).format()
            if msg:
                print msg
    
    
    查询请求

    payload_length -> Packet length: 3字节
    sequence_id -> Packet Number:1字节
    payload -> Command:1字节
    Packet Data:4字节后的所有内容

    包的基础结构
    https://dev.mysql.com/doc/internals/en/mysql-packet.html
    Packet length: 3字节
    Packet Number:1字节
    Packet Data:4字节后的所有内容

    解压缩 https://dev.mysql.com/doc/internals/en/uncompressed-payload.html

    不压缩的情况:
    set length of payload before compression to 0

    the compressed payload contains the uncompressed payload instead.

  • 相关阅读:
    django template extends
    python sys.path的用法
    django form 显示
    django form 验证
    WingIDE 下载,介绍和配置
    python startswith
    django reverse()
    python 动态创建类
    django form 定义
    如何学习python
  • 原文地址:https://www.cnblogs.com/jiangxu67/p/16183950.html
Copyright © 2020-2023  润新知