[prev in list] [next in list] [prev in thread] [next in thread] 

List:       oss-security
Subject:    [oss-security] [CVE-2020-12667] Knot Resolver 5.1.1 NXNSAttack mitigation
From:       Petr Špaček <petr.spacek () nic ! cz>
Date:       2020-05-19 10:40:00
Message-ID: 07abfd99-f183-0dff-6de3-7f3f3ffd0c60 () nic ! cz
[Download RAW message or body]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

Hello,

Knot Resolver versions before 5.1.1 allows traffic amplification via
a crafted DNS answer from an attacker-controlled server, aka an "NXNSAttack" issue.

Minimal patch is attached but we generally do not recommend backporting.

Knot Resolver version 5.1.1 includes mitigation and is available from
https://www.knot-resolver.cz/download/

Longer description:
DNS protocol vulnerability NXNSAttack, combined with Insufficient
Control of Network Message Volume in iterator component of CZ.NIC Knot
Resolver version 5.1.0 or older allows remote attacker to amplify
network traffic towards victim's DNS servers via sending DNS query a
vulnerable resolver and sending specially crafted answer from
authoritative server under attacker's control.

This is DNS protocol vulnerability affecting basically all DNS
recursive resolvers. Other vendors requested separate CVE IDs for
mitigation in their products.

Further details:
https://en.blog.nic.cz/2020/05/19/nxnsattack-upgrade-resolvers-to-stop-new-kind-of-random-subdomain-attack/

Research paper:
Paper describing the attack by Lior Shafir, Yehuda Afek, Anat
Bremler-Barr is available from http://nxnsattack.com/

- -- 
Petr  paček  @  CZ.NIC

-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEvibrucvgWbORDKNbzo3WoaUKIeQFAl7Dt3gACgkQzo3WoaUK
IeQJRg/9H8H19V7ond79EwN1rElEy+Hf1mp1IOqRZfDs23q0eIjfAi1epDRRBSVl
wVp/OdQhE/qIcla/mNO1BvTAh9OwGk3QwMpoi6GuIIiSLcs/YRk8T3O3LTn0+sF1
7DUZc70HGICxdQmoja17Clv3mNz5GWkjuGJXyEuNZwVQa3A5hJrkfGz7vuTHXNmp
h0CG9LIhvyuaP6SOxcE3Zl4iNDqnMgdCv1047ijVgUgkrA2Of0vOkDCHCV9Ee1mF
4TMuhpMREyWqtaoDF7I3ush0MabkD2sixgTZQ0So7xhtPm33/d+z5iYYak65qtny
qT9zeLp8HzBW35TnG3eDUbuaEOtw/dmWX3LGJXvjxv2pWxiYlAWchT6vWqqrLC5a
4YJ06T4Yy3e4dsVkOi+ozV4MrRCWZQ/lj6rKRWvnbE9zkSSUsp7FXbpPlYpwHoIs
VEqkzhxtwceH0y3WlmdRgM/SrSUFe31CHJrA/W7mdkkNOQi0vM/Dxr0YmGnZJQHK
kfKkRklsk3at09h2tT/oK51mvyUQycV/dWlgBLkkN4u/PPe5rH5Sw308x74h/G4b
sBJ7W61yXeV1BvyNsiGyUMNAQOwZ8hGXnQlrgW7K4RGsi0b8KxuwmQ/nRWdFf/Gn
WXV6GdvF1S2IbHbqClZPKi3gt8exXd37K3YeIpPRX44gt82Rq8s=
=J8cL
-----END PGP SIGNATURE-----

["CVE-2020-12667.patch" (text/x-patch)]

diff --git a/daemon/lua/kres-gen.lua b/daemon/lua/kres-gen.lua
index 853d23d7..3f5cb779 100644
--- a/daemon/lua/kres-gen.lua
+++ b/daemon/lua/kres-gen.lua
@@ -193,6 +193,8 @@ struct kr_request {
 	int vars_ref;
 	knot_mm_t pool;
 	unsigned int uid;
+	unsigned int count_no_nsaddr;
+	unsigned int count_fail_row;
 };
 enum kr_rank {KR_RANK_INITIAL, KR_RANK_OMIT, KR_RANK_TRY, KR_RANK_INDET = 4, KR_RANK_BOGUS, \
KR_RANK_MISMATCH, KR_RANK_MISSING, KR_RANK_INSECURE, KR_RANK_AUTH = 16, KR_RANK_SECURE = 32};  \
                struct kr_cdb_stats {
diff --git a/lib/defines.h b/lib/defines.h
index b4ed5b58..be2d3a94 100644
--- a/lib/defines.h
+++ b/lib/defines.h
@@ -52,6 +52,8 @@ static inline int KR_COLD kr_error(int x) {
 #define KR_CNAME_CHAIN_LIMIT 13 /* Built-in maximum CNAME chain length */
 #define KR_TIMEOUT_LIMIT 4   /* Maximum number of retries after timeout. */
 #define KR_QUERY_NSRETRY_LIMIT 4 /* Maximum number of retries per query. */
+#define KR_COUNT_NO_NSADDR_LIMIT 5
+#define KR_CONSUME_FAIL_ROW_LIMIT 3 /* Maximum number of KR_STATE_FAIL in a row. */
 
 /*
  * Defines.
diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c
index 3d2a93cb..780e9d56 100644
--- a/lib/layer/iterate.c
+++ b/lib/layer/iterate.c
@@ -869,7 +869,8 @@ static int process_stub(knot_pkt_t *pkt, struct kr_request *req)
 }
 
 
-/** Error handling, RFC1034 5.3.3, 4d. */
+/** Error handling, RFC1034 5.3.3, 4d.
+ * NOTE: returing this does not prevent further queries (by itself). */
 static int resolve_error(knot_pkt_t *pkt, struct kr_request *req)
 {
 	return KR_STATE_FAIL;
diff --git a/lib/resolve.c b/lib/resolve.c
index fd67a3a6..3d7aacd6 100644
--- a/lib/resolve.c
+++ b/lib/resolve.c
@@ -299,10 +299,10 @@ static int ns_fetch_cut(struct kr_query *qry, const knot_dname_t \
*requested_name  return KR_STATE_PRODUCE;
 }
 
-static int ns_resolve_addr(struct kr_query *qry, struct kr_request *param)
+static int ns_resolve_addr(struct kr_query *qry, struct kr_request *req)
 {
-	struct kr_rplan *rplan = &param->rplan;
-	struct kr_context *ctx = param->ctx;
+	struct kr_rplan *rplan = &req->rplan;
+	struct kr_context *ctx = req->ctx;
 
 
 	/* Start NS queries from root, to avoid certain cases
@@ -333,7 +333,9 @@ static int ns_resolve_addr(struct kr_query *qry, struct kr_request *param)
 			return kr_error(EAGAIN);
 		}
 		/* No IPv4 nor IPv6, flag server as unusable. */
-		VERBOSE_MSG(qry, "=> unresolvable NS address, bailing out\n");
+		++req->count_no_nsaddr;
+		VERBOSE_MSG(qry, "=> unresolvable NS address, bailing out (counter: %u)\n",
+				req->count_no_nsaddr);
 		qry->ns.reputation |= KR_NS_NOIP4 | KR_NS_NOIP6;
 		kr_nsrep_update_rep(&qry->ns, qry->ns.reputation, ctx->cache_rep);
 		invalidate_ns(rplan, qry);
@@ -937,6 +939,23 @@ int kr_resolve_consume(struct kr_request *request, const struct sockaddr \
*src, k  qry->flags.RESOLVED = false;
 	}
 
+	/* For multiple errors in a row; invalidate_ns() is not enough. */
+	if (!qry->flags.CACHED) {
+		if (request->state & KR_STATE_FAIL) {
+			if (++request->count_fail_row > KR_CONSUME_FAIL_ROW_LIMIT) {
+				if (VERBOSE_STATUS || kr_log_rtrace_enabled(request)) {
+					kr_log_req(request, 0, 2, "resl",
+						"=> too many failures in a row, "
+						"bail out (mitigation for NXNSAttack "
+						"CVE-2020-12667)");
+				}
+				return KR_STATE_FAIL;
+			}
+		} else {
+			request->count_fail_row = 0;
+		}
+	}
+
 	/* Pop query if resolved. */
 	if (request->state == KR_STATE_YIELD) {
 		return KR_STATE_PRODUCE; /* Requery */
@@ -1396,6 +1415,11 @@ int kr_resolve_produce(struct kr_request *request, struct sockaddr \
**dst, int *t  
 ns_election:
 
+	if (unlikely(request->count_no_nsaddr >= KR_COUNT_NO_NSADDR_LIMIT)) {
+		VERBOSE_MSG(qry, "=> too many unresolvable NSs, bail out "
+				"(mitigation for NXNSAttack CVE-2020-12667)\n");
+		return KR_STATE_FAIL;
+	}
 	/* If the query has already selected a NS and is waiting for IPv4/IPv6 record,
 	 * elect best address only, otherwise elect a completely new NS.
 	 */
diff --git a/lib/resolve.h b/lib/resolve.h
index 1b339ff3..3a55fefe 100644
--- a/lib/resolve.h
+++ b/lib/resolve.h
@@ -227,6 +227,8 @@ struct kr_request {
 	int vars_ref; /**< Reference to per-request variable table. LUA_NOREF if not set. */
 	knot_mm_t pool;
 	unsigned int uid; /** for logging purposes only */
+	unsigned int count_no_nsaddr;
+	unsigned int count_fail_row;
 };
 
 /** Initializer for an array of *_selected. */


["CVE-2020-12667.patch.sig" (application/octet-stream)]

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic