Compare commits

..

3 Commits

14 changed files with 49 additions and 63 deletions

View File

@@ -77,10 +77,9 @@ jobs:
python-version: '3.9'
- name: Install dependencies
shell: bash
run: |
pip install -U pip
make deps
python -m pip install -U pip
python -m pip install -r requirements-dev.txt
- name: Build project
shell: bash

View File

@@ -10,7 +10,7 @@ name: Release
jobs:
build:
name: Upload Release Asset
runs-on: ubuntu-18.04
runs-on: ubuntu-16.04
steps:
- name: Checkout code
uses: actions/checkout@v2
@@ -18,14 +18,12 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.8'
python-version: '3.9'
- name: Install dependencies
shell: bash
run: |
pip install -U pip
pip install pyinstaller
make deps
python -m pip install -U pip
python -m pip install -r requirements-dev.txt
- name: Build project
shell: bash

View File

@@ -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]
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-16.04]
steps:
- uses: actions/checkout@v2
@@ -38,11 +38,11 @@ jobs:
${{ matrix.os }}-${{ matrix.python-version }}-
- name: Install dependencies
shell: bash
run: |
pip install -U pip
make dev-deps
make install
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
- name: Test
shell: bash

BIN
MITRE.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

View File

@@ -31,7 +31,7 @@ lint-check:
.PHONY: test
test:
python -m pytest
pytest
.PHONY: build
build:

View File

@@ -18,7 +18,8 @@ kube-hunter hunts for security weaknesses in Kubernetes clusters. The tool was d
**Run kube-hunter**: kube-hunter is available as a container (aquasec/kube-hunter), and we also offer a web site at [kube-hunter.aquasec.com](https://kube-hunter.aquasec.com) where you can register online to receive a token allowing you to see and share the results online. You can also run the Python code yourself as described below.
**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/
**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).
@@ -28,6 +29,7 @@ Table of Contents
=================
- [Table of Contents](#table-of-contents)
- [Kuberentes ATT&CK Matrix](#kuberentes-attck-matrix)
- [Hunting](#hunting)
- [Where should I run kube-hunter?](#where-should-i-run-kube-hunter)
- [Scanning options](#scanning-options)
@@ -48,7 +50,19 @@ Table of Contents
- [Pod](#pod)
- [Contribution](#contribution)
- [License](#license)
---
## Kuberentes ATT&CK Matrix
kube-hunter now supports the new format of the Kubernetes ATT&CK matrix.
While kube-hunter's vulnerabilities are a collection of creative techniques designed to mimic an attacker in the cluster (or outside it)
The Mitre's ATT&CK defines a more general standardised categories of techniques to do so.
You can think of kube-hunter vulnerabilities as small steps for an attacker, which follows the track of a more general technique he would aim for.
Most of kube-hunter's hunters and vulnerabilities can closly fall under those techniques, That's why we moved to follow the Matrix standard.
_Some kube-hunter vulnerabities which we could not map to Mitre technique, are prefixed with the `General` keyword_
![kube-hunter](./MITRE.png)
## Hunting
### Where should I run kube-hunter?
@@ -61,6 +75,7 @@ You can run kube-hunter directly on a machine in the cluster, and select the opt
You can also run kube-hunter in a pod within the cluster. This indicates how exposed your cluster would be if one of your application pods is compromised (through a software vulnerability, for example). (_`--pod` flag_)
### Scanning options
First check for these **[pre-requisites](#prerequisites)**.
@@ -141,7 +156,8 @@ 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.

View File

@@ -28,7 +28,6 @@ config = Config(
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,
)
setup_logger(args.log, args.log_file)
set_config(config)

View File

@@ -21,7 +21,6 @@ class Config:
- remote: Hosts to scan
- report: Output format
- statistics: Include hunters statistics
- enable_cve_hunting: enables cve hunting, shows cve results
"""
active: bool = False
@@ -40,7 +39,6 @@ class Config:
k8s_auto_discover_nodes: bool = False
service_account_token: Optional[str] = None
kubeconfig: Optional[str] = None
enable_cve_hunting: bool = False
_config: Optional[Config] = None

View File

@@ -76,12 +76,6 @@ def parser_add_arguments(parser):
parser.add_argument("--active", action="store_true", help="Enables active hunting")
parser.add_argument(
"--enable-cve-hunting",
action="store_true",
help="Show cluster CVEs based on discovered version (Depending on different vendors, may result in False Positives)",
)
parser.add_argument(
"--log",
type=str,

View File

@@ -62,7 +62,7 @@ class EventQueue(Queue):
######################################################
"""
def subscribe(self, event, hook=None, predicate=None, is_register=True):
def subscribe(self, event, hook=None, predicate=None):
"""
The Subscribe Decorator - For Regular Registration
Use this to register for one event only. Your hunter will execute each time this event is published
@@ -74,12 +74,12 @@ class EventQueue(Queue):
"""
def wrapper(hook):
self.subscribe_event(event, hook=hook, predicate=predicate, is_register=is_register)
self.subscribe_event(event, hook=hook, predicate=predicate)
return hook
return wrapper
def subscribe_many(self, events, hook=None, predicates=None, is_register=True):
def subscribe_many(self, events, hook=None, predicates=None):
"""
The Subscribe Many Decorator - For Multiple Registration,
When your attack needs several prerequisites to exist in the cluster, You need to register for multiple events.
@@ -99,12 +99,12 @@ class EventQueue(Queue):
"""
def wrapper(hook):
self.subscribe_events(events, hook=hook, predicates=predicates, is_register=is_register)
self.subscribe_events(events, hook=hook, predicates=predicates)
return hook
return wrapper
def subscribe_once(self, event, hook=None, predicate=None, is_register=True):
def subscribe_once(self, event, hook=None, predicate=None):
"""
The Subscribe Once Decorator - For Single Trigger Registration,
Use this when you want your hunter to execute only in your entire program run
@@ -125,8 +125,7 @@ class EventQueue(Queue):
hook.__new__ = __new__unsubscribe_self
self.subscribe_event(event, hook=hook, predicate=predicate, is_register=is_register)
self.subscribe_event(event, hook=hook, predicate=predicate)
return hook
return wrapper
@@ -257,9 +256,7 @@ class EventQueue(Queue):
self.hooks[event].append((hook, predicate))
logging.debug("{} subscribed to {}".format(hook, event))
def subscribe_event(self, event, hook=None, predicate=None, is_register=True):
if not is_register:
return
def subscribe_event(self, event, hook=None, predicate=None):
if not self._register_hunters(hook):
return
@@ -270,9 +267,7 @@ class EventQueue(Queue):
else:
self._register_hook(event, hook, predicate)
def subscribe_events(self, events, hook=None, predicates=None, is_register=True):
if not is_register:
return False
def subscribe_events(self, events, hook=None, predicates=None):
if not self._register_hunters(hook):
return False

View File

@@ -166,9 +166,7 @@ class FromPodHostDiscovery(Discovery):
return True
except requests.exceptions.ConnectionError:
logger.debug("Failed to connect AWS metadata server v1")
except Exception:
logger.debug("Unknown error when trying to connect to AWS metadata v1 API")
return False
return False
def is_aws_pod_v2(self):
config = get_config()
@@ -191,9 +189,7 @@ class FromPodHostDiscovery(Discovery):
return True
except requests.exceptions.ConnectionError:
logger.debug("Failed to connect AWS metadata server v2")
except Exception:
logger.debug("Unknown error when trying to connect to AWS metadata v2 API")
return False
return False
def is_azure_pod(self):
config = get_config()
@@ -210,9 +206,7 @@ class FromPodHostDiscovery(Discovery):
return True
except requests.exceptions.ConnectionError:
logger.debug("Failed to connect Azure metadata server")
except Exception:
logger.debug("Unknown error when trying to connect to Azure metadata server")
return False
return False
# for pod scanning
def gateway_discovery(self):

View File

@@ -3,8 +3,7 @@ from packaging import version
from kube_hunter.conf import get_config
from kube_hunter.core.events import handler
from kube_hunter.core.events.types import K8sVersionDisclosure, Vulnerability, Event
from kube_hunter.core.events.types import Vulnerability, Event, K8sVersionDisclosure
from kube_hunter.core.types import (
Hunter,
KubectlClient,
@@ -16,7 +15,6 @@ from kube_hunter.core.types import (
from kube_hunter.modules.discovery.kubectl import KubectlClientEvent
logger = logging.getLogger(__name__)
config = get_config()
class ServerApiVersionEndPointAccessPE(Vulnerability, Event):
@@ -201,7 +199,7 @@ class CveUtils:
return vulnerable
@handler.subscribe_once(K8sVersionDisclosure, is_register=config.enable_cve_hunting)
@handler.subscribe_once(K8sVersionDisclosure)
class K8sClusterCveHunter(Hunter):
"""K8s CVE Hunter
Checks if Node is running a Kubernetes version vulnerable to
@@ -226,7 +224,6 @@ class K8sClusterCveHunter(Hunter):
self.publish_event(vulnerability(self.event.version))
# Removed due to incomplete implementation for multiple vendors revisions of kubernetes
@handler.subscribe(KubectlClientEvent)
class KubectlCVEHunter(Hunter):
"""Kubectl CVE Hunter

View File

@@ -1,3 +1,5 @@
-r requirements.txt
flake8
pytest >= 2.9.1
requests-mock >= 1.8

View File

@@ -1,6 +1,6 @@
# flake8: noqa: E402
from kube_hunter.conf import Config, set_config, get_config
from kube_hunter.conf import Config, set_config
set_config(Config(active=True))
@@ -23,9 +23,7 @@ from kube_hunter.modules.hunting.apiserver import (
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
from kube_hunter.modules.hunting.cves import KubectlCVEHunter
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
@@ -42,8 +40,6 @@ from kube_hunter.modules.hunting.mounts import VarLogMountHunter, ProveVarLogMou
from kube_hunter.modules.hunting.proxy import KubeProxy, ProveProxyExposed, K8sVersionDisclosureProve
from kube_hunter.modules.hunting.secrets import AccessSecrets
config = get_config()
PASSIVE_HUNTERS = {
ApiServiceDiscovery,
KubeDashboardDiscovery,
@@ -60,6 +56,7 @@ PASSIVE_HUNTERS = {
ApiVersionHunter,
PodCapabilitiesHunter,
CertificateDiscovery,
K8sClusterCveHunter,
KubectlCVEHunter,
KubeDashboard,
EtcdRemoteAccess,
@@ -70,9 +67,6 @@ PASSIVE_HUNTERS = {
AccessSecrets,
}
# if config.enable_cve_hunting:
# PASSIVE_HUNTERS.append(K8sClusterCveHunter)
ACTIVE_HUNTERS = {
ProveAzureSpnExposure,
AccessApiServerActive,