diff --git a/src/core/events/types/common.py b/src/core/events/types/common.py index 25222cc..f17a3da 100644 --- a/src/core/events/types/common.py +++ b/src/core/events/types/common.py @@ -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 """ diff --git a/src/modules/discovery/apiserver.py b/src/modules/discovery/apiserver.py new file mode 100644 index 0000000..26243a3 --- /dev/null +++ b/src/modules/discovery/apiserver.py @@ -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" \ No newline at end of file diff --git a/src/modules/discovery/hosts.py b/src/modules/discovery/hosts.py index b04354e..91dff44 100644 --- a/src/modules/discovery/hosts.py +++ b/src/modules/discovery/hosts.py @@ -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))) diff --git a/src/modules/hunting/aks.py b/src/modules/hunting/aks.py index 276a844..b6ed5c3 100644 --- a/src/modules/hunting/aks.py +++ b/src/modules/hunting/aks.py @@ -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() diff --git a/src/modules/hunting/kubelet.py b/src/modules/hunting/kubelet.py index dbe261e..d09a259 100644 --- a/src/modules/hunting/kubelet.py +++ b/src/modules/hunting/kubelet.py @@ -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