Add monkey kill option from island
This commit is contained in:
parent
84496dd3f5
commit
3d5d972cf8
|
@ -120,7 +120,7 @@ class ControlClient(object):
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
WormConfiguration.from_dict(reply.json().get('config'))
|
WormConfiguration.from_dict(reply.json()["objects"][0].get('config'))
|
||||||
LOG.info("New configuration was loaded from server: %r" % (WormConfiguration.as_dict(),))
|
LOG.info("New configuration was loaded from server: %r" % (WormConfiguration.as_dict(),))
|
||||||
except Exception, exc:
|
except Exception, exc:
|
||||||
# we don't continue with default conf here because it might be dangerous
|
# we don't continue with default conf here because it might be dangerous
|
||||||
|
@ -128,6 +128,11 @@ class ControlClient(object):
|
||||||
WormConfiguration.current_server, reply._content, exc)
|
WormConfiguration.current_server, reply._content, exc)
|
||||||
raise Exception("Couldn't load from from server's configuration, aborting. %s" % exc)
|
raise Exception("Couldn't load from from server's configuration, aborting. %s" % exc)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def check_for_stop():
|
||||||
|
ControlClient.load_control_config()
|
||||||
|
return not WormConfiguration.alive
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def download_monkey_exe(host):
|
def download_monkey_exe(host):
|
||||||
if not WormConfiguration.current_server:
|
if not WormConfiguration.current_server:
|
||||||
|
|
|
@ -46,7 +46,7 @@ class ChaosMonkey(object):
|
||||||
arg_parser.add_argument('-s', '--server')
|
arg_parser.add_argument('-s', '--server')
|
||||||
arg_parser.add_argument('-d', '--depth')
|
arg_parser.add_argument('-d', '--depth')
|
||||||
opts, self._args = arg_parser.parse_known_args(self._args)
|
opts, self._args = arg_parser.parse_known_args(self._args)
|
||||||
|
|
||||||
self._parent = opts.parent
|
self._parent = opts.parent
|
||||||
self._default_tunnel = opts.tunnel
|
self._default_tunnel = opts.tunnel
|
||||||
self._default_server = opts.server
|
self._default_server = opts.server
|
||||||
|
@ -69,10 +69,18 @@ class ChaosMonkey(object):
|
||||||
if firewall.is_enabled():
|
if firewall.is_enabled():
|
||||||
firewall.add_firewall_rule()
|
firewall.add_firewall_rule()
|
||||||
ControlClient.wakeup(parent=self._parent, default_tunnel=self._default_tunnel)
|
ControlClient.wakeup(parent=self._parent, default_tunnel=self._default_tunnel)
|
||||||
|
ControlClient.load_control_config()
|
||||||
|
|
||||||
|
if not WormConfiguration.alive:
|
||||||
|
LOG.info("Marked not alive from configuration")
|
||||||
|
return
|
||||||
|
|
||||||
monkey_tunnel = ControlClient.create_control_tunnel()
|
monkey_tunnel = ControlClient.create_control_tunnel()
|
||||||
if monkey_tunnel:
|
if monkey_tunnel:
|
||||||
monkey_tunnel.start()
|
monkey_tunnel.start()
|
||||||
|
|
||||||
|
ControlClient.send_telemetry("state", {'done': False})
|
||||||
|
|
||||||
self._default_server = WormConfiguration.current_server
|
self._default_server = WormConfiguration.current_server
|
||||||
LOG.debug("default server: %s" % self._default_server)
|
LOG.debug("default server: %s" % self._default_server)
|
||||||
ControlClient.send_telemetry("tunnel", ControlClient.proxies.get('https'))
|
ControlClient.send_telemetry("tunnel", ControlClient.proxies.get('https'))
|
||||||
|
@ -103,12 +111,16 @@ class ChaosMonkey(object):
|
||||||
break
|
break
|
||||||
|
|
||||||
machines = self._network.get_victim_machines(WormConfiguration.scanner_class,
|
machines = self._network.get_victim_machines(WormConfiguration.scanner_class,
|
||||||
max_find=WormConfiguration.victims_max_find)
|
max_find=WormConfiguration.victims_max_find,
|
||||||
|
stop_callback=ControlClient.check_for_stop)
|
||||||
is_empty = True
|
is_empty = True
|
||||||
for machine in machines:
|
for machine in machines:
|
||||||
|
if ControlClient.check_for_stop():
|
||||||
|
break
|
||||||
|
|
||||||
is_empty = False
|
is_empty = False
|
||||||
for finger in self._fingerprint:
|
for finger in self._fingerprint:
|
||||||
LOG.info("Trying to get OS fingerprint from %r with module %s",
|
LOG.info("Trying to get OS fingerprint from %r with module %s",
|
||||||
machine, finger.__class__.__name__)
|
machine, finger.__class__.__name__)
|
||||||
finger.get_host_fingerprint(machine)
|
finger.get_host_fingerprint(machine)
|
||||||
|
|
||||||
|
@ -156,8 +168,8 @@ class ChaosMonkey(object):
|
||||||
|
|
||||||
if successful_exploiter:
|
if successful_exploiter:
|
||||||
self._exploited_machines.add(machine)
|
self._exploited_machines.add(machine)
|
||||||
ControlClient.send_telemetry('exploit', {'machine': machine.__dict__,
|
ControlClient.send_telemetry('exploit', {'machine': machine.__dict__,
|
||||||
'exploiter': successful_exploiter.__class__.__name__})
|
'exploiter': successful_exploiter.__class__.__name__})
|
||||||
|
|
||||||
LOG.info("Successfully propagated to %s using %s",
|
LOG.info("Successfully propagated to %s using %s",
|
||||||
machine, successful_exploiter.__class__.__name__)
|
machine, successful_exploiter.__class__.__name__)
|
||||||
|
@ -202,13 +214,14 @@ class ChaosMonkey(object):
|
||||||
from _subprocess import SW_HIDE, STARTF_USESHOWWINDOW, CREATE_NEW_CONSOLE
|
from _subprocess import SW_HIDE, STARTF_USESHOWWINDOW, CREATE_NEW_CONSOLE
|
||||||
startupinfo = subprocess.STARTUPINFO()
|
startupinfo = subprocess.STARTUPINFO()
|
||||||
startupinfo.dwFlags = CREATE_NEW_CONSOLE | STARTF_USESHOWWINDOW
|
startupinfo.dwFlags = CREATE_NEW_CONSOLE | STARTF_USESHOWWINDOW
|
||||||
startupinfo.wShowWindow = SW_HIDE
|
startupinfo.wShowWindow = SW_HIDE
|
||||||
subprocess.Popen(DELAY_DELETE_CMD % {'file_path': sys.executable},
|
subprocess.Popen(DELAY_DELETE_CMD % {'file_path': sys.executable},
|
||||||
stdin=None, stdout=None, stderr=None,
|
stdin=None, stdout=None, stderr=None,
|
||||||
close_fds=True, startupinfo=startupinfo)
|
close_fds=True, startupinfo=startupinfo)
|
||||||
else:
|
else:
|
||||||
os.remove(sys.executable)
|
os.remove(sys.executable)
|
||||||
except Exception, exc:
|
except Exception, exc:
|
||||||
LOG.error("Exception in self delete: %s", exc)
|
LOG.error("Exception in self delete: %s", exc)
|
||||||
|
|
||||||
LOG.info("Monkey is shutting down")
|
ControlClient.send_telemetry("state", {'done': True})
|
||||||
|
LOG.info("Monkey is shutting down")
|
|
@ -33,7 +33,7 @@ class NetworkScanner(object):
|
||||||
for ip_address in self._ip_addresses]
|
for ip_address in self._ip_addresses]
|
||||||
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):
|
def get_victim_machines(self, scan_type, max_find=5, stop_callback=None):
|
||||||
assert issubclass(scan_type, HostScanner)
|
assert issubclass(scan_type, HostScanner)
|
||||||
|
|
||||||
scanner = scan_type()
|
scanner = scan_type()
|
||||||
|
@ -42,6 +42,10 @@ class NetworkScanner(object):
|
||||||
for range in self._ranges:
|
for range in self._ranges:
|
||||||
LOG.debug("Scanning for potential victims in the network %r", range)
|
LOG.debug("Scanning for potential victims in the network %r", range)
|
||||||
for victim in range:
|
for victim in range:
|
||||||
|
if stop_callback and stop_callback():
|
||||||
|
LOG.debug("Got stop signal")
|
||||||
|
break
|
||||||
|
|
||||||
# skip self IP address
|
# skip self IP address
|
||||||
if victim.ip_addr in self._ip_addresses:
|
if victim.ip_addr in self._ip_addresses:
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -123,6 +123,34 @@
|
||||||
<div id="selectionInfo">
|
<div id="selectionInfo">
|
||||||
<label>No selection</label>
|
<label>No selection</label>
|
||||||
</div>
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<a href="#mconfig" data-toggle="collapse">Monkey Config</a>
|
||||||
|
</div>
|
||||||
|
<div id="mconfig" style="overflow: visible" class="panel-body panel-collapse collapse in" aria-expanded="true">
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<button id="btnConfigLoad" style="display: none;" class="btn btn-default" type="button"
|
||||||
|
onclick="loadMonkeyConfig()" style="margin-top:-4px">
|
||||||
|
Refresh
|
||||||
|
</button>
|
||||||
|
<button id="btnConfigUpdate" style="display: none;" class="btn btn-default" type="button"
|
||||||
|
onclick="updateMonkeyConfig()" style="margin-top:-4px">
|
||||||
|
Update
|
||||||
|
</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>
|
||||||
|
<div style="display: none;" id="monkey-config">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -132,7 +160,7 @@
|
||||||
<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="#config" data-toggle="collapse">Config</a>
|
<a href="#config" data-toggle="collapse">General Config</a>
|
||||||
</div>
|
</div>
|
||||||
<div id="config" style="overflow: visible" class="panel-body panel-collapse collapse in" aria-expanded="true">
|
<div id="config" style="overflow: visible" class="panel-body panel-collapse collapse in" aria-expanded="true">
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
|
@ -146,23 +174,11 @@
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
<div id="new-config">
|
<div id="new-config">
|
||||||
</div>
|
|
||||||
<span class="input-group-btn">
|
|
||||||
<button id="btnConfigLoad" style="display: none;" class="btn btn-default" type="button"
|
|
||||||
onclick="loadMonkeyConfig()" style="margin-top:-4px">
|
|
||||||
Load
|
|
||||||
</button>
|
|
||||||
<button id="btnConfigUpdate" style="display: none;" class="btn btn-default" type="button"
|
|
||||||
onclick="updateMonkeyConfig()" style="margin-top:-4px">
|
|
||||||
Update
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
<div style="display: none;" id="monkey-config">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.Config section -->
|
<!-- /.Config section -->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,8 @@ function initAdmin() {
|
||||||
"ordering": false,
|
"ordering": false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
loadNewMonkeysConfig();
|
||||||
|
|
||||||
window.setTimeout(updateMonkeys, 10000);
|
window.setTimeout(updateMonkeys, 10000);
|
||||||
|
|
||||||
addEventsListeners();
|
addEventsListeners();
|
||||||
|
@ -134,7 +136,15 @@ function updateMonkeys() {
|
||||||
createEdges();
|
createEdges();
|
||||||
createTunnels();
|
createTunnels();
|
||||||
|
|
||||||
|
// keep old selection
|
||||||
|
var selNode = network.getSelectedNodes();
|
||||||
network.setData({nodes: nodes, edges: edges});
|
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);
|
||||||
|
@ -269,8 +279,16 @@ function buildMonkeyDescription(monkey) {
|
||||||
var html =
|
var html =
|
||||||
"<label>Name:</label> " + monkey.hostname + "</br>" +
|
"<label>Name:</label> " + monkey.hostname + "</br>" +
|
||||||
"<label>Description:</label> " + monkey.description + "</br>" +
|
"<label>Description:</label> " + monkey.description + "</br>" +
|
||||||
"<label>Internet Access:</label> " + monkey.internet_access + "</br>" +
|
"<label>Internet Access:</label> " + monkey.internet_access + "</br>";
|
||||||
"<label>IP Address:</label></br>"
|
if (monkey.dead) {
|
||||||
|
html += "<label>State:</label> Dead </br>";
|
||||||
|
}
|
||||||
|
if (!monkey.config.alive) {
|
||||||
|
html += "<label>Note:</label> Marked to be dead</br>";
|
||||||
|
}
|
||||||
|
html +=
|
||||||
|
"<label>Last Seen:</label> " + monkey.keepalive + "</br>" +
|
||||||
|
"<label>IP Address:</label></br>";
|
||||||
|
|
||||||
for (var i = 0; i < monkey.ip_addresses.length; i++) {
|
for (var i = 0; i < monkey.ip_addresses.length; i++) {
|
||||||
html += monkey.ip_addresses[i] + "</br>"
|
html += monkey.ip_addresses[i] + "</br>"
|
||||||
|
@ -352,7 +370,7 @@ 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').hide();
|
$('#btnConfigLoad, #btnConfigUpdate, #btnKillMonkey, #btnReviveMonkey').hide();
|
||||||
telemTable.clear();
|
telemTable.clear();
|
||||||
telemTable.draw();
|
telemTable.draw();
|
||||||
}
|
}
|
||||||
|
@ -382,6 +400,17 @@ function onNodeSelect(nodeId) {
|
||||||
$('#monkey-config').show()
|
$('#monkey-config').show()
|
||||||
$('#btnConfigLoad, #btnConfigUpdate').show();
|
$('#btnConfigLoad, #btnConfigUpdate').show();
|
||||||
|
|
||||||
|
loadMonkeyConfig();
|
||||||
|
|
||||||
|
if (monkey.config.alive) {
|
||||||
|
$('#btnKillMonkey').show();
|
||||||
|
$('#btnReviveMonkey').hide();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('#btnKillMonkey').hide();
|
||||||
|
$('#btnReviveMonkey').show();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$.getJSON('/api/telemetry/' + monkey.guid, function(json) {
|
$.getJSON('/api/telemetry/' + monkey.guid, function(json) {
|
||||||
telemTable.clear();
|
telemTable.clear();
|
||||||
|
@ -394,7 +423,6 @@ function onNodeSelect(nodeId) {
|
||||||
telemTable.draw();
|
telemTable.draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
network.selectNodes([nodeId]);
|
network.selectNodes([nodeId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,6 +434,19 @@ function onEdgeSelect(edge) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function killMonkey() {
|
||||||
|
var curr_config = monkeyCfg.getValue();
|
||||||
|
curr_config.alive = false;
|
||||||
|
monkeyCfg.setValue(curr_config);
|
||||||
|
updateMonkeyConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
function reviveMonkey() {
|
||||||
|
var curr_config = monkeyCfg.getValue();
|
||||||
|
curr_config.alive = true;
|
||||||
|
monkeyCfg.setValue(curr_config);
|
||||||
|
updateMonkeyConfig();
|
||||||
|
}
|
||||||
|
|
||||||
function toggleFocusOnNode() {
|
function toggleFocusOnNode() {
|
||||||
if (focusedOnNode) {
|
if (focusedOnNode) {
|
||||||
|
@ -413,7 +454,7 @@ function toggleFocusOnNode() {
|
||||||
focusedOnNode = false;
|
focusedOnNode = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
selectNode(undefined, zoom=true);
|
selectNode(undefined, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,26 +501,26 @@ function updateNewMonkeysConfig() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadMonkeyConfig() {
|
function loadMonkeyConfig() {
|
||||||
nodes = network.getSelectedNodes();
|
var node = network.getSelectedNodes();
|
||||||
|
|
||||||
if(nodes.length != 1) {
|
if(node.length != 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var monkey = getMonkey(nodes[0]);
|
var monkey = getMonkey(node[0]);
|
||||||
|
|
||||||
monkeyCfg.setValue(monkey.config);
|
monkeyCfg.setValue(monkey.config);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateMonkeyConfig() {
|
function updateMonkeyConfig() {
|
||||||
nodes = network.getSelectedNodes();
|
var node = network.getSelectedNodes();
|
||||||
if(nodes.length != 1) {
|
if(node.length != 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var monkey = getMonkey(nodes[0]);
|
var monkey = getMonkey(node[0]);
|
||||||
|
|
||||||
var curr_config = monkeyCfg.getValue()
|
var curr_config = monkeyCfg.getValue();
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
headers : {
|
headers : {
|
||||||
|
@ -491,7 +532,8 @@ function updateMonkeyConfig() {
|
||||||
data : JSON.stringify({config: curr_config}),
|
data : JSON.stringify({config: curr_config}),
|
||||||
success : function(response, textStatus, jqXhr) {
|
success : function(response, textStatus, jqXhr) {
|
||||||
monkey.config = curr_config;
|
monkey.config = curr_config;
|
||||||
console.log("Monkey config successfully updated!");
|
console.log("Monkey config successfully updated! (" + monkey.hostname + ")");
|
||||||
|
selectNode(monkey.hostname, false);
|
||||||
},
|
},
|
||||||
error : function(jqXHR, textStatus, errorThrown) {
|
error : function(jqXHR, textStatus, errorThrown) {
|
||||||
// log the error to the console
|
// log the error to the console
|
||||||
|
|
|
@ -167,7 +167,15 @@ class Telemetry(restful.Resource):
|
||||||
mongo.db.monkey.update({"guid": telemetry_json['monkey_guid']},
|
mongo.db.monkey.update({"guid": telemetry_json['monkey_guid']},
|
||||||
{'$unset': {'tunnel_guid':''}},
|
{'$unset': {'tunnel_guid':''}},
|
||||||
upsert=True)
|
upsert=True)
|
||||||
|
elif telemetry_json.get('telem_type') == 'state':
|
||||||
|
if telemetry_json['data']['done']:
|
||||||
|
mongo.db.monkey.update({"guid": telemetry_json['monkey_guid']},
|
||||||
|
{'$set': {'dead': True}},
|
||||||
|
upsert=True)
|
||||||
|
else:
|
||||||
|
mongo.db.monkey.update({"guid": telemetry_json['monkey_guid']},
|
||||||
|
{'$set': {'dead': False}},
|
||||||
|
upsert=True)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue