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:
Ori Agmon
2018-12-05 23:30:45 +02:00
committed by jerbia
parent c3d51d530a
commit cb0164edd1
3 changed files with 108 additions and 4 deletions

View File

@@ -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

View 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))

View File

@@ -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)