漏洞修复 --- CVE-1999-0524
漏洞原理
-
暴露的服务信息
当主机响应 ICMP 时间戳请求(Timestamp Request, Type 13) 时,会在回复包(Timestamp Reply, Type 14)中包含当前系统的精确时间戳(以毫秒为单位的 UTC 时间)。 -
协议设计缺陷
ICMP 时间戳协议(RFC 792)设计于早期网络环境,未考虑安全风险。许多系统默认开启此功能,且未对请求来源做过滤。现在已经将这个功能视为漏洞不在支持
风险影响
-
系统指纹识别
通过时间戳可推断:-
操作系统的默认时间格式(如 Unix 时间戳 vs Windows 时间)
-
系统时区配置(通过 UTC 时间偏移计算)
-
设备类型(服务器/工控设备等持续运行的系统时间戳数值更大)
-
-
网络侦察辅助
-
探测主机存活状态(绕过禁 ping 策略)
-
绘制网络拓扑(结合 TTL 值判断跃点数)
-
-
高级攻击铺垫
-
时间同步攻击:为伪造 Kerberos 票据等时间敏感攻击提供参考基准
-
服务漏洞利用:识别老旧系统(如 Windows NT/95)以针对性投递漏洞利用载荷
-
poc:
没找到合适的ip测试,只有测试脚本
#!/usr/bin/env python3 # 指定使用Python3解释器运行此脚本 # -*- coding: utf-8 -*- # 设置文件编码为UTF-8,支持中文字符 """ CVE-1999-0524 ICMP Timestamp and Address Mask Request Exploit ICMP 时间戳和地址掩码请求信息泄露漏洞利用代码 漏洞描述: - 某些系统会响应ICMP时间戳请求,泄露系统时间信息 - 某些系统会响应ICMP地址掩码请求,泄露网络配置信息 - 攻击者可以利用这些信息进行网络侦察 注意:此代码仅用于教育和安全测试目的 """ import socket # 导入socket模块,用于网络通信 import struct # 导入struct模块,用于二进制数据的打包和解包 import time # 导入time模块,用于时间相关操作 import sys # 导入sys模块,用于系统相关操作(如退出程序) import argparse # 导入argparse模块,用于解析命令行参数 from datetime import datetime # 从datetime模块导入datetime类,用于时间格式化 # ICMP 类型定义 - 这些是网络协议中规定的标准数值 ICMP_ECHO_REQUEST = 8 # ICMP回显请求(ping命令使用的类型) ICMP_ECHO_REPLY = 0 # ICMP回显应答(ping响应的类型) ICMP_TIMESTAMP_REQUEST = 13 # ICMP时间戳请求(询问目标系统时间) ICMP_TIMESTAMP_REPLY = 14 # ICMP时间戳应答(目标系统回复时间) ICMP_ADDRESS_MASK_REQUEST = 17 # ICMP地址掩码请求(询问目标网络配置) ICMP_ADDRESS_MASK_REPLY = 18 # ICMP地址掩码应答(目标系统回复网络配置) def calculate_checksum(data): # 定义计算ICMP校验和的函数 """ 计算ICMP校验和 - 用于验证数据包完整性 参数: data: 需要计算校验和的二进制数据 返回: 校验和值(16位整数) """ if len(data) % 2: # 如果数据长度为奇数 data += b'\x00' # 在末尾补一个0字节,确保长度为偶数 checksum = 0 # 初始化校验和为0 for i in range(0, len(data), 2): # 每次处理2个字节(16位) word = (data[i] << 8) + data[i + 1] # 将两个字节组合成一个16位整数 checksum += word # 累加到校验和中 while checksum >> 16: # 处理进位(如果校验和超过16位) checksum = (checksum & 0xFFFF) + (checksum >> 16) # 将高位进位加到低位 return ~checksum & 0xFFFF # 取反并保留低16位作为最终校验和 def create_icmp_packet(icmp_type, icmp_code=0, icmp_id=0, icmp_seq=0, data=b''): # 定义创建ICMP数据包的函数 """ 创建完整的ICMP数据包 参数: icmp_type: ICMP类型(如13表示时间戳请求) icmp_code: ICMP代码(通常为0) icmp_id: ICMP标识符(用于匹配请求和响应) icmp_seq: ICMP序列号(用于区分不同的请求) data: 附加数据(如时间戳数据) 返回: 完整的ICMP数据包(字节串) """ icmp_header = struct.pack('!BBHHH', icmp_type, icmp_code, 0, icmp_id, icmp_seq) # 创建ICMP头部,校验和暂时为0 # struct.pack格式说明: # '!' = 网络字节序(大端序) # 'B' = 无符号字符(1字节)- icmp_type # 'B' = 无符号字符(1字节)- icmp_code # 'H' = 无符号短整型(2字节)- checksum(暂时为0) # 'H' = 无符号短整型(2字节)- icmp_id # 'H' = 无符号短整型(2字节)- icmp_seq icmp_packet = icmp_header + data # 将头部和数据组合成完整数据包 checksum = calculate_checksum(icmp_packet) # 计算整个数据包的校验和 icmp_header = struct.pack('!BBHHH', icmp_type, icmp_code, checksum, icmp_id, icmp_seq) # 重新创建头部,包含正确的校验和 return icmp_header + data # 返回包含正确校验和的完整ICMP数据包 def send_timestamp_request(target_ip): # 定义发送时间戳请求的函数 """ 发送ICMP时间戳请求到目标主机 参数: target_ip: 目标IP地址(字符串格式) 返回: True: 成功获取时间戳信息 False: 请求失败或超时 """ print(f"[+] 向 {target_ip} 发送ICMP时间戳请求...") # 显示正在发送请求的信息 try: # 开始异常处理块 sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP) # 创建原始套接字 # socket.AF_INET = IPv4地址族 # socket.SOCK_RAW = 原始套接字类型(可以发送自定义协议数据包) # socket.IPPROTO_ICMP = ICMP协议 sock.settimeout(5) # 设置套接字超时时间为5秒 current_time = int(time.time() * 1000) % (2**32) # 获取当前时间戳(毫秒),并限制在32位范围内 timestamp_data = struct.pack('!III', current_time, 0, 0) # 创建时间戳数据 # 格式:原始时间戳、接收时间戳(0)、传输时间戳(0) # '!III' = 网络字节序,3个无符号32位整数 packet = create_icmp_packet( # 创建ICMP时间戳请求包 ICMP_TIMESTAMP_REQUEST, # ICMP类型:时间戳请求(13) icmp_id=12345, # 标识符:12345(任意选择的数值) icmp_seq=1, # 序列号:1 data=timestamp_data # 附加数据:时间戳数据 ) sock.sendto(packet, (target_ip, 0)) # 发送数据包到目标IP # sendto用于无连接套接字,第二个参数是目标地址 # 端口号为0,因为ICMP不使用端口 print(f"[+] 时间戳请求已发送到 {target_ip}") # 显示发送成功信息 try: # 开始接收响应的异常处理 response, addr = sock.recvfrom(1024) # 接收响应数据包(最大1024字节) print(f"[+] 收到来自 {addr[0]} 的响应") # 显示收到响应的信息 icmp_response = response[20:] # 跳过IP头部(前20字节),获取ICMP部分 icmp_type, icmp_code, checksum, icmp_id, icmp_seq = struct.unpack('!BBHHH', icmp_response[:8]) # 解析ICMP头部 if icmp_type == ICMP_TIMESTAMP_REPLY: # 如果收到的是时间戳回复(类型14) print("[+] 成功!目标响应了时间戳请求") # 显示成功信息 if len(icmp_response) >= 20: # 如果响应数据足够长(包含时间戳数据) orig_timestamp, recv_timestamp, trans_timestamp = struct.unpack('!III', icmp_response[8:20]) # 解析时间戳数据 print(f"[+] 原始时间戳: {orig_timestamp}") # 显示原始时间戳 print(f"[+] 接收时间戳: {recv_timestamp}") # 显示接收时间戳 print(f"[+] 传输时间戳: {trans_timestamp}") # 显示传输时间戳 if recv_timestamp > 0: # 如果接收时间戳有效 readable_time = datetime.fromtimestamp(recv_timestamp / 1000.0) # 转换为可读时间格式 print(f"[+] 目标系统时间: {readable_time}") # 显示目标系统的时间 return True # 返回成功标志 else: # 如果收到的不是时间戳回复 print(f"[-] 收到非时间戳响应,类型: {icmp_type}") # 显示错误信息 return False # 返回失败标志 except socket.timeout: # 如果接收超时 print("[-] 超时:目标未响应时间戳请求") # 显示超时信息 return False # 返回失败标志 except PermissionError: # 如果权限不足 print("[-] 错误:需要管理员权限来创建原始套接字") # 显示权限错误信息 return False # 返回失败标志 except Exception as e: # 如果发生其他异常 print(f"[-] 发送时间戳请求时出错: {e}") # 显示具体错误信息 return False # 返回失败标志 finally: # 无论如何都会执行的清理代码 sock.close() # 关闭套接字,释放资源 def send_address_mask_request(target_ip): # 定义发送地址掩码请求的函数 """ 发送ICMP地址掩码请求到目标主机 参数: target_ip: 目标IP地址(字符串格式) 返回: True: 成功获取地址掩码信息 False: 请求失败或超时 """ print(f"\n[+] 向 {target_ip} 发送ICMP地址掩码请求...") # 显示正在发送请求的信息(\n表示换行) try: # 开始异常处理块 sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP) # 创建原始套接字 sock.settimeout(5) # 设置5秒超时 mask_data = struct.pack('!I', 0) # 创建地址掩码请求数据(4字节,初始值为0) # '!I' = 网络字节序,1个无符号32位整数 packet = create_icmp_packet( # 创建ICMP地址掩码请求包 ICMP_ADDRESS_MASK_REQUEST, # ICMP类型:地址掩码请求(17) icmp_id=12346, # 标识符:12346(与时间戳请求区分) icmp_seq=1, # 序列号:1 data=mask_data # 附加数据:地址掩码数据 ) sock.sendto(packet, (target_ip, 0)) # 发送数据包到目标IP print(f"[+] 地址掩码请求已发送到 {target_ip}") # 显示发送成功信息 try: # 开始接收响应的异常处理 response, addr = sock.recvfrom(1024) # 接收响应数据包 print(f"[+] 收到来自 {addr[0]} 的响应") # 显示收到响应的信息 icmp_response = response[20:] # 跳过IP头部,获取ICMP部分 icmp_type, icmp_code, checksum, icmp_id, icmp_seq = struct.unpack('!BBHHH', icmp_response[:8]) # 解析ICMP头部 if icmp_type == ICMP_ADDRESS_MASK_REPLY: # 如果收到的是地址掩码回复(类型18) print("[+] 成功!目标响应了地址掩码请求") # 显示成功信息 if len(icmp_response) >= 12: # 如果响应数据足够长(包含地址掩码) address_mask = struct.unpack('!I', icmp_response[8:12])[0] # 解析地址掩码(32位整数) mask_str = socket.inet_ntoa(struct.pack('!I', address_mask)) # 转换为点分十进制格式 # inet_ntoa将32位整数转换为IP地址字符串格式 print(f"[+] 地址掩码: {mask_str}") # 显示地址掩码 mask_bits = bin(address_mask).count('1') # 计算掩码中1的个数(网络位数) # bin()将整数转换为二进制字符串,count('1')统计1的个数 print(f"[+] 子网掩码位数: /{mask_bits}") # 显示CIDR格式的子网掩码 return True # 返回成功标志 else: # 如果收到的不是地址掩码回复 print(f"[-] 收到非地址掩码响应,类型: {icmp_type}") # 显示错误信息 return False # 返回失败标志 except socket.timeout: # 如果接收超时 print("[-] 超时:目标未响应地址掩码请求") # 显示超时信息 return False # 返回失败标志 except PermissionError: # 如果权限不足 print("[-] 错误:需要管理员权限来创建原始套接字") # 显示权限错误信息 return False # 返回失败标志 except Exception as e: # 如果发生其他异常 print(f"[-] 发送地址掩码请求时出错: {e}") # 显示具体错误信息 return False # 返回失败标志 finally: # 无论如何都会执行的清理代码 sock.close() # 关闭套接字,释放资源 def main(): # 定义主函数,程序的入口点 """ 主函数 - 程序的控制中心 """ parser = argparse.ArgumentParser(description='CVE-1999-0524 ICMP信息泄露漏洞测试工具') # 创建命令行参数解析器 parser.add_argument('target', help='目标IP地址') # 添加必需参数:目标IP地址 parser.add_argument('-t', '--timestamp', action='store_true', help='发送时间戳请求') # 添加可选参数:时间戳测试 parser.add_argument('-m', '--mask', action='store_true', help='发送地址掩码请求') # 添加可选参数:地址掩码测试 parser.add_argument('-a', '--all', action='store_true', help='发送所有类型的请求') # 添加可选参数:全部测试 args = parser.parse_args() # 解析命令行参数 try: # 验证IP地址格式 socket.inet_aton(args.target) # 尝试将字符串转换为网络地址 # inet_aton如果IP地址格式无效会抛出异常 except socket.error: # 如果IP地址格式无效 print(f"[-] 无效的IP地址: {args.target}") # 显示错误信息 sys.exit(1) # 退出程序,返回错误代码1 print("=" * 60) # 打印分隔线(60个等号) print("CVE-1999-0524 ICMP信息泄露漏洞测试工具") # 打印程序标题 print("=" * 60) # 打印分隔线 print(f"目标: {args.target}") # 显示目标IP地址 print(f"时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") # 显示当前时间 print("=" * 60) # 打印分隔线 try: # 检查是否有管理员权限 test_sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP) # 尝试创建原始套接字 test_sock.close() # 立即关闭测试套接字 except PermissionError: # 如果权限不足 print("[-] 错误:此工具需要管理员权限运行") # 显示权限错误信息 print("[-] 请以管理员身份运行此脚本") # 显示解决方案 sys.exit(1) # 退出程序 success_count = 0 # 初始化成功计数器 if args.all or args.timestamp: # 如果用户选择了全部测试或时间戳测试 if send_timestamp_request(args.target): # 发送时间戳请求 success_count += 1 # 如果成功,计数器加1 if args.all or args.mask: # 如果用户选择了全部测试或地址掩码测试 if send_address_mask_request(args.target): # 发送地址掩码请求 success_count += 1 # 如果成功,计数器加1 if not (args.timestamp or args.mask or args.all): # 如果用户没有指定任何测试类型 print("[-] 请指定要执行的测试类型 (-t, -m, 或 -a)") # 显示使用提示 parser.print_help() # 打印帮助信息 sys.exit(1) # 退出程序 print("\n" + "=" * 60) # 打印结果分隔线 print("测试完成") # 显示测试完成信息 print(f"成功的请求: {success_count}") # 显示成功的请求数量 if success_count > 0: # 如果有成功的请求 print("\n[!] 警告:目标系统存在信息泄露漏洞") # 显示安全警告 print("[!] 建议:") # 显示修复建议标题 print(" 1. 配置防火墙阻止不必要的ICMP请求") # 建议1 print(" 2. 禁用ICMP时间戳和地址掩码响应") # 建议2 print(" 3. 实施网络分段和访问控制") # 建议3 else: # 如果没有成功的请求 print("\n[+] 目标系统未响应测试请求,可能已经修复或配置了防护措施") # 显示安全信息 print("=" * 60) # 打印结束分隔线 if __name__ == "__main__": # 如果脚本被直接运行(而不是被导入) main() # 调用主函数

修复:
ICMP Timestamp 请求响应漏洞修复方案 (CVE-1999-0524)
Windows 系统修复方法:
-
通过防火墙禁用 ICMP Timestamp
# 创建入站规则 (阻止 Timestamp 请求) New-NetFirewallRule -DisplayName "Block ICMP Timestamp Request" ` -Direction Inbound ` -Protocol ICMPv4 ` -IcmpType 13 ` -Action Block # 创建出站规则 (阻止 Timestamp 响应) New-NetFirewallRule -DisplayName "Block ICMP Timestamp Reply" ` -Direction Outbound ` -Protocol ICMPv4 ` -IcmpType 14 ` -Action Block -
组策略配置 (域环境)
-
打开
gpedit.msc -
导航:
计算机配置 > Windows 设置 > 安全设置 > 高级安全 Windows 防火墙 -
分别创建入站/出站规则,阻止 ICMP 类型 13 和 14
-
Linux 系统修复方法:
-
使用 iptables 禁用
# 阻止入站 Timestamp 请求 (类型13) sudo iptables -A INPUT -p icmp --icmp-type timestamp-request -j DROP # 阻止出站 Timestamp 响应 (类型14) sudo iptables -A OUTPUT -p icmp --icmp-type timestamp-reply -j DROP # 永久保存规则 (根据发行版选择) sudo iptables-save | sudo tee /etc/iptables/rules.v4 -
使用 firewalld (RHEL/CentOS/Fedora)
# 添加富规则阻止 ICMP 类型 sudo firewall-cmd --permanent \ --add-rich-rule='rule icmp-type name="timestamp-request" drop' sudo firewall-cmd --permanent \ --add-rich-rule='rule icmp-type name="timestamp-reply" drop' sudo firewall-cmd --reload -
内核参数调整 (可选)
# 禁用 ICMP 时间戳响应 echo 1 | sudo tee /proc/sys/net/ipv4/icmp_echo_ignore_all # 永久生效 echo "net.ipv4.icmp_echo_ignore_all = 1" | sudo tee -a /etc/sysctl.conf sudo sysctl -p
网络设备层修复:
-
在边界防火墙/路由器添加规则:
# Cisco 示例 access-list 101 deny icmp any any timestamp-request access-list 101 deny icmp any any timestamp-reply
-
云平台安全组配置:
-
AWS/Azure/GCP 安全组中拒绝 ICMP 类型 13 和 14
-
验证方法:
# Windows 验证
使用上面的py脚本
# Linux 验证 (需安装 nmap)
nmap -PP -sP TARGET_IP
# 应看不到时间戳响应
注意:该漏洞威胁值较低(2.1分),修复时应评估业务影响。建议优先在网络边界拦截,避免影响内部合法使用。现代操作系统已默认加强防护,此漏洞主要影响遗留系统。
浙公网安备 33010602011771号