Ejemplo n.º 1
0
import json

from types import SimpleNamespace
from requests_mock import Mocker
from kube_hunter.conf import Config, set_config

set_config(Config())

from kube_hunter.modules.hunting.dashboard import KubeDashboard  # noqa: E402


class TestKubeDashboard:
    @staticmethod
    def get_nodes_mock(result: dict, **kwargs):
        with Mocker() as m:
            m.get("http://mockdashboard:8000/api/v1/node",
                  text=json.dumps(result),
                  **kwargs)
            hunter = KubeDashboard(
                SimpleNamespace(host="mockdashboard", port=8000))
            return hunter.get_nodes()

    @staticmethod
    def test_get_nodes_with_result():
        nodes = {"nodes": [{"objectMeta": {"name": "node1"}}]}
        expected = ["node1"]
        actual = TestKubeDashboard.get_nodes_mock(nodes)

        assert expected == actual

    @staticmethod
Ejemplo n.º 2
0
# flake8: noqa: E402

from kube_hunter.conf import Config, set_config

set_config(Config(active=True))

from kube_hunter.core.events.handler import handler
from kube_hunter.modules.discovery.apiserver import ApiServiceDiscovery
from kube_hunter.modules.discovery.dashboard import KubeDashboard as KubeDashboardDiscovery
from kube_hunter.modules.discovery.etcd import EtcdRemoteAccess as EtcdRemoteAccessDiscovery
from kube_hunter.modules.discovery.hosts import FromPodHostDiscovery, HostDiscovery
from kube_hunter.modules.discovery.kubectl import KubectlClientDiscovery
from kube_hunter.modules.discovery.kubelet import KubeletDiscovery
from kube_hunter.modules.discovery.ports import PortDiscovery
from kube_hunter.modules.discovery.proxy import KubeProxy as KubeProxyDiscovery
from kube_hunter.modules.hunting.aks import AzureSpnHunter, ProveAzureSpnExposure
from kube_hunter.modules.hunting.apiserver import (
    AccessApiServer,
    ApiVersionHunter,
    AccessApiServerActive,
    AccessApiServerWithToken,
)
from kube_hunter.modules.hunting.arp import ArpSpoofHunter
from kube_hunter.modules.hunting.capabilities import PodCapabilitiesHunter
from kube_hunter.modules.hunting.certificates import CertificateDiscovery
from kube_hunter.modules.hunting.cves import K8sClusterCveHunter, KubectlCVEHunter
from kube_hunter.modules.hunting.dashboard import KubeDashboard
from kube_hunter.modules.hunting.dns import DnsSpoofHunter
from kube_hunter.modules.hunting.etcd import EtcdRemoteAccess, EtcdRemoteAccessActive
from kube_hunter.modules.hunting.kubelet import (
    ProveAnonymousAuth,
Ejemplo n.º 3
0
from kube_hunter.conf import Config, set_config
from kube_hunter.conf.parser import parse_args
from kube_hunter.conf.logging import setup_logger

from kube_hunter.plugins import initialize_plugin_manager

pm = initialize_plugin_manager()
# Using a plugin hook for adding arguments before parsing
args = parse_args(add_args_hook=pm.hook.parser_add_arguments)
config = Config(
    active=args.active,
    cidr=args.cidr,
    include_patched_versions=args.include_patched_versions,
    interface=args.interface,
    log_file=args.log_file,
    mapping=args.mapping,
    network_timeout=args.network_timeout,
    pod=args.pod,
    quick=args.quick,
    remote=args.remote,
    statistics=args.statistics,
)
setup_logger(args.log, args.log_file)
set_config(config)

# Running all other registered plugins before execution
pm.hook.load_plugin(args=args)

from kube_hunter.core.events import handler
from kube_hunter.core.events.types import HuntFinished, HuntStarted
from kube_hunter.modules.discovery.hosts import RunningAsPodEvent, HostScanEvent
Ejemplo n.º 4
0
from kube_hunter.conf.logging import setup_logger

from kube_hunter.plugins import initialize_plugin_manager

pm = initialize_plugin_manager()
# Using a plugin hook for adding arguments before parsing
args = parse_args(add_args_hook=pm.hook.parser_add_arguments)
config = Config(
    active=args.active,
    cidr=args.cidr,
    include_patched_versions=args.include_patched_versions,
    interface=args.interface,
    log_file=args.log_file,
    mapping=args.mapping,
    network_timeout=args.network_timeout,
    pod=args.pod,
    quick=args.quick,
    remote=args.remote,
    statistics=args.statistics,
    k8s_auto_discover_nodes=args.k8s_auto_discover_nodes,
    service_account_token=args.service_account_token,
    kubeconfig=args.kubeconfig,
    enable_cve_hunting=args.enable_cve_hunting,
    custom=args.custom,
)
setup_logger(args.log, args.log_file)
set_config(config)

# Running all other registered plugins before execution
pm.hook.load_plugin(args=args)

from kube_hunter.core.events import handler
Ejemplo n.º 5
0
class TestExposedLogsOnContainerFileSystemHunter:
    POD_NAMESPACE = "my_namespace"
    POD_ID = "my_id"
    CONTAINER_NAME = "my_c_name"

    class DummyEvent:
        def __init__(self):
            self.host = HOST
            self.session = requests.session()

    HUNTER = ExposedLogsOnContainerFileSystemHunter(DummyEvent())
    CONFIG = Config()

    def test__init__(self):
        assert self.HUNTER.base_url == f"https://{HOST}:10250"

    def test_find_all_pods(self):
        scenarios = {
            json.dumps({"should": "ignore"}): None,
            json.dumps({"items": [1, 2]}): [1, 2]
        }

        for scenario, expected_result in scenarios.items():
            with requests_mock.Mocker() as mock:
                mock.get(f"https://{HOST}:10250/pods", text=scenario)

                result = self.HUNTER._find_all_pods(self.CONFIG)
                assert result == expected_result

    def test_send_run_request(self):
        cmd = "my_cmd"

        def return_false(s):
            return False

        def return_true(s):
            return True

        scenarios = {
            ("", None): None,
            ("   ", None): None,
            ("Some String", None): "Some String",
            ("Some String", return_false): None,
            ("Some String", return_true): "Some String",
        }

        for scenario, expected_result in scenarios.items():
            with requests_mock.Mocker() as mock:
                mock.post(
                    f"https://{HOST}:10250/run/{self.POD_NAMESPACE}/{self.POD_ID}/{self.CONTAINER_NAME}?"
                    f"cmd={cmd}",
                    text=scenario[0])

                result = self.HUNTER._send_run_request(
                    config=self.CONFIG,
                    pod_namespace=self.POD_NAMESPACE,
                    pod_id=self.POD_ID,
                    container_name=self.CONTAINER_NAME,
                    cmd=cmd,
                    is_valid_response_func=scenario[1])

                assert result == expected_result

    def test_find_log_files(self):
        cmd = "find /var/log -type f -print"

        scenarios = {
            "": None,
            " No such file or directory ": None,
            " file1.log \n  file2.log \n  ": ["file1.log", "file2.log"]
        }

        for scenario, expected_result in scenarios.items():
            with requests_mock.Mocker() as mock:
                mock.post(
                    f"https://{HOST}:10250/run/{self.POD_NAMESPACE}/{self.POD_ID}/{self.CONTAINER_NAME}?"
                    f"cmd={cmd}",
                    text=scenario)

                result = self.HUNTER._find_log_files(self.CONFIG,
                                                     self.POD_NAMESPACE,
                                                     self.POD_ID,
                                                     self.CONTAINER_NAME)
                assert result == expected_result

    def test_read_contents_of_file(self):
        log = "my.log"
        cmd = f"tail {log}"

        scenarios = {
            "": None,
            f"tail: {log}: Permission denied": None,
            "This text was in the file": "This text was in the file"
        }

        for scenario, expected_result in scenarios.items():
            with requests_mock.Mocker() as mock:
                mock.post(
                    f"https://{HOST}:10250/run/{self.POD_NAMESPACE}/{self.POD_ID}/{self.CONTAINER_NAME}?"
                    f"cmd={cmd}",
                    text=scenario)

                result = self.HUNTER._read_contents_of_file(
                    self.CONFIG,
                    self.POD_NAMESPACE,
                    self.POD_ID,
                    self.CONTAINER_NAME,
                    log_file=log)
                assert result == expected_result

    def test_find_contents_of_any_log_file_with_no_logs(self):
        with requests_mock.Mocker() as mock:
            mock.post(
                f"https://{HOST}:10250/run/{self.POD_NAMESPACE}/{self.POD_ID}/{self.CONTAINER_NAME}?"
                f"cmd=find /var/log -type f -print",
                text="exited with 126")

            assert self.HUNTER._find_contents_of_any_log_file(
                self.CONFIG, self.POD_NAMESPACE, self.POD_ID,
                self.CONTAINER_NAME) == (None, None)

    def test_find_contents_of_any_log_file(self):
        with requests_mock.Mocker() as mock:
            mock.post(
                f"https://{HOST}:10250/run/{self.POD_NAMESPACE}/{self.POD_ID}/{self.CONTAINER_NAME}?"
                f"cmd=find /var/log -type f -print",
                text="log1.log\nlog2.log")

            mock.post(
                f"https://{HOST}:10250/run/{self.POD_NAMESPACE}/{self.POD_ID}/{self.CONTAINER_NAME}?"
                f"cmd=tail log1.log",
                text="tail: log1.log: Permission denied")

            mock.post(
                f"https://{HOST}:10250/run/{self.POD_NAMESPACE}/{self.POD_ID}/{self.CONTAINER_NAME}?"
                f"cmd=tail log2.log",
                text="This is the contents of of the file")

            assert self.HUNTER._find_contents_of_any_log_file(
                self.CONFIG, self.POD_NAMESPACE, self.POD_ID, self.CONTAINER_NAME) == \
                ("log2.log", "This is the contents of of the file")

    def test_execute(self):
        PUBLISHED_EVENTS.clear()
        assert len(PUBLISHED_EVENTS) == 0

        pods_data = [
            # Should Ignore As No Containers
            {
                "metadata": {
                    "namespace": "namespace_1",
                    "name": "pod_id_1"
                },
                "spec": {
                    "containers": []
                }
            },

            # Should find the logs in container_2
            {
                "metadata": {
                    "namespace": f"{self.POD_NAMESPACE}",
                    "name": f"{self.POD_ID}"
                },
                "spec": {
                    "containers": [{
                        "name": "container_1"
                    }, {
                        "name": "container_2"
                    }]
                }
            },

            # Should ignore as we've already found a log in the above container
            {
                "metadata": {
                    "namespace": f"{self.POD_NAMESPACE}_2",
                    "name": f"{self.POD_ID}_2"
                },
                "spec": {
                    "containers": [{
                        "name": "container_3"
                    }, {
                        "name": "container_4"
                    }]
                }
            },
        ]

        with requests_mock.Mocker() as mock:
            mock.get(f"https://{HOST}:10250/pods",
                     text=json.dumps({"items": pods_data}))

            mock.post(
                f"https://{HOST}:10250/run/{self.POD_NAMESPACE}/{self.POD_ID}/"
                + f"container_1?cmd=find%20/var/log%20-type%20f%20-print",
                text="")
            mock.post(
                f"https://{HOST}:10250/run/{self.POD_NAMESPACE}/{self.POD_ID}/"
                + f"container_2?cmd=find%20/var/log%20-type%20f%20-print",
                text="log1.log \n log2.log")

            mock.post(
                f"https://{HOST}:10250/run/{self.POD_NAMESPACE}/{self.POD_ID}/container_2?"
                f"cmd=tail%20log1.log",
                text="tail: log1.log: Permission denied")
            mock.post(
                f"https://{HOST}:10250/run/{self.POD_NAMESPACE}/{self.POD_ID}/container_2?"
                f"cmd=tail%20log2.log",
                text="file contents")

            self.HUNTER.execute()

            assert len(PUBLISHED_EVENTS) == 1
            assert PUBLISHED_EVENTS[0].vid == "KHV052"
            assert PUBLISHED_EVENTS[0].evidence == f"PodId: {self.POD_ID}, ContainerName: container_2, " \
                f"File: log2.log, Contents: file contents"
Ejemplo n.º 6
0
 def test_execute_scan_remote(self):
     set_config(Config(remote="1.2.3.4"))
     f = FromPodHostDiscovery(RunningAsPodEvent())
     f.execute()
Ejemplo n.º 7
0
 def test_execute_scan_cidr(self):
     set_config(Config(cidr="1.2.3.4/30"))
     f = FromPodHostDiscovery(RunningAsPodEvent())
     f.execute()