Files
kube-hunter/hunters/dashboard.py
daniel_sagi c8c8cd9ebd Fixed failed tries to scan unimplemented services
Added an empty url to dashboard hunter
Added chrome binary to automatically be install
2018-04-23 20:06:20 +03:00

105 lines
3.0 KiB
Python

from io import BytesIO
from logging import info, warning, debug
from PIL import Image
from requests import get
from selenium import webdriver
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.ui import WebDriverWait
from hunters.hunter import Hunter
DASHBOARD_PATHS = [
"",
"/ui",
"/api/v1/namespaces/kube-system/services/kubernetes-dashboard/proxy"
]
API = {
"overview": "/api/v1/overview/default?itemsPerPage=100",
"nodes": "/api/v1/node?itemsPerPage=100"
}
XPATH = {
"login_skip": "/html/body/kd-login/form/kd-content-card/div/div/div/kd-content/button[2]"
}
def test_url(url):
r = get(url)
if r.status_code == 200:
return r.url
class Dashboard(Hunter):
def __init__(self, host):
self.host = host
if "://" not in host:
self.host_url = "http://{}".format(host)
else:
self.host_url = host
self._is_auth_required = None
self._base_path = None
def format_url(self, path):
return self.base_path + path
def list_nodes(self):
return [str(n["objectMeta"]["name"]) for n in get(self.format_url(API["nodes"])).json()["nodes"]]
@property
def base_path(self):
if self._base_path:
return self._base_path
for path in DASHBOARD_PATHS:
path = test_url(self.host_url + path)
if path:
self._base_path = path
return path
raise Exception("User interface URL path was not found")
@property
def is_auth_required(self):
if not self._is_auth_required:
overview = get(self.format_url(API["overview"])).json()
if "errors" in overview and overview["errors"]:
self._is_auth_required = any([e["ErrStatus"]["code"] == 403 for e in overview["errors"]])
else:
self._is_auth_required = False
return self._is_auth_required
def take_screenshot(self):
driver = webdriver.Chrome()
driver.fullscreen_window()
waiter = WebDriverWait(driver, 5)
driver.get(self.base_path)
waiter.until(lambda d: "Overview" in d.title or "Sign" in d.title)
skip_buttons = driver.find_elements_by_xpath(XPATH["login_skip"])
if skip_buttons:
skip_buttons[0].click()
waiter.until(expected_conditions.title_contains("Overview"))
result = driver.get_screenshot_as_png()
driver.quit()
return result
def hunt(self, *args, **kwargs):
debug("Hunting dashboard at {}".format(self.host))
debug("Checking authentication...")
if self.is_auth_required:
warning("Authentication is required")
return
debug("Authentication is not required")
debug("Listing nodes on the cluster...")
debug("Nodes: {}".format(self.list_nodes()))
debug("Taking a screenshot...")
Image.open(BytesIO(self.take_screenshot())).show()