参考:https://blog.csdn.net/Kevinhanser/article/details/80140427
第三章 网络:原始套接字 和流量嗅探
目录
技术原因,ICMP解码部分我还没有能力完成,未完待续......
Windows和Linux上的包嗅探
创建python文件(sniffer.py)
注意:要修改一处地方,host的赋值改为自己kali虚拟机的ip地址
import socket
import os
#监听的主机
host="192.168.1.6"
#创建原始套接字,然后绑定在公开接口上
if os.name=="nt":
socket_protocol=socket.IPPROTO_IP
else:
socket_protocol=socket.IPPROTO_ICMP
sniffer=socket.socket(socket.AF_INET,socket.SOCK_RAW,socket_protocol)
sniffer.bind((host,0))
#设置在捕获的数据包中包含IP头
sniffer.setsockopt(socket.IPPROTO_IP,socket.IP_HDRINCL,1)
#在windows平台上,我们需要设置IOCTL以启动混杂模式
if os.name=="nt":
sniffer.ioctl(socket.SIO_RCVALL,socket.RCVALL_ON)
#读取单个数据包
print(sniffer.recvfrom(65565))
#在Windows平台上关闭混杂模式
if os.name=="nt":
sniffer.ioctl(socket.SIO_RCVALL,socket.RCVALL_OFF)
运行以及运行结果如下:
打开两个终端(左,右),
右终端运行脚本如下:
┌──(root㉿kali)-[~]
└─# python sniffer.py
左终端运行以及运行结果如下:
┌──(root㉿kali)-[~]
└─# ping nostarch.com
ping: nostarch.com: 域名解析暂时失败
右终端变化如下:
┌──(root㉿kali)-[~]
└─# python sniffer.py
(b'E\xc0\x00V\xf4\xfb\x00\x00@\x01\x01\x8f\xc0\xa8\x01\x06\xc0\xa8\x01\x06\x03\x01\xc5\xa0\x00\x00\x00\x00E\x00\x00:\xb4\r@\x00@\x11\x03N\xc0\xa8\x01\x06\xc0\xa8\x01\x01\xa4\xb1\x005\x00&\x83\x8fv\xa5\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x08nostarch\x03com\x00\x00\x01\x00\x01', ('192.168.1.6', 0))
解码IP层
创建python文件(sniffer_ip_header_decode.py)
注意:有一处需要修改,host的赋值改为自己运行机器的ip地址
import socket
import os
import struct
from ctypes import *
#监听的主机
host = "192.168.107.234"
#IP头定义
class IP(Structure):
_fields_ = [
("ihl",c_ubyte,4),
("version",c_ubyte,4),
("tos",c_ubyte),
("len",c_ushort),
("id",c_ushort),
("offset",c_ushort),
("ttl",c_ubyte),
("protocol_num",c_ubyte),
("sum",c_ushort),
("src",c_ulong),
("dst",c_ulong)
]
def __new__(self,socket_buffer=None):
return self.from_buffer_copy(socket_buffer)
def __init__(self,socket_buffer=None):
#协议字段与协议名称对应
self.protocol_map = {1:"ICMP", 6:"TCP", 17:"UDP"}
#可读性更强的IP地址
self.src_address = socket.inet_ntoa(struct.pack("<L",self.src))
self.dst_address = socket.inet_ntoa(struct.pack("<L",self.dst))
#协议类型
try:
self.protocol = self.protocol_map[self.protocol_num]
except:
self.protocol = str(self.protocol_num)
#下面的代码类似于之前的例子
if os.name == "nt":
socket_protocol = socket.IPPROTO_IP
else:
socket_protocol = socket.IPPROTO_ICMP
sniffer = socket.socket(socket.AF_INET,socket.SOCK_RAW,socket_protocol)
sniffer.bind((host,0))
sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
if os.name == "nt":
sniffer.ioctl(socket.SIO_RCVALL,socket.RCVALL_ON)
try:
while True:
#读取数据包
raw_buffer = sniffer.recvfrom(65565)[0]
#将缓存区的前20个字节按IP头进行解析
ip_header = IP(raw_buffer[0:20])
#输出协议和通信双方IP地址
print("Protocol: %s %s -> %s" % (ip_header.protocol, ip_header.src_address,ip_header.dst_address))
#处理CTRL-C
except KeyboardInterrupt:
#如果运行在Windows上,关闭混杂模式
if os.name == "nt":
sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
运行以及运行结果如下:
可以使用Windows运行,也可以使用虚拟机运行。如上图是我使用windows运行的结果。
如若出现以下错误,请使用管理员身份打开命令提示符:
PS C:\Users\abc23\PycharmProjects\pythonProject2> python 7.19.py
Traceback (most recent call last):
File "7.19.py", line 75, in <module>
sniffer = socket.socket(socket.AF_INET,socket.SOCK_RAW,socket_protocol)
File "C:\Program Files\Python37\lib\socket.py", line 151, in __init__
_socket.socket.__init__(self, family, type, proto, fileno)
OSError: [WinError 10013] 以一种访问权限不允许的方式做了一个访问套接字的尝试。
在搜索行输入“cmd”即可,点击“以管理员身份运行”: