Merge branch 'master' of https://github.com/guardicore/monkey
# Conflicts: # chaos_monkey/config.py # chaos_monkey/network/info.py
This commit is contained in:
commit
5eb2379fa2
|
@ -33,7 +33,8 @@ The Monkey itself has been tested on Windows XP, 7, 8.1 and 10. The Linux build
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
For off the shelf use, download our pre-compiled binaries from our website, to setup the C&C server follow the instructions in [Monkey Island readme](monkey_island/readme.txt). If you with to compile the binaries yourself, follow the build instructions in the appropiate [readme](build_env/readme.txt).
|
For off the shelf use, download our pre-compiled binaries from our website, to setup the C&C server follow the instructions in [Monkey Island readme](monkey_island/readme.txt). If you with to compile the binaries yourself, follow the build instructions later on in this readme.
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
@ -148,7 +149,7 @@ Dependency | License |
|
||||||
----------------------------|----------------------------
|
----------------------------|----------------------------
|
||||||
libffi-dev | https://github.com/atgreen/libffi/blob/master/LICENSE
|
libffi-dev | https://github.com/atgreen/libffi/blob/master/LICENSE
|
||||||
PyCrypto | Public domain
|
PyCrypto | Public domain
|
||||||
upx | Custom license, http://upx.sourceforge.net/upx-license.html, according to it (IANL) we're fine as long as we're not modifying UPX
|
upx | Custom license, http://upx.sourceforge.net/upx-license.html
|
||||||
bson | BSD
|
bson | BSD
|
||||||
enum34 | BSD
|
enum34 | BSD
|
||||||
pyasn1 | BSD
|
pyasn1 | BSD
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
REM c:\Python27\python -m PyInstaller.main --name monkey -F -y --clean -i monkey.ico main.py
|
REM c:\Python27\python -m PyInstaller.main --name monkey -F -y --clean -i monkey.ico main.py
|
||||||
c:\python27\Scripts\pyinstaller --upx-dir=.\bin monkey.spec
|
c:\python27\Scripts\pyinstaller --log-level=DEBUG --clean --upx-dir=.\bin monkey.spec
|
||||||
|
|
|
@ -156,6 +156,9 @@ class Configuration(object):
|
||||||
# scanners config
|
# scanners config
|
||||||
###########################
|
###########################
|
||||||
|
|
||||||
|
# Auto detect and scan local subnets
|
||||||
|
local_network_scan = True
|
||||||
|
|
||||||
range_class = FixedRange
|
range_class = FixedRange
|
||||||
range_size = 1
|
range_size = 1
|
||||||
range_fixed = ["", ]
|
range_fixed = ["", ]
|
||||||
|
|
|
@ -53,7 +53,8 @@ class ControlClient(object):
|
||||||
data=json.dumps(monkey),
|
data=json.dumps(monkey),
|
||||||
headers={'content-type': 'application/json'},
|
headers={'content-type': 'application/json'},
|
||||||
verify=False,
|
verify=False,
|
||||||
proxies=ControlClient.proxies)
|
proxies=ControlClient.proxies,
|
||||||
|
timeout=20)
|
||||||
break
|
break
|
||||||
|
|
||||||
except Exception, exc:
|
except Exception, exc:
|
||||||
|
|
|
@ -68,6 +68,7 @@
|
||||||
"singleton_mutex_name": "{2384ec59-0df8-4ab9-918c-843740924a28}",
|
"singleton_mutex_name": "{2384ec59-0df8-4ab9-918c-843740924a28}",
|
||||||
"skip_exploit_if_file_exist": true,
|
"skip_exploit_if_file_exist": true,
|
||||||
"ssh_user": "root",
|
"ssh_user": "root",
|
||||||
|
"local_network_scan": true,
|
||||||
"tcp_scan_get_banner": true,
|
"tcp_scan_get_banner": true,
|
||||||
"tcp_scan_interval": 200,
|
"tcp_scan_interval": 200,
|
||||||
"tcp_scan_timeout": 10000,
|
"tcp_scan_timeout": 10000,
|
||||||
|
|
|
@ -3,46 +3,74 @@ import sys
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
import array
|
import array
|
||||||
|
import ipaddress
|
||||||
from random import randint
|
from random import randint
|
||||||
|
|
||||||
__author__ = 'hoffer'
|
|
||||||
|
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
|
import netifaces
|
||||||
|
|
||||||
def local_ips():
|
def local_ips():
|
||||||
local_hostname = socket.gethostname()
|
local_hostname = socket.gethostname()
|
||||||
return socket.gethostbyname_ex(local_hostname)[2]
|
return socket.gethostbyname_ex(local_hostname)[2]
|
||||||
|
|
||||||
|
def get_host_subnets(only_ips=False):
|
||||||
|
network_adapters = []
|
||||||
|
valid_ips = local_ips()
|
||||||
|
if only_ips:
|
||||||
|
return valid_ips
|
||||||
|
interfaces = [netifaces.ifaddresses(x) for x in netifaces.interfaces()]
|
||||||
|
for inte in interfaces:
|
||||||
|
if netifaces.AF_INET in inte:
|
||||||
|
for add in inte[netifaces.AF_INET]:
|
||||||
|
if "netmask" in add and add["addr"] in valid_ips:
|
||||||
|
network_adapters.append((add["addr"], add["netmask"]))
|
||||||
|
return network_adapters
|
||||||
|
|
||||||
else:
|
else:
|
||||||
import fcntl
|
import fcntl
|
||||||
|
|
||||||
def local_ips():
|
def get_host_subnets(only_ips=False):
|
||||||
result = []
|
"""Get the list of Linux network adapters."""
|
||||||
try:
|
import fcntl
|
||||||
|
max_bytes = 8096
|
||||||
is_64bits = sys.maxsize > 2 ** 32
|
is_64bits = sys.maxsize > 2 ** 32
|
||||||
struct_size = 40 if is_64bits else 32
|
if is_64bits:
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
offset1 = 16
|
||||||
max_possible = 8 # initial value
|
offset2 = 40
|
||||||
while True:
|
|
||||||
bytes = max_possible * struct_size
|
|
||||||
names = array.array('B', '\0' * bytes)
|
|
||||||
outbytes = struct.unpack('iL', fcntl.ioctl(
|
|
||||||
s.fileno(),
|
|
||||||
0x8912, # SIOCGIFCONF
|
|
||||||
struct.pack('iL', bytes, names.buffer_info()[0])
|
|
||||||
))[0]
|
|
||||||
if outbytes == bytes:
|
|
||||||
max_possible *= 2
|
|
||||||
else:
|
else:
|
||||||
break
|
offset1 = 32
|
||||||
namestr = names.tostring()
|
offset2 = 32
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
names = array.array('B', '\0' * max_bytes)
|
||||||
|
outbytes = struct.unpack('iL', fcntl.ioctl(
|
||||||
|
sock.fileno(),
|
||||||
|
0x8912,
|
||||||
|
struct.pack('iL', max_bytes, names.buffer_info()[0])))[0]
|
||||||
|
adapter_names = [names.tostring()[n_cnt:n_cnt + offset1].split('\0', 1)[0]
|
||||||
|
for n_cnt in xrange(0, outbytes, offset2)]
|
||||||
|
network_adapters = []
|
||||||
|
for adapter_name in adapter_names:
|
||||||
|
ip_address = socket.inet_ntoa(fcntl.ioctl(
|
||||||
|
sock.fileno(),
|
||||||
|
0x8915,
|
||||||
|
struct.pack('256s', adapter_name))[20:24])
|
||||||
|
if ip_address.startswith('127'):
|
||||||
|
continue
|
||||||
|
subnet_mask = socket.inet_ntoa(fcntl.ioctl(
|
||||||
|
sock.fileno(),
|
||||||
|
0x891b,
|
||||||
|
struct.pack('256s', adapter_name))[20:24])
|
||||||
|
|
||||||
for i in range(0, outbytes, struct_size):
|
if only_ips:
|
||||||
addr = socket.inet_ntoa(namestr[i+20:i+24])
|
network_adapters.append(ip_address)
|
||||||
if not addr.startswith('127'):
|
else:
|
||||||
result.append(addr)
|
network_adapters.append((ip_address, subnet_mask))
|
||||||
# name of interface is (namestr[i:i+16].split('\0', 1)[0]
|
|
||||||
finally:
|
return network_adapters
|
||||||
return result
|
|
||||||
|
|
||||||
|
def local_ips():
|
||||||
|
return get_host_subnets(only_ips=True)
|
||||||
|
|
||||||
|
|
||||||
def get_free_tcp_port(min_range=1000, max_range=65535):
|
def get_free_tcp_port(min_range=1000, max_range=65535):
|
||||||
|
@ -59,9 +87,25 @@ def get_free_tcp_port(min_range=1000, max_range=65535):
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def check_internet_access(services):
|
def check_internet_access(services):
|
||||||
ping_str = "-n 1" if sys.platform.startswith("win") else "-c 1"
|
ping_str = "-n 1" if sys.platform.startswith("win") else "-c 1"
|
||||||
for host in services:
|
for host in services:
|
||||||
if os.system("ping " + ping_str + " " + host) == 0:
|
if os.system("ping " + ping_str + " " + host) == 0:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def get_ips_from_interfaces():
|
||||||
|
res = []
|
||||||
|
ifs = get_host_subnets()
|
||||||
|
for interface in ifs:
|
||||||
|
ipint = ipaddress.ip_interface(u"%s/%s" % interface)
|
||||||
|
# limit subnet scans to class C only
|
||||||
|
if ipint.network.num_addresses > 255:
|
||||||
|
ipint = ipaddress.ip_interface(u"%s/24" % interface[0])
|
||||||
|
for addr in ipint.network.hosts():
|
||||||
|
if str(addr) == interface[0]:
|
||||||
|
continue
|
||||||
|
res.append(str(addr))
|
||||||
|
return res
|
||||||
|
|
|
@ -2,7 +2,7 @@ import time
|
||||||
import logging
|
import logging
|
||||||
from . import HostScanner
|
from . import HostScanner
|
||||||
from config import WormConfiguration
|
from config import WormConfiguration
|
||||||
from info import local_ips
|
from info import local_ips, get_ips_from_interfaces
|
||||||
from range import *
|
from range import *
|
||||||
|
|
||||||
__author__ = 'itamar'
|
__author__ = 'itamar'
|
||||||
|
@ -27,10 +27,12 @@ class NetworkScanner(object):
|
||||||
LOG.info("Found local IP addresses of the machine: %r", self._ip_addresses)
|
LOG.info("Found local IP addresses of the machine: %r", self._ip_addresses)
|
||||||
# for fixed range, only scan once.
|
# for fixed range, only scan once.
|
||||||
if WormConfiguration.range_class is FixedRange:
|
if WormConfiguration.range_class is FixedRange:
|
||||||
self._ranges = [WormConfiguration.range_class('0.0.0.0')]
|
self._ranges = [WormConfiguration.range_class(None)]
|
||||||
else:
|
else:
|
||||||
self._ranges = [WormConfiguration.range_class(ip_address)
|
self._ranges = [WormConfiguration.range_class(ip_address)
|
||||||
for ip_address in self._ip_addresses]
|
for ip_address in self._ip_addresses]
|
||||||
|
if WormConfiguration.local_network_scan:
|
||||||
|
self._ranges += [FixedRange([ip_address for ip_address in get_ips_from_interfaces()])]
|
||||||
LOG.info("Base local networks to scan are: %r", self._ranges)
|
LOG.info("Base local networks to scan are: %r", self._ranges)
|
||||||
|
|
||||||
def get_victim_machines(self, scan_type, max_find=5, stop_callback=None):
|
def get_victim_machines(self, scan_type, max_find=5, stop_callback=None):
|
||||||
|
|
|
@ -58,10 +58,16 @@ class RelativeRange(NetworkRange):
|
||||||
|
|
||||||
|
|
||||||
class FixedRange(NetworkRange):
|
class FixedRange(NetworkRange):
|
||||||
def __init__(self, base_address, shuffle=True):
|
def __init__(self, fixed_addresses=None, shuffle=True):
|
||||||
base_address = 0
|
base_address = 0
|
||||||
super(FixedRange, self).__init__(base_address, shuffle=shuffle)
|
super(FixedRange, self).__init__(base_address, shuffle=shuffle)
|
||||||
|
if not fixed_addresses:
|
||||||
self._fixed_addresses = self._config.range_fixed
|
self._fixed_addresses = self._config.range_fixed
|
||||||
|
else:
|
||||||
|
if type(fixed_addresses) is str:
|
||||||
|
self._fixed_addresses = [fixed_addresses]
|
||||||
|
else:
|
||||||
|
self._fixed_addresses = list(fixed_addresses)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<FixedRange %s>" % (",".join(self._fixed_addresses))
|
return "<FixedRange %s>" % (",".join(self._fixed_addresses))
|
||||||
|
|
|
@ -22,6 +22,7 @@ Windows:
|
||||||
python -m pip install odict
|
python -m pip install odict
|
||||||
python -m pip install paramiko
|
python -m pip install paramiko
|
||||||
python -m pip install psutil
|
python -m pip install psutil
|
||||||
|
python -m pip install netifaces
|
||||||
python -m pip install PyInstaller
|
python -m pip install PyInstaller
|
||||||
type > C:\Python27\Lib\site-packages\zope\__init__.py
|
type > C:\Python27\Lib\site-packages\zope\__init__.py
|
||||||
7. Download and extract UPX binary to [source-path]\monkey\chaos_monkey\bin\upx.exe:
|
7. Download and extract UPX binary to [source-path]\monkey\chaos_monkey\bin\upx.exe:
|
||||||
|
|
File diff suppressed because one or more lines are too long
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
|
@ -10,6 +10,7 @@
|
||||||
<script type="text/javascript" src="./js/typeahead.bundle.min.js"></script>
|
<script type="text/javascript" src="./js/typeahead.bundle.min.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="./js/bootstrap.min.js"></script>
|
<script type="text/javascript" src="./js/bootstrap.min.js"></script>
|
||||||
|
<script type="text/javascript" src="./js/bootstrap-switch.min.js"></script>
|
||||||
<script type="text/javascript" src="./js/sb-admin-2/sb-admin-2.js"></script>
|
<script type="text/javascript" src="./js/sb-admin-2/sb-admin-2.js"></script>
|
||||||
<script type="text/javascript" src="./js/sb-admin-2/metisMenu.js"></script>
|
<script type="text/javascript" src="./js/sb-admin-2/metisMenu.js"></script>
|
||||||
<script type="text/javascript" src="./js/jsoneditor.js"></script>
|
<script type="text/javascript" src="./js/jsoneditor.js"></script>
|
||||||
|
@ -23,6 +24,7 @@
|
||||||
<link type="text/css" href="./css/typeahead.css" rel="stylesheet"/>
|
<link type="text/css" href="./css/typeahead.css" rel="stylesheet"/>
|
||||||
<!-- <link type="text/css" href="./css/font-awesome.min.css" rel="stylesheet"/> -->
|
<!-- <link type="text/css" href="./css/font-awesome.min.css" rel="stylesheet"/> -->
|
||||||
<link type="text/css" href="./css/bootstrap.min.css" rel="stylesheet"/>
|
<link type="text/css" href="./css/bootstrap.min.css" rel="stylesheet"/>
|
||||||
|
<link type="text/css" href="./css/bootstrap-switch.min.css" rel="stylesheet"/>
|
||||||
<link type="text/css" href="./css/sb-admin-2/sb-admin-2.css" rel="stylesheet"/>
|
<link type="text/css" href="./css/sb-admin-2/sb-admin-2.css" rel="stylesheet"/>
|
||||||
<link type="text/css" href="./css/sb-admin-2/metisMenu.css" rel="stylesheet"/>
|
<link type="text/css" href="./css/sb-admin-2/metisMenu.css" rel="stylesheet"/>
|
||||||
<link type="text/css" href="./css/jquery.dataTables.min.css" rel="stylesheet"/>
|
<link type="text/css" href="./css/jquery.dataTables.min.css" rel="stylesheet"/>
|
||||||
|
@ -71,11 +73,33 @@
|
||||||
</div>
|
</div>
|
||||||
<!-- /.Network section -->
|
<!-- /.Network section -->
|
||||||
|
|
||||||
|
<!-- Info section -->
|
||||||
|
<div class="col-lg-3 col-md-6 col-sm-6">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<a href="#info" data-toggle="collapse">General Info</a>
|
||||||
|
</div>
|
||||||
|
<div id="info" class="panel-body panel-collapse collapse in">
|
||||||
|
<div>
|
||||||
|
Num of Monkeys: <label id="infoNumOfMonkeys">0</label> (<label id="infoNumOfParents">0</label> by exploiting)<br/>
|
||||||
|
Num of Hosts Detected: <label id="infoNumOfHosts">0</label><br/>
|
||||||
|
Num of Tunnels Used: <label id="infoNumOfTunnels">0</label><br/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Display Scanned Hosts: <input type="checkbox" data-size="mini" name="chboxShowScanned" checked>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- /.Info section -->
|
||||||
|
|
||||||
<!-- Details section -->
|
<!-- Details section -->
|
||||||
<div class="col-lg-3 col-md-6 col-sm-6">
|
<div class="col-lg-3 col-md-6 col-sm-6">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<a href="#details" data-toggle="collapse">Details</a>
|
<a href="#details" data-toggle="collapse">Monkey Details</a>
|
||||||
</div>
|
</div>
|
||||||
<div id="details" class="panel-body panel-collapse collapse in">
|
<div id="details" class="panel-body panel-collapse collapse in">
|
||||||
<div id="search" class="input-group custom-search-form">
|
<div id="search" class="input-group custom-search-form">
|
||||||
|
@ -99,6 +123,10 @@
|
||||||
<a href="#mconfig" data-toggle="collapse">Monkey Config</a>
|
<a href="#mconfig" data-toggle="collapse">Monkey Config</a>
|
||||||
</div>
|
</div>
|
||||||
<div id="mconfig" style="overflow: visible" class="panel-body panel-collapse collapse in" aria-expanded="true">
|
<div id="mconfig" style="overflow: visible" class="panel-body panel-collapse collapse in" aria-expanded="true">
|
||||||
|
<div style="display: none;" id="monkey-enabled">
|
||||||
|
Allow running: <input type="checkbox" data-size="mini" name="chboxMonkeyEnabled" checked>
|
||||||
|
</div><br/>
|
||||||
|
<div>
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<button id="btnConfigLoad" style="display: none;" class="btn btn-default" type="button"
|
<button id="btnConfigLoad" style="display: none;" class="btn btn-default" type="button"
|
||||||
onclick="loadMonkeyConfig()" style="margin-top:-4px">
|
onclick="loadMonkeyConfig()" style="margin-top:-4px">
|
||||||
|
@ -108,15 +136,8 @@
|
||||||
onclick="updateMonkeyConfig()" style="margin-top:-4px">
|
onclick="updateMonkeyConfig()" style="margin-top:-4px">
|
||||||
Update
|
Update
|
||||||
</button>
|
</button>
|
||||||
<button id="btnKillMonkey" style="display: none;" class="btn btn-default" type="button"
|
|
||||||
onclick="killMonkey()" style="margin-top:-4px">
|
|
||||||
Mark for Kill
|
|
||||||
</button>
|
|
||||||
<button id="btnReviveMonkey" style="display: none;" class="btn btn-default" type="button"
|
|
||||||
onclick="reviveMonkey()" style="margin-top:-4px">
|
|
||||||
Revive Monkey
|
|
||||||
</button>
|
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
<div style="display: none;" id="monkey-config">
|
<div style="display: none;" id="monkey-config">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -21,15 +21,27 @@ $.getJSON(jsonFile, function(json) {
|
||||||
var network = null;
|
var network = null;
|
||||||
var nodes = [];
|
var nodes = [];
|
||||||
var edges = [];
|
var edges = [];
|
||||||
|
var numOfParentLinks = 0;
|
||||||
|
var numOfTunnelLinks = 0;
|
||||||
|
var numOfScanLinks = 0;
|
||||||
|
|
||||||
|
var showScannedHosts = true;
|
||||||
|
|
||||||
// Images/icons constants
|
// Images/icons constants
|
||||||
const ICONS_DIR = "./css/img/objects/";
|
const ICONS_DIR = "./css/img/objects/";
|
||||||
const ICONS_EXT = ".png";
|
const ICONS_EXT = ".png";
|
||||||
|
|
||||||
|
const HOST_TYPE_MONKEY = "monkey";
|
||||||
|
const HOST_TYPE_SCAN = "scanned";
|
||||||
|
|
||||||
const EDGE_TYPE_PARENT = "parent";
|
const EDGE_TYPE_PARENT = "parent";
|
||||||
const EDGE_TYPE_TUNNEL = "tunnel";
|
const EDGE_TYPE_TUNNEL = "tunnel";
|
||||||
const EDGE_TYPE_SCAN = "scan";
|
const EDGE_TYPE_SCAN = "scan";
|
||||||
|
|
||||||
|
const EDGE_COLOR_PARENT = "red";
|
||||||
|
const EDGE_COLOR_TUNNEL = "blue";
|
||||||
|
const EDGE_COLOR_SCAN = "gray";
|
||||||
|
|
||||||
// General options
|
// General options
|
||||||
// If variable from local storage != null, assign it, otherwise set it's default value.
|
// If variable from local storage != null, assign it, otherwise set it's default value.
|
||||||
|
|
||||||
|
@ -59,6 +71,8 @@ function initAdmin() {
|
||||||
edges: edges
|
edges: edges
|
||||||
};
|
};
|
||||||
|
|
||||||
|
updateCounters();
|
||||||
|
|
||||||
var options = {
|
var options = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -67,6 +81,9 @@ function initAdmin() {
|
||||||
|
|
||||||
network = new vis.Network(container, data, options);
|
network = new vis.Network(container, data, options);
|
||||||
|
|
||||||
|
$("[name='chboxShowScanned']").bootstrapSwitch('onSwitchChange', toggleScannedHosts);
|
||||||
|
$("[name='chboxMonkeyEnabled']").bootstrapSwitch('onSwitchChange', toggleMonkeyEnabled);
|
||||||
|
|
||||||
prepareSearchEngine();
|
prepareSearchEngine();
|
||||||
|
|
||||||
monkeyCfg = new JSONEditor(document.getElementById('monkey-config'),{
|
monkeyCfg = new JSONEditor(document.getElementById('monkey-config'),{
|
||||||
|
@ -115,6 +132,55 @@ function initAdmin() {
|
||||||
addEventsListeners();
|
addEventsListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleScannedHosts(event, state) {
|
||||||
|
if (event.type != "switchChange") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (state) {
|
||||||
|
showScannedHosts = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
showScannedHosts = false;
|
||||||
|
}
|
||||||
|
refreshDrawing();
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshDrawing() {
|
||||||
|
// function called before first init
|
||||||
|
if (network == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// keep old selection
|
||||||
|
var selNode = network.getSelectedNodes();
|
||||||
|
|
||||||
|
if (showScannedHosts) {
|
||||||
|
network.setData({nodes: nodes, edges: edges});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var selectiveNodes = [];
|
||||||
|
var selectiveEdges = [];
|
||||||
|
for (var i=0; i<nodes.length; i++) {
|
||||||
|
if (nodes[i].type != HOST_TYPE_SCAN) {
|
||||||
|
selectiveNodes.push(nodes[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var i=0; i<edges.length; i++) {
|
||||||
|
if (edges[i].type != EDGE_TYPE_SCAN) {
|
||||||
|
selectiveEdges.push(edges[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
network.setData({nodes: selectiveNodes, edges: selectiveEdges});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selNode.length) {
|
||||||
|
var monkey = getMonkey(selNode[0]);
|
||||||
|
if (monkey) { // The selection might be no longer valid if the monkey was deleted
|
||||||
|
selectNode(monkey.hostname, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateMonkeys() {
|
function updateMonkeys() {
|
||||||
$.getJSON(jsonFile + '?timestamp='+ generationDate, function(json) {
|
$.getJSON(jsonFile + '?timestamp='+ generationDate, function(json) {
|
||||||
generationDate = json.timestamp;
|
generationDate = json.timestamp;
|
||||||
|
@ -128,6 +194,7 @@ function updateMonkeys() {
|
||||||
{
|
{
|
||||||
monkeys.push(new_monkeys[i]);
|
monkeys.push(new_monkeys[i]);
|
||||||
nodes.push(createMonkeyNode(new_monkeys[i]));
|
nodes.push(createMonkeyNode(new_monkeys[i]));
|
||||||
|
updateCounters();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,16 +202,7 @@ function updateMonkeys() {
|
||||||
{
|
{
|
||||||
createEdges();
|
createEdges();
|
||||||
createTunnels();
|
createTunnels();
|
||||||
|
refreshDrawing();
|
||||||
// keep old selection
|
|
||||||
var selNode = network.getSelectedNodes();
|
|
||||||
network.setData({nodes: nodes, edges: edges});
|
|
||||||
if (selNode.length) {
|
|
||||||
var monkey = getMonkey(selNode[0]);
|
|
||||||
if (monkey) { // The selection might be no longer valid if the monkey was deleted
|
|
||||||
selectNode(monkey.hostname, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
createScanned();
|
createScanned();
|
||||||
window.setTimeout(updateMonkeys, 10000);
|
window.setTimeout(updateMonkeys, 10000);
|
||||||
|
@ -163,7 +221,6 @@ function createNodes() {
|
||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function createMonkeyNode(monkey) {
|
function createMonkeyNode(monkey) {
|
||||||
var title = undefined;
|
var title = undefined;
|
||||||
var img = "monkey";
|
var img = "monkey";
|
||||||
|
@ -187,12 +244,24 @@ function createMonkeyNode(monkey) {
|
||||||
'image': img,
|
'image': img,
|
||||||
'title': title,
|
'title': title,
|
||||||
'value': undefined,
|
'value': undefined,
|
||||||
|
'type' : HOST_TYPE_MONKEY,
|
||||||
'mass': 1,
|
'mass': 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMachineNode(machine) {
|
function createMachineNode(machine) {
|
||||||
img = ICONS_DIR + "computer" + ICONS_EXT;
|
img = "computer";
|
||||||
|
|
||||||
|
if (undefined != machine.os.type) {
|
||||||
|
if (machine.os.type == "linux") {
|
||||||
|
img += "-linux";
|
||||||
|
}
|
||||||
|
else if (machine.os.type == "windows") {
|
||||||
|
img += "-windows";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
img = ICONS_DIR + img + ICONS_EXT;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'id': machine.ip_addr,
|
'id': machine.ip_addr,
|
||||||
|
@ -202,6 +271,7 @@ function createMachineNode(machine) {
|
||||||
'image': img,
|
'image': img,
|
||||||
'title': undefined,
|
'title': undefined,
|
||||||
'value': undefined,
|
'value': undefined,
|
||||||
|
'type' : HOST_TYPE_SCAN,
|
||||||
'mass': 1,
|
'mass': 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -213,7 +283,8 @@ function createEdges() {
|
||||||
var parent = getMonkeyByGuid(monkey.parent);
|
var parent = getMonkeyByGuid(monkey.parent);
|
||||||
|
|
||||||
if(parent && !edgeExists([parent.id, monkey.id, EDGE_TYPE_PARENT])) {
|
if(parent && !edgeExists([parent.id, monkey.id, EDGE_TYPE_PARENT])) {
|
||||||
edges.push({from: parent.id, to: monkey.id, arrows:'middle', type: EDGE_TYPE_PARENT, color: 'red'});
|
edges.push({from: parent.id, to: monkey.id, arrows:'middle', type: EDGE_TYPE_PARENT, color: EDGE_COLOR_PARENT});
|
||||||
|
numOfParentLinks++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,7 +299,8 @@ function createTunnels() {
|
||||||
var tunnel = getMonkeyByGuid(monkey.tunnel_guid);
|
var tunnel = getMonkeyByGuid(monkey.tunnel_guid);
|
||||||
|
|
||||||
if(tunnel && !edgeExists([monkey.id, tunnel.id, EDGE_TYPE_TUNNEL])) {
|
if(tunnel && !edgeExists([monkey.id, tunnel.id, EDGE_TYPE_TUNNEL])) {
|
||||||
edges.push({from: monkey.id, to: tunnel.id, arrows:'middle', type: EDGE_TYPE_TUNNEL, color:'blue'});
|
edges.push({from: monkey.id, to: tunnel.id, arrows:'middle', type: EDGE_TYPE_TUNNEL, color: EDGE_COLOR_TUNNEL});
|
||||||
|
numOfTunnelLinks++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,13 +309,14 @@ function createTunnels() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function createScanned() {
|
function createScanned() {
|
||||||
|
var genTime = temelGenerationDate; // save the initial value as it's going to be changed in each json call
|
||||||
// For each existing monkey, gets all the scans performed by it
|
// For each existing monkey, gets all the scans performed by it
|
||||||
// For each non exploited machine, adds a new node and connects it as a scanned node.
|
// For each non exploited machine, adds a new node and connects it as a scanned node.
|
||||||
for (var i = 0; i < monkeys.length; i++) {
|
for (var i = 0; i < monkeys.length; i++) {
|
||||||
var monkey = monkeys[i];
|
var monkey = monkeys[i];
|
||||||
// Get scans for each monkey
|
// Get scans for each monkey
|
||||||
// Reading the JSON file containing the monkeys' informations
|
// Reading the JSON file containing the monkeys' informations
|
||||||
$.getJSON(jsonFileTelemetry +'?timestamp='+ temelGenerationDate+ "&monkey_guid=" + monkey.guid+"&telem_type=scan", function(json) {
|
$.getJSON(jsonFileTelemetry +'?timestamp='+ genTime + "&monkey_guid=" + monkey.guid+"&telem_type=scan", function(json) {
|
||||||
temelGenerationDate = json.timestamp;
|
temelGenerationDate = json.timestamp;
|
||||||
var scans = json.objects;
|
var scans = json.objects;
|
||||||
for (var i = 0; i < scans.length; i++) {
|
for (var i = 0; i < scans.length; i++) {
|
||||||
|
@ -265,9 +338,14 @@ function createScanned() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!edgeExists([monkey.id, machineNode.id, EDGE_TYPE_SCAN])) {
|
if(!edgeExists([monkey.id, machineNode.id, EDGE_TYPE_SCAN])) {
|
||||||
edges.push({from: monkey.id, to: machineNode.id, arrows:'middle', type: EDGE_TYPE_SCAN, color: 'red'});
|
edges.push({from: monkey.id, to: machineNode.id, arrows:'middle', type: EDGE_TYPE_SCAN, color: EDGE_COLOR_SCAN});
|
||||||
|
numOfScanLinks++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (scans.length > 0) {
|
||||||
|
refreshDrawing();
|
||||||
|
updateCounters();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,6 +375,13 @@ function buildMonkeyDescription(monkey) {
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateCounters() {
|
||||||
|
$('#infoNumOfMonkeys').html(monkeys.length);
|
||||||
|
$('#infoNumOfHosts').html(scannedMachines.length);
|
||||||
|
$('#infoNumOfParents').html(numOfParentLinks);
|
||||||
|
$('#infoNumOfTunnels').html(numOfTunnelLinks);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preparing the autocompletion search engine for the monkeys
|
* Preparing the autocompletion search engine for the monkeys
|
||||||
|
@ -370,7 +455,8 @@ function onSelect(properties) {
|
||||||
var content = "<b>No selection</b>"
|
var content = "<b>No selection</b>"
|
||||||
$("#selectionInfo").html(content);
|
$("#selectionInfo").html(content);
|
||||||
$('#monkey-config').hide()
|
$('#monkey-config').hide()
|
||||||
$('#btnConfigLoad, #btnConfigUpdate, #btnKillMonkey, #btnReviveMonkey').hide();
|
$('#btnConfigLoad, #btnConfigUpdate').hide();
|
||||||
|
$('#monkey-enabled').hide();
|
||||||
telemTable.clear();
|
telemTable.clear();
|
||||||
telemTable.draw();
|
telemTable.draw();
|
||||||
}
|
}
|
||||||
|
@ -403,14 +489,12 @@ function onNodeSelect(nodeId) {
|
||||||
loadMonkeyConfig();
|
loadMonkeyConfig();
|
||||||
|
|
||||||
if (monkey.config.alive) {
|
if (monkey.config.alive) {
|
||||||
$('#btnKillMonkey').show();
|
$("[name='chboxMonkeyEnabled']").bootstrapSwitch('state', true);
|
||||||
$('#btnReviveMonkey').hide();
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$('#btnKillMonkey').hide();
|
$("[name='chboxMonkeyEnabled']").bootstrapSwitch('state', false);
|
||||||
$('#btnReviveMonkey').show();
|
|
||||||
}
|
}
|
||||||
|
$('#monkey-enabled').show();
|
||||||
|
|
||||||
$.getJSON('/api/telemetry/' + monkey.guid, function(json) {
|
$.getJSON('/api/telemetry/' + monkey.guid, function(json) {
|
||||||
telemTable.clear();
|
telemTable.clear();
|
||||||
|
@ -434,6 +518,19 @@ function onEdgeSelect(edge) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleMonkeyEnabled(event, state) {
|
||||||
|
if (event.type != "switchChange") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (state) {
|
||||||
|
reviveMonkey();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
killMonkey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function killMonkey() {
|
function killMonkey() {
|
||||||
var curr_config = monkeyCfg.getValue();
|
var curr_config = monkeyCfg.getValue();
|
||||||
curr_config.alive = false;
|
curr_config.alive = false;
|
||||||
|
|
|
@ -11,27 +11,19 @@ How to set C&C server:
|
||||||
python -m pip install Flask-Pymongo
|
python -m pip install Flask-Pymongo
|
||||||
python -m pip install Flask-Restful
|
python -m pip install Flask-Restful
|
||||||
python -m pip install python-dateutil
|
python -m pip install python-dateutil
|
||||||
mkdir C:\MonkeyIsland\bin
|
mkdir MonkeyIsland\bin
|
||||||
mkdir C:\MonkeyIsland\db
|
mkdir MonkeyIsland\db
|
||||||
mkdir C:\MonkeyIsland\cc\binaries
|
mkdir MonkeyIsland\cc\binaries
|
||||||
4. Put monkey binaries in C:\MonkeyIsland\cc\binaries:
|
4. Put monkey binaries in MonkeyIsland\cc\binaries:
|
||||||
monkey-linux-64 - monkey binary for linux 64bit
|
monkey-linux-64 - monkey binary for linux 64bit
|
||||||
monkey-linux-32 - monkey binary for linux 32bit
|
monkey-linux-32 - monkey binary for linux 32bit
|
||||||
monkey-windows-32.exe - monkey binary for windows 32bit
|
monkey-windows-32.exe - monkey binary for windows 32bit
|
||||||
monkey-windows-64.exe - monkey binary for windows 64bit
|
monkey-windows-64.exe - monkey binary for windows 64bit
|
||||||
4. Download MongoDB & Extract to C:\MonkeyIsland\bin\mongodb
|
4. Download MongoDB & Extract to MonkeyIsland\bin\mongodb
|
||||||
http://downloads.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-latest.zip
|
http://downloads.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-latest.zip
|
||||||
5. Install OpenSSL
|
5. Install OpenSSL
|
||||||
https://slproweb.com/download/Win64OpenSSL_Light-1_0_2d.exe
|
https://slproweb.com/download/Win64OpenSSL_Light-1_0_2d.exe
|
||||||
6. Generate SSL Certificate, Run create_certificate.bat
|
6. Generate SSL Certificate, run create_certificate.bat when your current working directory is MonkeyIsland
|
||||||
|
|
||||||
How to Connect to build environment:
|
|
||||||
1. set hostname to MONKEYCC
|
|
||||||
2. Put monkey source code at C:\Code\monkey
|
|
||||||
3. Run:
|
|
||||||
net share binaries=C:\MonkeyIsland\cc\binaries
|
|
||||||
net share sources=C:\Code\monkey\chaos_monkey
|
|
||||||
4. Run batch/sh script according to build environment readme
|
|
||||||
|
|
||||||
How to run:
|
How to run:
|
||||||
1. start run_mongodb.bat
|
1. start run_mongodb.bat
|
||||||
|
|
Loading…
Reference in New Issue