Knot Resolver mishandles some cases when bad dns response packet is received
Hi,
When Knot Resolver iteratively queries the malicious domain name server, it returns some malformed dns packets, and dnsmasq returns the packet to the client without proper verification, which will give the user a distrust or malicious data. Other authoritative dns resolver have done correct verification.
There are two bugs below, you can start a fake domain name server locally and return specific data.
In order to easily reproduce these bugs, I turn off case randomlization by adding policy.add(policy.all(policy.FLAGS({'NO_0X20'})))
to the knot.conf
.
First Bug
Description
When the return answer type in the answer section dose not match the query class type, (for example, the query class type is 0x0001 and the return answer type is 0xdf01), the answer packet is forwarded to the client and the RCODE of the Knot Resolver return packet is 0.
Expected/Actual behavior
Bind and Pdns return the response packet with a RCODE of 2.
Steps to reproduce
1、Turn on a fake name server and return a specific payload.
https://643684107.oss-cn-beijing.aliyuncs.com/knot-test/dns_server.py
https://643684107.oss-cn-beijing.aliyuncs.com/knot-test/response1
The details of the response packet(response1) from the fake server are as follows:
+ HEADER
+ transaction, flags, questions, answers, authority, additional:
+ 38 CB 81 80 00 01 00 01 00 02 00 01
+
+ QUESTION
+ 06 63 65 72 74 30 31 07 65 78 61 6D 70 6C 65 00 00 25 00 01
+
+ ANSWER
+ C0 0C 00 25 DF 01 00 00 00 00 00 55
+ FF FE FF FF FE 33 11 5C 6F 2F 64 FF 2B DE 74 C7
+ D0 80 AC E1 1F 97 AB D0 CB BF BC 82 F3 E3 92 24
+ B2 47 1E 14 68 22 58 29 FF 1B 11 E1 6A 2E 95 02
+ E1 C0 A0 D5 33 E1 8A 14 D6 D5 5F 48 24 AA 41 89
+ FA FF FD 75 53 A3 65 77 CD 23 11 E0 BC 69 3A CE
+ F8 A2 A6 09 A6
+
+ AUTHORITY
+ C0 13 00 02 00 01 00 00 00 00 00 06
+ 03 6E 73 34 C0 13
+ C0 13 00 02 00 01 00 00 00 00 00 06
+ 03 6E 73 32 C0 13
+
+ ADDITIONAL
+ 00 00 29 10 00 00 00 00 00 00 00
Download them and run this script like so:
python3 dns_server.py response1
2、Start Knot Resolver.
The configuration options are as follows:
-- SPDX-License-Identifier: CC0-1.0
-- vim:syntax=lua:set ts=4 sw=4:
-- Refer to manual: https://knot-resolver.readthedocs.org/en/stable/
-- Network interface configuration
net.listen('127.0.0.1', 5555, { kind = 'dns' })
--net.listen('127.0.0.1', 853, { kind = 'tls' })
--net.listen('127.0.0.1', 443, { kind = 'doh2' })
--net.listen('::1', 53, { kind = 'dns', freebind = true })
--net.listen('::1', 853, { kind = 'tls', freebind = true })
--net.listen('::1', 443, { kind = 'doh2' })
-- Load useful modules
modules = {
'policy',
'view',
}
modules.unload('priming')
trust_anchors.remove('.')
log_level('debug')
-- Cache size
-- cache.size = 100 * MB
-- view:addr('127.0.0.1/8', function (req, qry) return policy.PASS end)
policy.add(policy.all(policy.FLAGS({'NO_0X20'})))
policy.add(policy.all(policy.FLAGS({'NO_CACHE'})))
policy.add(policy.all(policy.STUB({'127.0.0.1'})))
Then run like this:
./kresd -c knot.conf -n
3、Send the corresponding dns request.
https://643684107.oss-cn-beijing.aliyuncs.com/knot-test/dns_request.py
https://643684107.oss-cn-beijing.aliyuncs.com/knot-test/request1
The details of the request packet(request1) from client are as follows:
+ HEADER
+ transaction, flags, questions, answers, authority, additional:
+ 31 32 01 00 00 01 00 00 00 00 00 00
+
+ QUESTION
+ 06 63 65 72 74 30 31 07 65 78 61 6D 70 6C 65 00 00 25 00 01
+
+ ANSWER
+
+ AUTHORITY
+
+ ADDITIONAL
Download them and run this script like so:
python3 dns_request.py request1 5555
Second bug
Description
When Knot Resolver iteratively queries the malicious domain name server as a DNS forwarder, the domain name server returns some malformed dns packets, (for exameple, the Addtional RRS is 0x0001 but the number of records in the Addtional Records section is 2 ), and Knot Resolver returns a correctly formatted packet with a RCODE of 0 to the client.
Expected/Actual behavior
Bind and Pdns returns the response packet with a RCODE of 2.
According to RFC5625-6.3(https://datatracker.ietf.org/doc/html/rfc5625#section-6.3), when dns resolver receives malformed packet, it SHOULD synthesise a suitable DNS error(i.e., SERVFAIL) response to the client.
Steps to reproduce
1、Turn on a fake name server and return a specific payload.
https://643684107.oss-cn-beijing.aliyuncs.com/knot-test/dns_server.py
https://643684107.oss-cn-beijing.aliyuncs.com/knot-test/response3
The details of the response packet(response3) from the fake server are as follows:
+ 0000 31 32 81 80 00 01 00 00 00 02 00 01 06 63 65 72 .............cer
+ 0010 74 30 31 07 65 78 61 6D 70 6C 65 00 00 25 00 01 t01.example..%..
+ 0020 C0 0C 00 25 00 01 00 00 00 00 00 55 FF FE FF FF ...%.......U....
+ 0030 FE 33 11 5C 6F 2F 64 FF 2B DE 74 C7 D0 80 AC E1 .3.\o/d.+.t.....
+ 0040 1F 97 AB D0 CB BF BC 82 F3 E3 92 24 B2 47 1E 14 ...........$.G..
+ 0050 68 22 58 29 FF 1B 11 E1 6A 2E 95 02 E1 C0 A0 D5 h"X)....j.......
+ 0060 33 E1 8A 14 D6 D5 5F 48 24 AA 41 89 FA FF FD 75 3....._H$.A....u
+ 0070 53 A3 65 77 CD 23 11 E0 BC 69 3A CE F8 A2 A6 09 S.ew.#...i:.....
+ 0080 A6 C0 13 00 02 00 01 00 00 00 00 00 06 03 6E 73 ..............ns
+ 0090 34 C0 13 C0 13 00 02 00 01 00 00 00 00 00 06 03 4...............
+ 00A0 6E 73 32 C0 13 00 00 29 10 00 00 00 00 00 00 00 ns2....)........
Download them and run this script like so:
python3 dns_server.py response3
2、Start Knot Resolver.
The configuration options are as follows:
-- SPDX-License-Identifier: CC0-1.0
-- vim:syntax=lua:set ts=4 sw=4:
-- Refer to manual: https://knot-resolver.readthedocs.org/en/stable/
-- Network interface configuration
net.listen('127.0.0.1', 5555, { kind = 'dns' })
--net.listen('127.0.0.1', 853, { kind = 'tls' })
--net.listen('127.0.0.1', 443, { kind = 'doh2' })
--net.listen('::1', 53, { kind = 'dns', freebind = true })
--net.listen('::1', 853, { kind = 'tls', freebind = true })
--net.listen('::1', 443, { kind = 'doh2' })
-- Load useful modules
modules = {
'policy',
'view',
}
modules.unload('priming')
trust_anchors.remove('.')
log_level('debug')
-- Cache size
-- cache.size = 100 * MB
-- view:addr('127.0.0.1/8', function (req, qry) return policy.PASS end)
policy.add(policy.all(policy.FLAGS({'NO_0X20'})))
policy.add(policy.all(policy.FLAGS({'NO_CACHE'})))
policy.add(policy.all(policy.STUB({'127.0.0.1'})))
Then run like this:
./kresd -c knot.conf -n
3、Send the corresponding dns request.
https://643684107.oss-cn-beijing.aliyuncs.com/knot-test/dns_request.py
https://643684107.oss-cn-beijing.aliyuncs.com/knot-test/request3
The details of the request packet(request1) from client are as follows:
+ HEADER
+ transaction, flags, questions, answers, authority, additional:
+ 31 32 81 80 00 01 00 00 00 02 00 00
+
+ QUESTION
+ 06 63 65 72 74 30 31 07 65 78 61 6D 70 6C 65 00 00 25 00 01
+
+ ANSWER
+
+ AUTHORITY
+ C0 0C 00 25 00 01 00 00 00 00 00 55
+ FF FE FF FF FE 33 11 5C 6F 2F 64 FF 2B DE 74 C7
+ D0 80 AC E1 1F 97 AB D0 CB BF BC 82 F3 E3 92 24
+ B2 47 1E 14 68 22 58 29 FF 1B 11 E1 6A 2E 95 02
+ E1 C0 A0 D5 33 E1 8A 14 D6 D5 5F 48 24 AA 41 89
+ FA FF FD 75 53 A3 65 77 CD 23 11 E0 BC 69 3A CE
+ F8 A2 A6 09 A6
+ C0 13 00 02 00 01 00 00 00 00 00 06
+ 03 6E 73 34 C0 13
+
+ ADDITIONAL
Download them and run this script like so:
python3 dns_request.py request3 5555
Thanks