聚焦源代码安全,网罗国内外最新资讯!
编译:奇安信代码卫士
该漏洞影响早于 9.11.31 和9.16.15 之前的 BIND 版本,可遭远程触发且无需认证,可导致在堆内存上的界外 (OOB) 读取并将信息泄露给远程攻击者。攻击者还可能利用该漏洞和之前提交的漏洞在受影响 BIND 服务器上执行任意代码。
产生该漏洞的根因在于 der_match_tag_and_length() 函数,用于匹配标记并从网络包中获得如下的长度字段。从 BIND 中 der_get_length() 的正常用途来看,解析的长度字段 length_ret 应该被调用程序进行验证。然而, der_match_tag_and_length() 是例外之一。
static intder_match_tag_and_length(const unsigned char *p, size_t len, Der_class xclass,Der_type type, int tag, size_t *length_ret,size_t *size) {size_t l, ret = 0;int e;e = der_match_tag(p, len, xclass, type, tag, &l);if (e) {return (e);}p += l;len -= l;ret += l;e = der_get_length(p, len, length_ret, &l); // (1)if (e) {return (e);}/* p += l; */len -= l;POST(len);ret += l;if (size) {*size = ret;}return (0);}
位于 (1)处的length_ret 是受控的且并未得到验证。来看下 der_match_tag_and_length() 的调用程序之一:
OM_uint32gss_accept_sec_context_spnego(...){// ...ret = der_match_tag_and_length(buf, buf_size, ASN1_C_CONTEXT, CONS, 0,&len, &taglen);if (ret) {return (ret);}ret = decode_NegTokenInit(buf + taglen, len, &init_token, &ni_len); // (2)// ...}
不可信的 len 之后用于解码位于 (2) 处的 negTokenInit。Decode_NegTokenInit() 中的很多检查都基于 len。当前这些检查是不正确的,可导致在不同子字段(如mechTypes、reqFlags、mechToken等)上的 OOB 访问权限。
用于复现该 bug 的配置和第一个 bug 一样。如下截屏是为该 bug 构造的 SPNEGO 请求。

位于 (1) 处的 length_ret 从偏移量 0xa5 as 0x91929394 受控。子字段 mechToken 是一个十进制字符串,它的长度是构造的值 0x727374,出现在偏离量 0xcd 处。
收到这个构造的请求后,在处理字段 mechToken 过程中触发 OOB。如下调用栈基于 BIND 版本 9.16.13。
#0 __memmove_avx_unaligned_erms at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:494#1 der_get_octet_string at spnego.c:830#2 decode_octet_string at spnego.c:1015#3 decode_NegTokenInit at spnego_asn1.c:607#4 gss_accept_sec_context_spnego at spnego.c:593#5 dst_gssapi_acceptctx at gssapictx.c:730#6 process_gsstkey at tkey.c:551#7 dns_tkey_processquery at tkey.c:882#8 ns_query_start at query.c:11653#9 ns__client_request at client.c:2169#10 isc__nm_async_readcb at netmgr.c:1861#11 isc__nm_readcb at netmgr.c:1836#12 processbuffer at tcpdns.c:997#13 process_sock_buffer at tcpdns.c:1639#14 read_cb at tcpdns.c:1060...
在受影响服务器上造成数据泄露的方法可能如下。
OM_uint32gss_accept_sec_context_spnego(...){// ...ret = decode_NegTokenInit(buf + taglen, len, &init_token, &ni_len);if (ret) {*minor_status = EINVAL; /* XXX */return (GSS_S_DEFECTIVE_TOKEN);}for (i = 0; !found && i < init_token.mechTypes.len; ++i) { // (3)unsigned char mechbuf[17];size_t mech_len;ret = der_put_oid(mechbuf + sizeof(mechbuf) - 1,sizeof(mechbuf), &init_token.mechTypes.val[i],&mech_len);if (ret) {free_NegTokenInit(&init_token);return (GSS_S_DEFECTIVE_TOKEN);}if (mech_len == GSS_KRB5_MECH->length &&isc_safe_memequal(GSS_KRB5_MECH->elements,mechbuf + sizeof(mechbuf) - mech_len,mech_len)){found = 1;break;}if (mech_len == GSS_MSKRB5_MECH->length &&isc_safe_memequal(GSS_MSKRB5_MECH->elements,mechbuf + sizeof(mechbuf) - mech_len,mech_len)){found = 1;if (i == 0) {pref = GSS_MSKRB5_MECH;}break;}}if (!found) {free_NegTokenInit(&init_token);return (send_reject(minor_status, output_token)); // (5)}// ...ret = send_accept(&minor_status2, output_token, ot, pref); // (4)// ...}
Decode_NegTokenInit() 解析 negTokenInit 及其子字段后,(3) 处的循环在被解析的 mechTypes 过程中搜索有效的 OIDs。如找到合法的 OID,则服务器以在 (4) 处的接收信息响应。否则,服务器以位于 (5) 处的拒绝信息响应。这就使得我们能够为某些堆块获得偏移量。很有可能可以结合利用之前提交的对缓冲区溢出漏洞实施利用但需要更多的研究工作。
从版本9.16.15开始,SPNEGO 的 ISC 实现就从 BIND 9 源代码删除。BIND 9 当前总是使用系统 GSSAPI 库提供的 SPNEGO 实现。鉴于此,相关漏洞也别删除,这一功能变化也适用于版本9.1.1.31。
用户应当确保目前使用的是已修复 BIND 版本,因为很多 OS 发行版本提供的 BIND 包不同于官方发布的 ISC 发布版本。具体而言,某个发行版本常常会为 BIND 程序包选择稳定的基准版本,之后选择性地为他们认为应当包含的漏洞应用所选补丁。这样做的后果之一是,即使版本号不同(而且很可能)小于 ISC 已修复的版本号,但 BIND 中可能包含修复方案。
ISC BIND 是互联网上最流行的 DNS 服务器,其影响范围很大,尤其是在该漏洞可被远程触发且无需认证的情况下更是如此。建议所有用户尽快更新 DNS 服务器。这名匿名研究员还报告了存在于 TKEY 查询处理过程中的一个远程代码执行漏洞,最近也已被修复。
https://www.zerodayinitiative.com/blog/2021/6/15/zdi-21-502-an-information-disclosure-bug-in-isc-bind-server
题图:Pixabay License
本文由奇安信编译,不代表奇安信观点。转载请注明“转自奇安信代码卫士 https://codesafe.qianxin.com”。
奇安信代码卫士 (codesafe)
国内首个专注于软件开发安全的
产品线。
觉得不错,就点个 “在看” 或 "赞” 吧~

