日前,知名web服务器和反向代理服务器Nginx暴露严重漏洞NSresolverOff-by-Oneheapwrite漏洞,该漏洞存在于DNS解析模块Nginx的ngx_resolver_copy()。攻击者可以利用该漏洞进行远程DDos攻击,甚至远程执行。概述在处理DNS响应时,ngx_resolver_copy()中存在一个差一错误。通过利用此漏洞,网络攻击者可以在堆分配的缓冲区中写入点字符(.',0x2E)并使其超出范围。所有使用解析器语法配置的(resolverxxxx)Nginx实例都可以通过DNS响应(对来自Nginx的DNS请求的响应)触发漏洞。特制的数据包允许使用0x2E覆盖下一个堆块的元数据的最低有效字节。利用此漏洞的攻击者可以实现Ddos拒绝服务甚至远程代码执行。由于Nginx中缺乏DNS欺骗缓解措施以及在检查DNS事务ID之前调用易受攻击的函数,远程攻击者可以通过向中毒服务器注入中毒DNS响应来利用此漏洞。漏洞影响严重性评级:高漏洞向量:远程/DNS确认受影响版本:0.6.18-1.20.0确认修补版本:1.21.0、1.20.1供应商:F5,Inc.状态:公开CVE:CVE-2021-23017CWE:193CVSS分数:8.1CVSS向量:CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H/E:U/RL:O/RC:C漏洞分析当在Nginx配置中设置resolver时,使用NginxDNS解析器(core/ngx_resolver.c)通过DNS解析多个模块的主机名。DNS响应中包含的每个DNS域名都通过Nginx中的ngx_resolver_copy()调用进行验证和解压缩,它接收网络数据包作为输入和指向正在处理的名称的指针,并返回指向包含未压缩的新分配缓冲区的指针指向该区域的成功指针上的名称。调用整体分两步完成。计算未压缩域名大小的长度len,验证输入数据包的合法性。丢弃包含超过128个指针的域名或包含超出输入缓冲区边界的域名。分配一个输出缓冲区并将未压缩的域名复制到其中。part1的size计算和part2的未压缩域名不匹配导致一个len的off-by-one错误,导致一个dotcharacter允许以一个字节为单位写入name->the数据的边界。当压缩名称的最后部分包含指向NUL字节的指针时,会发生计算错误。虽然计算步骤只考虑标签之间的点,但解压步骤每处理一个标签都会写入一个点字符,并且后面的字符是非NUL。当label后跟一个指向NUL字节的指针时,解压过程会://1)copythelabeltotheoutputbuffer,ngx_strlow(dst,src,n);dst+=n;src+=n;//2)readnextcharacter,n=*src++;//3)asitsapointer,itsnotNUL,if(n!=0){//4)soadotcharacterthatwasnotaccountedforiswrittenoutofbounds*dst++='.';}//5)Afterwards,thepointerisfollowed,if(n&0xc0){n=((n&0x3f)<<8)+*src;src=&buf[n];n=*src++;}//6)andNULLbyteisfound,signalingtheendofthefunctionif(n==0){name->len=dst-name->data;returnNGX_OK;}如果计算与堆块大小完全对齐,超出范围的点字符将覆盖下一个堆块长度的元数据中的最低有效字节。这可能会直接导致写入下一个堆块的大小,而且还会覆盖3个标志,导致PREV_INUSE被清除并设置IS_MMAPPED。==7863==Invalidwriteofsize1==7863==at0x137C2E:ngx_resolver_copy(ngx_resolver.c:4018)==7863==by0x13D12B:ngx_resolver_process_a(ngx_resolver.c:2470)==7863==by0x13D12B:ngx_resolver_process_response4.cx:1response4.cx:1响应)==7863==by0x13D46A:ngx_resolver_udp_read(ngx_resolver.c:1574)==7863==by0x14AB19:ngx_epoll_process_events(ngx_epoll_module.c:901)==7863==by0x1414D4:ngx_process_events_and_timers(ngx_event=.c8:2437)==78:24=by0x148E57:ngx_worker_process_cycle(ngx_process_cycle.c:719)==7863==by0x1474DA:ngx_spawn_process(ngx_process.c:199)==7863==by0x1480A8:ngx_start_worker_processes(ngx_process_cycle.c:344)==7863==by0x149_52D:cyclengngx_process_cycle.c:130)==7863==by0x12237F:main(Nginx.c:383)==7863==Address0x4bbcfb8is0bytesafterablockofsize24alloc'd==7863==at0x483E77F:malloc(vg_replace_malloc.c:307)==7863==by0x1448C4:ngx_alloc(ngx_alloc.c:22)==7863==by0x137AE4:ngx_resolver_alloc(ngx_resolver.c:4119)==7863==by0x137B26:ngx_resolver_copy(ngx_resolver.c:3994)==7863==by0x13D12B:ngx_resolver_process_a(ngx_resolver.c:2470)==7863==by0x13D12B:ngx_resolver_process_response(ngx_resolver.c:1844)==7863==by0x13D46A(ngx_resolver.x_==7udp8_read653)==by0x14AB19:ngx_epoll_process_events(ngx_epoll_module.c:901)==7863==by0x1414D4:ngx_process_events_and_timers(ngx_event.c:247)==7863==by0x148E57:ngx_worker_process_cycle(ngx_process_cycle(139_process)==7(ngx_process_cycle(139_process)==7=4xprocess_process_da0x1)c:199)==7863==by0x1480A8:ngx_start_worker_processes(ngx_process_cycle.c:344)==7863==by0x14952D:ngx_master_process_cycle(ngx_process_cycle.c:130)理论上还没有出来这个漏洞可以被远程代码执行攻击向量分析DNS响应可以通过多种方式触发漏洞。首先,Nginx必须发送DNS请求并且必须等待响应。然后可以在DNS响应的多个部分进行投毒:DNSquestionsQNAME、DNSanswers名称,DNS回答CNAME和SRV响应的RDATA,作者:crafti带有多个中毒QNAME、NAME或RDATA值的ng响应,可以在处理响应时多次命中易受攻击的函数,有效地执行多次离线写入。此外,当攻击者提供中毒的CNAME时,它会被递归解析,在ngx_resolve_name_locked()调用ngx_strlow()(ngx_resolver.c:594)期间以及在其他OOB读取ngx_resolver_dup()(ngx_resolver.c:790)和ngx_crc32_short()(ngx_resolver.c:596)。带有受污染CNAME的“example.net”请求的DNS响应负载示例:略有不同的负载(poc.py中的负载)填充了足够的字节以覆盖带点的next_chunk.mchunk_size的最小值有效字节:24字节的标记导致分配一个24字节的缓冲区,其中填充了24个字节+一个超出范围的点字符。漏洞修复和解决方法通过在解析域名时为域名末尾的虚假点字符分配一个额外的字节来缓解此问题。受漏洞影响的配置daemonoff;http{access_loglogs/access.log;server{listen8080;location/{resolver127.0.0.1:1053;set$dnsexample.net;proxy_pass$dns;}}}events{worker_connections1024;}
