RSS Feed
更好更安全的互联网

NTPD拒绝服务漏洞(CVE-2016-7434) 分析

2016-12-23

Author: LG, dawu (知道创宇404实验室)

前言


NTP服务对于互联网来说是不可或缺的,很多东西都能和它联系到一起。就在不久前,轰动一时的德国断网事件中也出现了它的影子。保证NTP服务器的安全是很重要的!

0x00 漏洞概述


1.漏洞简介

NTPD是一个linux系统下同步不同机器时间的服务程序。
近日NTP.org公布了一个拒绝服务漏洞,该漏洞能够导致NTPD服务遭受远程DoS攻击。

2.漏洞影响

受影响版本面临DoS攻击风险

3.影响版本

  • 4.3.90
  • 4.3.25
  • 4.3
  • 4.3.93
  • 4.3.92
  • 4.3.77
  • 4.3.70
  • 4.2.8p8
  • 4.2.8p7
  • 4.2.8p6
  • 4.2.8p5
  • 4.2.8p4
  • 4.2.8p3
  • 4.2.8p2
  • 4.2.8p1
  • 4.2.7p22

0x01 漏洞详情


1.漏洞细节

NTPD服务端配置安全性低,能接收任意端mrulist数据包。此时攻击者能够远程发送经过构造的mrulist数据包对其进行Dos攻击。

2.漏洞检测方法

使用以下命令检测NTP版本: # ntpq -c version 受影响版本列表中的版本未作相关安全配置将受漏洞影响。 github上已有公布的漏洞利用poc,但是该poc会使NTPD服务崩溃,利用后需要重启服务。
漏洞利用poc

3.漏洞复现

docker搭建环境:

ntpd1

之后命令行输入:

最后NTPD服务崩溃

--1

--2

4.漏洞分析

4.1 payload分析

漏洞发现者构造了这样一段mrulist数据包

base64解码后

base64

base64解码(以16进制显示):

此处参考NTP协议格式:

NTP packet = NTP header + Four TimeStamps = 48byte

NTP header : 16byte

LI(LeapYearIndicator) VN(VersionNumber) Mode Stratum Poll(PollInterval) Precision
2bit 3bit 3bit 8bit 8bit 8bit

详情请看 NTP报文格式

主要字段的解释如下: ·LI(Leap Indicator,闰秒提示):长度为2比特,值为“11”时表示告警状态,时钟未被同步。为其他值时NTP本身不做处理。 ·VN(Version Number,版本号):长度为3比特,表示NTP的版本号,目前的最新版本为4。 ·Mode:长度为3比特,表示NTP的工作模式。不同的值所表示的含义分别是:0未定义、1表示主动对等体模式、2表示被动对等体模式、3表示客户模式、4表示服务器模式、5表示广播模式或组播模式、6表示此报文为NTP控制报文、7预留给内部使用。 ·Stratum:系统时钟的层数,取值范围为1~16,它定义了时钟的准确度。层数为1的时钟准确度最高,准确度从1到16依次递减,层数为16的时钟处于未同步状态。 ·Poll:轮询时间,即两个连续NTP报文之间的时间间隔。 ·Precision:系统时钟的精度。

了解了NTP的报文格式后,上文数据包中的NTP header:

payload分析到这里暂时无下文,于是我们转去研究了漏洞触发点部分

4.2漏洞触发点分析

如下图,我们根据valgrind给出的调试信息寻找漏洞触发点

----

判断漏洞触发点位于ntpd/ntpcontrol.c:4041,readmru_list()函数体内

----1

漏洞触发原因是estrdup函数空指针的引用。

estrdup函数的参数不能为NULL,否则会使程序崩溃。因为estrdup函数包含了strdup函数,而strdup函数又包含了strlen函数,该函数参数不能是NULL

那么这说明val是有可能引入空指针的了? val是由ctl_getitem()函数引入的,稍后我们上溯去看。

我们先来看readmrulist函数中var list

它把mrulist数据包中各字段输入in_parms中,并且用到了sizeof()

看到这里,我们明白了nonce_text字段长度是6字节。

接着我们上溯ctl_getitem函数。它的功能是处理解码后数据包中的数据。首先处理的就是nonce_text字段。ctl1

这里val就是*data,*var_list就是in_parms,v就是每个字段的数据

ctl3

注意line(3103-3107)以及line(3111-3116)处的代码: while循环的条件是从字符串首部开始扫描,出现空或者,就把reqpt右移一个字节。
for循环的判断语句中以,为终止标志,以=为赋值标志。如果没有出现=来进行判断后赋值,字段就会一直为空。
关键点出现了:在之前构造payload时,目标就是这里(阻止=的出现)。

4.3payload构造分析

我们延续对payload的分析,结合上文payload分析base64解码部分信息,其实已经显示出来了。6nonce,大家注意到了吗? nonce前面的一个字节正常格式原本应该是=的,漏洞发现者把它置为6了(16进制就是\x36)。其实只要构造"nonce"前一个字节不是=(16进制是\x3d)而且前3个字节都为NULL,漏洞触发条件就满足了。

我们来验证一下:

--1-1

--2-1

到此总结一下: payload构造关键点在于上文中NTP header格式如下
NULL NULL NULL 非= nonce,

ps:非=需要的是能正常解码出来的字符串,乱码是不行的。

5.补丁分析

ntp4.2.8p9版本修补了这个漏洞。官方修补方案是在read_mru_list()中严格地进行val参数的检测并做了一些限制措施。此外官方在最新版ntp_control.c的release中又对ctl_getitem函数进行了安全修改。

GitLab代码补丁对比链接

1

2

我们分析后认为补丁关键点如下:

其中char * val 变为const char * val

修改后逻辑运行为必须通过void * 从指针中去掉const属性。 接着严格判断val是不是NULL,若val指针为NULL则中断。 在此情况下原漏洞触发点处变为先判断*val,判断式只会为真,避免了空指针的引用,从而修复了此处漏洞。

6.漏洞利用分析

在实际场景中,存在漏洞的NTPD服务器如果未作任何防护措施,攻击者极易对其进行远程DoS攻击。但是攻击结果仅是使服务崩溃,重启服务就能正常运行,对NTP服务器本身无其他深层影响。 但是,如实验室,飞机场,银行等机构的业务结算对于时间的校验应该非常严格。一旦针对性地攻击与它们相关联的NTP服务器导致系统时间无法正常同步,对于业务结算等是能够造成一定冲击的。

0x02 漏洞防护措施


  1. 只允许接收来自信任主机的mrulist查询包
  2. 升级到ntpd4.2.8p9
  3. 执行BCP-38标准

0x03 参考


 

作者:kk | Categories:技术分享 | Tags: