NTP 放大攻击,原理与实践

昨天在微博上看到乌云知识库分享了一篇关于 NTP 放大攻击的文章,点进去看了一下,发现内容很有意思,漏洞本身利用的原理很简单,实现的难度也并不高,但是产生的效果却十分明显,于是决定按照文章中的方式简单复现一下攻击。

本文大部分内容来自 《NTP Amplification Discovery》 原文链接

首先在进行介绍之前,需要你具有基本的背景知识,比如什么是 DDos 攻击。

NTP 放大攻击所利用的协议是 NTP 协议,全称是 Network Time Protocol,网络时间协议。是用于在互联网中对不同主机进行时间同步的协议。其中运行某些版本NTP 的服务器默认开启了对 MONLIST 命令的支持,这条命令的作用是向请求者返回最近通过 NTP 协议与本服务器进行通信的 IP 地址列表,最多支持返回600条记录。也就是说,如果一台 NTP 服务器有超过600个 IP 地址使用过它提供的 NTP 服务,那么通过一次 MONLIST 请求,你会收到返回的包含600条记录的数据包。这应该远远大于你发送查询命令的数据包大小。

那么,都有谁可以发起 MONLIST 查询请求呢?与 DNS 协议类似,NTP 协议也是基于 UDP 实现的,并且无法识别伪造了来源的请求数据包,使得任何人都可以伪装成需要攻击的目标主机对 NTP 服务器发起查询请求,支持 MONLIST 命令的 NTP 服务器在收到攻击者的数据包后,会将结果通过 UDP 的方式发送到攻击者指定的 IP 地址,造成流量攻击。而 NTP 放大攻击的可怕之处在于,它能够将攻击流量上百倍的放大,在最理想的情况下,可以将攻击的流量放大206倍(来源:https://blog.cloudflare.com/understanding-and-mitigating-ntp-based-ddos-attacks/)。在我后面的测试中,放大的效果也很轻松的达到了100倍以上。

介绍完相关背景,下面开始记录一次简单的模拟攻击流程。

首先第一步是发现网络上开启了 NTP 协议的主机,NTP 协议使用的端口是123端口。所以可以通过扫描123端口来获得一份开启 NTP 的主机列表。使用 Masscan 工具可以快递的完成大量的端口扫描任务。

./masscan -pU:123 -oX ntp_alive.xml --rate 160000 100.0.0.0-220.0.0.0 --exclude 255.255.255.255

其中,–exclude 255.255.255.255 是在扫描量较大的时候要求强制使用的,否则无法发起扫描,会得到如下的错误提示。

FAIL: range too big, need confirmation
 [hint] to prevent acccidents, at least one --exclude must be specified
 [hint] use "--exclude 255.255.255.255" as a simple confirmatio

在进行测试的时候,不需要使用100.0.0.0-220.0.0.0这样巨大的范围,因为这样的话,你的网络流量将会变成下面这样。

masscan_traffic

在 25Mbps 的带宽下,这个扫描请求跑了近三个半小时才完成。绿色部分代表出口流量,蓝色部分代表返回流量。即便是当发出和收到的数据包大小相等的时候,在线的 NTP 主机占比也不到10%,实际上考虑到 NTP 的放大效应,粗略地估计最终捕获到的主机数量所占扫描总量的比例应该在0.1%以内。

我一共对120*2^24=2013265920台主机的123端口进行了扫描,其中包括了一些非公网的 IP 地址,大约是16777216+1048576+65536=17891328。所以一共是1995374592+1(127.0.0.1)个IP。最终得到的扫描结果去重后是263493,大概占到了0.013%。

下一步是删选出可以接受 MONLIST 命令的主机,使用开头链接里博客给出的代码

from scapy.all import *
import thread
#Raw packet data used to request Monlist from NTP server
rawData = "\x17\x00\x03\x2a" + "\x00" * 61
#File containing all IP addresses with NTP port open.
logfile = open('uniq_ntp.txt', 'r')
#Output file used to store all monlist enabled servers
outputFile = open('monlistServers.txt', 'a')
def sniffer():
    #Sniffs incomming network traffic on UDP port 48769, all packets meeting thease requirements run through the analyser function.
    sniffedPacket = sniff(filter="udp port 48769 and dst net your_server_ip", store=0, prn=analyser)

def analyser(packet):
    #If the server responds to the GET_MONLIST command.
    if len(packet) > 200:
        if packet.haslayer(IP):
            print packet.getlayer(IP).src
            #Outputs the IP address to a log file.
            outputFile.write(packet.getlayer(IP).src + '\n')

thread.start_new_thread(sniffer, ())

for address in logfile:
    #Creates a UDP packet with NTP port 123 as the destination and the MON_GETLIST payload.
    send(IP(dst=address)/UDP(sport=48769, dport=123)/Raw(load=rawData))
print 'End'

需要将代码部分中 your_server_ip 替换成进行测试的主机 IP,这样才能接受到返回的 MONLIST 数据包并对主机是否可用进行判断。最终这263493主机中,筛选出了5121台主机。比 Cloudfare 遭受攻击时使用的4529台服务器还要多。

其实在这里是可以进行优化的,因为每台 NTP 主机所在的网络环境和繁忙程度不同,可能一部分 NTP 主机只有为数不多的主机与其进行通信,这样他返回的数据包的大小并没有比请求的数据包高出太多,会拉低整体的放大效果。因此可以稍微修改 analyser 函数,将放大倍数较小的主机抛弃,或者依据返回的大小安排不同的权重,从而达到在有限带宽下获得最大放大倍数的效果。

接下来我们已经有了一份可以利用的 IP 列表并进行测试了。这里我拿自己的 VPS 进行了简单的测试,测试的方法和数据可能不是十分准确,但是应该足以说明这种攻击方式的实现难度和效果了。

iptraf

通过图中的数字可以看到 48769测试端口收到的流量是102050K,发出的流量是1253082,简单的计算后81.44倍的放大效果。实际上放大倍数比这个值要大,因为数据包发出后服务器收到再返回会有一定的延迟,所以实际最后收到的流量应该大于当前实时看到的数字。在我上午进行的测试中,最后的放大倍数在110左右。在没经过任何优化的情况下取得这样的效果,还是很可怕的。具体的攻击测试脚本就不放出来了。以免造成了不希望看到的结果,如果需要测试的话可以在前面的扫描脚本上进行简单的修改就能够得到一个威力强大的攻击工具。如果部署在一定数量的服务器上同时运行,会产生很可观的攻击流量。

相关参考:

https://blog.cloudflare.com/understanding-and-mitigating-ntp-based-ddos-attacks/

https://blog.cloudflare.com/technical-details-behind-a-400gbps-ntp-amplification-ddos-attack/

 

无线热点登陆认证原理探究

在使用需要认证的公共热点时,通常我们都需要在一个 web 页面完成认证后才可以访问外网。这个从技术实现上来说也许不难获得思路,通过劫持请求重定向到认证页面应该就可以实现。但是在使用 CMCC 一类的运营商热点时,连接到热点后没有进行任何操作就可以在设备上调用浏览器弹出认证页面,或者在 iOS 设备上打开一个专门的特殊窗口来要求认证,这一点是怎么实现的还没有想通。而且既然可以在 iOS 设备中调出专门的窗口来认证,应该使用了某些被广泛支持的协议标准来做这件事。那么现在心里的两个疑问就是:
1.一个通常的认证流程是什么样的,从设备接入到认证前后发生了哪些动作?
2.如何实现设备接入后弹出自定义的窗口,可不可以作为攻击者利用这一点搞一些事情?

这篇日志我就想记录我寻找这两个问题答案的过程。

首先来解决第一个问题。

第一步需要了解这套强制认证的技术叫什么,经过初步的搜索得到的答案是这种认证方式叫做 Portal 认证。根据 Wikipedia 上对 Captive Portal 技术的简单介绍,这套流程的基本思路和本文开头的猜测基本相同。具体的实施方式有不止一种,例如:

  • Redirection by HTTP(HTTP 重定向)
  • ICMP Redirect (ICMP 重定向)
  • Redirection by DNS (DNS 重定向)

在设备第一次接入到无线网络的时候,会通过 DHCP 服务获取到一个 IP 地址,可能是公有地址也可能是私有地址。不论分配到的 IP 地址属于公有或者私有,此时客户端都只具备访问指定站点的权限,需要在 Portal 页面上完成认证(确认接受使用条款,验证账号密码等),在 Portal 页面完成认证后,这个系统通常会立即执行一系列的动作包括,重新分配地址(在原本是私有地址时可选),更新这台设备对应的权限控制列表(ACL)中的信息解除访问限制,并开始计时/计费等动作。

当用户需要停止使用这类网络时,通常在 Portal 页面上会提供主动断开的按钮,或者服务器会在一段时间没有检测到该客户端网络流量时将你的设备做下线处理,以保证计费准确并及时释放占用的 IP 地址。

以上就是一台新设备接入到需要 Portal 认证的网络环境中在获得访问互联网权限之前的大致步骤。那在一台设备完成介入后,以后再访问这类网络是否可以不必进行重复的认证就直接接入网络呢?答案当然是肯定的,否则在网络条件不好时无穷无尽的输入账号密码登陆不用强调也知道是一件折磨死人的事情,而这个问题的解决使用了叫做无感知认证的解决方案。关于无感知认证在参考资料中给出了常见的认证方式下实现无感知认证的方案。无感知认证的思想总结起来就是在完成了首次认证后再次接入时会利用已保存的信息进行后台验证,不需要用户主动输入口令进行登陆。不过这并不是我想了解的重点,于是不再继续深入了解。

当时产生这个疑问的时候,是用 iPhone 连接到热点后,系统会弹出一个类似浏览器的窗口,那么这个窗口是怎么弹出来的,触发的条件又是什么呢。根据前面收集到的信息,我使用 Captive Portal iOS 作为关键字在谷歌进行搜索,找到了一些相关的信息,大致介绍了这里面相关的细节。iOS设备所弹出的认证窗口是由 Apple Captive Network Assistant(CNA) 来完成的。大体的流程是当你首先链接到 Wi-Fi 网络后,iOS 设备会从它所属的众多域名下的特定域名选择一个或多个进行访问,例如

  • www.appleiphonecell.com
  • captive.apple.com
  • captive.apple.com
  • www.apple.com
  • www.itools.info
  • www.ibook.info
  • www.airport.us
  • www.thinkdifferent.us

当域名能够被解析且对特定的网页访问得到正确的响应(通常是 Success )时,CNA 会判定设备成功的链接到了互联网,比如这个页面,。如果域名被解析但访问特定页面返回的内容不是预期的结果,那么 CNA 会认为设备所处网络存在Captive Portal,因此会调用一个专门的类似浏览器的页面来发起网络请求并触发 Portal 页面,来引导用户进行登录或者认证。

根据参考资料3中的链接,在 iOS 6 及更早的版本中,一个典型的 CNA 测试请求如下:

GET /library/test/success.html

HTTP/1.0

Host: www.apple.com

User-Agent:CaptiveNetworkSupport/1.0 wispr

Connection: close

 

可以看到,在请求特定的页面时,CNA 也使用了一个自定的 User-Agent,这有助于我们识别iOS设备的 Captive Portal 探测请求并选择性的绕过,来实现自定的认证方式。也就是开头提到的第二个问题。

在提供的参考资料3中的几个链接,可以很好的帮助理解 Captive Portal 的相关概念和在 iOS 下 CNA 的大概工作机制,鉴于版本更迭中具体的实现策略可能不时更改,而且我手头暂时也没有进一步研究利用的精力,所以第二个问题就不再做深入的研究了,待日后再次遇到相关的问题后再更新本文。

参考资料

1.Portal Authentication Technology White Paper.PDF 

2.无感知认证方案技术介绍

3.Helpful Links

http://stackoverflow.com/questions/19055502/facebook-com-and-the-ios7-captive-portal-detection

http://stackoverflow.com/questions/18891706/ios7-and-captive-portals-changes-to-apple-request-url

https://supportforums.cisco.com/document/11934456/captive-portal-ios7-public

http://stackoverflow.com/questions/3615147/how-to-create-wifi-popup-login-page

http://blog.tanaza.com/blog/bid/318805/iOS-7-and-captive-portal-a-guide-to-captive-portal-requirements