Add monkey kill option from island

This commit is contained in:
itsikkes 2016-07-04 10:44:57 +03:00
parent 84496dd3f5
commit 3d5d972cf8
6 changed files with 126 additions and 38 deletions

View File

@ -120,7 +120,7 @@ class ControlClient(object):
return
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(),))
except Exception, exc:
# 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)
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
def download_monkey_exe(host):
if not WormConfiguration.current_server:

View File

@ -46,7 +46,7 @@ class ChaosMonkey(object):
arg_parser.add_argument('-s', '--server')
arg_parser.add_argument('-d', '--depth')
opts, self._args = arg_parser.parse_known_args(self._args)
self._parent = opts.parent
self._default_tunnel = opts.tunnel
self._default_server = opts.server
@ -69,10 +69,18 @@ class ChaosMonkey(object):
if firewall.is_enabled():
firewall.add_firewall_rule()
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()
if monkey_tunnel:
monkey_tunnel.start()
ControlClient.send_telemetry("state", {'done': False})
self._default_server = WormConfiguration.current_server
LOG.debug("default server: %s" % self._default_server)
ControlClient.send_telemetry("tunnel", ControlClient.proxies.get('https'))
@ -103,12 +111,16 @@ class ChaosMonkey(object):
break
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
for machine in machines:
if ControlClient.check_for_stop():
break
is_empty = False
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__)
finger.get_host_fingerprint(machine)
@ -156,8 +168,8 @@ class ChaosMonkey(object):
if successful_exploiter:
self._exploited_machines.add(machine)
ControlClient.send_telemetry('exploit', {'machine': machine.__dict__,
'exploiter': successful_exploiter.__class__.__name__})
ControlClient.send_telemetry('exploit', {'machine': machine.__dict__,
'exploiter': successful_exploiter.__class__.__name__})
LOG.info("Successfully propagated to %s using %s",
machine, successful_exploiter.__class__.__name__)
@ -202,13 +214,14 @@ class ChaosMonkey(object):
from _subprocess import SW_HIDE, STARTF_USESHOWWINDOW, CREATE_NEW_CONSOLE
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags = CREATE_NEW_CONSOLE | STARTF_USESHOWWINDOW
startupinfo.wShowWindow = SW_HIDE
startupinfo.wShowWindow = SW_HIDE
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)
else:
os.remove(sys.executable)
except Exception, 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")

View File

@ -33,7 +33,7 @@ class NetworkScanner(object):
for ip_address in self._ip_addresses]
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)
scanner = scan_type()
@ -42,6 +42,10 @@ class NetworkScanner(object):
for range in self._ranges:
LOG.debug("Scanning for potential victims in the network %r", range)
for victim in range:
if stop_callback and stop_callback():
LOG.debug("Got stop signal")
break
# skip self IP address
if victim.ip_addr in self._ip_addresses:
continue

View File

@ -123,6 +123,34 @@
<div id="selectionInfo">
<label>No selection</label>
</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>
@ -132,7 +160,7 @@
<div class="col-lg-3 col-md-6 col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">
<a href="#config" data-toggle="collapse">Config</a>
<a href="#config" data-toggle="collapse">General Config</a>
</div>
<div id="config" style="overflow: visible" class="panel-body panel-collapse collapse in" aria-expanded="true">
<span class="input-group-btn">
@ -146,23 +174,11 @@
</button>
</span>
<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>
<!-- /.Config section -->
<!-- /.Config section -->
</div>

View File

@ -108,6 +108,8 @@ function initAdmin() {
"ordering": false,
});
loadNewMonkeysConfig();
window.setTimeout(updateMonkeys, 10000);
addEventsListeners();
@ -134,7 +136,15 @@ function updateMonkeys() {
createEdges();
createTunnels();
// 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();
window.setTimeout(updateMonkeys, 10000);
@ -269,8 +279,16 @@ function buildMonkeyDescription(monkey) {
var html =
"<label>Name:</label> " + monkey.hostname + "</br>" +
"<label>Description:</label> " + monkey.description + "</br>" +
"<label>Internet Access:</label> " + monkey.internet_access + "</br>" +
"<label>IP Address:</label></br>"
"<label>Internet Access:</label> " + monkey.internet_access + "</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++) {
html += monkey.ip_addresses[i] + "</br>"
@ -352,7 +370,7 @@ function onSelect(properties) {
var content = "<b>No selection</b>"
$("#selectionInfo").html(content);
$('#monkey-config').hide()
$('#btnConfigLoad, #btnConfigUpdate').hide();
$('#btnConfigLoad, #btnConfigUpdate, #btnKillMonkey, #btnReviveMonkey').hide();
telemTable.clear();
telemTable.draw();
}
@ -382,6 +400,17 @@ function onNodeSelect(nodeId) {
$('#monkey-config').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) {
telemTable.clear();
@ -394,7 +423,6 @@ function onNodeSelect(nodeId) {
telemTable.draw();
});
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() {
if (focusedOnNode) {
@ -413,7 +454,7 @@ function toggleFocusOnNode() {
focusedOnNode = false;
}
else {
selectNode(undefined, zoom=true);
selectNode(undefined, true);
}
}
@ -460,26 +501,26 @@ function updateNewMonkeysConfig() {
}
function loadMonkeyConfig() {
nodes = network.getSelectedNodes();
var node = network.getSelectedNodes();
if(nodes.length != 1) {
if(node.length != 1) {
return;
}
var monkey = getMonkey(nodes[0]);
var monkey = getMonkey(node[0]);
monkeyCfg.setValue(monkey.config);
}
function updateMonkeyConfig() {
nodes = network.getSelectedNodes();
if(nodes.length != 1) {
var node = network.getSelectedNodes();
if(node.length != 1) {
return;
}
var monkey = getMonkey(nodes[0]);
var monkey = getMonkey(node[0]);
var curr_config = monkeyCfg.getValue()
var curr_config = monkeyCfg.getValue();
$.ajax({
headers : {
@ -491,7 +532,8 @@ function updateMonkeyConfig() {
data : JSON.stringify({config: curr_config}),
success : function(response, textStatus, jqXhr) {
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) {
// log the error to the console

View File

@ -167,7 +167,15 @@ class Telemetry(restful.Resource):
mongo.db.monkey.update({"guid": telemetry_json['monkey_guid']},
{'$unset': {'tunnel_guid':''}},
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:
pass