现在总算琢磨出点道道了,还是很有意思的,现在分析一下如何解析scapy获取的网络数据包
以获取DNS解析为例,DNS服务器为192.168.1.1,获取www.baidu.com的IP地址
创建一个DNS请求包
>>> dns=DNS(rd=1,qd=DNSQR(qname='www.baidu.com')) #设置递归查询请求,并且查询域名www.baidu.com
>>> sr1(IP(dst='192.168.1.1')/UDP()/dns)
Begin emission:
.........Finished to send 1 packets.
....*
Received 14 packets, got 1 answers, remaining 0 packets
<IP version=4L ihl=5L tos=0x0 len=118 id=51445 flags= frag=0L ttl=60 proto=udp chksum=0x31c8 src=192.168.1.1 dst=192.168.1.104 options=[] |<UDP sport=domain dport=domain len=98 chksum=0xe264 |<DNS id=0 qr=1L opcode=QUERY aa=0L tc=0L rd=1L ra=1L z=0L rcode=ok qdcount=1 ancount=3 nscount=0 arcount=0 qd=<DNSQR qname='www.baidu.com.' qtype=A qclass=IN |> an=<DNSRR rrname='www.baidu.com.' type=CNAME rclass=IN ttl=407 rdata='www.a.shifen.com.' |<DNSRR rrname='www.a.shifen.com.' type=A rclass=IN ttl=406 rdata='61.135.169.105' |<DNSRR rrname='www.a.shifen.com.' type=A rclass=IN ttl=406 rdata='61.135.169.125' |>>> ns=None ar=None |>>>
>>> p=_
可以看出,已经返回了DNS应答,将应答包赋值给了p
具体DNS请求的结构可以看看p.show()
>>> p[DNS].show()
###[ DNS ]###
id= 0
qr= 1L #设置为1表示是DNS应答,如果设置为0表示请求
opcode= QUERY
aa= 0L
tc= 0L
rd= 1L #还记得设置的rd=1么?如果不希望递归查询,就设置为0
ra= 1L
z= 0L
rcode= ok
qdcount= 1
ancount= 3
nscount= 0
arcount= 0
qd
|###[ DNS Question Record ]###
| qname= 'www.baidu.com.' #进行DNS解析请求,这个是必须的
| qtype= A
| qclass= IN
an
|###[ DNS Resource Record ]###
| rrname= 'www.baidu.com.'
| type= CNAME
| rclass= IN
| ttl= 407
| rdlen= 18
| rdata= 'www.a.shifen.com.'
|###[ DNS Resource Record ]###
| rrname= 'www.a.shifen.com.'
| type= A
| rclass= IN
| ttl= 406
| rdlen= 4
| rdata= '61.135.169.105'
|###[ DNS Resource Record ]###
| rrname= 'www.a.shifen.com.'
| type= A
| rclass= IN
| ttl= 406
| rdlen= 4
| rdata= '61.135.169.125'
ns= None
ar= None
层次结构非常清楚,从这里也可以看出一个DNS应答包的封装格式,关于DNS报文的格式与类型,可以参看RFC文档,也可以参考这里的文章
http://lcx.cc/?FoxNews=1247.html
原来比较困惑的是递归查询与迭代查询,在DNS应答包里面显示的非常清楚,就看ra字段就ok了,如果ra=1,那么DNS服务器支持递归查询,ra=0就表示不支持递归查询。非常方便,还有rd=1的话,表示建议DNS服务器进行递归解析。
这样的话,就得到了包含DNS应答的数据包,储存在p里面
如果在脚本里面,需要对DNS应答包进行判断,如果包含DNS层,那么表示DNS应答是有效的,可以使用haslayer()方法
p.haslayer(DNS)
>>> p.haslayer(DNS)
1
返回值为1,表示有DNS数据层,那么定位p数据包中的DNS,使用getlayer()方法
answer=p.getlayer(DNS)
显示answer
>>> answer
<DNS id=0 qr=1L opcode=QUERY aa=0L tc=0L rd=1L ra=1L z=0L rcode=ok qdcount=1 ancount=3 nscount=0 arcount=0 qd=<DNSQR qname='www.baidu.com.' qtype=A qclass=IN |> an=<DNSRR rrname='www.baidu.com.' type=CNAME rclass=IN ttl=407 rdata='www.a.shifen.com.' |<DNSRR rrname='www.a.shifen.com.' type=A rclass=IN ttl=406 rdata='61.135.169.105' |<DNSRR rrname='www.a.shifen.com.' type=A rclass=IN ttl=406 rdata='61.135.169.125' |>>> ns=None ar=None |>
由于百度的域名解析给出了3个结果,这个可以从ancount=3知道,而且有的解析结果还是CNAME格式的,也就是别名,真正的域名解析是A记录,所以通过判断语句筛选一下
if p.haslayer(DNS):
answer=p.getlayer(DNS)
for x in range(answer.ancount):
if answer.an[x].type==1: #排除CNAME类型,只要A类型,在DNS中,CNAME=5,A=1
answer.an[x].rdata #这里可以使用变量储存解析到的IP地址
这样就获取到了DNS应答给出的IP地址,里面还有很多有意义的信息,就不多解释了,可以参看关于DNS应答包结构的文章
其实,在Scapy中,还有很多有意思的属性或方法,在不同的对象下,有不同的属性
输入p的
>>> p.
p.add_payload p.chksum p.dissect p.extract_padding p.get_field p.id p.name p.post_build p.route p.summary
p.add_underlayer p.clone_with p.dissection_done p.fields p.getfield_and_val p.ihl p.options p.post_dissect p.send p.time
p.aliastypes p.command p.do_build p.fields_desc p.getfieldval p.init_fields p.ottl p.post_dissection p.sent_time p.tos
p.answers p.copy p.do_build_ps p.fieldtype p.getlayer p.initialized p.overload_fields p.post_transforms p.setfieldval p.ttl
p.build p.decode_payload_as p.do_dissect p.firstlayer p.guess_payload_class p.lastlayer p.overloaded_fields p.pre_dissect p.show p.underlayer
p.build_done p.default_fields p.do_dissect_payload p.flags p.hashret p.len p.packetfields p.proto p.show2 p.upper_bonds
p.build_payload p.default_payload_class p.do_init_fields p.frag p.haslayer p.libnet p.payload p.psdump p.show_indent p.version
p.build_ps p.delfieldval p.dst p.fragment p.hide_defaults p.lower_bonds p.payload_guess p.remove_payload p.sprintf p.whois
p.canvas_dump p.display p.explicit p.from_hexcap p.hops p.mysummary p.pdfdump p.remove_underlayer p.src
输入answer的
>>> answer.
answer.aa answer.build_ps answer.do_build answer.from_hexcap answer.lastlayer answer.payload_guess answer.rcode answer.tc
answer.add_payload answer.canvas_dump answer.do_build_ps answer.get_field answer.libnet answer.pdfdump answer.rd answer.time
answer.add_underlayer answer.clone_with answer.do_dissect answer.getfield_and_val answer.lower_bonds answer.post_build answer.remove_payload answer.underlayer
answer.aliastypes answer.command answer.do_dissect_payload answer.getfieldval answer.mysummary answer.post_dissect answer.remove_underlayer answer.upper_bonds
answer.an answer.copy answer.do_init_fields answer.getlayer answer.name answer.post_dissection answer.route answer.z
answer.ancount answer.decode_payload_as answer.explicit answer.guess_payload_class answer.ns answer.post_transforms answer.sent_time
answer.answers answer.default_fields answer.extract_padding answer.hashret answer.nscount answer.pre_dissect answer.setfieldval
answer.ar answer.default_payload_class answer.fields answer.haslayer answer.opcode answer.psdump answer.show
answer.arcount answer.delfieldval answer.fields_desc answer.hide_defaults answer.overload_fields answer.qd answer.show2
answer.build answer.display answer.fieldtype answer.id answer.overloaded_fields answer.qdcount answer.show_indent
answer.build_done answer.dissect answer.firstlayer answer.init_fields answer.packetfields answer.qr answer.sprintf
answer.build_payload answer.dissection_done answer.fragment answer.initialized answer.payload answer.ra answer.summary
输入answer.an的 #answer.an是DNS层的回答,包含域名解析信息
>>> answer.an.
answer.an.add_payload answer.an.command answer.an.do_build_ps answer.an.fragment answer.an.init_fields answer.an.payload answer.an.rdata answer.an.show_indent
answer.an.add_underlayer answer.an.copy answer.an.do_dissect answer.an.from_hexcap answer.an.initialized answer.an.payload_guess answer.an.rdlen answer.an.sprintf
answer.an.aliastypes answer.an.decode_payload_as answer.an.do_dissect_payload answer.an.get_field answer.an.lastlayer answer.an.pdfdump answer.an.remove_payload answer.an.summary
answer.an.answers answer.an.default_fields answer.an.do_init_fields answer.an.getfield_and_val answer.an.libnet answer.an.post_build answer.an.remove_underlayer answer.an.time
answer.an.build answer.an.default_payload_class answer.an.explicit answer.an.getfieldval answer.an.lower_bonds answer.an.post_dissect answer.an.route answer.an.ttl
answer.an.build_done answer.an.delfieldval answer.an.extract_padding answer.an.getlayer answer.an.mysummary answer.an.post_dissection answer.an.rrname answer.an.type
answer.an.build_payload answer.an.display answer.an.fields answer.an.guess_payload_class answer.an.name answer.an.post_transforms answer.an.sent_time answer.an.underlayer
answer.an.build_ps answer.an.dissect answer.an.fields_desc answer.an.hashret answer.an.overload_fields answer.an.pre_dissect answer.an.setfieldval answer.an.upper_bonds
answer.an.canvas_dump answer.an.dissection_done answer.an.fieldtype answer.an.haslayer answer.an.overloaded_fields answer.an.psdump answer.an.show
answer.an.clone_with answer.an.do_build answer.an.firstlayer answer.an.hide_defaults answer.an.packetfields answer.an.rclass answer.an.show2