mirror of
https://github.com/aquasecurity/kube-hunter.git
synced 2026-05-19 07:38:47 +00:00
Refactor And Major Bug Fixes in Version and CVE hunting (#162)
* changed version hunting to be on a a new version disclosure vulnerability * fixed version publish * added logging and fixed typo * changed whole way of comparing versions in cve hunter * changed K8sVersionDisclosure vulnerability to one core vulnerability, that takes an endpoint. changed all usage * added tests * merged kubectl cve hunting with apiserver hunting. and simplified the code of apiserver cve hunting * fixed tests to new names * changed name of module to cves.py * drastically improved the cve vulnerble detection utility function. now works with all types of versioning methods * added packaging in requirementes.txt * added another test, and improved logic on cve comparison for more complicated versions * changed CveHunter to subscribe_once, to prevent duplicates duplicates * fixed tests for new improvements * removed unnecessary ternary on doc * removed unnecessary join split * improved compare function, made it util * improved cve checking to use mapping
This commit is contained in:
@@ -2,7 +2,7 @@ import logging
|
||||
import requests
|
||||
import json
|
||||
import threading
|
||||
from src.core.types import InformationDisclosure, DenialOfService, RemoteCodeExec, IdentityTheft, PrivilegeEscalation, AccessRisk, UnauthenticatedAccess
|
||||
from src.core.types import InformationDisclosure, DenialOfService, RemoteCodeExec, IdentityTheft, PrivilegeEscalation, AccessRisk, UnauthenticatedAccess, KubernetesCluster
|
||||
|
||||
class EventFilterBase(object):
|
||||
def __init__(self, event):
|
||||
@@ -139,6 +139,7 @@ class OpenPortEvent(Event):
|
||||
location = str(self.port)
|
||||
return location
|
||||
|
||||
|
||||
class HuntFinished(Event):
|
||||
pass
|
||||
|
||||
@@ -149,3 +150,17 @@ class HuntStarted(Event):
|
||||
|
||||
class ReportDispatched(Event):
|
||||
pass
|
||||
|
||||
|
||||
""" Core Vulnerabilites """
|
||||
class K8sVersionDisclosure(Vulnerability, Event):
|
||||
"""The kubernetes version could be obtained from the {} endpoint """
|
||||
def __init__(self, version, from_endpoint, extra_info=""):
|
||||
Vulnerability.__init__(self, KubernetesCluster, "K8s Version Disclosure", category=InformationDisclosure)
|
||||
self.version = version
|
||||
self.from_endpoint = from_endpoint
|
||||
self.extra_info = extra_info
|
||||
self.evidence = version
|
||||
|
||||
def explain(self):
|
||||
return self.__doc__.format(self.from_endpoint) + self.extra_info
|
||||
|
||||
@@ -5,7 +5,7 @@ import uuid
|
||||
import copy
|
||||
|
||||
from ...core.events import handler
|
||||
from ...core.events.types import Vulnerability, Event
|
||||
from ...core.events.types import Vulnerability, Event, K8sVersionDisclosure
|
||||
from ..discovery.apiserver import ApiServer
|
||||
from ...core.types import Hunter, ActiveHunter, KubernetesCluster
|
||||
from ...core.types import RemoteCodeExec, AccessRisk, InformationDisclosure, UnauthenticatedAccess
|
||||
@@ -13,7 +13,6 @@ from ...core.types import RemoteCodeExec, AccessRisk, InformationDisclosure, Una
|
||||
|
||||
""" Vulnerabilities """
|
||||
|
||||
|
||||
class ServerApiAccess(Vulnerability, Event):
|
||||
""" The API Server port is accessible. Depending on your RBAC settings this could expose access to or control of your cluster. """
|
||||
|
||||
@@ -557,3 +556,25 @@ class AccessApiServerActive(ActiveHunter):
|
||||
|
||||
# Note: we are not binding any role or cluster role because
|
||||
# -- in certain cases it might effect the running pod within the cluster (and we don't want to do that).
|
||||
|
||||
@handler.subscribe(ApiServer)
|
||||
class ApiVersionHunter(Hunter):
|
||||
"""Api Version Hunter
|
||||
Tries to obtain the Api Server's version directly from /version endpoint
|
||||
"""
|
||||
def __init__(self, event):
|
||||
self.event = event
|
||||
self.path = "{}://{}:{}".format(self.event.protocol, self.event.host, self.event.port)
|
||||
self.session = requests.Session()
|
||||
self.session.verify = False
|
||||
if self.event.auth_token:
|
||||
self.session.headers.update({"Authorization": "Bearer {}".format(self.event.auth_token)})
|
||||
|
||||
def execute(self):
|
||||
if self.event.auth_token:
|
||||
logging.debug('Passive Hunter is attempting to access the API server version end point using the pod\'s service account token on {}:{} \t'.format(self.event.host, self.event.port))
|
||||
else:
|
||||
logging.debug('Passive Hunter is attempting to access the API server version end point anonymously')
|
||||
version = json.loads(self.session.get(self.path + "/version").text)["gitVersion"]
|
||||
logging.debug("Discovered version of api server {}".format(version))
|
||||
self.publish_event(K8sVersionDisclosure(version=version, from_endpoint="/version"))
|
||||
@@ -1,114 +0,0 @@
|
||||
import logging
|
||||
import json
|
||||
import requests
|
||||
|
||||
from ...core.events import handler
|
||||
from ...core.events.types import Vulnerability, Event
|
||||
from ..discovery.apiserver import ApiServer
|
||||
from ...core.types import Hunter, ActiveHunter, KubernetesCluster, RemoteCodeExec, AccessRisk, InformationDisclosure, \
|
||||
PrivilegeEscalation, DenialOfService
|
||||
|
||||
""" Vulnerabilities """
|
||||
|
||||
|
||||
class ServerApiVersionEndPointAccessPE(Vulnerability, Event):
|
||||
"""Node is vulnerable to critical CVE-2018-1002105"""
|
||||
|
||||
def __init__(self, evidence):
|
||||
Vulnerability.__init__(self, KubernetesCluster, name="Critical Privilege Escalation CVE", category=PrivilegeEscalation)
|
||||
self.evidence = evidence
|
||||
|
||||
|
||||
class ServerApiVersionEndPointAccessDos(Vulnerability, Event):
|
||||
"""Node not patched for CVE-2019-1002100. Depending on your RBAC settings, a crafted json-patch could cause a Denial of Service."""
|
||||
|
||||
def __init__(self, evidence):
|
||||
Vulnerability.__init__(self, KubernetesCluster, name="Denial of Service to Kubernetes API Server", category=DenialOfService)
|
||||
self.evidence = evidence
|
||||
|
||||
|
||||
# Passive Hunter
|
||||
@handler.subscribe(ApiServer)
|
||||
class IsVulnerableToCVEAttack(Hunter):
|
||||
"""CVE hunter
|
||||
Checks if Node is running a Kubernetes version vulnerable to critical CVEs
|
||||
"""
|
||||
|
||||
def __init__(self, event):
|
||||
self.event = event
|
||||
self.headers = dict()
|
||||
# From within a Pod we may have extra credentials
|
||||
if self.event.auth_token:
|
||||
self.headers = {'Authorization': 'Bearer ' + self.event.auth_token}
|
||||
self.path = "{}://{}:{}".format(self.event.protocol, self.event.host, self.event.port)
|
||||
self.api_server_evidence = ''
|
||||
self.k8sVersion = ''
|
||||
|
||||
def get_api_server_version_end_point(self):
|
||||
logging.debug(self.event.host)
|
||||
if 'Authorization' in self.headers:
|
||||
logging.debug('Passive Hunter is attempting to access the API server version end point using the pod\'s service account token: \t%s', str(self.headers))
|
||||
else:
|
||||
logging.debug('Passive Hunter is attempting to access the API server version end point anonymously')
|
||||
try:
|
||||
res = requests.get("{path}/version".format(path=self.path),
|
||||
headers=self.headers, verify=False)
|
||||
self.api_server_evidence = res.text
|
||||
resDict = json.loads(res.text)
|
||||
version = resDict["gitVersion"].split('.')
|
||||
first_two_minor_digits = int(version[1])
|
||||
last_two_minor_digits = int(version[2])
|
||||
logging.debug('Passive Hunter got version from the API server version end point: %d.%d', first_two_minor_digits, last_two_minor_digits)
|
||||
return [first_two_minor_digits, last_two_minor_digits]
|
||||
|
||||
except (requests.exceptions.ConnectionError, KeyError):
|
||||
return None
|
||||
|
||||
def check_cve_2018_1002105(self, api_version):
|
||||
first_two_minor_digists = api_version[0]
|
||||
last_two_minor_digists = api_version[1]
|
||||
|
||||
if first_two_minor_digists == 10 and last_two_minor_digists < 11:
|
||||
return True
|
||||
elif first_two_minor_digists == 11 and last_two_minor_digists < 5:
|
||||
return True
|
||||
elif first_two_minor_digists == 12 and last_two_minor_digists < 3:
|
||||
return True
|
||||
elif first_two_minor_digists < 10:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def check_cve_2019_1002100(self, api_version):
|
||||
"""
|
||||
Kubernetes v1.0.x-1.10.x
|
||||
Kubernetes v1.11.0-1.11.7 (fixed in v1.11.8)
|
||||
Kubernetes v1.12.0-1.12.5 (fixed in v1.12.6)
|
||||
Kubernetes v1.13.0-1.13.3 (fixed in v1.13.4)
|
||||
"""
|
||||
|
||||
first_two_minor_digists = api_version[0]
|
||||
last_two_minor_digists = api_version[1]
|
||||
|
||||
if first_two_minor_digists == 11 and last_two_minor_digists < 8:
|
||||
return True
|
||||
elif first_two_minor_digists == 12 and last_two_minor_digists < 6:
|
||||
return True
|
||||
elif first_two_minor_digists == 13 and last_two_minor_digists < 4:
|
||||
return True
|
||||
elif first_two_minor_digists < 11:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def execute(self):
|
||||
api_version = self.get_api_server_version_end_point()
|
||||
|
||||
if api_version:
|
||||
if self.check_cve_2018_1002105(api_version):
|
||||
self.publish_event(ServerApiVersionEndPointAccessPE(self.api_server_evidence))
|
||||
|
||||
if self.check_cve_2019_1002100(api_version):
|
||||
self.publish_event(ServerApiVersionEndPointAccessDos(self.api_server_evidence))
|
||||
|
||||
|
||||
146
src/modules/hunting/cves.py
Normal file
146
src/modules/hunting/cves.py
Normal file
@@ -0,0 +1,146 @@
|
||||
import logging
|
||||
import json
|
||||
import requests
|
||||
|
||||
from ...core.events import handler
|
||||
from ...core.events.types import Vulnerability, Event, K8sVersionDisclosure
|
||||
from ...core.types import Hunter, ActiveHunter, KubernetesCluster, RemoteCodeExec, AccessRisk, InformationDisclosure, \
|
||||
PrivilegeEscalation, DenialOfService, KubectlClient
|
||||
from ..discovery.kubectl import KubectlClientEvent
|
||||
|
||||
from packaging import version
|
||||
|
||||
""" CVE Vulnerabilities """
|
||||
|
||||
class ServerApiVersionEndPointAccessPE(Vulnerability, Event):
|
||||
"""Node is vulnerable to critical CVE-2018-1002105"""
|
||||
def __init__(self, evidence):
|
||||
Vulnerability.__init__(self, KubernetesCluster, name="Critical Privilege Escalation CVE", category=PrivilegeEscalation)
|
||||
self.evidence = evidence
|
||||
|
||||
class ServerApiVersionEndPointAccessDos(Vulnerability, Event):
|
||||
"""Node not patched for CVE-2019-1002100. Depending on your RBAC settings, a crafted json-patch could cause a Denial of Service."""
|
||||
def __init__(self, evidence):
|
||||
Vulnerability.__init__(self, KubernetesCluster, name="Denial of Service to Kubernetes API Server", category=DenialOfService)
|
||||
self.evidence = evidence
|
||||
|
||||
class IncompleteFixToKubectlCpVulnerability(Vulnerability, Event):
|
||||
"""The kubectl client is vulnerable to CVE-2019-11246, an attacker could potentially execute arbitrary code on the client's machine"""
|
||||
def __init__(self, binary_version):
|
||||
Vulnerability.__init__(self, KubectlClient, "Kubectl Vulnerable To CVE-2019-11246", category=RemoteCodeExec)
|
||||
self.binary_version = binary_version
|
||||
self.evidence = "kubectl version: {}".format(self.binary_version)
|
||||
|
||||
class KubectlCpVulnerability(Vulnerability, Event):
|
||||
"""The kubectl client is vulnerable to CVE-2019-1002101, an attacker could potentially execute arbitrary code on the client's machine"""
|
||||
def __init__(self, binary_version):
|
||||
Vulnerability.__init__(self, KubectlClient, "Kubectl Vulnerable To CVE-2019-1002101", category=RemoteCodeExec)
|
||||
self.binary_version = binary_version
|
||||
self.evidence = "kubectl version: {}".format(self.binary_version)
|
||||
|
||||
|
||||
class CveUtils:
|
||||
@staticmethod
|
||||
def get_base_release(full_ver):
|
||||
# if LecacyVersion, converting manually to a base version
|
||||
if type(full_ver) == version.LegacyVersion:
|
||||
return version.parse('.'.join(full_ver._version.split('.')[:2]))
|
||||
else:
|
||||
return version.parse('.'.join(map(str, full_ver._version.release[:2])))
|
||||
|
||||
@staticmethod
|
||||
def to_legacy(full_ver):
|
||||
# converting version to verison.LegacyVersion
|
||||
return version.LegacyVersion('.'.join(map(str, full_ver._version.release)))
|
||||
|
||||
@staticmethod
|
||||
def to_raw_version(v):
|
||||
if type(v) != version.LegacyVersion:
|
||||
return '.'.join(map(str, v._version.release))
|
||||
return v._version
|
||||
|
||||
@staticmethod
|
||||
def version_compare(v1, v2):
|
||||
"""Function compares two versions, handling differences with convertion to LegacyVersion"""
|
||||
# getting raw version, while striping 'v' char at the start. if exists.
|
||||
# removing this char lets us safely compare the two version.
|
||||
v1_raw, v2_raw = CveUtils.to_raw_version(v1).strip('v'), CveUtils.to_raw_version(v2).strip('v')
|
||||
new_v1 = version.LegacyVersion(v1_raw)
|
||||
new_v2 = version.LegacyVersion(v2_raw)
|
||||
|
||||
return CveUtils.basic_compare(new_v1, new_v2)
|
||||
|
||||
@staticmethod
|
||||
def basic_compare(v1, v2):
|
||||
return (v1>v2)-(v1<v2)
|
||||
|
||||
@staticmethod
|
||||
def is_vulnerable(fix_versions, check_version):
|
||||
"""Function determines if a version is vulnerable, by comparing to given fix versions by base release"""
|
||||
vulnerable = False
|
||||
check_v = version.parse(check_version)
|
||||
base_check_v = CveUtils.get_base_release(check_v)
|
||||
|
||||
# default to classic compare, unless the check_version is legacy.
|
||||
version_compare_func = CveUtils.basic_compare
|
||||
if type(check_v) == version.LegacyVersion:
|
||||
version_compare_func = CveUtils.version_compare
|
||||
|
||||
if check_version not in fix_versions:
|
||||
# comparing ease base release for a fix
|
||||
for fix_v in fix_versions:
|
||||
fix_v = version.parse(fix_v)
|
||||
base_fix_v = CveUtils.get_base_release(fix_v)
|
||||
|
||||
# if the check version and the current fix has the same base release
|
||||
if base_check_v == base_fix_v:
|
||||
# when check_version is legacy, we use a custom compare func, to handle differnces between versions.
|
||||
if version_compare_func(check_v, fix_v) == -1:
|
||||
# determine vulnerable if smaller and with same base version
|
||||
vulnerable = True
|
||||
break
|
||||
|
||||
# if we did't find a fix in the fix releases, checking if the version is smaller that the first fix
|
||||
if not vulnerable and version_compare_func(check_v, version.parse(fix_versions[0])) == -1:
|
||||
vulnerable = True
|
||||
|
||||
return vulnerable
|
||||
|
||||
|
||||
@handler.subscribe_once(K8sVersionDisclosure)
|
||||
class K8sClusterCveHunter(Hunter):
|
||||
"""K8s CVE Hunter
|
||||
Checks if Node is running a Kubernetes version vulnerable to known CVEs
|
||||
"""
|
||||
|
||||
def __init__(self, event):
|
||||
self.event = event
|
||||
|
||||
def execute(self):
|
||||
logging.debug('Api Cve Hunter determining vulnerable version: {}'.format(self.event.version))
|
||||
cve_mapping = {
|
||||
ServerApiVersionEndPointAccessPE: ["1.10.11", "1.11.5", "1.12.3"],
|
||||
ServerApiVersionEndPointAccessDos: ["1.11.8", "1.12.6", "1.13.4"],
|
||||
}
|
||||
for vulnerability, fix_versions in cve_mapping.items():
|
||||
if CveUtils.is_vulnerable(fix_versions, self.event.version):
|
||||
self.publish_event(vulnerability(self.event.version))
|
||||
|
||||
|
||||
@handler.subscribe(KubectlClientEvent)
|
||||
class KubectlCVEHunter(Hunter):
|
||||
"""Kubectl CVE Hunter
|
||||
Checks if the kubectl client is vulnerable to known CVEs
|
||||
"""
|
||||
def __init__(self, event):
|
||||
self.event = event
|
||||
|
||||
def execute(self):
|
||||
cve_mapping = {
|
||||
KubectlCpVulnerability: ['1.11.9', '1.12.7', '1.13.5' '1.14.0'],
|
||||
IncompleteFixToKubectlCpVulnerability: ['1.12.9', '1.13.6', '1.14.2']
|
||||
}
|
||||
logging.debug('Kubectl Cve Hunter determining vulnerable version: {}'.format(self.event.version))
|
||||
for vulnerability, fix_versions in cve_mapping.items():
|
||||
if CveUtils.is_vulnerable(fix_versions, self.event.version):
|
||||
self.publish_event(vulnerability(binary_version=self.event.version))
|
||||
@@ -1,64 +0,0 @@
|
||||
import logging
|
||||
|
||||
from ...core.events import handler
|
||||
from ...core.types import Hunter, RemoteCodeExec, KubectlClient
|
||||
from ...core.events.types import Vulnerability, Event
|
||||
from ..discovery.kubectl import KubectlClientEvent
|
||||
|
||||
from distutils.version import LooseVersion, StrictVersion
|
||||
|
||||
class IncompleteFixToKubectlCpVulnerability(Vulnerability, Event):
|
||||
"""The kubectl client is vulnerable to CVE-2019-11246, an attacker could potentially execute arbitrary code on the client's machine"""
|
||||
def __init__(self, binary_version):
|
||||
Vulnerability.__init__(self, KubectlClient, "Kubectl Vulnerable To CVE-2019-11246", category=RemoteCodeExec)
|
||||
self.binary_version = binary_version
|
||||
self.evidence = "kubectl version: {}".format(self.binary_version)
|
||||
|
||||
class KubectlCpVulnerability(Vulnerability, Event):
|
||||
"""The kubectl client is vulnerable to CVE-2019-1002101, an attacker could potentially execute arbitrary code on the client's machine"""
|
||||
def __init__(self, binary_version):
|
||||
Vulnerability.__init__(self, KubectlClient, "Kubectl Vulnerable To CVE-2019-1002101", category=RemoteCodeExec)
|
||||
self.binary_version = binary_version
|
||||
self.evidence = "kubectl version: {}".format(self.binary_version)
|
||||
|
||||
|
||||
@handler.subscribe(KubectlClientEvent)
|
||||
class KubectlCVEHunter(Hunter):
|
||||
"""Kubectl CVE Hunter
|
||||
Compares version of the kubectl binary to known CVE affected versions
|
||||
"""
|
||||
def __init__(self, event):
|
||||
self.event = event
|
||||
|
||||
def is_older_than(self, fix_versions, check_version):
|
||||
"""Function determines if a version is vulnerable, by comparing to given fix versions"""
|
||||
logging.debug("Passive hunter is comparing the kubectl binary version to vulnerable versions")
|
||||
# in case version is in short version, converting
|
||||
if len(LooseVersion(check_version).version) < 3:
|
||||
check_version += '.0'
|
||||
|
||||
vulnerable = False
|
||||
if check_version not in fix_versions:
|
||||
for fix_v in fix_versions:
|
||||
fix_v = LooseVersion(fix_v)
|
||||
base_v = '.'.join(map(lambda x: str(x), fix_v.version[:2]) )
|
||||
|
||||
if check_version.startswith(base_v):
|
||||
if LooseVersion(check_version) < fix_v:
|
||||
vulnerable = True
|
||||
break
|
||||
# if version is smaller than smaller fix version
|
||||
if not vulnerable and LooseVersion(check_version) < LooseVersion(fix_versions[0]):
|
||||
vulnerable = True
|
||||
|
||||
return vulnerable
|
||||
|
||||
def execute(self):
|
||||
cve_2019_1002101_fix_versions = ['1.11.9', '1.12.7', '1.13.5' '1.14.0']
|
||||
cve_2019_11246_fix_versions = ['1.12.9', '1.13.6', '1.14.2']
|
||||
|
||||
if self.is_older_than(fix_versions=cve_2019_1002101_fix_versions, check_version=self.event.version):
|
||||
self.publish_event(KubectlCpVulnerability(binary_version=self.event.version))
|
||||
|
||||
if self.is_older_than(fix_versions=cve_2019_11246_fix_versions, check_version=self.event.version):
|
||||
self.publish_event(IncompleteFixToKubectlCpVulnerability(binary_version=self.event.version))
|
||||
@@ -8,7 +8,7 @@ import urllib3
|
||||
|
||||
from __main__ import config
|
||||
from ...core.events import handler
|
||||
from ...core.events.types import Vulnerability, Event
|
||||
from ...core.events.types import Vulnerability, Event, K8sVersionDisclosure
|
||||
from ..discovery.kubelet import ReadOnlyKubeletEvent, SecureKubeletEvent
|
||||
from ...core.types import Hunter, ActiveHunter, KubernetesCluster, Kubelet, InformationDisclosure, RemoteCodeExec, AccessRisk
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
@@ -75,13 +75,6 @@ class ExposedHealthzHandler(Vulnerability, Event):
|
||||
self.evidence = "status: {}".format(self.status)
|
||||
|
||||
|
||||
class K8sVersionDisclosure(Vulnerability, Event):
|
||||
"""The kubernetes version could be obtained from logs in the /metrics endpoint"""
|
||||
def __init__(self, version):
|
||||
Vulnerability.__init__(self, Kubelet, "K8s Version Disclosure", category=InformationDisclosure)
|
||||
self.evidence = version
|
||||
|
||||
|
||||
class PrivilegedContainers(Vulnerability, Event):
|
||||
"""A Privileged container exist on a node. could expose the node/cluster to unwanted root operations"""
|
||||
def __init__(self, containers):
|
||||
@@ -165,7 +158,7 @@ class ReadOnlyKubeletPortHunter(Hunter):
|
||||
privileged_containers = self.find_privileged_containers()
|
||||
healthz = self.check_healthz_endpoint()
|
||||
if k8s_version:
|
||||
self.publish_event(K8sVersionDisclosure(version=k8s_version))
|
||||
self.publish_event(K8sVersionDisclosure(version=k8s_version, from_endpoint="/metrics", extra_info="on the Kubelet"))
|
||||
if privileged_containers:
|
||||
self.publish_event(PrivilegedContainers(containers=privileged_containers))
|
||||
if healthz:
|
||||
|
||||
@@ -5,7 +5,7 @@ import requests
|
||||
import json
|
||||
|
||||
from ...core.events import handler
|
||||
from ...core.events.types import Event, Vulnerability
|
||||
from ...core.events.types import Event, Vulnerability, K8sVersionDisclosure
|
||||
from ...core.types import ActiveHunter, Hunter, KubernetesCluster, InformationDisclosure
|
||||
from ..discovery.dashboard import KubeDashboardEvent
|
||||
from ..discovery.proxy import KubeProxyEvent
|
||||
@@ -16,12 +16,6 @@ class KubeProxyExposed(Vulnerability, Event):
|
||||
def __init__(self):
|
||||
Vulnerability.__init__(self, KubernetesCluster, "Proxy Exposed", category=InformationDisclosure)
|
||||
|
||||
class K8sVersionDisclosure(Vulnerability, Event):
|
||||
"""The Kubernetes version is exposed from kube-proxy"""
|
||||
def __init__(self):
|
||||
Vulnerability.__init__(self, KubernetesCluster, "K8s Version Disclosure", category=InformationDisclosure)
|
||||
|
||||
|
||||
class Service(Enum):
|
||||
DASHBOARD = "kubernetes-dashboard"
|
||||
|
||||
@@ -36,7 +30,6 @@ class KubeProxy(Hunter):
|
||||
|
||||
def execute(self):
|
||||
self.publish_event(KubeProxyExposed())
|
||||
self.publish_event(K8sVersionDisclosure())
|
||||
for namespace, services in self.services.items():
|
||||
for service in services:
|
||||
if service == Service.DASHBOARD.value:
|
||||
@@ -83,8 +76,8 @@ class ProveProxyExposed(ActiveHunter):
|
||||
if "buildDate" in version_metadata:
|
||||
self.event.evidence = "build date: {}".format(version_metadata["buildDate"])
|
||||
|
||||
@handler.subscribe(K8sVersionDisclosure)
|
||||
class ProveK8sVersionDisclosure(ActiveHunter):
|
||||
@handler.subscribe(KubeProxyExposed)
|
||||
class K8sVersionDisclosureProve(ActiveHunter):
|
||||
"""K8s Version Hunter
|
||||
Hunts Proxy when exposed, extracts the version
|
||||
"""
|
||||
@@ -97,4 +90,4 @@ class ProveK8sVersionDisclosure(ActiveHunter):
|
||||
port=self.event.port,
|
||||
), verify=False).text)
|
||||
if "gitVersion" in version_metadata:
|
||||
self.event.evidence = "version: {}".format(version_metadata["gitVersion"])
|
||||
self.publish_event(K8sVersionDisclosure(version=version_metadata["gitVersion"], from_endpoint="/version", extra_info="on the kube-proxy"))
|
||||
Reference in New Issue
Block a user