最近经历了Twisted的打击,这个网络编程实在看不懂,都摸不透它的内在逻辑,看来网络编程不是那么好弄的。还好,看到了scapy,这种网络的大杀器,让我一看就爱不释手,这才是我需要的网络工具啊。Scapy的功能如此之多,以至于。。。我到现在还是没看懂。在官方网站也介绍的不多,后来搜了一下,有一本书Security
Power
Tools一书中,第六章介绍了Scapy,虽然简单,但是还是不明白,这两天一直在忙活着看Scapy。看了几个应用,比较不错的有几个
1。扫描局域网内的客户机,将IP与MAC地址列出来
2。找DHCP服务器,列出IP与MAC地址
3。DNS解析
Scapy的强大之处就是它的自由度啊,可以自己封装一个网络包,然后发出去,包的内容自己定义,自由度太大了,现在才明白了OSI七层结构跟TCP/IP结构啊。真是受益匪浅。对包的结构涉及很深,对包的结构有很高的要求,反正我也看不懂,只是用来解决一些实际的问题。
Scapy的安装很简单,看官网的安装就可以
安装完成后,先去下载一个OSI七层结构图,以作参考
对照这张图,可以快速定位一些七层应用的底层协议,非常方便,因为Scapy就是按照这个结构组织包的
进入Scapy后,先记住两个常用的命令
ls()与lsc()
ls()是显示Scapy中的类与函数的
lsc()是显示Scapy中的方法,例如发3层包的方法send()与发送2层包的方法sendp()
非常有用
操作Scapy第一步是首先封装一个包,这个包可以自己选择在哪一层,具体可以使用ls()查看,例如,设置一个IP层的包,如果不做其它的设定,Scapy会按照默认值封装其它层的包
一个简单的TCP包
IP()/TCP()
>>>
IP()/TCP()
|
|>>
一个有效的TCP/IP包应该在IP层包括目标IP地址,那么可以这么设置
>>>
a=IP()/TCP()
>>> a.dst
'127.0.0.1'
>>>
a.dst='www.baidu.com'
在IP包设置完目的地址后,还需要在TCP包中的目的端口,否则是目的地的端口没有开,是不会返回应答包的,这就要涉及到TCP建立联系的三次握手,这三次握手分别是发送SYN,远端回复SYN-ACK,本地发送ACK,可以通过ls(TCP())来查看具体的标识
>>>
TCP().show()
###[ TCP ]###
sport= ftp_data
dport= http
seq= 0
ack= 0
dataofs= None
reserved= 0
flags= S
window= 8192
chksum= None
urgptr= 0
options= {}
查看这个包的目的端口
>>> a.dport
80
这是默认值,通过a.dport=num来设置
TCP可设置的东西很多,可以查看TCP包头的具体参数,在Scapy中,这个都有默认值。
建立好一个简单的包后,就需要发送了,发送的方法可以使用lsc()查看,一般发送用send(),发送接收用sr(),发送一次用sr1()
把建立好的包a发送出去,并接收目的地发送的返回包
>>> sr(a)
......Begin emission:
........Finished to send 1 packets.
...*
Received 18 packets, got 1 answers, remaining 0 packets
(
Other:0>,
ICMP:0 Other:0>)
结果分为两部分,一部分为发送的包与应答包,一部分为没有应答的包,所以在Scapy中,一般用
ans,unans分别调用不同的值,ans与unans都是自定义的变量,可以使用任何值
ans,unans=_ (_在python中代表上一次运行的结果,比较好用,是最近才发现的)
主要研究返回的包
>>> ans
Other:0>
可以看出,返回了一个TCP包
>>> len(ans)
1
ans是以列表的形式返回的,所以可以使用标号来访问
>>> ans[0]
(
dst=61.135.169.125 |
|>>,
len=44 id=1 flags= frag=0L ttl=54 proto=tcp chksum=0xdbb6
src=61.135.169.125 dst=192.168.1.104 options=[]
|
seq=2140061027 ack=1 dataofs=6L reserved=0L flags=SA window=8192
chksum=0x91be urgptr=0 options=[('MSS', 1440)]
|
|>>>)
这个包清晰的表明了层次结构,最左面的是IP包,
dst=61.135.169.125 |
|>>
逗号后面的是TCP包,就到TCP层,木有别的数据
光有这些不好用,如果scapy就这功能的话,还不如nmap好使,脚本比命令的最大优势就是对数据的操作能力,在python中,返回的可都是对象。所以可以对返回的结果进行筛选,还记得TCP()所显示的内容么?里面可都是对象的属性,例如TCP的窗口windows,要是显示的话,可以这么做
>>>
ans[0][1][TCP]
seq=2140061027 ack=1 dataofs=6L reserved=0L flags=SA window=8192
chksum=0x91be urgptr=0 options=[('MSS', 1440)]
|
|>>
>>>
ans[0][1][TCP].window
8192
都是层次化的结构,可是这些包并不是固定的数据结构,如果TCP包很多(这很正常),那么如何去定位呢?
这就要用到scapy里面有用的工具sprintf()了,这个工具可以对包中的每个层的数据进行格式化,以层的名称与层的字段显示数据,要理解这个,先要看看ans对象的内容
在得到回答的包集合ans中,有两部分包,一个是发送的数据包,一个是收到的数据包,在python中,可以这么表示
for snd,rcv in ans:
如果只分析接收到的包,那么只要关注rcv就可以,snd是发送的包
res=rcv.sprintf(‘%IP.src%:%TCP.sport%’)
对于ans包含多个包的情况,最好建立空列表,在循环中,将生成的res附加到空列表中
collect=[]
collect.append(res)
在sprintd()中,%IP%是接收到的包rcv的IP层,%TCP%是rcv的TCP层,看rcv的结构就一目了然了
>>> ans[0][1]
len=44 id=1 flags= frag=0L ttl=55 proto=tcp chksum=0xdaca
src=61.135.169.105 dst=192.168.1.104 options=[]
|
seq=3054601323 ack=1 dataofs=6L reserved=0L flags=SA window=8192
chksum=0x9447 urgptr=0 options=[('MSS', 1440)]
|
|>>>
那调用其中的字段,就直接用字段名就ok了,例如,需要返回的包rcv中,IP层的src字段,也就是远端服务器的IP地址,就用%IP.src%来表示,远端服务器的源端口就用sport来显示,综合起来就是
conf.verb=0 (这个找了半天,不知道干嘛用的,只是看到别人都是这么写的)
collect=[]
for snd,rcv in ans:
res=rcv.sprintf(‘%IP.src%:%TCP.sport%’)
collect.append(res)
这样就会只显示这个HTTP服务器的IP地址与端口号,非常的方便,这种方法还可以用在对局域网内的机器进行扫描,显示可以对ARP进行应答的机器IP地址与MAC地址,通过python的socket模块,还可以显示机器名,就相当于完成了局域网内的机器扫描。哇靠,非常简单
对接收包的数据检索,还有一种方法,个人感觉非常简洁,就是使用lambda表达式
ans.summary(lambda(s,r):r.sprinf(‘%IP.src%:%TCP.sport%’))
简洁的语句,非常喜欢
如果稍微改进一下,对生成的包进行定义,并定义IP()的src与dst,TCP()中的dport,对结果进行判断,就可以完成端口扫描的工作,特么的原来端口扫描就是这样
理解了这点,就可以做很多事情了,例如在网中有未经授权DHCP服务器,就可以找出它的MAC地址,进行追踪。准备写一下如何追踪DHCP,或者端口扫描。