mirror of
https://github.com/aquasecurity/kube-hunter.git
synced 2026-05-06 09:18:36 +00:00
Shallow detection cve 2018 1002105 (#65)
* added the CVE hunter, haven't checked the hunter yet * fixed illegal name for import file * Completed & Tested
This commit is contained in:
@@ -13,29 +13,40 @@ class KubernetesCluster():
|
||||
"""Kubernetes Cluster"""
|
||||
name = "Kubernetes Cluster"
|
||||
|
||||
|
||||
class Kubelet(KubernetesCluster):
|
||||
"""The kubelet is the primary "node agent" that runs on each node"""
|
||||
name = "Kubelet"
|
||||
|
||||
|
||||
class Azure(KubernetesCluster):
|
||||
"""Azure Cluster"""
|
||||
name = "Azure"
|
||||
|
||||
|
||||
""" Categories """
|
||||
class InformationDisclosure(object):
|
||||
name = "Information Disclosure"
|
||||
|
||||
|
||||
class RemoteCodeExec(object):
|
||||
name = "Remote Code Execution"
|
||||
|
||||
|
||||
class IdentityTheft(object):
|
||||
name = "Identity Theft"
|
||||
|
||||
|
||||
class UnauthenticatedAccess(object):
|
||||
name = "Unauthenticated Access"
|
||||
|
||||
|
||||
class AccessRisk(object):
|
||||
name = "Access Risk"
|
||||
|
||||
|
||||
class PrivilegeEscalation(KubernetesCluster):
|
||||
name = "Privilege Escalation"
|
||||
|
||||
|
||||
from events import handler # import is in the bottom to break import loops
|
||||
74
src/modules/hunting/CVE_2018_1002105.py
Normal file
74
src/modules/hunting/CVE_2018_1002105.py
Normal file
@@ -0,0 +1,74 @@
|
||||
import logging
|
||||
import json
|
||||
import requests
|
||||
import uuid
|
||||
import ast
|
||||
|
||||
from ...core.events import handler
|
||||
from ...core.events.types import Vulnerability, Event, OpenPortEvent
|
||||
from ...core.types import Hunter, ActiveHunter, KubernetesCluster, RemoteCodeExec, AccessRisk, InformationDisclosure, PrivilegeEscalation
|
||||
|
||||
""" Vulnerabilities """
|
||||
|
||||
|
||||
class ServerApiVersionEndPointAccess(Vulnerability, Event):
|
||||
""" Accessing the server API within a compromised pod would help an attacker gain full control over the cluster"""
|
||||
|
||||
def __init__(self, evidence):
|
||||
Vulnerability.__init__(self, KubernetesCluster, name="Critical PrivilegedEscalation CVE", category=PrivilegeEscalation)
|
||||
self.evidence = evidence
|
||||
|
||||
# Passive Hunter
|
||||
@handler.subscribe(OpenPortEvent, predicate=lambda x: x.port == 443 or x.port == 6443)
|
||||
class IsVulnerableToCVEAttack(Hunter):
|
||||
""" API Server Hunter
|
||||
Accessing the API server within a compromised pod might grant an attacker full control over the cluster
|
||||
"""
|
||||
|
||||
def __init__(self, event):
|
||||
self.event = event
|
||||
self.headers = dict()
|
||||
self.path = "https://{}:{}".format(self.event.host, self.event.port)
|
||||
self.service_account_token_evidence = ''
|
||||
self.api_server_evidence = ''
|
||||
self.k8sVersion = ''
|
||||
|
||||
def access_api_server_version_end_point(self):
|
||||
logging.debug(self.event.host)
|
||||
logging.debug('Passive Hunter is attempting to access the API server /version end point using the pod\'s service account token')
|
||||
try:
|
||||
res = requests.get("{path}/version".format(path=self.path),
|
||||
headers=self.headers, verify=False)
|
||||
self.api_server_evidence = res.content
|
||||
resDict = ast.literal_eval(res.content)
|
||||
version = resDict["gitVersion"].split('.')
|
||||
first_two_minor_digists = eval(version[1])
|
||||
last_two_minor_digists = eval(version[2])
|
||||
|
||||
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
|
||||
except (requests.exceptions.ConnectionError, KeyError):
|
||||
return False
|
||||
|
||||
def get_service_account_token(self):
|
||||
logging.debug(self.event.host)
|
||||
logging.debug('Passive Hunter is attempting to access pod\'s service account token')
|
||||
try:
|
||||
with open('/var/run/secrets/kubernetes.io/serviceaccount/token', 'r') as token:
|
||||
data = token.read()
|
||||
self.service_account_token_evidence = data
|
||||
self.headers = {'Authorization': 'Bearer ' + self.service_account_token_evidence}
|
||||
return True
|
||||
except IOError: # Couldn't read file
|
||||
return False
|
||||
|
||||
def execute(self):
|
||||
if self.get_service_account_token(): # From within a Pod
|
||||
if self.access_api_server_version_end_point():
|
||||
self.publish_event(ServerApiVersionEndPointAccess(self.api_server_evidence))
|
||||
@@ -20,17 +20,20 @@ class ExposedPodsHandler(Vulnerability, Event):
|
||||
Vulnerability.__init__(self, Kubelet, "Exposed Pods", category=InformationDisclosure)
|
||||
self.count = count
|
||||
self.evidence = "count: {}".format(self.count)
|
||||
|
||||
|
||||
|
||||
class AnonymousAuthEnabled(Vulnerability, Event):
|
||||
"""The kubelet is misconfigured, potentially allowing secure access to all requests on the kubelet, without the need to authenticate"""
|
||||
def __init__(self):
|
||||
Vulnerability.__init__(self, Kubelet, "Anonymous Authentication", category=RemoteCodeExec)
|
||||
|
||||
|
||||
class ExposedContainerLogsHandler(Vulnerability, Event):
|
||||
"""Output logs from a running container are using the exposed /containerLogs endpoint"""
|
||||
def __init__(self):
|
||||
Vulnerability.__init__(self, Kubelet, "Exposed Container Logs", category=InformationDisclosure)
|
||||
|
||||
|
||||
|
||||
class ExposedRunningPodsHandler(Vulnerability, Event):
|
||||
"""Outputs a list of currently running pods, and some of their metadata, which can reveal sensitive information"""
|
||||
def __init__(self, count):
|
||||
@@ -38,26 +41,31 @@ class ExposedRunningPodsHandler(Vulnerability, Event):
|
||||
self.count = count
|
||||
self.evidence = "{} running pods".format(self.count)
|
||||
|
||||
|
||||
class ExposedExecHandler(Vulnerability, Event):
|
||||
"""An attacker could run arbitrary commands on a container"""
|
||||
def __init__(self):
|
||||
Vulnerability.__init__(self, Kubelet, "Exposed Exec On Container", category=RemoteCodeExec)
|
||||
|
||||
|
||||
class ExposedRunHandler(Vulnerability, Event):
|
||||
"""An attacker could run an arbitrary command inside a container"""
|
||||
def __init__(self):
|
||||
Vulnerability.__init__(self, Kubelet, "Exposed Run Inside Container", category=RemoteCodeExec)
|
||||
|
||||
|
||||
class ExposedPortForwardHandler(Vulnerability, Event):
|
||||
"""An attacker could set port forwaring rule on a pod"""
|
||||
def __init__(self):
|
||||
Vulnerability.__init__(self, Kubelet, "Exposed Port Forward", category=RemoteCodeExec)
|
||||
|
||||
|
||||
class ExposedAttachHandler(Vulnerability, Event):
|
||||
"""Opens a websocket that could enable an attacker to attach to a running container"""
|
||||
def __init__(self):
|
||||
Vulnerability.__init__(self, Kubelet, "Exposed Attaching To Container", category=RemoteCodeExec)
|
||||
|
||||
|
||||
class ExposedHealthzHandler(Vulnerability, Event):
|
||||
"""By accessing the open /healthz handler, an attacker could get the cluster health state without authenticating"""
|
||||
def __init__(self, status):
|
||||
@@ -65,19 +73,30 @@ class ExposedHealthzHandler(Vulnerability, Event):
|
||||
self.status = status
|
||||
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):
|
||||
Vulnerability.__init__(self, KubernetesCluster, "Privileged Container", category=AccessRisk)
|
||||
self.containers = containers
|
||||
self.evidence = "pod: {}, container: {}".format(containers[0][0], containers[0][1])
|
||||
|
||||
|
||||
|
||||
class PrivilegeEscalation(Vulnerability, Event):
|
||||
"""Privilege escalation allows an attacker to grant root permissions and control the cluster"""
|
||||
|
||||
def __init__(self, containers):
|
||||
Vulnerability.__init__(self, KubernetesCluster, "Privilege Escalation", category=PrivilegeEscalation)
|
||||
self.containers = containers
|
||||
self.evidence = "pod: {}, container: {}".format(containers[0][0], containers[0][1])
|
||||
|
||||
|
||||
""" dividing ports for seperate hunters """
|
||||
@handler.subscribe(ReadOnlyKubeletEvent)
|
||||
|
||||
Reference in New Issue
Block a user