飞道的博客

NTP放大攻击研究发现

318人阅读  评论(0)

声明:

本文内容仅供学术研究,不作为违法乱纪使用,如有出现违规行为皆与作者、编辑、机构无关。

一、介绍

NTP放大攻击是DDOS的一种形式,它使用NTP服务器将小请求转换为大响应,然后将其定向到受害计算机。

NTP放大使用MONLIST命令。MONLIST命令指示NTP服务器使用使用该服务器的最后600个IP地址进行响应。通过欺骗MONLIST请求的源IP地址,它将使NTP服务器对欺骗的IP地址进行数据响应。您可以想象使用大量NTP服务器。如果所有邮件都发送了相同的MONLIST请求,其中欺骗者IP被欺骗为源地址,则可以将其用作DOS方法。

我显然不容忍这样做,但是尽管找到多少个NTP服务器可以放大数据很有趣。这绝不是一种新的攻击形式,因此您希望许多NTP服务器不响应MONLIST命令。这个怎么运作。

为了确定有多少NTP服务器响应MONLIST命令,我经历了两个单独的阶段。

阶段一 :

第一步是对UDP端口123(NTP端口)执行初始扫描。我使用以下命令使用masscan工具进行了此操作:

./masscan -pU:123 -oX ntp.xml --rate 160000 101.0.0.0-120.0.0.0

我的服务器只有很少的带宽,因此扫描速度很慢。因此,我选择仅在101.0.0.0-120.0.0.0地址范围上执行测试。范围是随机选择的。

扫描完成后,我将得到一个XML文件,其中包含已扫描并打开了端口123的所有设备。由于某种原因,我的masscan输出文件包含许多相同IP地址的重复条目。有时每个地址有100条记录。我创建了一个简单的python脚本,能够解析大型masscan输出文件,并删除所有重复的条目。该脚本将单个条目存储到名为port123.txt的文件中。

我用来执行此操作的脚本可以在下面找到:

from lxml import etree
port = None
address = None
parsedServers = []
#Opens the file used to store single enteries.
outputFile = open('port123.txt', 'a')
#Iterates through the masscan XML file.
for event, element in etree.iterparse('ntp.xml', tag="host"):
    for child in element:
        if child.tag == 'address':
            #Assigns the current iterations address to the address variable.
            address = child.attrib['addr']
        if child.tag == 'ports':
            for a in child:
                #Assigns the current iterations port to the port variable.
                port = a.attrib['portid']
        #is both port and IP address are present.
        if port > 1 and address > 1:
            #If the IP hasnt yet been added to the output file.
            if address not in parsedServers:
                print address
                #Write the IP address to the file.
                outputFile.write(address + '\n')
                #write the IP to the parsedServers list
                parsedServers.append(address)
            port = None
            address = None
    element.clear()
outputFile.close()
print 'End'

因此,一旦该脚本运行ii,将有一个port123.txt文件,其中包含打开了端口123的所有IP地址(无重复)。

阶段二 :

第二阶段是解析port123.txt文件并确定NTP是否正在端口上运行,如果是,它是否响应MONLIST命令。

为此,我编写了一个使用scapy的小python脚本。

我首先导入该库对脚本的所有不良需求,并初始化一些变量。

from scapy.all import *
import thread

然后,我创建原始的MONLIST请求数据字符串,该字符串将发送到NTP服务器。我不知道为什么,但是除非请求的大小一定,否则服务器不会回复数据。我发现超过60个字节的内容都可以正常工作。因此\ x00已附加到末尾61次。

rawData = "\x17\x00\x03\x2a" + "\x00" * 61

然后,我同时打开用于编写响应MONLIST请求的NTP服务器的输出文件和用于解析masscan找到的地址的port123.txt文件。

logfile = open('port123.txt', 'r')
outputFile = open('monlistServers.txt', 'a')

然后,我定义一个称为嗅探器的函数。此函数在端口48769上侦听传入的UDP数据。此端口是发送单表请求时使用的源端口。因此,任何响应monlist请求的NTP服务器都将在该端口上做出响应。dst的网络地址应该是NTP服务器将响应的IP地址。在此示例中,我将其设置为99.99.99.99。

def sniffer():
    sniffedPacket = sniff(filter="udp port 48769 and dst net 99.99.99.99", store=0, prn=analyser)

嗅探器拾取的任何符合UDP端口48769要求的数据包都将通过称为分析器的功能运行,我将在后面简短介绍。

现在定义了嗅探器函数,它在线程中执行。这使它可以在后台运行。

thread.start_new_thread(sniffer, ())

接下来,我遍历masscan找到的IP地址。对于每个地址,我从目标端口48769向端口123发送UDP数据包,其中在脚本开头定义了rawData字符串。因此,此循环本质上是向mascan找到的所有服务器发出MON_GETLIST请求。

for address in logfile:
    send(IP(dst=address)/UDP(sport=48769, dport=123)/Raw(load=rawData))

任何响应MON_GETLIST请求的设备都将发送回数据,该数据将由线程中运行的嗅探器拾取。该嗅探器通过分析器功能运行所有收到的数据包。分析器功能检查捕获的数据包的长度,以确保其大小超过200个字节。我在测试过程中发现,如果NTP服务器不支持MONLIST命令,则响应通常为60、90字节大小或不存在。但是,如果服务器确实响应MONLIST命令,则响应会大得多,并包含多个数据包。通常每个数据包约480字节。因此,通过检查接收到的数据包是否大于200个字节,表明MONLIST命令在特定的NTP服务器上有效。显然是这种情况,因为以这种方式使用NTP放大的决定因素之一是响应的大小很大。如果响应大于200个字节,则将IP地址写入outputFile。

if len(packet) > 200:
    if packet.haslayer(IP):
        outputFile.write(packet.getlayer(IP).src + '\n')

服务器响应monlist命令时会返回包含所有IP地址数据的多个数据包,这很常见。(取决于返回的地址数。)因此,outputFile通常包含许多重复的地址。嗅探器捕获所有返回的数据。因此,我通过排序和uniq将输出文件运行到第一组相同的地址,然后使用以下命令删除重复项:

sort monlistServers.txt | uniq

结果是一个包含所有启用了monlist的NTP服务器的文件。

如前所述,完整的脚本可以在下面找到:

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('output.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 99.99.99.99", 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'

结果

如前所述,我的VPS带宽很差。因此,我选择仅对地址范围101.0.0.0-120.0.0.0执行扫描。如果我的数学正确,那么总共有318,767,104个地址(19 * 256 * 256 * 256)。

Masscan发现253,994个设备已打开NTP端口123。这是扫描设备的0.08%。

在253,994台设备中,其中7005台响应了monlist命令(2.76%)。

如果这些值等于在整个扫描中对启用了monlist的NTP服务器进行的整个扫描所发现的值,则意味着大约有91,000启用monlist的NTP服务器。

关注:Hunter网络安全 获取更多资讯
网站:bbs.kylzrv.com
CTF团队:Hunter网络安全
文章:Xtrato
排版:Hunter-匿名者


转载:https://blog.csdn.net/qq_25879801/article/details/110749520
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场