Merge pull request #97 from idanr1986/cve_hunter

Cve hunter
This commit is contained in:
Liz Rice
2019-03-04 10:47:55 +00:00
committed by GitHub
3 changed files with 123 additions and 72 deletions

View File

@@ -48,5 +48,7 @@ class AccessRisk(object):
class PrivilegeEscalation(KubernetesCluster):
name = "Privilege Escalation"
class DenialOfService(object):
name = "Denial of Service"
from events import handler # import is in the bottom to break import loops

View File

@@ -1,72 +0,0 @@
import logging
import json
import requests
import uuid
import ast
from ...core.events import handler
from ...core.events.types import Vulnerability, Event
from ..discovery.apiserver import ApiServer
from ...core.types import Hunter, ActiveHunter, KubernetesCluster, RemoteCodeExec, AccessRisk, InformationDisclosure, PrivilegeEscalation
""" Vulnerabilities """
class ServerApiVersionEndPointAccess(Vulnerability, Event):
""" Node is vulnerable to critical CVE-2018-1002105 """
def __init__(self, evidence):
Vulnerability.__init__(self, KubernetesCluster, name="Critical Privilege Escalation CVE", category=PrivilegeEscalation)
self.evidence = evidence
# Passive Hunter
@handler.subscribe(ApiServer)
class IsVulnerableToCVEAttack(Hunter):
""" Node is running a Kubernetes version vulnerable to critical CVE-2018-1002105 """
def __init__(self, event):
self.event = event
self.headers = dict()
self.path = "https://{}:{}".format(self.event.host, self.event.port)
self.service_account_token_evidence = ''
self.api_server_evidence = ''
self.k8sVersion = ''
def access_api_server_version_end_point(self):
logging.debug(self.event.host)
logging.debug('Passive Hunter is attempting to access the API server /version end point using the pod\'s service account token')
try:
res = requests.get("{path}/version".format(path=self.path),
headers=self.headers, verify=False)
self.api_server_evidence = res.content
resDict = ast.literal_eval(res.content)
version = resDict["gitVersion"].split('.')
first_two_minor_digists = eval(version[1])
last_two_minor_digists = eval(version[2])
if first_two_minor_digists == 10 and last_two_minor_digists < 11:
return True
elif first_two_minor_digists == 11 and last_two_minor_digists < 5:
return True
elif first_two_minor_digists == 12 and last_two_minor_digists < 3:
return True
elif first_two_minor_digists < 10:
return True
except (requests.exceptions.ConnectionError, KeyError):
return False
def get_service_account_token(self):
logging.debug(self.event.host)
logging.debug('Passive Hunter is attempting to access pod\'s service account token')
try:
with open('/var/run/secrets/kubernetes.io/serviceaccount/token', 'r') as token:
data = token.read()
self.service_account_token_evidence = data
self.headers = {'Authorization': 'Bearer ' + self.service_account_token_evidence}
return True
except IOError: # Couldn't read file
return False
def execute(self):
self.get_service_account_token() # From within a Pod we may have extra credentials
if self.access_api_server_version_end_point():
self.publish_event(ServerApiVersionEndPointAccess(self.api_server_evidence))

View File

@@ -0,0 +1,121 @@
import logging
import json
import requests
import uuid
import ast
from ...core.events import handler
from ...core.events.types import Vulnerability, Event
from ..discovery.apiserver import ApiServer
from ...core.types import Hunter, ActiveHunter, KubernetesCluster, RemoteCodeExec, AccessRisk, InformationDisclosure, \
PrivilegeEscalation, DenialOfService
""" Vulnerabilities """
class ServerApiVersionEndPointAccessPE(Vulnerability, Event):
"""Node is vulnerable to critical CVE-2018-1002105"""
def __init__(self, evidence):
Vulnerability.__init__(self, KubernetesCluster, name="Critical Privilege Escalation CVE", category=PrivilegeEscalation)
self.evidence = evidence
class ServerApiVersionEndPointAccessDos(Vulnerability, Event):
"""Node is vulnerable to critical CVE-2019-1002100"""
def __init__(self, evidence):
Vulnerability.__init__(self, KubernetesCluster, name="Medium Denial of Service CVE", category=DenialOfService)
self.evidence = evidence
# Passive Hunter
@handler.subscribe(ApiServer)
class IsVulnerableToCVEAttack(Hunter):
""" Node is running a Kubernetes version vulnerable to critical CVE-2018-1002105 """
def __init__(self, event):
self.event = event
self.headers = dict()
self.path = "https://{}:{}".format(self.event.host, self.event.port)
self.service_account_token_evidence = ''
self.api_server_evidence = ''
self.k8sVersion = ''
def get_service_account_token(self):
logging.debug(self.event.host)
logging.debug('Passive Hunter is attempting to access pod\'s service account token')
try:
with open('/var/run/secrets/kubernetes.io/serviceaccount/token', 'r') as token:
data = token.read()
self.service_account_token_evidence = data
self.headers = {'Authorization': 'Bearer ' + self.service_account_token_evidence}
return True
except IOError: # Couldn't read file
return False
def get_api_server_version_end_point(self):
logging.debug(self.event.host)
logging.debug('Passive Hunter is attempting to access the API server version end point using the pod\'s service account token')
try:
res = requests.get("{path}/version".format(path=self.path),
headers=self.headers, verify=False)
self.api_server_evidence = res.content
resDict = ast.literal_eval(res.content)
version = resDict["gitVersion"].split('.')
first_two_minor_digits = eval(version[1])
last_two_minor_digits = eval(version[2])
return [first_two_minor_digits, last_two_minor_digits]
except (requests.exceptions.ConnectionError, KeyError):
return None
def check_cve_2018_1002105(self, api_version):
first_two_minor_digists = api_version[0]
last_two_minor_digists = api_version[1]
if first_two_minor_digists == 10 and last_two_minor_digists < 11:
return True
elif first_two_minor_digists == 11 and last_two_minor_digists < 5:
return True
elif first_two_minor_digists == 12 and last_two_minor_digists < 3:
return True
elif first_two_minor_digists < 10:
return True
return False
def check_cve_2019_1002100(self, api_version):
"""
Kubernetes v1.0.x-1.10.x
Kubernetes v1.11.0-1.11.7 (fixed in v1.11.8)
Kubernetes v1.12.0-1.12.5 (fixed in v1.12.6)
Kubernetes v1.13.0-1.13.3 (fixed in v1.13.4)
"""
first_two_minor_digists = api_version[0]
last_two_minor_digists = api_version[1]
if first_two_minor_digists == 11 and last_two_minor_digists < 8:
return True
elif first_two_minor_digists == 12 and last_two_minor_digists < 6:
return True
elif first_two_minor_digists == 13 and last_two_minor_digists < 4:
return True
elif first_two_minor_digists < 11:
return True
return False
def execute(self):
self.get_service_account_token() # From within a Pod we may have extra credentials
api_version = self.get_api_server_version_end_point()
if api_version:
if self.check_cve_2018_1002105(api_version):
self.publish_event(ServerApiVersionEndPointAccessPE(self.api_server_evidence))
if self.check_cve_2019_1002100(api_version):
self.publish_event(ServerApiVersionEndPointAccessDos(self.api_server_evidence))