mirror of
https://github.com/aquasecurity/kube-hunter.git
synced 2026-02-15 18:40:19 +00:00
Compare commits
3 Commits
feature/mi
...
bugfix/fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c16c997e47 | ||
|
|
a22debaa4e | ||
|
|
83b19d4208 |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -10,7 +10,7 @@ name: Release
|
||||
jobs:
|
||||
build:
|
||||
name: Upload Release Asset
|
||||
runs-on: ubuntu-16.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
20
.github/workflows/test.yml
vendored
20
.github/workflows/test.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["3.6", "3.7", "3.8", "3.9"]
|
||||
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-16.04]
|
||||
os: [ubuntu-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -23,26 +23,10 @@ jobs:
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Get pip cache dir
|
||||
id: pip-cache
|
||||
run: |
|
||||
echo "::set-output name=dir::$(pip cache dir)"
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.pip-cache.outputs.dir }}
|
||||
key:
|
||||
${{ matrix.os }}-${{ matrix.python-version }}-${{ hashFiles('requirements-dev.txt') }}
|
||||
restore-keys: |
|
||||
${{ matrix.os }}-${{ matrix.python-version }}-
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install -U pip
|
||||
python -m pip install -U wheel
|
||||
python -m pip install -r requirements.txt
|
||||
python -m pip install -r requirements-dev.txt
|
||||
python -m pip install -e .
|
||||
|
||||
- name: Test
|
||||
shell: bash
|
||||
|
||||
@@ -141,7 +141,7 @@ Available dispatch methods are:
|
||||
* KUBEHUNTER_HTTP_DISPATCH_URL (defaults to: https://localhost)
|
||||
* KUBEHUNTER_HTTP_DISPATCH_METHOD (defaults to: POST)
|
||||
|
||||
### Advanced Usage
|
||||
### Advanced Usage
|
||||
#### Azure Quick Scanning
|
||||
When running **as a Pod in an Azure or AWS environment**, kube-hunter will fetch subnets from the Instance Metadata Service. Naturally this makes the discovery process take longer.
|
||||
To hardlimit subnet scanning to a `/24` CIDR, use the `--quick` option.
|
||||
|
||||
@@ -3,15 +3,32 @@ import threading
|
||||
import requests
|
||||
|
||||
from kube_hunter.conf import get_config
|
||||
from kube_hunter.core.types import (
|
||||
InformationDisclosure,
|
||||
DenialOfService,
|
||||
RemoteCodeExec,
|
||||
IdentityTheft,
|
||||
PrivilegeEscalation,
|
||||
AccessRisk,
|
||||
UnauthenticatedAccess,
|
||||
KubernetesCluster,
|
||||
from kube_hunter.core.types import KubernetesCluster
|
||||
from kube_hunter.core.types.vulnerabilities import (
|
||||
GeneralSensitiveInformationTechnique,
|
||||
ExposedSensitiveInterfacesTechnique,
|
||||
MountServicePrincipalTechnique,
|
||||
ListK8sSecretsTechnique,
|
||||
AccessContainerServiceAccountTechnique,
|
||||
AccessK8sApiServerTechnique,
|
||||
AccessKubeletAPITechnique,
|
||||
AccessK8sDashboardTechnique,
|
||||
InstanceMetadataApiTechnique,
|
||||
ExecIntoContainerTechnique,
|
||||
SidecarInjectionTechnique,
|
||||
NewContainerTechnique,
|
||||
GeneralPersistenceTechnique,
|
||||
HostPathMountPrivilegeEscalationTechnique,
|
||||
PrivilegedContainerTechnique,
|
||||
ClusterAdminBindingTechnique,
|
||||
ARPPoisoningTechnique,
|
||||
CoreDNSPoisoningTechnique,
|
||||
DataDestructionTechnique,
|
||||
GeneralDefenseEvasionTechnique,
|
||||
ConnectFromProxyServerTechnique,
|
||||
CVERemoteCodeExecutionCategory,
|
||||
CVEPrivilegeEscalationCategory,
|
||||
CVEDenialOfServiceTechnique,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -102,13 +119,30 @@ class Service:
|
||||
class Vulnerability:
|
||||
severity = dict(
|
||||
{
|
||||
InformationDisclosure: "medium",
|
||||
DenialOfService: "medium",
|
||||
RemoteCodeExec: "high",
|
||||
IdentityTheft: "high",
|
||||
PrivilegeEscalation: "high",
|
||||
AccessRisk: "low",
|
||||
UnauthenticatedAccess: "low",
|
||||
GeneralSensitiveInformationTechnique: "low",
|
||||
ExposedSensitiveInterfacesTechnique: "high",
|
||||
MountServicePrincipalTechnique: "high",
|
||||
ListK8sSecretsTechnique: "high",
|
||||
AccessContainerServiceAccountTechnique: "low",
|
||||
AccessK8sApiServerTechnique: "medium",
|
||||
AccessKubeletAPITechnique: "medium",
|
||||
AccessK8sDashboardTechnique: "medium",
|
||||
InstanceMetadataApiTechnique: "high",
|
||||
ExecIntoContainerTechnique: "high",
|
||||
SidecarInjectionTechnique: "high",
|
||||
NewContainerTechnique: "high",
|
||||
GeneralPersistenceTechnique: "high",
|
||||
HostPathMountPrivilegeEscalationTechnique: "high",
|
||||
PrivilegedContainerTechnique: "high",
|
||||
ClusterAdminBindingTechnique: "high",
|
||||
ARPPoisoningTechnique: "medium",
|
||||
CoreDNSPoisoningTechnique: "high",
|
||||
DataDestructionTechnique: "high",
|
||||
GeneralDefenseEvasionTechnique: "high",
|
||||
ConnectFromProxyServerTechnique: "low",
|
||||
CVERemoteCodeExecutionCategory: "high",
|
||||
CVEPrivilegeEscalationCategory: "high",
|
||||
CVEDenialOfServiceTechnique: "medium",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -213,18 +247,21 @@ class ReportDispatched(Event):
|
||||
class K8sVersionDisclosure(Vulnerability, Event):
|
||||
"""The kubernetes version could be obtained from the {} endpoint"""
|
||||
|
||||
def __init__(self, version, from_endpoint, extra_info=""):
|
||||
def __init__(self, version, from_endpoint, extra_info="", category=None):
|
||||
Vulnerability.__init__(
|
||||
self,
|
||||
KubernetesCluster,
|
||||
"K8s Version Disclosure",
|
||||
category=InformationDisclosure,
|
||||
category=ExposedSensitiveInterfacesTechnique,
|
||||
vid="KHV002",
|
||||
)
|
||||
self.version = version
|
||||
self.from_endpoint = from_endpoint
|
||||
self.extra_info = extra_info
|
||||
self.evidence = version
|
||||
# depending from where the version came from, we might want to also override the category
|
||||
if category:
|
||||
self.category = category
|
||||
|
||||
def explain(self):
|
||||
return self.__doc__.format(self.from_endpoint) + self.extra_info
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
class HunterBase:
|
||||
publishedVulnerabilities = 0
|
||||
|
||||
@staticmethod
|
||||
def parse_docs(docs):
|
||||
"""returns tuple of (name, docs)"""
|
||||
if not docs:
|
||||
return __name__, "<no documentation>"
|
||||
docs = docs.strip().split("\n")
|
||||
for i, line in enumerate(docs):
|
||||
docs[i] = line.strip()
|
||||
return docs[0], " ".join(docs[1:]) if len(docs[1:]) else "<no documentation>"
|
||||
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
name, _ = cls.parse_docs(cls.__doc__)
|
||||
return name
|
||||
|
||||
def publish_event(self, event):
|
||||
handler.publish_event(event, caller=self)
|
||||
|
||||
|
||||
class ActiveHunter(HunterBase):
|
||||
pass
|
||||
|
||||
|
||||
class Hunter(HunterBase):
|
||||
pass
|
||||
|
||||
|
||||
class Discovery(HunterBase):
|
||||
pass
|
||||
|
||||
|
||||
class KubernetesCluster:
|
||||
"""Kubernetes Cluster"""
|
||||
|
||||
name = "Kubernetes Cluster"
|
||||
|
||||
|
||||
class KubectlClient:
|
||||
"""The kubectl client binary is used by the user to interact with the cluster"""
|
||||
|
||||
name = "Kubectl Client"
|
||||
|
||||
|
||||
class Kubelet(KubernetesCluster):
|
||||
"""The kubelet is the primary "node agent" that runs on each node"""
|
||||
|
||||
name = "Kubelet"
|
||||
|
||||
|
||||
class AWS(KubernetesCluster):
|
||||
"""AWS Cluster"""
|
||||
|
||||
name = "AWS"
|
||||
|
||||
|
||||
class Azure(KubernetesCluster):
|
||||
"""Azure Cluster"""
|
||||
|
||||
name = "Azure"
|
||||
|
||||
|
||||
class InformationDisclosure:
|
||||
name = "Information Disclosure"
|
||||
|
||||
|
||||
class RemoteCodeExec:
|
||||
name = "Remote Code Execution"
|
||||
|
||||
|
||||
class IdentityTheft:
|
||||
name = "Identity Theft"
|
||||
|
||||
|
||||
class UnauthenticatedAccess:
|
||||
name = "Unauthenticated Access"
|
||||
|
||||
|
||||
class AccessRisk:
|
||||
name = "Access Risk"
|
||||
|
||||
|
||||
class PrivilegeEscalation(KubernetesCluster):
|
||||
name = "Privilege Escalation"
|
||||
|
||||
|
||||
class DenialOfService:
|
||||
name = "Denial of Service"
|
||||
|
||||
|
||||
# import is in the bottom to break import loops
|
||||
from .events import handler # noqa
|
||||
4
kube_hunter/core/types/__init__.py
Normal file
4
kube_hunter/core/types/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
# flake8: noqa: E402
|
||||
from .hunters import *
|
||||
from .components import *
|
||||
from .vulnerabilities import *
|
||||
28
kube_hunter/core/types/components.py
Normal file
28
kube_hunter/core/types/components.py
Normal file
@@ -0,0 +1,28 @@
|
||||
class KubernetesCluster:
|
||||
"""Kubernetes Cluster"""
|
||||
|
||||
name = "Kubernetes Cluster"
|
||||
|
||||
|
||||
class KubectlClient:
|
||||
"""The kubectl client binary is used by the user to interact with the cluster"""
|
||||
|
||||
name = "Kubectl Client"
|
||||
|
||||
|
||||
class Kubelet(KubernetesCluster):
|
||||
"""The kubelet is the primary "node agent" that runs on each node"""
|
||||
|
||||
name = "Kubelet"
|
||||
|
||||
|
||||
class AWS(KubernetesCluster):
|
||||
"""AWS Cluster"""
|
||||
|
||||
name = "AWS"
|
||||
|
||||
|
||||
class Azure(KubernetesCluster):
|
||||
"""Azure Cluster"""
|
||||
|
||||
name = "Azure"
|
||||
36
kube_hunter/core/types/hunters.py
Normal file
36
kube_hunter/core/types/hunters.py
Normal file
@@ -0,0 +1,36 @@
|
||||
class HunterBase:
|
||||
publishedVulnerabilities = 0
|
||||
|
||||
@staticmethod
|
||||
def parse_docs(docs):
|
||||
"""returns tuple of (name, docs)"""
|
||||
if not docs:
|
||||
return __name__, "<no documentation>"
|
||||
docs = docs.strip().split("\n")
|
||||
for i, line in enumerate(docs):
|
||||
docs[i] = line.strip()
|
||||
return docs[0], " ".join(docs[1:]) if len(docs[1:]) else "<no documentation>"
|
||||
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
name, _ = cls.parse_docs(cls.__doc__)
|
||||
return name
|
||||
|
||||
def publish_event(self, event):
|
||||
# Import here to avoid circular import from events package.
|
||||
# imports are cached in python so this should not affect runtime
|
||||
from ..events import handler # noqa
|
||||
|
||||
handler.publish_event(event, caller=self)
|
||||
|
||||
|
||||
class ActiveHunter(HunterBase):
|
||||
pass
|
||||
|
||||
|
||||
class Hunter(HunterBase):
|
||||
pass
|
||||
|
||||
|
||||
class Discovery(HunterBase):
|
||||
pass
|
||||
188
kube_hunter/core/types/vulnerabilities.py
Normal file
188
kube_hunter/core/types/vulnerabilities.py
Normal file
@@ -0,0 +1,188 @@
|
||||
"""
|
||||
Vulnerabilities are divided into 2 main categories.
|
||||
|
||||
MITRE Category
|
||||
--------------
|
||||
Vulnerability that correlates to a method in the official MITRE ATT&CK matrix for kubernetes
|
||||
|
||||
CVE Category
|
||||
-------------
|
||||
"General" category definition. The category is usually determined by the severity of the CVE
|
||||
"""
|
||||
|
||||
|
||||
class MITRECategory:
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
"""
|
||||
Returns the full name of MITRE technique: <MITRE CATEGORY> // <MITRE TECHNIQUE>
|
||||
Should only be used on a direct technique class at the end of the MITRE inheritance chain.
|
||||
|
||||
Example inheritance:
|
||||
MITRECategory -> InitialAccessCategory -> ExposedSensitiveInterfacesTechnique
|
||||
"""
|
||||
inheritance_chain = cls.__mro__
|
||||
if len(inheritance_chain) >= 4:
|
||||
# -3 == index of mitreCategory class. (object class is first)
|
||||
mitre_category_class = inheritance_chain[-3]
|
||||
return f"{mitre_category_class.name} // {cls.name}"
|
||||
|
||||
|
||||
class CVECategory:
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
"""
|
||||
Returns the full name of the category: CVE // <CVE Category name>
|
||||
"""
|
||||
return f"CVE // {cls.name}"
|
||||
|
||||
|
||||
"""
|
||||
MITRE ATT&CK Technique Categories
|
||||
"""
|
||||
|
||||
|
||||
class InitialAccessCategory(MITRECategory):
|
||||
name = "Initial Access"
|
||||
|
||||
|
||||
class ExecutionCategory(MITRECategory):
|
||||
name = "Execution"
|
||||
|
||||
|
||||
class PersistenceCategory(MITRECategory):
|
||||
name = "Persistence"
|
||||
|
||||
|
||||
class PrivilegeEscalationCategory(MITRECategory):
|
||||
name = "Privilege Escalation"
|
||||
|
||||
|
||||
class DefenseEvasionCategory(MITRECategory):
|
||||
name = "Defense Evasion"
|
||||
|
||||
|
||||
class CredentialAccessCategory(MITRECategory):
|
||||
name = "Credential Access"
|
||||
|
||||
|
||||
class DiscoveryCategory(MITRECategory):
|
||||
name = "Discovery"
|
||||
|
||||
|
||||
class LateralMovementCategory(MITRECategory):
|
||||
name = "Lateral Movement"
|
||||
|
||||
|
||||
class CollectionCategory(MITRECategory):
|
||||
name = "Collection"
|
||||
|
||||
|
||||
class ImpactCategory(MITRECategory):
|
||||
name = "Impact"
|
||||
|
||||
|
||||
"""
|
||||
MITRE ATT&CK Techniques
|
||||
"""
|
||||
|
||||
|
||||
class GeneralSensitiveInformationTechnique(InitialAccessCategory):
|
||||
name = "General Sensitive Information"
|
||||
|
||||
|
||||
class ExposedSensitiveInterfacesTechnique(InitialAccessCategory):
|
||||
name = "Exposed sensitive interfaces"
|
||||
|
||||
|
||||
class MountServicePrincipalTechnique(CredentialAccessCategory):
|
||||
name = "Mount service principal"
|
||||
|
||||
|
||||
class ListK8sSecretsTechnique(CredentialAccessCategory):
|
||||
name = "List K8S secrets"
|
||||
|
||||
|
||||
class AccessContainerServiceAccountTechnique(CredentialAccessCategory):
|
||||
name = "Access container service account"
|
||||
|
||||
|
||||
class AccessK8sApiServerTechnique(DiscoveryCategory):
|
||||
name = "Access the K8S API Server"
|
||||
|
||||
|
||||
class AccessKubeletAPITechnique(DiscoveryCategory):
|
||||
name = "Access Kubelet API"
|
||||
|
||||
|
||||
class AccessK8sDashboardTechnique(DiscoveryCategory):
|
||||
name = "Access Kubernetes Dashboard"
|
||||
|
||||
|
||||
class InstanceMetadataApiTechnique(DiscoveryCategory):
|
||||
name = "Instance Metadata API"
|
||||
|
||||
|
||||
class ExecIntoContainerTechnique(ExecutionCategory):
|
||||
name = "Exec into container"
|
||||
|
||||
|
||||
class SidecarInjectionTechnique(ExecutionCategory):
|
||||
name = "Sidecar injection"
|
||||
|
||||
|
||||
class NewContainerTechnique(ExecutionCategory):
|
||||
name = "New container"
|
||||
|
||||
|
||||
class GeneralPersistenceTechnique(PersistenceCategory):
|
||||
name = "General Peristence"
|
||||
|
||||
|
||||
class HostPathMountPrivilegeEscalationTechnique(PrivilegeEscalationCategory):
|
||||
name = "hostPath mount"
|
||||
|
||||
|
||||
class PrivilegedContainerTechnique(PrivilegeEscalationCategory):
|
||||
name = "Privileged container"
|
||||
|
||||
|
||||
class ClusterAdminBindingTechnique(PrivilegeEscalationCategory):
|
||||
name = "Cluser-admin binding"
|
||||
|
||||
|
||||
class ARPPoisoningTechnique(LateralMovementCategory):
|
||||
name = "ARP poisoning and IP spoofing"
|
||||
|
||||
|
||||
class CoreDNSPoisoningTechnique(LateralMovementCategory):
|
||||
name = "CoreDNS poisoning"
|
||||
|
||||
|
||||
class DataDestructionTechnique(ImpactCategory):
|
||||
name = "Data Destruction"
|
||||
|
||||
|
||||
class GeneralDefenseEvasionTechnique(DefenseEvasionCategory):
|
||||
name = "General Defense Evasion"
|
||||
|
||||
|
||||
class ConnectFromProxyServerTechnique(DefenseEvasionCategory):
|
||||
name = "Connect from Proxy server"
|
||||
|
||||
|
||||
"""
|
||||
CVE Categories
|
||||
"""
|
||||
|
||||
|
||||
class CVERemoteCodeExecutionCategory(CVECategory):
|
||||
name = "Remote Code Execution (CVE)"
|
||||
|
||||
|
||||
class CVEPrivilegeEscalationCategory(CVECategory):
|
||||
name = "Privilege Escalation (CVE)"
|
||||
|
||||
|
||||
class CVEDenialOfServiceTechnique(CVECategory):
|
||||
name = "Denial Of Service (CVE)"
|
||||
@@ -11,7 +11,7 @@ from kube_hunter.conf import get_config
|
||||
from kube_hunter.modules.discovery.kubernetes_client import list_all_k8s_cluster_nodes
|
||||
from kube_hunter.core.events import handler
|
||||
from kube_hunter.core.events.types import Event, NewHostEvent, Vulnerability
|
||||
from kube_hunter.core.types import Discovery, InformationDisclosure, AWS, Azure
|
||||
from kube_hunter.core.types import Discovery, AWS, Azure, InstanceMetadataApiTechnique
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -55,7 +55,7 @@ class AWSMetadataApi(Vulnerability, Event):
|
||||
self,
|
||||
AWS,
|
||||
"AWS Metadata Exposure",
|
||||
category=InformationDisclosure,
|
||||
category=InstanceMetadataApiTechnique,
|
||||
vid="KHV053",
|
||||
)
|
||||
self.cidr = cidr
|
||||
@@ -70,7 +70,7 @@ class AzureMetadataApi(Vulnerability, Event):
|
||||
self,
|
||||
Azure,
|
||||
"Azure Metadata Exposure",
|
||||
category=InformationDisclosure,
|
||||
category=InstanceMetadataApiTechnique,
|
||||
vid="KHV003",
|
||||
)
|
||||
self.cidr = cidr
|
||||
|
||||
@@ -7,7 +7,7 @@ from kube_hunter.conf import get_config
|
||||
from kube_hunter.modules.hunting.kubelet import ExposedPodsHandler, SecureKubeletPortHunter
|
||||
from kube_hunter.core.events import handler
|
||||
from kube_hunter.core.events.types import Event, Vulnerability
|
||||
from kube_hunter.core.types import Hunter, ActiveHunter, IdentityTheft, Azure
|
||||
from kube_hunter.core.types import Hunter, ActiveHunter, MountServicePrincipalTechnique, Azure
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -20,7 +20,7 @@ class AzureSpnExposure(Vulnerability, Event):
|
||||
self,
|
||||
Azure,
|
||||
"Azure SPN Exposure",
|
||||
category=IdentityTheft,
|
||||
category=MountServicePrincipalTechnique,
|
||||
vid="KHV004",
|
||||
)
|
||||
self.container = container
|
||||
|
||||
@@ -8,10 +8,15 @@ from kube_hunter.modules.discovery.apiserver import ApiServer
|
||||
from kube_hunter.core.events import handler
|
||||
from kube_hunter.core.events.types import Vulnerability, Event, K8sVersionDisclosure
|
||||
from kube_hunter.core.types import Hunter, ActiveHunter, KubernetesCluster
|
||||
from kube_hunter.core.types import (
|
||||
AccessRisk,
|
||||
InformationDisclosure,
|
||||
UnauthenticatedAccess,
|
||||
from kube_hunter.core.types.vulnerabilities import (
|
||||
AccessK8sApiServerTechnique,
|
||||
ExposedSensitiveInterfacesTechnique,
|
||||
GeneralDefenseEvasionTechnique,
|
||||
DataDestructionTechnique,
|
||||
ClusterAdminBindingTechnique,
|
||||
NewContainerTechnique,
|
||||
PrivilegedContainerTechnique,
|
||||
SidecarInjectionTechnique,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -24,10 +29,10 @@ class ServerApiAccess(Vulnerability, Event):
|
||||
def __init__(self, evidence, using_token):
|
||||
if using_token:
|
||||
name = "Access to API using service account token"
|
||||
category = InformationDisclosure
|
||||
category = AccessK8sApiServerTechnique
|
||||
else:
|
||||
name = "Unauthenticated access to API"
|
||||
category = UnauthenticatedAccess
|
||||
category = ExposedSensitiveInterfacesTechnique
|
||||
Vulnerability.__init__(
|
||||
self,
|
||||
KubernetesCluster,
|
||||
@@ -44,7 +49,7 @@ class ServerApiHTTPAccess(Vulnerability, Event):
|
||||
|
||||
def __init__(self, evidence):
|
||||
name = "Insecure (HTTP) access to API"
|
||||
category = UnauthenticatedAccess
|
||||
category = ExposedSensitiveInterfacesTechnique
|
||||
Vulnerability.__init__(
|
||||
self,
|
||||
KubernetesCluster,
|
||||
@@ -59,7 +64,7 @@ class ApiInfoDisclosure(Vulnerability, Event):
|
||||
"""Information Disclosure depending upon RBAC permissions and Kube-Cluster Setup"""
|
||||
|
||||
def __init__(self, evidence, using_token, name):
|
||||
category = InformationDisclosure
|
||||
category = AccessK8sApiServerTechnique
|
||||
if using_token:
|
||||
name += " using default service account token"
|
||||
else:
|
||||
@@ -111,7 +116,7 @@ class CreateANamespace(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Created a namespace",
|
||||
category=AccessRisk,
|
||||
category=GeneralDefenseEvasionTechnique,
|
||||
)
|
||||
self.evidence = evidence
|
||||
|
||||
@@ -125,7 +130,7 @@ class DeleteANamespace(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Delete a namespace",
|
||||
category=AccessRisk,
|
||||
category=DataDestructionTechnique,
|
||||
)
|
||||
self.evidence = evidence
|
||||
|
||||
@@ -136,7 +141,7 @@ class CreateARole(Vulnerability, Event):
|
||||
"""
|
||||
|
||||
def __init__(self, evidence):
|
||||
Vulnerability.__init__(self, KubernetesCluster, name="Created a role", category=AccessRisk)
|
||||
Vulnerability.__init__(self, KubernetesCluster, name="Created a role", category=GeneralDefenseEvasionTechnique)
|
||||
self.evidence = evidence
|
||||
|
||||
|
||||
@@ -150,7 +155,7 @@ class CreateAClusterRole(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Created a cluster role",
|
||||
category=AccessRisk,
|
||||
category=ClusterAdminBindingTechnique,
|
||||
)
|
||||
self.evidence = evidence
|
||||
|
||||
@@ -165,7 +170,7 @@ class PatchARole(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Patched a role",
|
||||
category=AccessRisk,
|
||||
category=ClusterAdminBindingTechnique,
|
||||
)
|
||||
self.evidence = evidence
|
||||
|
||||
@@ -180,7 +185,7 @@ class PatchAClusterRole(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Patched a cluster role",
|
||||
category=AccessRisk,
|
||||
category=ClusterAdminBindingTechnique,
|
||||
)
|
||||
self.evidence = evidence
|
||||
|
||||
@@ -193,7 +198,7 @@ class DeleteARole(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Deleted a role",
|
||||
category=AccessRisk,
|
||||
category=DataDestructionTechnique,
|
||||
)
|
||||
self.evidence = evidence
|
||||
|
||||
@@ -206,7 +211,7 @@ class DeleteAClusterRole(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Deleted a cluster role",
|
||||
category=AccessRisk,
|
||||
category=DataDestructionTechnique,
|
||||
)
|
||||
self.evidence = evidence
|
||||
|
||||
@@ -219,7 +224,7 @@ class CreateAPod(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Created A Pod",
|
||||
category=AccessRisk,
|
||||
category=NewContainerTechnique,
|
||||
)
|
||||
self.evidence = evidence
|
||||
|
||||
@@ -232,7 +237,7 @@ class CreateAPrivilegedPod(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Created A PRIVILEGED Pod",
|
||||
category=AccessRisk,
|
||||
category=PrivilegedContainerTechnique,
|
||||
)
|
||||
self.evidence = evidence
|
||||
|
||||
@@ -245,7 +250,7 @@ class PatchAPod(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Patched A Pod",
|
||||
category=AccessRisk,
|
||||
category=SidecarInjectionTechnique,
|
||||
)
|
||||
self.evidence = evidence
|
||||
|
||||
@@ -258,7 +263,7 @@ class DeleteAPod(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Deleted A Pod",
|
||||
category=AccessRisk,
|
||||
category=DataDestructionTechnique,
|
||||
)
|
||||
self.evidence = evidence
|
||||
|
||||
@@ -377,7 +382,7 @@ class AccessApiServerWithToken(AccessApiServer):
|
||||
super().__init__(event)
|
||||
assert self.event.auth_token
|
||||
self.headers = {"Authorization": f"Bearer {self.event.auth_token}"}
|
||||
self.category = InformationDisclosure
|
||||
self.category = AccessK8sApiServerTechnique
|
||||
self.with_token = True
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ from scapy.all import ARP, IP, ICMP, Ether, sr1, srp
|
||||
from kube_hunter.conf import get_config
|
||||
from kube_hunter.core.events import handler
|
||||
from kube_hunter.core.events.types import Event, Vulnerability
|
||||
from kube_hunter.core.types import ActiveHunter, KubernetesCluster, IdentityTheft
|
||||
from kube_hunter.core.types import ActiveHunter, KubernetesCluster, ARPPoisoningTechnique
|
||||
from kube_hunter.modules.hunting.capabilities import CapNetRawEnabled
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -20,7 +20,7 @@ class PossibleArpSpoofing(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
"Possible Arp Spoof",
|
||||
category=IdentityTheft,
|
||||
category=ARPPoisoningTechnique,
|
||||
vid="KHV020",
|
||||
)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import logging
|
||||
from kube_hunter.modules.discovery.hosts import RunningAsPodEvent
|
||||
from kube_hunter.core.events import handler
|
||||
from kube_hunter.core.events.types import Event, Vulnerability
|
||||
from kube_hunter.core.types import Hunter, AccessRisk, KubernetesCluster
|
||||
from kube_hunter.core.types import Hunter, ARPPoisoningTechnique, KubernetesCluster
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -20,7 +20,7 @@ class CapNetRawEnabled(Event, Vulnerability):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="CAP_NET_RAW Enabled",
|
||||
category=AccessRisk,
|
||||
category=ARPPoisoningTechnique,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import logging
|
||||
import base64
|
||||
import re
|
||||
|
||||
from kube_hunter.core.types import Hunter, KubernetesCluster, InformationDisclosure
|
||||
from kube_hunter.core.types import Hunter, KubernetesCluster, GeneralSensitiveInformationTechnique
|
||||
from kube_hunter.core.events import handler
|
||||
from kube_hunter.core.events.types import Vulnerability, Event, Service
|
||||
|
||||
@@ -21,7 +21,7 @@ class CertificateEmail(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
"Certificate Includes Email Address",
|
||||
category=InformationDisclosure,
|
||||
category=GeneralSensitiveInformationTechnique,
|
||||
vid="KHV021",
|
||||
)
|
||||
self.email = email
|
||||
|
||||
@@ -6,11 +6,11 @@ from kube_hunter.core.events import handler
|
||||
from kube_hunter.core.events.types import Vulnerability, Event, K8sVersionDisclosure
|
||||
from kube_hunter.core.types import (
|
||||
Hunter,
|
||||
KubernetesCluster,
|
||||
RemoteCodeExec,
|
||||
PrivilegeEscalation,
|
||||
DenialOfService,
|
||||
KubectlClient,
|
||||
KubernetesCluster,
|
||||
CVERemoteCodeExecutionCategory,
|
||||
CVEPrivilegeEscalationCategory,
|
||||
CVEDenialOfServiceTechnique,
|
||||
)
|
||||
from kube_hunter.modules.discovery.kubectl import KubectlClientEvent
|
||||
|
||||
@@ -25,7 +25,7 @@ class ServerApiVersionEndPointAccessPE(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Critical Privilege Escalation CVE",
|
||||
category=PrivilegeEscalation,
|
||||
category=CVEPrivilegeEscalationCategory,
|
||||
vid="KHV022",
|
||||
)
|
||||
self.evidence = evidence
|
||||
@@ -40,7 +40,7 @@ class ServerApiVersionEndPointAccessDos(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Denial of Service to Kubernetes API Server",
|
||||
category=DenialOfService,
|
||||
category=CVEDenialOfServiceTechnique,
|
||||
vid="KHV023",
|
||||
)
|
||||
self.evidence = evidence
|
||||
@@ -55,7 +55,7 @@ class PingFloodHttp2Implementation(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Possible Ping Flood Attack",
|
||||
category=DenialOfService,
|
||||
category=CVEDenialOfServiceTechnique,
|
||||
vid="KHV024",
|
||||
)
|
||||
self.evidence = evidence
|
||||
@@ -70,7 +70,7 @@ class ResetFloodHttp2Implementation(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Possible Reset Flood Attack",
|
||||
category=DenialOfService,
|
||||
category=CVEDenialOfServiceTechnique,
|
||||
vid="KHV025",
|
||||
)
|
||||
self.evidence = evidence
|
||||
@@ -85,7 +85,7 @@ class ServerApiClusterScopedResourcesAccess(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Arbitrary Access To Cluster Scoped Resources",
|
||||
category=PrivilegeEscalation,
|
||||
category=CVEPrivilegeEscalationCategory,
|
||||
vid="KHV026",
|
||||
)
|
||||
self.evidence = evidence
|
||||
@@ -100,7 +100,7 @@ class IncompleteFixToKubectlCpVulnerability(Vulnerability, Event):
|
||||
self,
|
||||
KubectlClient,
|
||||
"Kubectl Vulnerable To CVE-2019-11246",
|
||||
category=RemoteCodeExec,
|
||||
category=CVERemoteCodeExecutionCategory,
|
||||
vid="KHV027",
|
||||
)
|
||||
self.binary_version = binary_version
|
||||
@@ -116,7 +116,7 @@ class KubectlCpVulnerability(Vulnerability, Event):
|
||||
self,
|
||||
KubectlClient,
|
||||
"Kubectl Vulnerable To CVE-2019-1002101",
|
||||
category=RemoteCodeExec,
|
||||
category=CVERemoteCodeExecutionCategory,
|
||||
vid="KHV028",
|
||||
)
|
||||
self.binary_version = binary_version
|
||||
|
||||
@@ -3,7 +3,7 @@ import json
|
||||
import requests
|
||||
|
||||
from kube_hunter.conf import get_config
|
||||
from kube_hunter.core.types import Hunter, RemoteCodeExec, KubernetesCluster
|
||||
from kube_hunter.core.types import Hunter, AccessK8sDashboardTechnique, KubernetesCluster
|
||||
from kube_hunter.core.events import handler
|
||||
from kube_hunter.core.events.types import Vulnerability, Event
|
||||
from kube_hunter.modules.discovery.dashboard import KubeDashboardEvent
|
||||
@@ -19,7 +19,7 @@ class DashboardExposed(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
"Dashboard Exposed",
|
||||
category=RemoteCodeExec,
|
||||
category=AccessK8sDashboardTechnique,
|
||||
vid="KHV029",
|
||||
)
|
||||
self.evidence = "nodes: {}".format(" ".join(nodes)) if nodes else None
|
||||
|
||||
@@ -6,7 +6,7 @@ from scapy.all import IP, ICMP, UDP, DNS, DNSQR, ARP, Ether, sr1, srp1, srp
|
||||
from kube_hunter.conf import get_config
|
||||
from kube_hunter.core.events import handler
|
||||
from kube_hunter.core.events.types import Event, Vulnerability
|
||||
from kube_hunter.core.types import ActiveHunter, KubernetesCluster, IdentityTheft
|
||||
from kube_hunter.core.types import ActiveHunter, KubernetesCluster, CoreDNSPoisoningTechnique
|
||||
from kube_hunter.modules.hunting.arp import PossibleArpSpoofing
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -21,7 +21,7 @@ class PossibleDnsSpoofing(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
"Possible DNS Spoof",
|
||||
category=IdentityTheft,
|
||||
category=CoreDNSPoisoningTechnique,
|
||||
vid="KHV030",
|
||||
)
|
||||
self.kubedns_pod_ip = kubedns_pod_ip
|
||||
|
||||
@@ -8,10 +8,10 @@ from kube_hunter.core.types import (
|
||||
ActiveHunter,
|
||||
Hunter,
|
||||
KubernetesCluster,
|
||||
InformationDisclosure,
|
||||
RemoteCodeExec,
|
||||
UnauthenticatedAccess,
|
||||
AccessRisk,
|
||||
GeneralSensitiveInformationTechnique,
|
||||
GeneralPersistenceTechnique,
|
||||
ListK8sSecretsTechnique,
|
||||
ExposedSensitiveInterfacesTechnique,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -29,7 +29,7 @@ class EtcdRemoteWriteAccessEvent(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Etcd Remote Write Access Event",
|
||||
category=RemoteCodeExec,
|
||||
category=GeneralPersistenceTechnique,
|
||||
vid="KHV031",
|
||||
)
|
||||
self.evidence = write_res
|
||||
@@ -43,7 +43,7 @@ class EtcdRemoteReadAccessEvent(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Etcd Remote Read Access Event",
|
||||
category=AccessRisk,
|
||||
category=ListK8sSecretsTechnique,
|
||||
vid="KHV032",
|
||||
)
|
||||
self.evidence = keys
|
||||
@@ -58,7 +58,7 @@ class EtcdRemoteVersionDisclosureEvent(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Etcd Remote version disclosure",
|
||||
category=InformationDisclosure,
|
||||
category=GeneralSensitiveInformationTechnique,
|
||||
vid="KHV033",
|
||||
)
|
||||
self.evidence = version
|
||||
@@ -74,7 +74,7 @@ class EtcdAccessEnabledWithoutAuthEvent(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Etcd is accessible using insecure connection (HTTP)",
|
||||
category=UnauthenticatedAccess,
|
||||
category=ExposedSensitiveInterfacesTechnique,
|
||||
vid="KHV034",
|
||||
)
|
||||
self.evidence = version
|
||||
|
||||
@@ -16,9 +16,12 @@ from kube_hunter.core.types import (
|
||||
ActiveHunter,
|
||||
KubernetesCluster,
|
||||
Kubelet,
|
||||
InformationDisclosure,
|
||||
RemoteCodeExec,
|
||||
AccessRisk,
|
||||
ExposedSensitiveInterfacesTechnique,
|
||||
ExecIntoContainerTechnique,
|
||||
GeneralDefenseEvasionTechnique,
|
||||
GeneralSensitiveInformationTechnique,
|
||||
PrivilegedContainerTechnique,
|
||||
AccessKubeletAPITechnique,
|
||||
)
|
||||
from kube_hunter.modules.discovery.kubelet import (
|
||||
ReadOnlyKubeletEvent,
|
||||
@@ -35,7 +38,7 @@ class ExposedPodsHandler(Vulnerability, Event):
|
||||
|
||||
def __init__(self, pods):
|
||||
Vulnerability.__init__(
|
||||
self, component=Kubelet, name="Exposed Pods", category=InformationDisclosure, vid="KHV052"
|
||||
self, component=Kubelet, name="Exposed Pods", category=AccessKubeletAPITechnique, vid="KHV052"
|
||||
)
|
||||
self.pods = pods
|
||||
self.evidence = f"count: {len(self.pods)}"
|
||||
@@ -50,7 +53,7 @@ class AnonymousAuthEnabled(Vulnerability, Event):
|
||||
self,
|
||||
component=Kubelet,
|
||||
name="Anonymous Authentication",
|
||||
category=RemoteCodeExec,
|
||||
category=ExposedSensitiveInterfacesTechnique,
|
||||
vid="KHV036",
|
||||
)
|
||||
|
||||
@@ -63,7 +66,7 @@ class ExposedContainerLogsHandler(Vulnerability, Event):
|
||||
self,
|
||||
component=Kubelet,
|
||||
name="Exposed Container Logs",
|
||||
category=InformationDisclosure,
|
||||
category=AccessKubeletAPITechnique,
|
||||
vid="KHV037",
|
||||
)
|
||||
|
||||
@@ -77,7 +80,7 @@ class ExposedRunningPodsHandler(Vulnerability, Event):
|
||||
self,
|
||||
component=Kubelet,
|
||||
name="Exposed Running Pods",
|
||||
category=InformationDisclosure,
|
||||
category=AccessKubeletAPITechnique,
|
||||
vid="KHV038",
|
||||
)
|
||||
self.count = count
|
||||
@@ -92,7 +95,7 @@ class ExposedExecHandler(Vulnerability, Event):
|
||||
self,
|
||||
component=Kubelet,
|
||||
name="Exposed Exec On Container",
|
||||
category=RemoteCodeExec,
|
||||
category=ExecIntoContainerTechnique,
|
||||
vid="KHV039",
|
||||
)
|
||||
|
||||
@@ -105,7 +108,7 @@ class ExposedRunHandler(Vulnerability, Event):
|
||||
self,
|
||||
component=Kubelet,
|
||||
name="Exposed Run Inside Container",
|
||||
category=RemoteCodeExec,
|
||||
category=ExecIntoContainerTechnique,
|
||||
vid="KHV040",
|
||||
)
|
||||
|
||||
@@ -118,7 +121,7 @@ class ExposedPortForwardHandler(Vulnerability, Event):
|
||||
self,
|
||||
component=Kubelet,
|
||||
name="Exposed Port Forward",
|
||||
category=RemoteCodeExec,
|
||||
category=GeneralDefenseEvasionTechnique,
|
||||
vid="KHV041",
|
||||
)
|
||||
|
||||
@@ -132,7 +135,7 @@ class ExposedAttachHandler(Vulnerability, Event):
|
||||
self,
|
||||
component=Kubelet,
|
||||
name="Exposed Attaching To Container",
|
||||
category=RemoteCodeExec,
|
||||
category=ExecIntoContainerTechnique,
|
||||
vid="KHV042",
|
||||
)
|
||||
|
||||
@@ -146,7 +149,7 @@ class ExposedHealthzHandler(Vulnerability, Event):
|
||||
self,
|
||||
component=Kubelet,
|
||||
name="Cluster Health Disclosure",
|
||||
category=InformationDisclosure,
|
||||
category=GeneralSensitiveInformationTechnique,
|
||||
vid="KHV043",
|
||||
)
|
||||
self.status = status
|
||||
@@ -163,7 +166,7 @@ the whole cluster"""
|
||||
self,
|
||||
component=KubernetesCluster,
|
||||
name="Exposed Existing Privileged Container(s) Via Secure Kubelet Port",
|
||||
category=AccessRisk,
|
||||
category=PrivilegedContainerTechnique,
|
||||
vid="KHV051",
|
||||
)
|
||||
self.exposed_existing_privileged_containers = exposed_existing_privileged_containers
|
||||
@@ -178,7 +181,7 @@ class PrivilegedContainers(Vulnerability, Event):
|
||||
self,
|
||||
component=KubernetesCluster,
|
||||
name="Privileged Container",
|
||||
category=AccessRisk,
|
||||
category=PrivilegedContainerTechnique,
|
||||
vid="KHV044",
|
||||
)
|
||||
self.containers = containers
|
||||
@@ -193,7 +196,7 @@ class ExposedSystemLogs(Vulnerability, Event):
|
||||
self,
|
||||
component=Kubelet,
|
||||
name="Exposed System Logs",
|
||||
category=InformationDisclosure,
|
||||
category=AccessKubeletAPITechnique,
|
||||
vid="KHV045",
|
||||
)
|
||||
|
||||
@@ -206,7 +209,7 @@ class ExposedKubeletCmdline(Vulnerability, Event):
|
||||
self,
|
||||
component=Kubelet,
|
||||
name="Exposed Kubelet Cmdline",
|
||||
category=InformationDisclosure,
|
||||
category=AccessKubeletAPITechnique,
|
||||
vid="KHV046",
|
||||
)
|
||||
self.cmdline = cmdline
|
||||
|
||||
@@ -5,12 +5,7 @@ import uuid
|
||||
from kube_hunter.conf import get_config
|
||||
from kube_hunter.core.events import handler
|
||||
from kube_hunter.core.events.types import Event, Vulnerability
|
||||
from kube_hunter.core.types import (
|
||||
ActiveHunter,
|
||||
Hunter,
|
||||
KubernetesCluster,
|
||||
PrivilegeEscalation,
|
||||
)
|
||||
from kube_hunter.core.types import ActiveHunter, Hunter, KubernetesCluster, HostPathMountPrivilegeEscalationTechnique
|
||||
from kube_hunter.modules.hunting.kubelet import (
|
||||
ExposedPodsHandler,
|
||||
ExposedRunHandler,
|
||||
@@ -28,7 +23,7 @@ class WriteMountToVarLog(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
"Pod With Mount To /var/log",
|
||||
category=PrivilegeEscalation,
|
||||
category=HostPathMountPrivilegeEscalationTechnique,
|
||||
vid="KHV047",
|
||||
)
|
||||
self.pods = pods
|
||||
@@ -44,7 +39,7 @@ class DirectoryTraversalWithKubelet(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
"Root Traversal Read On The Kubelet",
|
||||
category=PrivilegeEscalation,
|
||||
category=HostPathMountPrivilegeEscalationTechnique,
|
||||
)
|
||||
self.output = output
|
||||
self.evidence = f"output: {self.output}"
|
||||
|
||||
@@ -10,7 +10,7 @@ from kube_hunter.core.types import (
|
||||
ActiveHunter,
|
||||
Hunter,
|
||||
KubernetesCluster,
|
||||
InformationDisclosure,
|
||||
ConnectFromProxyServerTechnique,
|
||||
)
|
||||
from kube_hunter.modules.discovery.dashboard import KubeDashboardEvent
|
||||
from kube_hunter.modules.discovery.proxy import KubeProxyEvent
|
||||
@@ -26,7 +26,7 @@ class KubeProxyExposed(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
"Proxy Exposed",
|
||||
category=InformationDisclosure,
|
||||
category=ConnectFromProxyServerTechnique,
|
||||
vid="KHV049",
|
||||
)
|
||||
|
||||
@@ -123,5 +123,6 @@ class K8sVersionDisclosureProve(ActiveHunter):
|
||||
version=version_metadata["gitVersion"],
|
||||
from_endpoint="/version",
|
||||
extra_info="on kube-proxy",
|
||||
category=ConnectFromProxyServerTechnique,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@ import os
|
||||
|
||||
from kube_hunter.core.events import handler
|
||||
from kube_hunter.core.events.types import Vulnerability, Event
|
||||
from kube_hunter.core.types import Hunter, KubernetesCluster, AccessRisk
|
||||
from kube_hunter.core.types import Hunter, KubernetesCluster, AccessContainerServiceAccountTechnique
|
||||
from kube_hunter.modules.discovery.hosts import RunningAsPodEvent
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -17,7 +17,7 @@ class ServiceAccountTokenAccess(Vulnerability, Event):
|
||||
self,
|
||||
KubernetesCluster,
|
||||
name="Read access to pod's service account token",
|
||||
category=AccessRisk,
|
||||
category=AccessContainerServiceAccountTechnique,
|
||||
vid="KHV050",
|
||||
)
|
||||
self.evidence = evidence
|
||||
@@ -31,7 +31,7 @@ class SecretsAccess(Vulnerability, Event):
|
||||
self,
|
||||
component=KubernetesCluster,
|
||||
name="Access to pod's secrets",
|
||||
category=AccessRisk,
|
||||
category=AccessContainerServiceAccountTechnique,
|
||||
)
|
||||
self.evidence = evidence
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ class BaseReporter:
|
||||
{
|
||||
"location": vuln.location(),
|
||||
"vid": vuln.get_vid(),
|
||||
"category": vuln.category.name,
|
||||
"category": vuln.category.get_name(),
|
||||
"severity": vuln.get_severity(),
|
||||
"vulnerability": vuln.get_name(),
|
||||
"description": vuln.explain(),
|
||||
|
||||
@@ -83,7 +83,7 @@ class PlainReporter(BaseReporter):
|
||||
column_names = [
|
||||
"ID",
|
||||
"Location",
|
||||
"Category",
|
||||
"MITRE Category",
|
||||
"Vulnerability",
|
||||
"Description",
|
||||
"Evidence",
|
||||
@@ -91,7 +91,7 @@ class PlainReporter(BaseReporter):
|
||||
vuln_table = PrettyTable(column_names, hrules=ALL)
|
||||
vuln_table.align = "l"
|
||||
vuln_table.max_width = MAX_TABLE_WIDTH
|
||||
vuln_table.sortby = "Category"
|
||||
vuln_table.sortby = "MITRE Category"
|
||||
vuln_table.reversesort = True
|
||||
vuln_table.padding_width = 1
|
||||
vuln_table.header_style = "upper"
|
||||
@@ -101,10 +101,11 @@ class PlainReporter(BaseReporter):
|
||||
evidence = str(vuln.evidence)
|
||||
if len(evidence) > EVIDENCE_PREVIEW:
|
||||
evidence = evidence[:EVIDENCE_PREVIEW] + "..."
|
||||
|
||||
row = [
|
||||
vuln.get_vid(),
|
||||
vuln.location(),
|
||||
vuln.category.name,
|
||||
vuln.category.get_name(),
|
||||
vuln.get_name(),
|
||||
vuln.explain(),
|
||||
evidence,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# flake8: noqa: E402
|
||||
from kube_hunter.core.types.vulnerabilities import AccessK8sApiServerTechnique
|
||||
import requests_mock
|
||||
import time
|
||||
|
||||
@@ -21,7 +22,7 @@ from kube_hunter.modules.hunting.apiserver import (
|
||||
from kube_hunter.modules.hunting.apiserver import ApiServerPassiveHunterFinished
|
||||
from kube_hunter.modules.hunting.apiserver import CreateANamespace, DeleteANamespace
|
||||
from kube_hunter.modules.discovery.apiserver import ApiServer
|
||||
from kube_hunter.core.types import UnauthenticatedAccess, InformationDisclosure
|
||||
from kube_hunter.core.types import ExposedSensitiveInterfacesTechnique, AccessK8sApiServerTechnique
|
||||
from kube_hunter.core.events import handler
|
||||
|
||||
counter = 0
|
||||
@@ -181,10 +182,10 @@ class test_ListClusterRoles:
|
||||
class test_ServerApiAccess:
|
||||
def __init__(self, event):
|
||||
print("ServerApiAccess")
|
||||
if event.category == UnauthenticatedAccess:
|
||||
if event.category == ExposedSensitiveInterfacesTechnique:
|
||||
assert event.auth_token is None
|
||||
else:
|
||||
assert event.category == InformationDisclosure
|
||||
assert event.category == AccessK8sApiServerTechnique
|
||||
assert event.auth_token == "so-secret"
|
||||
global counter
|
||||
counter += 1
|
||||
|
||||
Reference in New Issue
Block a user