)"
+ },
+ "internet_services": {
+ "title": "Internet services",
+ "type": "array",
+ "uniqueItems": True,
+ "items": {
+ "type": "string"
+ },
+ "default": [
+ "monkey.guardicore.com",
+ "www.google.com"
+ ],
+ "description":
+ "List of internet services to try and communicate with to determine internet"
+ " connectivity (use either ip or domain)"
+ },
+ "current_server": {
+ "title": "Current server",
+ "type": "string",
+ "default": "192.0.2.0:5000",
+ "description": "The current command server the monkey is communicating with"
+ }
+ }
+ },
+ 'aws_config': {
+ 'title': 'AWS Configuration',
+ 'type': 'object',
+ 'description': 'These credentials will be used in order to export the monkey\'s findings to the AWS Security Hub.',
+ 'properties': {
+ 'aws_account_id': {
+ 'title': 'AWS account ID',
+ 'type': 'string',
+ 'description': 'Your AWS account ID that is subscribed to security hub feeds',
+ 'default': ''
+ },
+ 'aws_access_key_id': {
+ 'title': 'AWS access key ID',
+ 'type': 'string',
+ 'description': 'Your AWS public access key ID, can be found in the IAM user interface in the AWS console.',
+ 'default': ''
+ },
+ 'aws_secret_access_key': {
+ 'title': 'AWS secret access key',
+ 'type': 'string',
+ 'description': 'Your AWS secret access key id, you can get this after creating a public access key in the console.',
+ 'default': ''
+ }
+ }
+ }
+ }
+ },
+ "exploits": {
+ "title": "Exploits",
+ "type": "object",
+ "properties": {
+ "general": {
+ "title": "General",
+ "type": "object",
+ "properties": {
+ "exploiter_classes": {
+ "title": "Exploits",
+ "type": "array",
+ "uniqueItems": True,
+ "items": {
+ "$ref": "#/definitions/exploiter_classes"
+ },
+ "default": [
+ "SmbExploiter",
+ "WmiExploiter",
+ "MSSQLExploiter",
+ "SSHExploiter",
+ "ShellShockExploiter",
+ "SambaCryExploiter",
+ "ElasticGroovyExploiter",
+ "Struts2Exploiter",
+ "WebLogicExploiter",
+ "HadoopExploiter"
+ ],
+ "description":
+ "Determines which exploits to use. " + WARNING_SIGN
+ + " Note that using unsafe exploits may cause crashes of the exploited machine/service"
+ },
+ "skip_exploit_if_file_exist": {
+ "title": "Skip exploit if file exists",
+ "type": "boolean",
+ "default": False,
+ "description": "Determines whether the monkey should skip the exploit if the monkey's file"
+ " is already on the remote machine"
+ }
+ }
+ },
+ "ms08_067": {
+ "title": "MS08_067",
+ "type": "object",
+ "properties": {
+ "ms08_067_exploit_attempts": {
+ "title": "MS08_067 exploit attempts",
+ "type": "integer",
+ "default": 5,
+ "description": "Number of attempts to exploit using MS08_067"
+ },
+ "user_to_add": {
+ "title": "Remote user",
+ "type": "string",
+ "default": "Monkey_IUSER_SUPPORT",
+ "description": "Username to add on successful exploit"
+ },
+ "remote_user_pass": {
+ "title": "Remote user password",
+ "type": "string",
+ "default": "Password1!",
+ "description": "Password to use for created user"
+ }
+ }
+ },
+ "rdp_grinder": {
+ "title": "RDP grinder",
+ "type": "object",
+ "properties": {
+ "rdp_use_vbs_download": {
+ "title": "Use VBS download",
+ "type": "boolean",
+ "default": True,
+ "description": "Determines whether to use VBS or BITS to download monkey to remote machine"
+ " (true=VBS, false=BITS)"
+ }
+ }
+ },
+ "sambacry": {
+ "title": "SambaCry",
+ "type": "object",
+ "properties": {
+ "sambacry_trigger_timeout": {
+ "title": "SambaCry trigger timeout",
+ "type": "integer",
+ "default": 5,
+ "description": "Timeout (in seconds) of SambaCry trigger"
+ },
+ "sambacry_folder_paths_to_guess": {
+ "title": "SambaCry folder paths to guess",
+ "type": "array",
+ "uniqueItems": True,
+ "items": {
+ "type": "string"
+ },
+ "default": [
+ '/',
+ '/mnt',
+ '/tmp',
+ '/storage',
+ '/export',
+ '/share',
+ '/shares',
+ '/home'
+ ],
+ "description": "List of full paths to share folder for SambaCry to guess"
+ },
+ "sambacry_shares_not_to_check": {
+ "title": "SambaCry shares not to check",
+ "type": "array",
+ "uniqueItems": True,
+ "items": {
+ "type": "string"
+ },
+ "default": [
+ "IPC$", "print$"
+ ],
+ "description": "These shares won't be checked when exploiting with SambaCry"
+ }
+ }
+ },
+ "smb_service": {
+ "title": "SMB service",
+ "type": "object",
+ "properties": {
+ "smb_download_timeout": {
+ "title": "SMB download timeout",
+ "type": "integer",
+ "default": 300,
+ "description":
+ "Timeout (in seconds) for SMB download operation (used in various exploits using SMB)"
+ },
+ "smb_service_name": {
+ "title": "SMB service name",
+ "type": "string",
+ "default": "InfectionMonkey",
+ "description": "Name of the SMB service that will be set up to download monkey"
+ }
+ }
+ }
+ }
+ },
+ "network": {
+ "title": "Network",
+ "type": "object",
+ "properties": {
+ "tcp_scanner": {
+ "title": "TCP scanner",
+ "type": "object",
+ "properties": {
+ "HTTP_PORTS": {
+ "title": "HTTP ports",
+ "type": "array",
+ "uniqueItems": True,
+ "items": {
+ "type": "integer"
+ },
+ "default": [
+ 80,
+ 8080,
+ 443,
+ 8008,
+ 7001
+ ],
+ "description": "List of ports the monkey will check if are being used for HTTP"
+ },
+ "tcp_target_ports": {
+ "title": "TCP target ports",
+ "type": "array",
+ "uniqueItems": True,
+ "items": {
+ "type": "integer"
+ },
+ "default": [
+ 22,
+ 2222,
+ 445,
+ 135,
+ 3389,
+ 80,
+ 8080,
+ 443,
+ 8008,
+ 3306,
+ 9200,
+ 7001
+ ],
+ "description": "List of TCP ports the monkey will check whether they're open"
+ },
+ "tcp_scan_interval": {
+ "title": "TCP scan interval",
+ "type": "integer",
+ "default": 0,
+ "description": "Time to sleep (in milliseconds) between scans"
+ },
+ "tcp_scan_timeout": {
+ "title": "TCP scan timeout",
+ "type": "integer",
+ "default": 3000,
+ "description": "Maximum time (in milliseconds) to wait for TCP response"
+ },
+ "tcp_scan_get_banner": {
+ "title": "TCP scan - get banner",
+ "type": "boolean",
+ "default": True,
+ "description": "Determines whether the TCP scan should try to get the banner"
+ }
+ }
+ },
+ "ping_scanner": {
+ "title": "Ping scanner",
+ "type": "object",
+ "properties": {
+ "ping_scan_timeout": {
+ "title": "Ping scan timeout",
+ "type": "integer",
+ "default": 1000,
+ "description": "Maximum time (in milliseconds) to wait for ping response"
+ }
+ }
+ }
+ }
+ }
+ },
+ "options": {
+ "collapsed": True
+ }
+}
diff --git a/monkey/monkey_island/cc/services/node.py b/monkey/monkey_island/cc/services/node.py
index 1f9b68ebe..50c921be8 100644
--- a/monkey/monkey_island/cc/services/node.py
+++ b/monkey/monkey_island/cc/services/node.py
@@ -6,6 +6,7 @@ import cc.services.log
from cc.database import mongo
from cc.services.edge import EdgeService
from cc.utils import local_ip_addresses
+import socket
__author__ = "itay.mizeretz"
@@ -41,6 +42,7 @@ class NodeService:
# node is uninfected
new_node = NodeService.node_to_net_node(node, for_report)
new_node["ip_addresses"] = node["ip_addresses"]
+ new_node["domain_name"] = node["domain_name"]
for edge in edges:
accessible_from_nodes.append(NodeService.get_monkey_label(NodeService.get_monkey_by_id(edge["from"])))
@@ -62,7 +64,10 @@ class NodeService:
@staticmethod
def get_node_label(node):
- return node["os"]["version"] + " : " + node["ip_addresses"][0]
+ domain_name = ""
+ if node["domain_name"]:
+ domain_name = " ("+node["domain_name"]+")"
+ return node["os"]["version"] + " : " + node["ip_addresses"][0] + domain_name
@staticmethod
def _cmp_exploits_by_timestamp(exploit_1, exploit_2):
@@ -137,6 +142,7 @@ class NodeService:
"group": NodeService.get_monkey_group(monkey),
"os": NodeService.get_monkey_os(monkey),
"dead": monkey["dead"],
+ "domain_name": ""
}
@staticmethod
@@ -176,10 +182,11 @@ class NodeService:
upsert=False)
@staticmethod
- def insert_node(ip_address):
+ def insert_node(ip_address, domain_name=''):
new_node_insert_result = mongo.db.node.insert_one(
{
"ip_addresses": [ip_address],
+ "domain_name": domain_name,
"exploited": False,
"creds": [],
"os":
@@ -191,10 +198,10 @@ class NodeService:
return mongo.db.node.find_one({"_id": new_node_insert_result.inserted_id})
@staticmethod
- def get_or_create_node(ip_address):
+ def get_or_create_node(ip_address, domain_name=''):
new_node = mongo.db.node.find_one({"ip_addresses": ip_address})
if new_node is None:
- new_node = NodeService.insert_node(ip_address)
+ new_node = NodeService.insert_node(ip_address, domain_name)
return new_node
@staticmethod
@@ -261,6 +268,7 @@ class NodeService:
def get_monkey_island_node():
island_node = NodeService.get_monkey_island_pseudo_net_node()
island_node["ip_addresses"] = local_ip_addresses()
+ island_node["domain_name"] = socket.gethostname()
return island_node
@staticmethod
diff --git a/monkey/monkey_island/cc/services/report.py b/monkey/monkey_island/cc/services/report.py
index bd03fb78c..73ca69b5b 100644
--- a/monkey/monkey_island/cc/services/report.py
+++ b/monkey/monkey_island/cc/services/report.py
@@ -3,13 +3,14 @@ import functools
import ipaddress
import logging
+
+from bson import json_util
from enum import Enum
from six import text_type
from cc.database import mongo
-from cc.environment.environment import load_env_from_file, AWS
-from cc.resources.aws_exporter import AWSExporter
+from cc.report_exporter_manager import ReportExporterManager
from cc.services.config import ConfigService
from cc.services.edge import EdgeService
from cc.services.node import NodeService
@@ -39,7 +40,8 @@ class ReportService:
'ShellShockExploiter': 'ShellShock Exploiter',
'Struts2Exploiter': 'Struts2 Exploiter',
'WebLogicExploiter': 'Oracle WebLogic Exploiter',
- 'HadoopExploiter': 'Hadoop/Yarn Exploiter'
+ 'HadoopExploiter': 'Hadoop/Yarn Exploiter',
+ 'MSSQLExploiter': 'MSSQL Exploiter'
}
class ISSUES_DICT(Enum):
@@ -54,7 +56,8 @@ class ReportService:
STRUTS2 = 8
WEBLOGIC = 9
HADOOP = 10
- PTH_CRIT_SERVICES_ACCESS = 11
+ PTH_CRIT_SERVICES_ACCESS = 11,
+ MSSQL = 12
class WARNINGS_DICT(Enum):
CROSS_SEGMENT = 0
@@ -128,7 +131,8 @@ class ReportService:
list((x['hostname'] for x in
(NodeService.get_displayed_node_by_id(edge['from'], True)
for edge in EdgeService.get_displayed_edges_by_to(node['id'], True)))),
- 'services': node['services']
+ 'services': node['services'],
+ 'domain_name': node['domain_name']
})
logger.info('Scanned nodes generated for reporting')
@@ -148,6 +152,7 @@ class ReportService:
{
'label': monkey['label'],
'ip_addresses': monkey['ip_addresses'],
+ 'domain_name': monkey['domain_name'],
'exploits': list(set(
[ReportService.EXPLOIT_DISPLAY_DICT[exploit['exploiter']] for exploit in monkey['exploits'] if
exploit['result']]))
@@ -328,6 +333,12 @@ class ReportService:
processed_exploit['type'] = 'hadoop'
return processed_exploit
+ @staticmethod
+ def process_mssql_exploit(exploit):
+ processed_exploit = ReportService.process_general_exploit(exploit)
+ processed_exploit['type'] = 'mssql'
+ return processed_exploit
+
@staticmethod
def process_exploit(exploit):
exploiter_type = exploit['data']['exploiter']
@@ -342,7 +353,8 @@ class ReportService:
'ShellShockExploiter': ReportService.process_shellshock_exploit,
'Struts2Exploiter': ReportService.process_struts2_exploit,
'WebLogicExploiter': ReportService.process_weblogic_exploit,
- 'HadoopExploiter': ReportService.process_hadoop_exploit
+ 'HadoopExploiter': ReportService.process_hadoop_exploit,
+ 'MSSQLExploiter': ReportService.process_mssql_exploit
}
return EXPLOIT_PROCESS_FUNCTION_DICT[exploiter_type](exploit)
@@ -570,6 +582,7 @@ class ReportService:
PTHReportService.get_duplicated_passwords_issues,
PTHReportService.get_strong_users_on_crit_issues
]
+
issues = functools.reduce(lambda acc, issue_gen: acc + issue_gen(), ISSUE_GENERATORS, [])
issues_dict = {}
@@ -642,6 +655,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'] == 'mssql':
+ issues_byte_array[ReportService.ISSUES_DICT.MSSQL.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 \
@@ -677,9 +692,7 @@ class ReportService:
@staticmethod
def is_report_generated():
generated_report = mongo.db.report.find_one({})
- if generated_report is None:
- return False
- return True
+ return generated_report is not None
@staticmethod
def generate_report():
@@ -726,14 +739,29 @@ class ReportService:
'latest_monkey_modifytime': monkey_latest_modify_time
}
}
- ReportService.export_to_exporters(report)
+ ReportExporterManager().export(report)
mongo.db.report.drop()
- mongo.db.report.insert_one(report)
+ mongo.db.report.insert_one(ReportService.encode_dot_char_before_mongo_insert(report))
return report
+ @staticmethod
+ def encode_dot_char_before_mongo_insert(report_dict):
+ """
+ mongodb doesn't allow for '.' and '$' in a key's name, this function replaces the '.' char with the unicode
+ ,,, combo instead.
+ :return: dict with formatted keys with no dots.
+ """
+ report_as_json = json_util.dumps(report_dict).replace('.', ',,,')
+ return json_util.loads(report_as_json)
+
+
@staticmethod
def is_latest_report_exists():
+ """
+ This function checks if a monkey report was already generated and if it's the latest one.
+ :return: True if report is the latest one, False if there isn't a report or its not the latest.
+ """
latest_report_doc = mongo.db.report.find_one({}, {'meta.latest_monkey_modifytime': 1})
if latest_report_doc:
@@ -743,10 +771,19 @@ class ReportService:
return False
+ @staticmethod
+ def decode_dot_char_before_mongo_insert(report_dict):
+ """
+ this function replaces the ',,,' combo with the '.' char instead.
+ :return: report dict with formatted keys (',,,' -> '.')
+ """
+ report_as_json = json_util.dumps(report_dict).replace(',,,', '.')
+ return json_util.loads(report_as_json)
+
@staticmethod
def get_report():
if ReportService.is_latest_report_exists():
- return mongo.db.report.find_one()
+ return ReportService.decode_dot_char_before_mongo_insert(mongo.db.report.find_one())
return ReportService.generate_report()
@staticmethod
@@ -754,16 +791,3 @@ class ReportService:
return mongo.db.edge.count(
{'exploits': {'$elemMatch': {'exploiter': exploit_type, 'result': True}}},
limit=1) > 0
-
- @staticmethod
- def get_active_exporters():
- # This function should be in another module in charge of building a list of active exporters
- exporters_list = []
- if str(load_env_from_file()) == AWS:
- exporters_list.append(AWSExporter)
- return exporters_list
-
- @staticmethod
- def export_to_exporters(report):
- for exporter in ReportService.get_active_exporters():
- exporter.handle_report(report)
diff --git a/monkey/monkey_island/cc/services/wmi_handler.py b/monkey/monkey_island/cc/services/wmi_handler.py
index 5842ae5c6..fec12c152 100644
--- a/monkey/monkey_island/cc/services/wmi_handler.py
+++ b/monkey/monkey_island/cc/services/wmi_handler.py
@@ -13,11 +13,18 @@ class WMIHandler(object):
self.monkey_id = monkey_id
self.info_for_mongo = {}
self.users_secrets = user_secrets
- self.users_info = wmi_info['Win32_UserAccount']
- self.groups_info = wmi_info['Win32_Group']
- self.groups_and_users = wmi_info['Win32_GroupUser']
- self.services = wmi_info['Win32_Service']
- self.products = wmi_info['Win32_Product']
+ if not wmi_info:
+ self.users_info = ""
+ self.groups_info = ""
+ self.groups_and_users = ""
+ self.services = ""
+ self.products = ""
+ else:
+ self.users_info = wmi_info['Win32_UserAccount']
+ self.groups_info = wmi_info['Win32_Group']
+ self.groups_and_users = wmi_info['Win32_GroupUser']
+ self.services = wmi_info['Win32_Service']
+ self.products = wmi_info['Win32_Product']
def process_and_handle_wmi_info(self):
@@ -25,7 +32,8 @@ class WMIHandler(object):
self.add_users_to_collection()
self.create_group_user_connection()
self.insert_info_to_mongo()
- self.add_admin(self.info_for_mongo[self.ADMINISTRATORS_GROUP_KNOWN_SID], self.monkey_id)
+ if self.info_for_mongo:
+ self.add_admin(self.info_for_mongo[self.ADMINISTRATORS_GROUP_KNOWN_SID], self.monkey_id)
self.update_admins_retrospective()
self.update_critical_services()
diff --git a/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js b/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js
index 61e80737b..b5ab30581 100644
--- a/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js
+++ b/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js
@@ -29,7 +29,8 @@ class ReportPageComponent extends AuthComponent {
STRUTS2: 8,
WEBLOGIC: 9,
HADOOP: 10,
- PTH_CRIT_SERVICES_ACCESS: 11
+ PTH_CRIT_SERVICES_ACCESS: 11,
+ MSSQL: 12
};
Warning =
@@ -104,7 +105,7 @@ class ReportPageComponent extends AuthComponent {
.then(res => res.json())
.then(res => {
res.edges.forEach(edge => {
- edge.color = edgeGroupToColor(edge.group);
+ edge.color = {'color': edgeGroupToColor(edge.group)};
});
this.setState({graph: res});
this.props.onStatusChange();
@@ -341,6 +342,8 @@ class ReportPageComponent extends AuthComponent {
Hadoop/Yarn servers are vulnerable to remote code execution. : null }
{this.state.report.overview.issues[this.Issue.PTH_CRIT_SERVICES_ACCESS] ?
Mimikatz found login credentials of a user who has admin access to a server defined as critical.: null }
+ {this.state.report.overview.issues[this.Issue.MSSQL] ?
+ MS-SQL servers are vulnerable to remote code execution via xp_cmdshell command. : null }
:
@@ -412,7 +415,6 @@ class ReportPageComponent extends AuthComponent {
{this.generateIssues(this.state.report.recommendations.issues)}
-
);
}
@@ -867,7 +869,23 @@ class ReportPageComponent extends AuthComponent {
);
}
-
+generateMSSQLIssue(issue) {
+ return(
+
+ Disable the xp_cmdshell option.
+
+ The machine {issue.machine} ({issue.ip_address}) is vulnerable to a MSSQL exploit attack.
+
+ The attack was made possible because the target machine used an outdated MSSQL server configuration allowing
+ the usage of the xp_cmdshell command. To learn more about how to disable this feature, read
+ Microsoft's documentation.
+
+
+ );
+ }
generateIssue = (issue) => {
let data;
@@ -935,6 +953,9 @@ class ReportPageComponent extends AuthComponent {
case 'hadoop':
data = this.generateHadoopIssue(issue);
break;
+ case 'mssql':
+ data = this.generateMSSQLIssue(issue);
+ break;
}
return data;
};
diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage.js
index 4543a5c34..5c93065c4 100644
--- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage.js
+++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage.js
@@ -52,7 +52,7 @@ class RunMonkeyPageComponent extends AuthComponent {
generateLinuxCmd(ip, is32Bit) {
let bitText = is32Bit ? '32' : '64';
- return `curl -O -k https://${ip}:5000/api/monkey/download/monkey-linux-${bitText}; chmod +x monkey-linux-${bitText}; ./monkey-linux-${bitText} m0nk3y -s ${ip}:5000`
+ return `wget --no-check-certificate https://${ip}:5000/api/monkey/download/monkey-linux-${bitText}; chmod +x monkey-linux-${bitText}; ./monkey-linux-${bitText} m0nk3y -s ${ip}:5000`
}
generateWindowsCmd(ip, is32Bit) {
diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/BreachedServers.js b/monkey/monkey_island/cc/ui/src/components/report-components/BreachedServers.js
index d23a14c38..16f445ce9 100644
--- a/monkey/monkey_island/cc/ui/src/components/report-components/BreachedServers.js
+++ b/monkey/monkey_island/cc/ui/src/components/report-components/BreachedServers.js
@@ -5,12 +5,17 @@ let renderArray = function(val) {
return ;
};
+let renderIpAddresses = function (val) {
+ return {renderArray(val.ip_addresses)} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}
;
+};
+
const columns = [
{
Header: 'Breached Servers',
columns: [
{Header: 'Machine', accessor: 'label'},
- {Header: 'IP Addresses', id: 'ip_addresses', accessor: x => renderArray(x.ip_addresses)},
+ {Header: 'IP Addresses', id: 'ip_addresses',
+ accessor: x => renderIpAddresses(x)},
{Header: 'Exploits', id: 'exploits', accessor: x => renderArray(x.exploits)}
]
}
diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/ScannedServers.js b/monkey/monkey_island/cc/ui/src/components/report-components/ScannedServers.js
index 9b62bbdc5..57418e415 100644
--- a/monkey/monkey_island/cc/ui/src/components/report-components/ScannedServers.js
+++ b/monkey/monkey_island/cc/ui/src/components/report-components/ScannedServers.js
@@ -5,12 +5,17 @@ let renderArray = function(val) {
return ;
};
+let renderIpAddresses = function (val) {
+ return {renderArray(val.ip_addresses)} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}
;
+};
+
const columns = [
{
Header: 'Scanned Servers',
columns: [
{ Header: 'Machine', accessor: 'label'},
- { Header: 'IP Addresses', id: 'ip_addresses', accessor: x => renderArray(x.ip_addresses)},
+ { Header: 'IP Addresses', id: 'ip_addresses',
+ accessor: x => renderIpAddresses(x)},
{ Header: 'Accessible From', id: 'accessible_from_nodes', accessor: x => renderArray(x.accessible_from_nodes)},
{ Header: 'Services', id: 'services', accessor: x => renderArray(x.services)}
]
diff --git a/monkey/monkey_island/linux/run.sh b/monkey/monkey_island/linux/run.sh
index 6770e2922..c72b5f3b9 100644
--- a/monkey/monkey_island/linux/run.sh
+++ b/monkey/monkey_island/linux/run.sh
@@ -2,4 +2,4 @@
cd /var/monkey
/var/monkey/monkey_island/bin/mongodb/bin/mongod --quiet --dbpath /var/monkey/monkey_island/db &
-/var/monkey/monkey_island/bin/python/bin/python monkey_island/cc/main.py
\ No newline at end of file
+/var/monkey/monkey_island/bin/python/bin/python monkey_island.py
\ No newline at end of file
diff --git a/monkey/monkey_island/readme.txt b/monkey/monkey_island/readme.txt
index 8f6095c7e..64cefcd36 100644
--- a/monkey/monkey_island/readme.txt
+++ b/monkey/monkey_island/readme.txt
@@ -1,3 +1,6 @@
+To get development versions of Monkey Island and Monkey look into deployment scripts folder.
+If you only want to run the software from source you may refer to the instructions below.
+
How to set up the Monkey Island server:
---------------- On Windows ----------------:
diff --git a/monkey/monkey_island/requirements.txt b/monkey/monkey_island/requirements.txt
index f094df947..858642d19 100644
--- a/monkey/monkey_island/requirements.txt
+++ b/monkey/monkey_island/requirements.txt
@@ -14,4 +14,5 @@ netifaces
ipaddress
enum34
PyCrypto
-boto3
\ No newline at end of file
+boto3
+awscli
\ No newline at end of file