py黑帽子学习笔记_网络嗅探器

编写基于udp的主机发现工具

目的:发现一个网络内有多少存活主机

原理:如果目标主机udp口没开一般会返回一个icmp响应,收到这个响应则表明目标主机存活。如果开udp口了则可能无响应,无法判断主机是否存活。选udp是开销较小

setsocket是抓包时包含包的IP头

当判断是windows系统时,会开闭网卡混杂模式,通过socket.ioctl方法实现开闭

验证效果如下图,先开一个窗口执行该脚本,则机器作为服务器运行,在其他窗口ping这个机器,服务器会打印详细信息

查看ip层

抓包的ip头是编码过的,无法直接看出其含义,可通过解码查看ip头具体信息

ip头为二进制,ip头是有结构的,解码需要解码对应的数据结构,具体 可通过py的ctypes或struct等库实现

典型ipv4头结构:

ctypes

struct

struct.unpack用了<BBHHHBBH4s4s,其中B表示1字节(unsigned char),H表示2字节(unsigned short),s表示字节数组,用s时前面需要带上数字,比如4s表示长度为4的字节数组

self.ver版本向后位移是因为ip头用struct映射为ver在一个字节的高四位,需要往后移四位

self.ihl与0xF与运算是为了消除一个字节八位里高四位的版本信息

icmp不需要这样的位运算,是因为icmp头信息长度基本是8的倍数,无需位运算

编写IP解码器

class为struct的类,后面的代码如下

raw_buffer[:20]是因为ip头默认参数长度为20Bytes

在虚机上执行脚本看下效果,在windows上ping虚机ip

发现只打印了ICMP信息,再看下windows侧执行脚本

小结

socket.socket

第二个参数为socket type,默认socket.SOCK_STREAM,文档写了,常用socket.SOCK_STREAM和socket.SOCK_DGRAM

socket — Low-level networking interface — Python 3.12.3 documentation

socket.socket.setsockopt

socket.socket.setsockopt为在某个level设置option的值为value

这个应该表示在socket.IPPROTO_IP level设置是否使用原始套接字为1(True),表示使用自定义IP头

socket.socket.ioctl

解码ICMP

注意到sniff函数多了对icmp头的判断,是通过ip头的协议类型判断是否icmp类型,然后通过字节位移获取icmp头部信息,此处逻辑可能为发icmp包先装icmp头,再在icmp头前面装ip头,所以获取icmp头时需要加上ip头的位移。ip头表示IP头长度的ihl(internet header length)单位为32比特,即4字节,需要乘以4,ihl用4位二进制表示。获取到icmp头后,用struct映射数据结构。那为什么获取ip头直接取前20个字节?因为前20个是必选参数,估计可选参数会占用一些空间,用ihl计算icmp位移估计是把ip头可选参数跳过算得准

进行校验,在虚机运行脚本,然后在宿主机ping虚机ip

给上面代码添加子网群发udp代码:

main函数中初始化scanner时,创建了server端监听socket

udp_sender中创建socket给子网内所有主机发消息,注意ipaddress.ip_network(subnet).hosts()是拼写出来的子网的所有主机,比如给ip_network方法传入的subnet参数是192.168.99.1/24,返回的结果是192.168.99.1, 192.168.99.2, 192.168.99.3, ...,254个ip地址,即子网下所有的主机地址。socket创建后通过socket发消息,调用socket的sendto方法,不需要显式连接目标ip,直接将目标ip作为参数传入sendto方法即可

嗅探逻辑为通过子网里的一个主机给子网所有ip地址发消息,如果主机活着会发一个icmp响应,这个响应的源ip地址即为活着的主机ip,看下效果

发现探测到子网内只有我们一个虚机就是运行脚本的虚机

注意给ipaddress.ip_network传入子网参数时,子网后面的位数一定要是0,不然报错

小结

socket.socket.sendto

其他

socket.recvfrom返回的是字节数组

socket.recvfrom返回的报文的数据在报文最末尾

可通过python库ipaddress判断某子网内是否有某个主机ip:ipaddress.ip_address(ipaddr) in ipaddress.IPv4Network(subnet_addr)

socket发udp时,仅需要在发数据时传入目标ip地址,不需要socket.connect,只有两步1初始化socket2调socket.sendto方法发udp请求,如果发tcp的话需要socket.connect其他和udp都一样

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值