Python UDP DNS到TCP DNS转换器

时间:2017-09-27 16:53:20

标签: python dns scapy

我正在尝试使用NFQUEUE和Scapy将任何UDP DNS请求转换为TCP DNS请求,然后使用基于TCP DNS共振的精心制作的UDP数据包响应UDP DNS请求。这是我到目前为止写的脚本:

#! /usr/bin/env python2.7
from scapy.all import *
from netfilterqueue import NetfilterQueue
import os
import dns.resolver

myResolver = dns.resolver.Resolver()

def resolv_dns(payload):
    udp_query_pkt = IP(payload.get_payload())
    domain =  udp_query_pkt[DNS].qd.qname
    ip_addrs = myResolver.query(domain, "A", tcp=True) 

    if not udp_query_pkt.haslayer(DNSQR):
        payload.set_verdict(nfqueue.NF_ACCEPT)
    else:
        if domain in udp_query_pkt[DNS].qd.qname:
            print str(ip_addrs[0])
            udp_resp_pkt = IP(dst=udp_query_pkt[IP].src, src=udp_query_pkt[IP].dst)/\
                          UDP(dport=udp_query_pkt[UDP].sport, sport=udp_query_pkt[UDP].dport)/\
                          DNS(id=udp_query_pkt[DNS].id, qr=1, aa=1, qd=udp_query_pkt[DNS].qd,\
                          an=DNSRR(rrname=udp_query_pkt[DNS].qd.qname, ttl=10, rdata=str(ip_addrs[0])))
            send(udp_resp_pkt)
            payload.drop()

nfqueue = NetfilterQueue()
nfqueue.bind(1, resolv_dns) 

try:
    os.system("iptables -A OUTPUT -p udp --dport 53 -j NFQUEUE --queue-num 1")
    print "[*] waiting for data"
    nfqueue.run()
except KeyboardInterrupt:
    os.system("iptables -D OUTPUT -p udp --dport 53 -j NFQUEUE --queue-num 1")
    pass

脚本的问题是它不起作用!

实际上我可以在wireshark中看到相应的DNS数据包,看起来没问题: enter image description here

但我无法打开任何网站!实际上UDP DNS请求超时了:

ebrahim@ebrahim:~$ dig www.xyw.com

; <<>> DiG 9.10.3-P4-Ubuntu <<>> www.xyw.com
;; global options: +cmd
;; connection timed out; no servers could be reached

怎么了?

更新

在@Pierre的回答之后,我更改了IPTable规则,将收到的UDP DNS响应发送到NFQUEUE(而不是发送DNS查询)然后我修改了resolv_dns函数如下(替换UDP中的IP地址)使用TCP DNS查询收到的新IP地址的DNS响应:

def resolv_dns(packet):
    pkt = IP(packet.get_payload())
    domain =  pkt[DNS].qd.qname
    ip_addrs = myResolver.query(domain, "A", tcp=True)
    pkt[DNS].an.rdata = str(ip_addrs[0])
    packet.set_payload(str(pkt))
    packet.accept()

但它仍然不起作用!

1 个答案:

答案 0 :(得分:1)

如果您的盒子是路由器拦截转发的数据包,您的脚本可能会有效。但由于您使用的是OUTPUT链,我认为截获的数据包来自本地主机。在这种情况下,我认为原始客户永远不会得到您的伪造答案。

在我看来,你最好的选择是

  • 编写一个UDP服务器,例如,它将侦听127.0.0.1:5300,它将读取DNS查询(您仍然可以使用Scapy,使用DNS(data_from_client)执行此操作),解决它(使用TCP,如你的脚本确实如此),并发送响应(同样,你可以从你的脚本发送使用DNS()调用创建的数据。)
  • 使用iptables,但不是拦截NFQUEUE目标的传出数据包,只需DNAT将它们发送到您的服务器(类似iptables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to 127.0.0.1:5300)。

更新:我不知道为什么你坚持使用NFQUEUE而不是使用DNAT的简单UDP服务器(让你的IP堆栈和netfilter完成这项工作) ,因为这可能是你想做的最好的方式,但你可能有充分的理由。请注意,根据您提出的第二个解决方案,您必须从DNS服务器获得响应才能使您的脚本正常工作(因此您必须拥有可用且可访问的UDP DNS解析器)。

在第二次尝试中,您修改UDP数据,因此您必须再次计算IP&amp; UDP校验和和长度字段(使用服务器+ DNAT解决方案,您的内核将完成该工作)。您可以使用del pkt[IP].chksum, pkt[IP].len, pkt[UDP].chksum, pkt[UDP].len执行此操作(Scapy将为您计算正确的值)。