首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Nginx DNS解析漏洞PoC公开细节

Nginx DNS解析漏洞PoC公开细节

作者头像
李俊鹏
发布2021-07-06 16:13:04
发布2021-07-06 16:13:04
4K0
举报
文章被收录于专栏:运维研习社运维研习社

漏洞描述

5月26日,由绿盟科技CERT监测到Nginx发布安全公告,修复了一个Nginx解析器中的DNS解析程序漏洞(CVE-2021-23017),由于ngx_resolver_copy处理DNS响应时存在错误,当Nginx配置文件中使用"resolver"指令时,未经身份验证的攻击者能够伪造来自DNS服务器的UDP数据包,构造特制的DNS响应导致1字节内存覆盖,从而造成拒绝服务或任意代码执行

影响范围

受影响版本

  • Nginx 0.6.18 - 1.20.0

不受影响版本

  • Nginx 1.20.1(stable)
  • Nginx 1.21.0(mainline)

漏洞CVE

CVE-2021-23017

CVSS评分

8.1

漏洞细节

nginx的DNS解析器(core/ngx_resolver.c)可以在设置解析器原语时,通过DNS解析多个模块的主机名

ngx_resolver_copy()会被调用以验证和解压缩DNS响应中包含的每个DNS域名,接收作为输入的网络包和指向正在处理的域名的指针,并在成功时返回指向包含未压缩域名的新分配缓冲区的指针。整个过程分为两步执行:

1、计算未压缩域名的大小len并验证输入数据包,丢弃包含128个以上指针或超出输入缓冲区边界指针的域名

2、分配一个输出缓冲区,并将未压缩的域名复制到其中

第1部分中的大小计算和第2部分中的域名解压之间的不匹配会导致len中的off-by-one错误,从而允许在name->data数据边界之外写入一个点字符

当压缩域名的最后一部分包含指向NULL字节的指针时,就会发生计算错误的情况。虽然计算步骤只考虑标签之间的点,但每次处理标签并且下一个字符不是NULL时,解压缩步骤都会写入一个点字符。当标签后跟指向NULL字节的指针时,解压缩过程将如下:

代码语言:javascript
复制
// 1) copy the label to the output buffer,
 ngx_strlow(dst, src, n);
            dst += n;
            src += n;
// 2) read next character,
            n = *src++;
// 3) as its a pointer, its not NUL,
            if (n != 0) {
// 4) so a dot character that was not accounted for is written out of bounds
                *dst++ = '.';
            }
// 5) Afterwards, the pointer is followed,
        if (n & 0xc0) {
            n = ((n & 0x3f) << 8) + *src;
            src = &buf[n];
            n = *src++;
        }
// 6) and a NULL byte is found, signaling the end of the function
        if (n == 0) {
            name->len = dst - name->data;
            return NGX_OK;
        }

如果计算出的大小正好与堆块大小对齐,则写入的点字符超出边界,将覆盖下一个堆块大小元数据的最低有效字节。这可能会修改下一个堆块的大小,但也会覆盖3个标志,从而清除PREV_INUSE并设置IS_MMAPPED

代码语言:javascript
复制
==7863== Invalid write of size 1
==7863==    at 0x137C2E: ngx_resolver_copy (ngx_resolver.c:4018)
==7863==    by 0x13D12B: ngx_resolver_process_a (ngx_resolver.c:2470)
==7863==    by 0x13D12B: ngx_resolver_process_response (ngx_resolver.c:1844)
==7863==    by 0x13D46A: ngx_resolver_udp_read (ngx_resolver.c:1574)
==7863==    by 0x14AB19: ngx_epoll_process_events (ngx_epoll_module.c:901)
==7863==    by 0x1414D4: ngx_process_events_and_timers (ngx_event.c:247)
==7863==    by 0x148E57: ngx_worker_process_cycle (ngx_process_cycle.c:719)
==7863==    by 0x1474DA: ngx_spawn_process (ngx_process.c:199)
==7863==    by 0x1480A8: ngx_start_worker_processes (ngx_process_cycle.c:344)
==7863==    by 0x14952D: ngx_master_process_cycle (ngx_process_cycle.c:130)
==7863==    by 0x12237F: main (nginx.c:383)
==7863==  Address 0x4bbcfb8 is 0 bytes after a block of size 24 alloc'd
==7863==    at 0x483E77F: malloc (vg_replace_malloc.c:307)
==7863==    by 0x1448C*4: ngx_alloc (ngx_alloc.c:22)
==7863==    by 0x137AE4: ngx_resolver_alloc (ngx_resolver.c:4119)
==7863==    by 0x137B26: ngx_resolver_copy (ngx_resolver.c:3994)
==7863==    by 0x13D12B: ngx_resolver_process_a (ngx_resolver.c:2470)
==7863==    by 0x13D12B: ngx_resolver_process_response (ngx_resolver.c:1844)
==7863==    by 0x13D46A: ngx_resolver_udp_read (ngx_resolver.c:1574)
==7863==    by 0x14AB19: ngx_epoll_process_events (ngx_epoll_module.c:901)
==7863==    by 0x1414D4: ngx_process_events_and_timers (ngx_event.c:247)
==7863==    by 0x148E57: ngx_worker_process_cycle (ngx_process_cycle.c:719)
==7863==    by 0x1474DA: ngx_spawn_process (ngx_process.c:199)
==7863==    by 0x1480A8: ngx_start_worker_processes (ngx_process_cycle.c:344)
==7863==    by 0x14952D: ngx_master_process_cycle (ngx_process_cycle.c:130)

考虑到nginx中与用户控制器数据的丰富交互机会以及记录在案的先例,这个漏洞将有可能允许攻击者在某些操作系统和体系结构上执行远程代码

漏洞利用PoC

研究人员可以通过valgrind来运行Nginx,对漏洞进行测试

代码语言:javascript
复制
valgrind --trace-children=yes objs/nginx -p ../runtime -c conf/reverse-proxy.conf

接着运行PoC,通过PoC启动DNS服务器(默认监听端口1053)

代码语言:javascript
复制
python poc.py

触发请求并发送至目标服务器

代码语言:javascript
复制
curl http://localhost:8080/

根据漏洞被触发时的堆内存布局,可能会出现几种不同形式的日志:

代码语言:javascript
复制
corrupted size vs. prev_size

2021/06/29 13:35:15 [alert] 2501#0: worker process 2502 exited on signal 6 (core dumped)

malloc(): invalid next size (unsorted)

2021/06/29 13:35:34 [alert] 2525#0: worker process 2526 exited on signal 6 (core dumped)

不过,valgrind和AdressSanitizer都是能够检测到这种内存崩溃事件的

测试使用的Nginx配置如下:

代码语言:javascript
复制
daemon off;
http{
    access_log logs/access.log;
    server{
        listen 8080;
        location / {
            resolver 127.0.0.1:1053;
            set $dns http://example.net;
            proxy_pass $dns;
        }
    }
}
events {
    worker_connections  1024;
}

参考:https://github.com/x41sec/advisories/blob/master/X41-2021-002

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-06-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 运维研习社 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 漏洞描述
  • 影响范围
  • 漏洞CVE
  • CVSS评分
  • 漏洞细节
  • 漏洞利用PoC
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档