Compare commits

...

12 Commits

Author SHA1 Message Date
Kiran Bodipi
bc47f08e88 fix: resolved severity discrepancy between kube-hunter report and docs for khv043 (#551) 2024-03-19 14:30:55 +02:00
Kiran Bodipi
3e1347290b fix: resolved severity discrepancy between kube-hunter report and docs (#550) 2024-03-11 14:22:47 +02:00
Andreas Lindhé
7479aae9ba Fix broken link to Trivy (#546)
Fixes #545
2023-11-15 15:30:45 +02:00
Itay Shakury
e8827b24f6 add maintenance notice (#544) 2023-11-11 01:05:12 +02:00
Itay Shakury
ff9f2c536f update logo (#520) 2022-09-04 09:39:33 +03:00
danielsagi
eb31026d8e Removing netifaces due to lack of maintainer (#519)
* removed dependency on netifaces entirely by using psutil and manually parsing /proc/net/route to figure out default gateway

* Checking if /proc/net/route is accessible. before commiting to parse it

* changed to using pyroute2 instead of manually parsing /proc/net/route and psutil for interface enum

* added pyroute2 as a dependency

* fixed bug in subnets appending

* added windows support using a powershell snippet for interface enum
2022-08-25 21:31:02 +03:00
danielsagi
a578726495 update manifest to 0.6.8 (#509) 2022-05-13 12:49:12 +03:00
rhtenhove
c442172715 pin image version (#504)
* pin image version to job

* change docker tag format

* update semver GA
2022-05-13 00:27:39 +03:00
danielsagi
d7df38fc95 Fix: Removed automatic import of handler object (#506)
* removed automatic import of handler object in events package and renamed handler.py to event_handler.py to solve name collision
2022-05-12 22:12:31 +03:00
danielsagi
9ce385a190 ignore E402 flake8 on test_cloud 2022-05-07 10:22:17 +03:00
danielsagi
ebd8e2e405 Moved config initialize to start of test_cloud.py to solve bug in testing 2022-05-07 10:22:17 +03:00
danielsagi
585b490f19 Changed help message of --num-worker-threads flag 2022-05-07 10:22:17 +03:00
44 changed files with 137 additions and 74 deletions

View File

@@ -39,7 +39,7 @@ jobs:
password: ${{ secrets.ECR_SECRET_ACCESS_KEY }}
- name: Get version
id: get_version
uses: crazy-max/ghaction-docker-meta@v1
uses: crazy-max/ghaction-docker-meta@v3
with:
images: ${{ env.REP }}
tag-semver: |

View File

@@ -1,18 +1,7 @@
![kube-hunter](https://github.com/aquasecurity/kube-hunter/blob/main/kube-hunter.png)
## Notice
kube-hunter is not under active development anymore. If you're interested in scanning Kubernetes clusters for known vulnerabilities, we recommend using [Trivy](https://github.com/aquasecurity/trivy). Specifically, Trivy's Kubernetes [misconfiguration scanning](https://blog.aquasec.com/trivy-kubernetes-cis-benchmark-scanning) and [KBOM vulnerability scanning](https://blog.aquasec.com/scanning-kbom-for-vulnerabilities-with-trivy). Learn more in the [Trivy Docs](https://aquasecurity.github.io/trivy/).
[![GitHub Release][release-img]][release]
![Downloads][download]
![Docker Pulls][docker-pull]
[![Build Status](https://github.com/aquasecurity/kube-hunter/workflows/Test/badge.svg)](https://github.com/aquasecurity/kube-hunter/actions)
[![codecov](https://codecov.io/gh/aquasecurity/kube-hunter/branch/main/graph/badge.svg)](https://codecov.io/gh/aquasecurity/kube-hunter)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![License](https://img.shields.io/github/license/aquasecurity/kube-hunter)](https://github.com/aquasecurity/kube-hunter/blob/main/LICENSE)
[![Docker image](https://images.microbadger.com/badges/image/aquasec/kube-hunter.svg)](https://microbadger.com/images/aquasec/kube-hunter "Get your own image badge on microbadger.com")
[download]: https://img.shields.io/github/downloads/aquasecurity/kube-hunter/total?logo=github
[release-img]: https://img.shields.io/github/release/aquasecurity/kube-hunter.svg?logo=github
[release]: https://github.com/aquasecurity/kube-hunter/releases
[docker-pull]: https://img.shields.io/docker/pulls/aquasec/kube-hunter?logo=docker&label=docker%20pulls%20%2F%20kube-hunter
---
kube-hunter hunts for security weaknesses in Kubernetes clusters. The tool was developed to increase awareness and visibility for security issues in Kubernetes environments. **You should NOT run kube-hunter on a Kubernetes cluster that you don't own!**
@@ -21,12 +10,9 @@ kube-hunter hunts for security weaknesses in Kubernetes clusters. The tool was d
**Explore vulnerabilities**: The kube-hunter knowledge base includes articles about discoverable vulnerabilities and issues. When kube-hunter reports an issue, it will show its VID (Vulnerability ID) so you can look it up in the KB at https://aquasecurity.github.io/kube-hunter/
_If you're interested in kube-hunter's integration with the Kubernetes ATT&CK Matrix [Continue Reading](#kuberentes-attck-matrix)_
**Contribute**: We welcome contributions, especially new hunter modules that perform additional tests. If you would like to develop your modules please read [Guidelines For Developing Your First kube-hunter Module](https://github.com/aquasecurity/kube-hunter/blob/main/CONTRIBUTING.md).
[kube-hunter demo video](https://youtu.be/s2-6rTkH8a8?t=57s)
[![kube-hunter demo video](https://github.com/aquasecurity/kube-hunter/blob/main/kube-hunter-screenshot.png)](https://youtu.be/s2-6rTkH8a8?t=57s)
Table of Contents
=================
## Table of Contents
- [Table of Contents](#table-of-contents)
- [Kubernetes ATT&CK Matrix](#kubernetes-attck-matrix)
@@ -52,7 +38,6 @@ Table of Contents
- [Contribution](#contribution)
- [License](#license)
---
## Kubernetes ATT&CK Matrix
kube-hunter now supports the new format of the Kubernetes ATT&CK matrix.

View File

@@ -2,7 +2,7 @@
vid: KHV002
title: Kubernetes version disclosure
categories: [Information Disclosure]
severity: low
severity: high
---
# {{ page.vid }} - {{ page.title }}

View File

@@ -2,7 +2,7 @@
vid: KHV036
title: Anonymous Authentication
categories: [Remote Code Execution]
severity: critical
severity: high
---
# {{ page.vid }} - {{ page.title }}

View File

@@ -2,7 +2,7 @@
vid: KHV043
title: Cluster Health Disclosure
categories: [Information Disclosure]
severity: high
severity: low
---
# {{ page.vid }} - {{ page.title }}

View File

@@ -2,7 +2,7 @@
vid: KHV052
title: Exposed Pods
categories: [Information Disclosure]
severity: high
severity: medium
---
# {{ page.vid }} - {{ page.title }}

View File

@@ -5,11 +5,13 @@ metadata:
name: kube-hunter
spec:
template:
metadata:
labels:
app: kube-hunter
spec:
containers:
- name: kube-hunter
image: aquasec/kube-hunter
image: aquasec/kube-hunter:0.6.8
command: ["kube-hunter"]
args: ["--pod"]
restartPolicy: Never
backoffLimit: 4

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -76,7 +76,7 @@ in order to prevent circular dependency bug.
Following the above example, let's figure out the imports:
```python
from kube_hunter.core.types import Hunter
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import OpenPortEvent
@@ -206,7 +206,7 @@ __Make sure to return the event from the execute method, or the event will not g
For example, if you don't want to hunt services found on a localhost IP, you can create the following module, in the `kube_hunter/modules/report/`
```python
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import Service, EventFilterBase
@handler.subscribe(Service)
@@ -222,7 +222,7 @@ That means other Hunters that are subscribed to this Service will not get trigge
That opens up a wide variety of possible operations, as this not only can __filter out__ events, but you can actually __change event attributes__, for example:
```python
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.types import InformationDisclosure
from kube_hunter.core.events.types import Vulnerability, EventFilterBase

View File

@@ -39,7 +39,7 @@ 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.event_handler import handler
from kube_hunter.core.events.types import HuntFinished, HuntStarted
from kube_hunter.modules.discovery.hosts import RunningAsPodEvent, HostScanEvent
from kube_hunter.modules.report import get_reporter, get_dispatcher

View File

@@ -133,10 +133,13 @@ def parser_add_arguments(parser):
parser.add_argument("--network-timeout", type=float, default=5.0, help="network operations timeout")
parser.add_argument("--num-worker-threads", type=int, default=800,
help="In some environments the default thread count of 800 is too much. "
"This crashes the process when trying to open more threads."
"In that case feel free to try a lower number, like 400 for example.")
parser.add_argument(
"--num-worker-threads",
type=int,
default=800,
help="In some environments the default thread count (800) can cause the process to crash. "
"In the case of a crash try lowering the thread count",
)
def parse_args(add_args_hook):

View File

@@ -1,3 +1,2 @@
# flake8: noqa: E402
from .handler import EventQueue, handler
from . import types

View File

@@ -19,7 +19,7 @@ class HunterBase:
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
from ..events.event_handler import handler # noqa
handler.publish_event(event, caller=self)

View File

@@ -2,7 +2,7 @@ import logging
import requests
from kube_hunter.core.types import Discovery
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import OpenPortEvent, Service, Event, EventFilterBase
from kube_hunter.conf import get_config

View File

@@ -3,7 +3,7 @@ import logging
import requests
from kube_hunter.conf import get_config
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import Event, OpenPortEvent, Service
from kube_hunter.core.types import Discovery

View File

@@ -1,4 +1,4 @@
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import Event, OpenPortEvent, Service
from kube_hunter.core.types import Discovery

View File

@@ -1,15 +1,17 @@
import json
import os
import sys
import socket
import logging
import itertools
import requests
from enum import Enum
from netaddr import IPNetwork, IPAddress, AddrFormatError
from netifaces import AF_INET, ifaddresses, interfaces, gateways
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.event_handler import handler
from kube_hunter.core.events.types import Event, NewHostEvent, Vulnerability
from kube_hunter.core.types import Discovery, AWS, Azure, InstanceMetadataApiTechnique
@@ -137,7 +139,9 @@ class FromPodHostDiscovery(Discovery):
elif self.is_aws_pod_v2():
subnets, cloud = self.aws_metadata_v2_discovery()
subnets += self.gateway_discovery()
gateway_subnet = self.gateway_discovery()
if gateway_subnet:
subnets.append(gateway_subnet)
should_scan_apiserver = False
if self.event.kubeservicehost:
@@ -217,7 +221,26 @@ class FromPodHostDiscovery(Discovery):
# for pod scanning
def gateway_discovery(self):
"""Retrieving default gateway of pod, which is usually also a contact point with the host"""
return [[gateways()["default"][AF_INET][0], "24"]]
# read the default gateway directly from /proc
# netifaces currently does not have a maintainer. so we backported to linux support only for this cause.
# TODO: implement WMI queries for windows support
# https://stackoverflow.com/a/6556951
if sys.platform in ["linux", "linux2"]:
try:
from pyroute2 import IPDB
ip = IPDB()
gateway_ip = ip.routes["default"]["gateway"]
ip.release()
return [gateway_ip, "24"]
except Exception as x:
logging.debug(f"Exception while fetching default gateway from container - {x}")
finally:
ip.release()
else:
logging.debug("Not running in a linux env, will not scan default subnet")
return False
# querying AWS's interface metadata api v1 | works only from a pod
def aws_metadata_v1_discovery(self):
@@ -338,13 +361,62 @@ class HostDiscovery(Discovery):
# generate all subnets from all internal network interfaces
def generate_interfaces_subnet(self, sn="24"):
for ifaceName in interfaces():
for ip in [i["addr"] for i in ifaddresses(ifaceName).setdefault(AF_INET, [])]:
if not self.event.localhost and InterfaceTypes.LOCALHOST.value in ip.__str__():
if sys.platform == "win32":
return self.generate_interfaces_subnet_windows()
elif sys.platform in ["linux", "linux2"]:
return self.generate_interfaces_subnet_linux()
def generate_interfaces_subnet_linux(self, sn="24"):
try:
from pyroute2 import IPRoute
ip = IPRoute()
for i in ip.get_addr():
# whitelist only ipv4 ips
if i["family"] == socket.AF_INET:
ipaddress = i[0].get_attr("IFA_ADDRESS")
# TODO: add this instead of hardcoded 24 subnet, (add a flag for full scan option)
# subnet = i['prefixlen']
# unless specified explicitly with localhost scan flag, skip localhost ip addresses
if not self.event.localhost and ipaddress.startswith(InterfaceTypes.LOCALHOST.value):
continue
ip_network = IPNetwork(f"{ipaddress}/{sn}")
for ip in ip_network:
yield ip
except Exception as x:
logging.debug(f"Exception while generating subnet scan from local interfaces: {x}")
finally:
ip.release()
def generate_interfaces_subnet_windows(self, sn="24"):
from subprocess import check_output
local_subnets = (
check_output(
"powershell -NoLogo -NoProfile -NonInteractive -ExecutionPolicy bypass -Command "
' "& {'
"Get-NetIPConfiguration | Get-NetIPAddress | Where-Object {$_.AddressFamily -eq 'IPv4'}"
" | Select-Object -Property IPAddress, PrefixLength | ConvertTo-Json "
' "}',
shell=True,
)
.decode()
.strip()
)
try:
subnets = json.loads(local_subnets)
for subnet in subnets:
if not self.event.localhost and subnet["IPAddress"].startswith(InterfaceTypes.LOCALHOST.value):
continue
for ip in IPNetwork(f"{ip}/{sn}"):
ip_network = IPNetwork(f"{subnet['IPAddress']}/{sn}")
for ip in ip_network:
yield ip
except Exception as x:
logging.debug(f"ERROR: Could not extract interface information using powershell - {x}")
# for comparing prefixes
class InterfaceTypes(Enum):

View File

@@ -2,7 +2,7 @@ import logging
import subprocess
from kube_hunter.core.types import Discovery
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import HuntStarted, Event
logger = logging.getLogger(__name__)

View File

@@ -5,7 +5,7 @@ from enum import Enum
from kube_hunter.conf import get_config
from kube_hunter.core.types import Discovery
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import OpenPortEvent, Event, Service
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

View File

@@ -2,7 +2,7 @@ import logging
from socket import socket
from kube_hunter.core.types import Discovery
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import NewHostEvent, OpenPortEvent
logger = logging.getLogger(__name__)

View File

@@ -3,7 +3,7 @@ import requests
from kube_hunter.conf import get_config
from kube_hunter.core.types import Discovery
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import Service, Event, OpenPortEvent
logger = logging.getLogger(__name__)

View File

@@ -5,7 +5,7 @@ import requests
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.event_handler import handler
from kube_hunter.core.events.types import Event, Vulnerability
from kube_hunter.core.types import Hunter, ActiveHunter, MountServicePrincipalTechnique, Azure

View File

@@ -5,7 +5,7 @@ import requests
from kube_hunter.conf import get_config
from kube_hunter.modules.discovery.apiserver import ApiServer
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler 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.vulnerabilities import (

View File

@@ -2,7 +2,7 @@ import socket
import logging
from kube_hunter.modules.discovery.hosts import RunningAsPodEvent
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import Event, Vulnerability
from kube_hunter.core.types import Hunter, ARPPoisoningTechnique, KubernetesCluster

View File

@@ -4,7 +4,7 @@ import base64
import re
from kube_hunter.core.types import Hunter, KubernetesCluster, GeneralSensitiveInformationTechnique
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import Vulnerability, Event, Service
logger = logging.getLogger(__name__)

View File

@@ -2,7 +2,7 @@ import logging
from packaging import version
from kube_hunter.conf import get_config
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import K8sVersionDisclosure, Vulnerability, Event
from kube_hunter.core.types import (

View File

@@ -4,7 +4,7 @@ import requests
from kube_hunter.conf import get_config
from kube_hunter.core.types import Hunter, AccessK8sDashboardTechnique, KubernetesCluster
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import Vulnerability, Event
from kube_hunter.modules.discovery.dashboard import KubeDashboardEvent

View File

@@ -2,7 +2,7 @@ import logging
import requests
from kube_hunter.conf import get_config
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import Vulnerability, Event, OpenPortEvent
from kube_hunter.core.types import (
ActiveHunter,

View File

@@ -9,7 +9,7 @@ import urllib3
import uuid
from kube_hunter.conf import get_config
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import Vulnerability, Event, K8sVersionDisclosure
from kube_hunter.core.types import (
Hunter,

View File

@@ -3,7 +3,7 @@ import re
import uuid
from kube_hunter.conf import get_config
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import Event, Vulnerability
from kube_hunter.core.types import ActiveHunter, Hunter, KubernetesCluster, HostPathMountPrivilegeEscalationTechnique
from kube_hunter.modules.hunting.kubelet import (

View File

@@ -4,7 +4,7 @@ import requests
from enum import Enum
from kube_hunter.conf import get_config
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import Event, Vulnerability, K8sVersionDisclosure
from kube_hunter.core.types import (
ActiveHunter,

View File

@@ -1,7 +1,7 @@
import logging
import os
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import Vulnerability, Event
from kube_hunter.core.types import Hunter, KubernetesCluster, AccessContainerServiceAccountTechnique
from kube_hunter.modules.discovery.hosts import RunningAsPodEvent

View File

@@ -2,7 +2,7 @@ import logging
import threading
from kube_hunter.conf import get_config
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import (
Event,
Service,

View File

@@ -31,7 +31,7 @@ zip_safe = False
packages = find:
install_requires =
netaddr
netifaces
pyroute2
requests
PrettyTable
urllib3>=1.24.3

View File

@@ -1,11 +1,13 @@
# flake8: noqa: E402
import requests_mock
import json
from kube_hunter.conf import Config, set_config
from kube_hunter.core.events.types import NewHostEvent
set_config(Config())
from kube_hunter.core.events.types import NewHostEvent
def test_presetcloud():
"""Testing if it doesn't try to run get_cloud if the cloud type is already set.

View File

@@ -4,7 +4,7 @@ from kube_hunter.conf import Config, set_config, get_config
set_config(Config(active=True))
from kube_hunter.core.events.handler import handler
from kube_hunter.core.events.event_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

View File

@@ -3,7 +3,7 @@ import time
from kube_hunter.conf import Config, set_config
from kube_hunter.core.types import Hunter
from kube_hunter.core.events.types import Event, Service
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
counter = 0
first_run = True

View File

@@ -8,7 +8,7 @@ set_config(Config())
from kube_hunter.modules.discovery.apiserver import ApiServer, ApiServiceDiscovery
from kube_hunter.core.events.types import Event
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
counter = 0

View File

@@ -6,7 +6,7 @@ from kube_hunter.modules.discovery.hosts import (
HostDiscoveryHelpers,
)
from kube_hunter.core.types import Hunter
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
import json
import requests_mock
import pytest

View File

@@ -23,7 +23,7 @@ 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 ExposedSensitiveInterfacesTechnique, AccessK8sApiServerTechnique
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
counter = 0

View File

@@ -5,7 +5,7 @@ set_config(Config())
from kube_hunter.core.events.types import Event
from kube_hunter.modules.hunting.certificates import CertificateDiscovery, CertificateEmail
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
def test_CertificateDiscovery():

View File

@@ -5,7 +5,7 @@ from kube_hunter.conf import Config, set_config
set_config(Config())
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.core.events.types import K8sVersionDisclosure
from kube_hunter.modules.hunting.cves import (
K8sClusterCveHunter,

View File

@@ -3,7 +3,7 @@ import requests_mock
import urllib.parse
import uuid
from kube_hunter.core.events import handler
from kube_hunter.core.events.event_handler import handler
from kube_hunter.modules.hunting.kubelet import (
AnonymousAuthEnabled,
ExposedExistingPrivilegedContainersViaSecureKubeletPort,