2025年2月14日 星期五 甲辰(龙)年 腊月十四 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > Python

使用python抓包并分析后存入数据库,或直接分析tcpdump和wireshark抓到的包,并存入数据库

时间:04-02来源:作者:点击数:53

准备工作

抓包首先要用到scapy包

安装scapy包

  • pip install scapy

在python代码中引用scapy包

  • from scapy.all import *
  • #为了省事,直接import *,你也可以根据你的需求去导入你想用到的

抓包

想要分析包,首先要有包,先从抓包开始说起

抓包使用的是scapy中的sniff()方法

  • pcaps = sniff(filter="",iface="any", prn=function, count="")
  • #filter的规则使用 Berkeley Packet Filter (BPF)语法
  • #iface用来指定要在哪个网络接口上进行抓包(通常不指定即所有网络接口)
  • #prn指定回调函数,每当一个符合filter的报文被探测到时,就会执行回调函数,通常使用lambda表达式来写回调函数
  • #count指定最多嗅探多少个报文(是指符合filter条件的报文,而非所有报文)

其中

filter为过滤规则,参照BPF语法填入过滤规则

例如:filter="ip src www.baidu.com" 获取源地址为www.baidu.com的报文

iface为从哪个网卡上抓包,后面填上网卡名

例如:iface="WLAN" 或 iface="eth0"

prn则为回调函数,简单用法例如:prn=lambda x:x.summary() 或prn=lambda x:x[IP].src

prn=lambda x:x.summary() 为打印出来报文的简要信息

效果:Ether / IP / TCP 192.168.2.204:4963 > 180.97.162.191:8202 A

prn=lambda x:x[IP].src为打印出来报文的源地址

效果:192.168.1.1

count为抓多少个报文

保存包

若抓到包想要保存下来,以便下次慢慢分析,可以使用如下方法保存

  • wrpcap("pc2.pcap", pcaps)

若不想保存,则直接下一步

分析包

抓到包以后,刚刚我们用回调函数的方法summary,展示了每个包的简要信息,还有很多花样打印出抓到包的信息的方式,具体参考下列代码

  • from scapy.all import *
  • dpkt = sniff(iface="WLAN", count=10)
  • print(dpkt)
  • # 打印出包的总信息,打印效果:
  • #<Sniffed: TCP:2 UDP:0 ICMP:0 Other:0>
  • print(dpkt[0])
  • #打印第一个包,其实这样打印是没什么用的,看不到什么,因为都是16进制,那个警告的意思也是这样打印没有任何意义的意思,打印效果
  • #WARNING: Calling str(pkt) on Python 3 makes no sense!
  • #b'X\x00\xe3Df\xfbh\xa8(/\xd7\t\x08\x00E\x00\x01{\xa6)@\x005\x11 \xef=\x97\xb4\xa2\xac\x1c\xdf\x03\x1f@\x0f\xb1\x01g\x06>\x02:-\x00\x17\xab\r2\xc2o\n\x00\x00\nF.v\x8e+\x80\x0e\x14\xa3/\'\x7f+_\xba%\xd86\xb8\x00\xda\n\x7f\xff\xc16\x13
  • -#\x15\t\xe4\xb6[U\xdcT\xfb\xf6\xfb\xc5!%~\x92U\xdd\x96\x88\xf6\x12\xc8.\xda9\xd0\x85\x9d{\xd7/,\xf6\xb2\x9a\xe9\xbcg\x1bw\xec-\xab9\xab\x8e\xc0\x94\xef\xdbneT\x8f\xe3c\xa0h=\xc0\n+\xec\xdf\xa2x\xb3\x03\xc7GR\x90~D\xa4\xbe\x8a\xf8\xa
  • #d\xb9I\x05\x16&%\xa6B\xabM\xd1\x1bh\xa8\xb1\xe8=\xc7HG\x11Qv\xa3\x11\x14\xf0\x98\xb2\x9c\xd3\x94\xd1\xa1&\x99;\x86\xa6.\x10\x1e\x1d\xf5\xa3H(\xa7I\x84\xf9\xa8k\x9f\r\x86\x05\xf9p\x0b\xc0\x8e\xda\xcer\x0e<\xaf\x16\xccT|\xae\xack\x1a\
  • #xd1\xae\\1\xc9\x98\xb4\xc4Um\xb6\xa1\xdfAoa\xc5\xa6N\xe9\xbd\x9fB\xed\x94\xf2\xe2\xb4\xa4O\xa46,\xbc\xe8\x86h,\x19\x0e\x01\x93\xa9*\\\xd0mW\x03\xb2r\xc6\x8cN\xf8#8\x8e\t\xfc\x08O.\x13\x9er2\x86\x81*[\xb1\xfb\xaaD\xc8\x83\xab\xc9\xda
  • #`\xac:\x02\xaf\x1a\xf9\xfb\x08\x93,\xd7q\x8b\xaev/\xd3}\xf3t*\xcf\xebUt\xe5[\x06\xe7\xab\x03eg\xe6hd\x81\xe3EH\\\x99MZW\x1c\xb9\x87"\xa4\xff\x03y\xf9Q#\x00B9qK\xbf\x99a"\n75\xc8Z\xa2\x03'
  • print(dpkt[0].show())
  • #展示包的详细信息,因为各个包有所不同,所以打印出来的效果可能会不同,我只展示了这一种包的打印效果,效果如下:
  • # ###[ Ethernet ]###
  • # dst = 68:a8: 28:2
  • # f: d7:0
  • # 9
  • # src = 58:00: e3:44: 66:fb
  • # type = IPv4
  • # ###[ IP ]###
  • # version = 4
  • # ihl = 5
  • # tos = 0x4
  • # len = 58
  • # id = 19004
  • # flags = DF
  • # frag = 0
  • # ttl = 200
  • # proto = tcp
  • # chksum = 0x6875
  • # src = 172.28.223.3
  • # dst = 172.31.200.200
  • # \options \
  • # ###[ TCP ]###
  • # sport = 49688
  • # dport = 9988
  • # seq = 2674031876
  • # ack = 3838184596
  • # dataofs = 5
  • # reserved = 0
  • # flags = PA
  • # window = 513
  • # chksum = 0xbe17
  • # urgptr = 0
  • # options = []
  • # ###[ Raw ]###
  • # load = "\x01LVSIs'\\x9e0\n\x00\x00\x00\x00\x00\x00\x00\x00"
  • #
  • #
  • # None
  • print(dpkt[0].time)
  • # 打印时间,打印效果如下:
  • # 1639643824.65736
  • print(dpkt[0].fields)
  • # {'dst': '01:00:5e:7f:ff:fa', 'src': '58:00:e3:44:66:fb', 'type': 2048}
  • #打印dpkt[0].show()中的信息
  • #例如打印上述IP里的src
  • print(dpkt[0][IP].src)
  • #例如打印TCP中的sport
  • print(dpkt[0]["TCP"].sport)
  • #0是指第0个包,如果想看第二个包,可以将0改为1,如果想遍历所有包,可以用循环替代里面的数字
  • #注意,有的包里可能没有TCP,甚至没有IP,遍历时需要判断

插入数据库

这里就不讲了,参考其他资料

整体代码

capture.yp

  • import Database
  • from scapy.all import *
  • def get_all_pcap(ifs, size=10, filter=""):
  • # 抓包
  • pcaps = sniff(iface=ifs, count=size, filter=filter)
  • # 保存数据包到文件
  • # wrpcap("pc2.pcap", dpkt)
  • data = []
  • for item in pcaps:
  • if item['Ethernet'].type == 2048:
  • # ipv4
  • ethernet_type = 'IPV4'
  • # 判断tcp还是udp
  • if item["IP"].proto == 6:
  • sport = item['TCP'].sport
  • dport = int(re.sub(r'[\(\)\,]', "", str(item['TCP'].dport)))
  • tcp_udp = 'TCP'
  • tcp_type = item['TCP'].flags
  • else:
  • sport = item['UDP'].sport
  • dport = re.sub(r'[\(\)\,]', "", str(item['UDP'].dport))
  • tcp_udp = 'UDP'
  • tcp_type = 'null'
  • src_ip = re.sub(r'[\(\)\,]', "", str(item['IP'].src))
  • dst_ip = re.sub(r'[\(\)\,]', "", str(item['IP'].dst))
  • elif item['Ethernet'].type == 2054:
  • # ARP
  • ethernet_type = 'ARP'
  • src_ip = item['ARP'].psrc
  • dst_ip = item['ARP'].pdst
  • sport = 'null'
  • dport = 'null'
  • tcp_udp = 'null'
  • tcp_type = 'null'
  • else:
  • # ipv6
  • ethernet_type = 'IPV6'
  • src_ip = item['IPv6'].src
  • dst_ip = item['IPv6'].dst
  • sport = 'null'
  • dport = 'null'
  • tcp_udp = 'null'
  • tcp_type = 'null'
  • time = item.time
  • # 向数组中插入数据
  • data.append([
  • ethernet_type,
  • src_ip,
  • dst_ip,
  • sport,
  • dport,
  • tcp_udp,
  • str(tcp_type),
  • int(time)
  • ])
  • return data
  • def insertToSQL(data):
  • field = ['ethernet_type', 'src_ip', 'dst_ip', 'sport', 'dport', 'TCP_UDP', 'tcp_type', 'time']
  • # 插入数据
  • result = Database.Database().insert_all('pack_info', field, data)
  • if result == 0:
  • return 'success'
  • else:
  • return 'error'
  • def main():
  • # 抓包
  • # ifs = 'WLAN' # 网卡
  • data = get_all_pcap('WLAN', 100, 'tcp')
  • # 插入数据库
  • result = insertToSQL(data)
  • print(result)
  • if __name__ == '__main__':
  • main()

Datebase.py

  • import pymysql.cursors
  • class Database:
  • connected = False
  • __conn = None
  • # 构造函数,初始化时直接连接数据库
  • def __init__(self):
  • conf = {
  • 'host': 'ip',
  • 'port': 3306,
  • 'user': '用户名',
  • 'pw': '密码',
  • 'db': '数据库'}
  • if type(conf) is not dict:
  • print('错误: 参数不是字典类型!')
  • else:
  • for key in ['host', 'port', 'user', 'pw', 'db']:
  • if key not in conf.keys():
  • print('错误: 参数字典缺少 %s' % key)
  • if 'charset' not in conf.keys():
  • conf['charset'] = 'utf8'
  • try:
  • self.__conn = pymysql.connect(
  • host=conf['host'],
  • port=conf['port'],
  • user=conf['user'],
  • passwd=conf['pw'],
  • db=conf['db'],
  • charset=conf['charset'],
  • cursorclass=pymysql.cursors.DictCursor)
  • self.connected = True
  • except pymysql.Error as e:
  • print('数据库连接失败:', end='')
  • # 插入一条数据到数据表
  • def insert_one(self, table, val_obj):
  • sql_top = 'INSERT INTO ' + table + ' ('
  • sql_tail = ') VALUES ('
  • try:
  • for key, val in val_obj.items():
  • sql_top += key + ','
  • if isinstance(val,int):
  • sql_tail += str(val) + ','
  • else:
  • sql_tail += '\'' + val + '\'' + ','
  • sql = sql_top[:-1] + sql_tail[:-1] + ')'
  • # 打印sql语句
  • # print(sql)
  • # exit()
  • with self.__conn.cursor() as cursor:
  • cursor.execute(sql)
  • self.__conn.commit()
  • return self.__conn.insert_id()
  • except pymysql.Error as e:
  • self.__conn.rollback()
  • return False
  • def insert_all(self,table,field,record):
  • sql_top = 'INSERT INTO ' + table + ' ('
  • sql_tail = ') VALUES ('
  • try:
  • for val in field:
  • sql_top += val + ','
  • for i in record:
  • for j in i:
  • if isinstance(j, int):
  • sql_tail += str(j) + ','
  • else:
  • sql_tail += '\'' + j + '\'' + ','
  • sql_tail = sql_tail[:-1] + '),('
  • sql = sql_top[:-1] + sql_tail[:-2]
  • # 打印sql语句
  • # print(sql)
  • # exit()
  • with self.__conn.cursor() as cursor:
  • cursor.execute(sql)
  • self.__conn.commit()
  • return self.__conn.insert_id()
  • except pymysql.Error as e:
  • self.__conn.rollback()
  • return False
  • # 销毁对象时关闭数据库连接
  • def __del__(self):
  • try:
  • self.__conn.close()
  • except pymysql.Error as e:
  • pass
  • # 关闭数据库连接
  • def close(self):
  • self.__del__()

纯属记录个人学习过程,我也是刚开始学python,我感觉上述代码肯定有错误的地方,若有不正确或不清晰的地方,欢迎指正。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门