2017-09-27 1 views
1

NFQUEUE와 Scapy를 사용하여 UDP DNS 요청을 TCP DNS 요청으로 변환 한 다음 TCP DNS resonance를 기반으로 만들어진 UDP 패킷으로 UDP DNS 요청에 응답하려고합니다. 이것은 내가 지금까지 쓴 스크립트입니다 :파이썬 UDP DNS에서 TCP 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 

스크립트의 문제는 작동하지 않는다는 것입니다!

사실 나는 와이어 샤크에서 correponding DNS 패킷을 볼 수 있고 괜찮아 보인다 enter image description here

을하지만 어떤 웹 사이트를 열 수 없습니다! 실제로 UDP DNS 요청 시간이 초과되었습니다 :

[email protected]:~$ dig www.xyw.com 

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

무엇이 잘못 되었습니까?


업데이트 :에 (피에르의 대답은, 내가 (대신 보낸 DNS 쿼리의)에 NFQUEUE에 수신 된 UDP의 DNS 응답을 보내도록 먼저, iptable 규칙을 변경 한 후 나는 다음과 같이 resolv_dns 기능을 수정

@ 후 UDP DNS 응답의 IP 주소를 TCP DNS 쿼리를 사용하여받은 새 IP 주소로 바꿉니다.) :

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

상자가 전달 된 패킷을 가로채는 라우터 인 경우 스크립트가 작동 할 것입니다. 하지만 OUTPUT 체인을 사용하고 있으므로 가로 채기 패킷이 로컬 호스트에서 왔다고 가정합니다. 이 경우, 나는 원래의 클라이언트가 절대로 당신의 위조 된 대답을 얻지 못할 것이라고 생각합니다. 제 생각에는

, 당신의 최선의 선택은

  • 에있는 DNS 쿼리를 읽을 것, 예를 들어 127.0.0.1:5300에서 수신 대기 것 UDP 서버를, 쓰기 (당신은 여전히 ​​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)을 사용하면됩니다.

업데이트 : 그게 아마 무엇을 할 수있는 가장 좋은 방법으로 난 당신이 (일을 할 당신의 IP 스택을시키는 & 넷 필터)를 오히려 DNAT 간단한 UDP 서버보다 NFQUEUE을 사용하여 주장 아무 생각이 왜 당신 하지만 당신은 아마 좋은 이유가 있습니다. 제안 된 두 번째 솔루션을 사용하려면 스크립트가 작동 할 수 있도록 DNS 서버에서 응답을 받아야합니다 (따라서 작동 가능한 UDP DNS 확인자가 있어야합니다).

두 번째 시도에서 UDP 데이터를 수정하므로 IP & UDP 체크섬 및 길이 필드를 다시 계산해야합니다 (서버 + DNAT 솔루션을 사용하면 커널이 해당 작업을 수행함). del pkt[IP].chksum, pkt[IP].len, pkt[UDP].chksum, pkt[UDP].len (Scapy가 올바른 값을 계산합니다)으로이 작업을 수행 할 수 있습니다.