mirror of
https://github.com/aquasecurity/kube-hunter.git
synced 2026-05-11 03:37:52 +00:00
Added checks on api responses before json.loads, added a quick scanning option, to scan part of the subnet
This commit is contained in:
@@ -40,6 +40,7 @@ class Service(object):
|
||||
self.name = name
|
||||
self.secure = secure
|
||||
self.path = path
|
||||
self.role = "Node"
|
||||
|
||||
def get_name(self):
|
||||
return self.name
|
||||
@@ -58,6 +59,7 @@ class Vulnerability(object):
|
||||
self.component = component
|
||||
self.name = name
|
||||
self.evidence = ""
|
||||
self.role = "Node"
|
||||
|
||||
def get_name(self):
|
||||
return self.name
|
||||
@@ -65,19 +67,6 @@ class Vulnerability(object):
|
||||
def explain(self):
|
||||
return self.__doc__
|
||||
|
||||
class Information(object):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def get_name(self):
|
||||
return self.name
|
||||
|
||||
def explain(self):
|
||||
return self.__doc__
|
||||
|
||||
def proof(self):
|
||||
return self.name
|
||||
|
||||
|
||||
event_id_count = 0
|
||||
""" Discovery/Hunting Events """
|
||||
|
||||
15
src/modules/discovery/apiserver.py
Normal file
15
src/modules/discovery/apiserver.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import requests
|
||||
|
||||
from ...core.types import Hunter
|
||||
from ...core.events import handler
|
||||
from ...core.events.types import OpenPortEvent
|
||||
|
||||
@handler.subscribe(OpenPortEvent, predicate=lambda x: x.port==443)
|
||||
class ApiServerDiscovery(Hunter):
|
||||
def __init__(self, event):
|
||||
self.event = event
|
||||
|
||||
def execute(self):
|
||||
main_request = requests.get("https://{}:{}".format(self.event.host, self.event.port), verify=False).text
|
||||
if "code" in main_request:
|
||||
self.event.role = "Master"
|
||||
@@ -90,7 +90,7 @@ class HostDiscovery(Hunter):
|
||||
address, subnet= "", ""
|
||||
for interface in machine_metadata["network"]["interface"]:
|
||||
address, subnet = interface["ipv4"]["subnet"][0]["address"], interface["ipv4"]["subnet"][0]["prefix"]
|
||||
for ip in self.generate_subnet(address, sn=subnet):
|
||||
for ip in self.generate_subnet(address, sn=subnet if not config.quick else "24"):
|
||||
self.publish_event(NewHostEvent(host=ip, cloud="Azure"))
|
||||
self.publish_event(AzureMetadataApi(cidr="{}/{}".format(address, subnet)))
|
||||
|
||||
|
||||
@@ -27,17 +27,19 @@ class AzureSpnHunter(Hunter):
|
||||
|
||||
# getting a container that has access to the azure.json file
|
||||
def get_key_container(self):
|
||||
pods_data = json.loads(requests.get(self.base_url + "/pods", verify=False).text)["items"]
|
||||
for pod_data in pods_data:
|
||||
for container in pod_data["spec"]["containers"]:
|
||||
for mount in container["volumeMounts"]:
|
||||
path = mount["mountPath"]
|
||||
if '/etc/kubernetes/azure.json'.startswith(path):
|
||||
return {
|
||||
"name": container["name"],
|
||||
"pod": pod_data["metadata"]["name"],
|
||||
"namespace": pod_data["metadata"]["namespace"]
|
||||
}
|
||||
raw_pods = requests.get(self.base_url + "/pods", verify=False).text
|
||||
if "items" in raw_pods:
|
||||
pods_data = json.loads(raw_pods)["items"]
|
||||
for pod_data in pods_data:
|
||||
for container in pod_data["spec"]["containers"]:
|
||||
for mount in container["volumeMounts"]:
|
||||
path = mount["mountPath"]
|
||||
if '/etc/kubernetes/azure.json'.startswith(path):
|
||||
return {
|
||||
"name": container["name"],
|
||||
"pod": pod_data["metadata"]["name"],
|
||||
"namespace": pod_data["metadata"]["namespace"]
|
||||
}
|
||||
|
||||
def execute(self):
|
||||
container = self.get_key_container()
|
||||
|
||||
@@ -7,7 +7,7 @@ import urllib3
|
||||
|
||||
from __main__ import config
|
||||
from ...core.events import handler
|
||||
from ...core.events.types import (KubernetesCluster, Kubelet, Vulnerability, Information, Event)
|
||||
from ...core.events.types import (KubernetesCluster, Kubelet, Vulnerability, Event)
|
||||
from ..discovery.kubelet import ReadOnlyKubeletEvent, SecureKubeletEvent, ExposedPodsHandler
|
||||
from ...core.types import Hunter, ActiveHunter
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
@@ -252,18 +252,20 @@ class ProveRunHandler(ActiveHunter):
|
||||
return requests.post(run_url, verify=False, params={'cmd': command}).text
|
||||
|
||||
def execute(self):
|
||||
pods_data = json.loads(requests.get("https://{host}:{port}/pods".format(host=self.event.host, port=self.event.port), verify=False).text)['items']
|
||||
for pod_data in pods_data:
|
||||
container_data = next((container_data for container_data in pod_data["spec"]["containers"]), None)
|
||||
if container_data:
|
||||
output = self.run("uname -a", container={
|
||||
"namespace": pod_data["metadata"]["namespace"],
|
||||
"pod": pod_data["metadata"]["name"],
|
||||
"name": container_data["name"]
|
||||
})
|
||||
if output and "exited with" not in output:
|
||||
self.event.evidence = "uname: " + output
|
||||
break
|
||||
pods_raw = requests.get("https://{host}:{port}/pods".format(host=self.event.host, port=self.event.port), verify=False).text
|
||||
if "items" in pods_raw:
|
||||
pods_data = json.loads(pods_raw)['items']
|
||||
for pod_data in pods_data:
|
||||
container_data = next((container_data for container_data in pod_data["spec"]["containers"]), None)
|
||||
if container_data:
|
||||
output = self.run("uname -a", container={
|
||||
"namespace": pod_data["metadata"]["namespace"],
|
||||
"pod": pod_data["metadata"]["name"],
|
||||
"name": container_data["name"]
|
||||
})
|
||||
if output and "exited with" not in output:
|
||||
self.event.evidence = "uname: " + output
|
||||
break
|
||||
|
||||
@handler.subscribe(ExposedPodsHandler)
|
||||
class ProvePodsHandler(ActiveHunter):
|
||||
@@ -272,13 +274,14 @@ class ProvePodsHandler(ActiveHunter):
|
||||
|
||||
def execute(self):
|
||||
protocol = "https" if self.event.port == 10250 else "http"
|
||||
pods_data = json.loads(requests.get("{protocol}://{host}:{port}/pods".format(
|
||||
pods_raw = requests.get("{protocol}://{host}:{port}/pods".format(
|
||||
protocol=protocol,
|
||||
host=self.event.host,
|
||||
port=self.event.port),
|
||||
verify=False)
|
||||
.text)['items']
|
||||
self.event.evidence = "bound pods: {}".format(len(pods_data))
|
||||
verify=False).text
|
||||
if "items" in pods_raw:
|
||||
pods_data = json.loads(pods_raw)['items']
|
||||
self.event.evidence = "bound pods: {}".format(len(pods_data))
|
||||
|
||||
@handler.subscribe(ExposedRunningPodsHandler)
|
||||
class ProveRunningPodsHandler(ActiveHunter):
|
||||
@@ -286,12 +289,13 @@ class ProveRunningPodsHandler(ActiveHunter):
|
||||
self.event = event
|
||||
|
||||
def execute(self):
|
||||
pods_data = json.loads(requests.get("https://{host}:{port}/runningpods".format(
|
||||
pods_raw = requests.get("https://{host}:{port}/pods".format(
|
||||
host=self.event.host,
|
||||
port=self.event.port),
|
||||
verify=False)
|
||||
.text)['items']
|
||||
self.event.evidence = "running pods: {}".format(len(pods_data))
|
||||
verify=False).text
|
||||
if "items" in pods_raw:
|
||||
pods_data = json.loads(pods_raw)['items']
|
||||
self.event.evidence = "running pods: {}".format(len(pods_data))
|
||||
|
||||
@handler.subscribe(ExposedContainerLogsHandler)
|
||||
class ProveContainerLogsHandler(ActiveHunter):
|
||||
@@ -301,18 +305,20 @@ class ProveContainerLogsHandler(ActiveHunter):
|
||||
self.base_url = "{protocol}://{host}:{port}".format(protocol=protocol, host=self.event.host, port=self.event.port)
|
||||
|
||||
def execute(self):
|
||||
pods_data = json.loads(requests.get(self.base_url + "/pods", verify=False).text)['items']
|
||||
for pod_data in pods_data:
|
||||
container_data = next((container_data for container_data in pod_data["spec"]["containers"]), None)
|
||||
if container_data:
|
||||
output = requests.get(self.base_url + "/containerLogs/{podNamespace}/{podID}/{containerName}".format(
|
||||
podNamespace=pod_data["metadata"]["namespace"],
|
||||
podID=pod_data["metadata"]["name"],
|
||||
containerName=container_data["name"]
|
||||
), verify=False)
|
||||
if output.status_code == 200 and output.text:
|
||||
self.event.evidence = "{}: {}".format(
|
||||
container_data["name"],
|
||||
output.text.encode('utf-8')
|
||||
)
|
||||
break
|
||||
pods_raw = requests.get(self.base_url + "/pods", verify=False).text
|
||||
if "items" in pods_raw:
|
||||
pods_data = json.loads(pods_raw)['items']
|
||||
for pod_data in pods_data:
|
||||
container_data = next((container_data for container_data in pod_data["spec"]["containers"]), None)
|
||||
if container_data:
|
||||
output = requests.get(self.base_url + "/containerLogs/{podNamespace}/{podID}/{containerName}".format(
|
||||
podNamespace=pod_data["metadata"]["namespace"],
|
||||
podID=pod_data["metadata"]["name"],
|
||||
containerName=container_data["name"]
|
||||
), verify=False)
|
||||
if output.status_code == 200 and output.text:
|
||||
self.event.evidence = "{}: {}".format(
|
||||
container_data["name"],
|
||||
output.text.encode('utf-8')
|
||||
)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user