声明:
本文内容仅供学术研究,不作为违法乱纪使用,如有出现违规行为皆与作者、编辑、机构无关。
一、介绍
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