Loading [MathJax]/jax/input/TeX/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >CVE-2021-23017:nginx DNS解析漏洞PoC公开

CVE-2021-23017:nginx DNS解析漏洞PoC公开

作者头像
FB客服
发布于 2021-07-02 16:50:46
发布于 2021-07-02 16:50:46
15.7K06
代码可运行
举报
文章被收录于专栏:FreeBufFreeBuf
运行总次数:6
代码可运行

漏洞评级

高危漏洞

确认受影响版本

0.6.18 - 1.20.0

确认修复版本

1.21.0、1.20.1

厂商

F5, Inc

厂商官网

https://nginx.org/

厂商参考资料

https://mailman.nginx.org/pipermail/nginx-announce/2021/000300.html

漏洞CVE

CVE-2021-23017

CWE

193

CVSS评分

8.1

漏洞概述及影响

在处理DNS响应时,ngx_resolver_copy()中的一个off-by-one错误将允许网络攻击者在堆分配的缓冲区中写入超出边界的点字符(‘.’, 0x2E)。配置解析程序原语时,响应nginx服务器DNS请求的DNS响应可能会触发该漏洞。

精心构造的数据包可以通过使用0x2E覆盖下一个堆块元数据的最低有效字节,此时,能够向nginx服务器提供DNS响应的网络攻击者可以实现拒绝服务攻击或远程代码执行攻击。

由于nginx中缺少DNS欺骗防御措施,并且在检查DNS事务ID之前调用了易受攻击的函数,因此远程攻击者可以通过在可行的时间内向目标服务器发送恶意DNS响应来利用该漏洞实施攻击。

漏洞成因分析

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

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

计算未压缩域名的大小len并验证输入数据包,丢弃包含128个以上指针或超出输入缓冲区边界指针的域名。 分配一个输出缓冲区,并将未压缩的域名复制到其中。

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 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
代码运行次数:0
运行
AI代码解释
复制
==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

漏洞利用PoC下载地址:【poc.py】

广大研究人员可以通过valgrind并运行nginx来对该漏洞进行测试:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
valgrind --trace-children=yes objs/nginx -p ../runtime -c conf/reverse-proxy.conf

接下来,运行DNS服务器(默认监听端口1053):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
python poc.py

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
curl http://127.0.0.1:8080/

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
corrupted size vs. prev_size

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

malloc(): invalid next size (unsorted)

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

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

所使用的nginx配置

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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://googleprojectzero.blogspot.com/2016/12/chrome-os-exploit-one-byte-overflow-and.html

https://googleprojectzero.blogspot.com/2014/08/the-poisoned-nul-byte-2014-edition.html

https://www.slideshare.net/codeblue_jp/cb16-matsukuma-en-68459606

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

本文分享自 FreeBuf 微信公众号,前往查看

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Nginx DNS解析漏洞PoC公开细节
5月26日,由绿盟科技CERT监测到Nginx发布安全公告,修复了一个Nginx解析器中的DNS解析程序漏洞(CVE-2021-23017),由于ngx_resolver_copy处理DNS响应时存在错误,当Nginx配置文件中使用"resolver"指令时,未经身份验证的攻击者能够伪造来自DNS服务器的UDP数据包,构造特制的DNS响应导致1字节内存覆盖,从而造成拒绝服务或任意代码执行
李俊鹏
2021/07/06
3.7K0
Nginx DNS解析漏洞PoC公开细节
使用 gdb 调试多进程程序 —— 以调试 nginx 为例
这里我们说的多进程程序指的是一个进程使用 Linux 系统调用 fork() 函数产生的子进程,没有相互关联的进程就是普通的 gdb 调试,不必刻意讨论。
范蠡
2020/07/09
3K0
nginx源码阅读(4)单进程epoll流程解析
我们这里以单进程启动为例 nginx.c中的main 函数调用ngx_single_process_cycle
golangLeetcode
2022/08/02
4680
万字多图,搞懂 Nginx 高性能网络工作原理!
在单进程的网络编程模型中。所有的网络相关的动作都是在一个进程里完成的,如监听 socket 的创建, bind、listen。再比如 epoll 的创建、要监听事件的添加,以及 epoll_wait 等待时间发生。这些统统都是在一个进程里搞定。
开发内功修炼
2022/05/09
5950
万字多图,搞懂 Nginx 高性能网络工作原理!
nginx dns解析源码分析
在使用同步IO的情况下,调用gethostbyname()或者gethostbyname_r()就可以根据域名查询到对应的IP地址,。
stan1ey
2021/06/07
1.9K0
nginx dns解析源码分析
买了很多书,看了很多教程,仍然看不懂开源代码......
想在技术上有所造诣或者想成为某一技术领域的专家的同学一定要认认真真的研读几个开源项目的源码。
范蠡
2023/01/04
1.3K0
买了很多书,看了很多教程,仍然看不懂开源代码......
Nginx(二): worker 进程处理流程框架解析
Nginx 启动起来之后,会有几个进程运行:1. master 进程接收用户命令并做出响应; 2. worker 进程负责处理各网络事件,并同时接收来自master的处理协调命令;
烂猪皮
2021/01/28
1.4K0
Nginx(二): worker 进程处理流程框架解析
nginx代码阅读第一天
https://www.kancloud.cn/digest/understandingnginx
早起的鸟儿有虫吃
2019/03/08
9250
Nginx平滑升级源码分析
一、平滑升级步骤 1、重命名之前的sbin/nginx文件,将新的nginx文件放到sbin/目录下 #mv ./sbin/nginx ./sbin/nginx.old #cp ~/nginx ./sbin/ 2、向正在运行的nginx发送USR2信号启动新的nginx,这个时候新老nginx都会接收请求,看那一个进程能抢到锁,抢到锁的worker进程可以accpet新请求 #kill -USR2  `cat nginx.pid` 3、观察新的nginx运行无误后,向旧nginx发信号 停止旧nginx的运
magicsoar
2018/02/06
1.3K0
Nginx平滑升级源码分析
nginx0.1.0之event模块初始化源码分析(4)
event的配置解析相关的代码已经分析完毕。下面分析一下另一个流程中event模块的实现。即在nginx创建进程,并且开始执行进程里的代码的时候。入口函数是ngx_worker_process_cycle。
theanarkh
2019/03/06
4170
Nginx(六):配置解析之location解析
nginx成为非常流行的代理服务软件,最根本的原因也许是在于其强悍性能。但还有一些必要的条件,比如功能的完整,配置的易用,能够解决各种各样的实际需求问题,这些是一个好的软件的必备特性。
烂猪皮
2021/01/28
2K0
Nginx(六):配置解析之location解析
nginx平台初探(100%)
众所周知,nginx性能高,而nginx的高性能与其架构是分不开的。那么nginx究竟是怎么样的呢?这一节我们先来初识一下nginx框架吧。
用户5640963
2019/07/26
1.2K0
nginx平台初探(100%)
gdb调试基础命令
LINUX默认不会打开程序崩溃时产生的core文件。使用`ulimit -c查看
doper
2022/09/26
1.8K0
Nginx 的异步非阻塞体现在哪里?从理论分析到源码验证
2、那业务层面的异步是怎么个异步法?同步异步的概念我就不说了,前面文章有。异步最重要的标志就是通知,通知,通知!!!
看、未来
2021/10/13
9770
Nginx 架构浅析
作者:handsomeli,腾讯 IEG 后台开发工程师 1.Nginx 基础架构 nginx 启动后以 daemon 形式在后台运行,后台进程包含一个 master 进程和多个 worker 进程。如下图所示: master与worker nginx 是由一个 master 管理进程,多个 worker 进程处理工作的多进程模型。基础架构设计,如下图所示: 基础架构设计 master 负责管理 worker 进程,worker 进程负责处理网络事件。整个框架被设计为一种依赖事件驱动、异步、非
腾讯技术工程官方号
2021/04/13
2.5K0
nginx惊群问题的解决方式
对于nginx的惊群问题,我们首先需要理解的是,在nginx启动过程中,master进程会监听配置文件中指定的各个端口,然后master进程就会调用fork()方法创建各个子进程,根据进程的工作原理,子进程是会继承父进程的全部内存数据以及监听的端口的,也就是说worker进程在启动之后也是会监听各个端口的。关于惊群,指的就是当客户端有新建连接的请求到来时,就会触发各个worker进程的连接建立事件,但是只有一个worker进程能够正常处理该事件,而其他的worker进程会发现事件已经失效,从而重新循环进入等待状态。这种由于一个事件而“惊”起了所有worker进程的现象就是惊群问题。很明显,如果所有的worker进程都被触发了,那么这将消耗大量的资源,本文则主要讲解nginx是如何处理惊群问题的。
用户4283147
2022/10/27
6160
nginx惊群问题的解决方式
nginx惊群问题
了解惊群问题首先要了解下nginx进程部署架构:nginx进程主要是一个主进程(master)和多个工作进程(worker)。master进程并不处理网络请求,主要负责初始化和调度工作进程,如加载配置、启动工作进程 ,升级等,worker进程用来处理网络请求,并且一个连接的多个阶段处理都在同一个worker中进行。既然是多个worker同时等待同一个socket事件,当这个事件发生时,所有worker同时唤醒,但最终只能有一个进程能建立成功,其他进程都会失败,造成了资源的浪费。
用户1215536
2019/07/23
9920
nginx架构模型分析
Nginx由内核和模块组成,从官方文档http://nginx.org/en/docs/下的Modules reference可以看到一些比较重要的模块,一般分为核心、基础模块以及第三方模块。
苏先生
2019/05/17
1K0
Nginx的时间管理
gettimeofday()的开销 在Linux中,Nginx通过gettimeofday()获取系统当前时间; gettimeofday是C库提供的函数(不是系统调用),它封装了内核里的sys_gettimeofday系统调用。 Linux的系统调用通过int 80h实现,用系统调用号来区分入口函数,步骤大致如下: 1 API将系统调用号存入EAX,然后通过中断调用使系统进入内核态; 2 内核中的中断处理函数根据系统调用号,调用对应的内核函数(系统调用); 3 系统调用完成相应功能,将返回值存入EAX,返回到中断处理函数; 4 中断处理函数返回到API中; 5 API将EAX返回给应用程序
星哥玩云
2022/07/03
5510
nginx事件模块源码分析
事件处理框架所要解决的问题是如何收集,管理,分发事件。这里所说的事件,主要以网络事件和定时器事件为主,而网络事件中又以TCP网络事件为主。由于网络事件与网卡中断处理程序,内核提供的系统调用密切相关,所以网络事件的驱动取决于不同的操作系统平台,在同一操作系统中也受制于不同的操作系统内核版本。因此不同操作系统有不同的事件驱动机制。
stan1ey
2021/08/11
7490
nginx事件模块源码分析
相关推荐
Nginx DNS解析漏洞PoC公开细节
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验