const jsonFile = "/api/monkey"; const jsonFileTelemetry = "/api/telemetry"; var monkeys = null; var scannedMachines = []; var generationDate = null; var temelGenerationDate = null; // The JSON must be fully loaded before onload() happens for calling draw() on 'monkeys' $.ajaxSetup({ async: false }); // Reading the JSON file containing the monkeys' informations $.getJSON(jsonFile, function(json) { monkeys = json.objects; generationDate = json.timestamp; }); // The objects used by vis var network = null; var nodes = []; var edges = []; var numOfParentLinks = 0; var numOfTunnelLinks = 0; var numOfScanLinks = 0; var showScannedHosts = true; // Images/icons constants const ICONS_DIR = "./css/img/objects/"; const ICONS_EXT = ".png"; const HOST_TYPE_MONKEY = "monkey"; const HOST_TYPE_SCAN = "scanned"; const EDGE_TYPE_PARENT = "parent"; const EDGE_TYPE_TUNNEL = "tunnel"; const EDGE_TYPE_SCAN = "scan"; const EDGE_COLOR_PARENT = "red"; const EDGE_COLOR_TUNNEL = "blue"; const EDGE_COLOR_SCAN = "gray"; const NODE_MANUAL_RUN_COLOR = "red"; const NODE_ALIVE_STROKECOLOR = "#aeeaae"; // General options // If variable from local storage != null, assign it, otherwise set it's default value. var focusedOnNode = false; var monkeyCfg = undefined; var newCfg = undefined; var telemTable = undefined; JSONEditor.defaults.theme = 'bootstrap3'; function initAdmin() { if (monkeys == null) { errorMessage = "Could not find '" + jsonFile + "'."; $("#networkmap").html(errorMessage); } nodes = []; edges = []; createNodes(); createEdges(); createTunnels(); createScanned(); var data = { nodes: nodes, edges: edges }; updateCounters(); var options = { layout: { improvedLayout: false } }; // Using jQuery to get the element does not work with vis.js library var container = document.getElementById("monkeysmap"); network = new vis.Network(container, data, options); $("[name='chboxShowScanned']").bootstrapSwitch('onSwitchChange', toggleScannedHosts); $("[name='chboxMonkeyEnabled']").bootstrapSwitch('onSwitchChange', toggleMonkeyEnabled); prepareSearchEngine(); monkeyCfg = new JSONEditor(document.getElementById('monkey-config'),{ schema: { type: "object", title: "Monkey", properties: { alive: { title: "Alive", type: "boolean", }, }, options: { "collapsed": true }, }, disable_edit_json: false, }); newCfg = new JSONEditor(document.getElementById('new-config'),{ schema: { type: "object", title: "New Monkeys", properties: { alive: { title: "Alive", type: "boolean", }, }, options: { "collapsed": true }, }, disable_edit_json: false, }); newCfg.setValue({alive: true}); telemTable = $("#telemetris-table").DataTable({ "ordering": false, }); loadNewMonkeysConfig(); setInterval(updateMonkeys, 10000); 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; iFrom: " + parent.hostname + "
To: " + monkey.hostname; edges.push({from: parent.id, to: monkey.id, arrows:'middle', type: EDGE_TYPE_PARENT, title: title, /*label: exploit, font: {color: 'red', size: 10, align: 'top'},*/ color: EDGE_COLOR_PARENT}); if (removeEdge([parent.id, monkey.id, EDGE_TYPE_SCAN])) { numOfScanLinks--; } numOfParentLinks++; } } } } return edges; } function createTunnels() { for (var i = 0; i < monkeys.length; i++) { var monkey = monkeys[i]; if(monkey.tunnel_guid) { var tunnel = getMonkeyByGuid(monkey.tunnel_guid); 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: EDGE_COLOR_TUNNEL}); numOfTunnelLinks++; } } } return edges; } function createScanned() { // Gets all the scans performed by monkeys // For each non exploited machine, adds a new node and connects it as a scanned node. // Reading the JSON file containing the monkeys' informations $.getJSON(jsonFileTelemetry +'?timestamp='+ temelGenerationDate + "&telem_type=scan", function(json) { temelGenerationDate = json.timestamp; var scans = json.objects; for (var i = 0; i < scans.length; i++) { var scan = scans[i]; var monkey = getMonkeyByGuid(scan.monkey_guid); // And check if we've already added this scanned machine var machineNode = getMonkeyByIP(scan.data.machine.ip_addr); if (null == machineNode) { machineNode = getScannedByIP(scan.data.machine.ip_addr); if (null == machineNode) { machineNode = createMachineNode(scan.data.machine); scannedMachines.push(machineNode); nodes.push(machineNode); } } if(!edgeExists([monkey.id, machineNode.id, EDGE_TYPE_SCAN]) && !edgeExists([monkey.id, machineNode.id, EDGE_TYPE_PARENT])) { 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(); } }); } /** * Builds node description */ function buildMonkeyDescription(monkey) { var html = " " + monkey.hostname + "
" + " " + monkey.description + "
" + " " + monkey.internet_access + "
"; if (monkey.dead) { html += " Dead
"; } if (!monkey.config.alive) { html += " Marked to be dead
"; } html += " " + monkey.keepalive + "
" + "
"; html += ""; if (monkey.parent != null) { html += "
" html += ""; } return html; } function updateCounters() { $('#infoNumOfMonkeys').html(monkeys.length); $('#infoNumOfHosts').html(scannedMachines.length); $('#infoNumOfParents').html(numOfParentLinks); $('#infoNumOfTunnels').html(numOfTunnelLinks); var numOfAlive = monkeys.length; for (var i=0;i 0) && getMonkey(properties.nodes[0])){ onNodeSelect(properties.nodes); } else { var content = "Monkey not selected" $("#selectionInfo").html(content); $('#monkey-config').hide() $('#btnConfigLoad, #btnConfigUpdate').hide(); $('#monkey-enabled').hide(); telemTable.clear(); telemTable.draw(); if (properties.edges.length > 0) { onEdgeSelect(properties.edges); } } } /** * Manage the event when a node is selected */ function onNodeSelect(nodeId) { var monkey = getMonkey(nodeId); var htmlContent = ""; if (monkey) { htmlContent = buildMonkeyDescription(monkey); $("#monkeySearch").val(monkey.hostname); $("#selectionInfo").html(htmlContent); $('#monkey-config').show() $('#btnConfigLoad, #btnConfigUpdate').show(); loadMonkeyConfig(); if (monkey.config.alive) { $("[name='chboxMonkeyEnabled']").bootstrapSwitch('state', true, true); } else { $("[name='chboxMonkeyEnabled']").bootstrapSwitch('state', false, true); } $('#monkey-enabled').show(); $.getJSON('/api/telemetry?monkey_guid=' + monkey.guid, function(json) { telemTable.clear(); var telemetries = json.objects; for (var i = 0; i < telemetries.length; i++) { telemTable.row.add([telemetries[i].timestamp, telemetries[i].telem_type, JSON.stringify(telemetries[i].data)]); } telemTable.draw(); }); } network.selectNodes([nodeId]); } /** * Manage the event when an edge is selected */ function onEdgeSelect(edge) { var edge = getEdge(edge); var monkey = getMonkey(edge.from); if (!monkey) {return;}; var target = undefined; if (edge.type == 'scan') { target = getScannedByIP(edge.to) } else { target = getMonkey(edge.to) } $.getJSON(jsonFileTelemetry + '?monkey_guid=' + monkey.guid, function(json) { telemTable.clear(); var telemetries = json.objects; for (var i = 0; i < telemetries.length; i++) { var telem = telemetries[i] if (telem.telem_type == 'scan' || telem.telem_type == 'exploit') { if (((edge.type == 'scan') && (telem.data.machine.ip_addr == target.id)) || ((edge.type == 'parent') && (0 <= $.inArray(telem.data.machine.ip_addr, target.ip_addresses)))) { telemTable.row.add([telemetries[i].timestamp, telemetries[i].telem_type, JSON.stringify(telemetries[i].data)]); } } } telemTable.draw(); }); } function toggleMonkeyEnabled(event, state) { if (event.type != "switchChange") { return; } if (state) { reviveMonkey(); } else { killMonkey(); } } function killMonkey() { var curr_config = monkeyCfg.getValue(); curr_config.alive = false; monkeyCfg.setValue(curr_config); } function reviveMonkey() { var curr_config = monkeyCfg.getValue(); curr_config.alive = true; monkeyCfg.setValue(curr_config); } function toggleFocusOnNode() { if (focusedOnNode) { network.zoomExtent({duration:0}); focusedOnNode = false; } else { selectNode(undefined, true); } } function loadNewMonkeysConfig() { $.getJSON('/api/config/new', function(json) { if (jQuery.isEmptyObject(json)) { newCfg.setValue({alive: true}); } else { if(undefined == json.alive) { json.alive = true; } delete json.id; newCfg.setValue(json); } newCfg.watch('root', updateNewMonkeysConfig); }); } function updateNewMonkeysConfig() { var curr_config = newCfg.getValue() $.ajax({ headers : { 'Accept' : 'application/json', 'Content-Type' : 'application/json' }, url : '/api/config/new', type : 'POST', data : JSON.stringify(curr_config), success : function(response, textStatus, jqXhr) { console.log("New monkeys config successfully updated!"); BootstrapDialog.show({ title: "Update New Monkeys Config", message: "New monkeys config successfully updated!" }); }, error : function(jqXHR, textStatus, errorThrown) { // log the error to the console console.log("The following error occured: " + textStatus, errorThrown); BootstrapDialog.show({ title: "Update New Monkeys Config", message: "The following error occured: " + textStatus }); }, complete : function() { console.log("Sending new monkeys config update..."); } }); } function loadMonkeyConfig() { var node = network.getSelectedNodes(); if(node.length != 1) { return; } var monkey = getMonkey(node[0]); monkeyCfg.unwatch('root', updateMonkeyConfig); monkeyCfg.setValue(monkey.config); monkeyCfg.watch('root', updateMonkeyConfig); } function updateMonkeyConfig() { var node = network.getSelectedNodes(); if(node.length != 1) { return; } var monkey = getMonkey(node[0]); var curr_config = monkeyCfg.getValue(); $.ajax({ headers : { 'Accept' : 'application/json', 'Content-Type' : 'application/json' }, url : '/api/monkey/' + monkey.guid, type : 'PATCH', data : JSON.stringify({config: curr_config}), success : function(response, textStatus, jqXhr) { monkey.config = curr_config; console.log("Monkey config successfully updated! (" + monkey.hostname + ")"); selectNode(monkey.hostname, false); BootstrapDialog.show({ title: "Update Monkey Config", message: "Monkey config successfully updated! (" + monkey.hostname + ")" }); }, error : function(jqXHR, textStatus, errorThrown) { // log the error to the console console.log("The following error occured: " + textStatus, errorThrown); BootstrapDialog.show({ title: "Update Monkey Config", message: "The following error occured: " + textStatus }); }, complete : function() { console.log("Sending monkey config update..."); } }); } function selectNode(hostname, zoom) { if (hostname == undefined) { hostname = $("#monkeySearch").val(); } if (hostname == "") { return; } for (var i = 0; i < monkeys.length; i++) { var monkey = monkeys[i]; if (monkey.hostname == hostname) { onNodeSelect([monkey.id]); if (zoom) { network.focus(monkey.id, {scale:1}); focusedOnNode = true; } break; } } } function showRunMonkeyDialog(addresses) { var selHtml = '' BootstrapDialog.show({ title: 'Run Monkey', message: 'This action will run infection monkey on the Island server.
Please choose the IP address to be used as the server for the monkeys:' + selHtml, type: BootstrapDialog.TYPE_GENERAL, buttons: [{ label: 'Run Monkey', cssClass: 'btn-success', action: function(dialogItself){ dialogItself.close(); $.ajax({ headers : { 'Accept' : 'application/json', 'Content-Type' : 'application/json' }, url : '/api/island', type : 'POST', data : JSON.stringify({"action": "monkey", "island_address": $("#islandInt option:selected").text()}), success : function(response, textStatus, jqXhr) { if (response.res[0] != true) { BootstrapDialog.show({ title: "Run Monkey", type: BootstrapDialog.TYPE_WARNING, message: "The following error occured: " + response.res[1] }); } else { BootstrapDialog.show({ title: "Run Monkey", type: BootstrapDialog.TYPE_SUCCESS, message: "Monkey Started!" }); } }, error : function(jqXHR, textStatus, errorThrown) { console.log("The following error occured: " + textStatus, errorThrown); BootstrapDialog.show({ title: "Run Monkey", type: BootstrapDialog.TYPE_WARNING, message: "The following error occured: " + textStatus }); }, }); } }, { label: 'Cancel', cssClass: 'btn-general', action: function(dialogItself){ dialogItself.close(); } }] }); } function runMonkey() { $.getJSON("/api/island?type=interfaces", function(json) { showRunMonkeyDialog(json["interfaces"]); }); } function killAll() { BootstrapDialog.show({ title: 'Kill All Monkeys', message: 'This action will mark all existing monkeys to die.
As some of the monkyes might be in the middle of exploitation, new monkeys might still apear, and you will need to perform this kill again.
Perform kill all?', type: BootstrapDialog.TYPE_DANGER, buttons: [{ label: 'Kill All', cssClass: 'btn-danger', action: function(dialogItself){ dialogItself.close(); $.ajax({ headers : { 'Accept' : 'application/json', }, url : '/api?action=killall', type : 'GET', success : function(response, textStatus, jqXhr) { console.log(response); if (response.status != 'OK') { BootstrapDialog.show({ title: 'Kill All Monkeys', message: "The following error occured: " + response.reason }); } else { console.log("All monkeys marked to die"); BootstrapDialog.show({ title: 'Kill All Monkeys', type: BootstrapDialog.TYPE_WARNING, message: "All existing monkeys marked to die" }); } }, error : function(jqXHR, textStatus, errorThrown) { console.log("The following error occured: " + textStatus, errorThrown); BootstrapDialog.show({ title: 'Kill All Monkeys', type: BootstrapDialog.TYPE_WARNING, message: "The following error occured: " + textStatus }); } }); } }, { label: 'Cancel', cssClass: 'btn-general', action: function(dialogItself){ dialogItself.close(); } }] }); } function resetDB() { if (confirm('Are you sure you want to empty the database?')) { $.ajax({ headers : { 'Accept' : 'application/json', }, url : '/api?action=reset', type : 'GET', success : function(response, textStatus, jqXhr) { console.log(response); if (response.status != 'OK') { BootstrapDialog.show({ title: "Reset DB", message: "The following error occured: " + response.reason }); } else { console.log("DB was successfully reset!"); location.reload(); } }, error : function(jqXHR, textStatus, errorThrown) { // log the error to the console console.log("The following error occured: " + textStatus, errorThrown); BootstrapDialog.show({ title: "Reset DB", message: "The following error occured: " + textStatus }); }, complete : function() { console.log("Trying to reset DB..."); } }); } } /** * Get a monkey from its id */ function getMonkey(id) { for (var i = 0; i < monkeys.length; i++) { if (monkeys[i].id == id) { return monkeys[i]; } } } function getMonkeyByGuid(guid) { for (var i = 0; i < monkeys.length; i++) { if (monkeys[i].guid == guid) { return monkeys[i]; } } return null; } function getMonkeyByIP(ip) { for (var i = 0; i < monkeys.length; i++) { var monkey = monkeys[i]; for (var j = 0; j< monkey.ip_addresses.length; j++) { if (monkey.ip_addresses[j] == ip) { return monkey; } } } return null; } function getScannedByIP(ip) { for (var i = 0; i < scannedMachines.length; i++) { var machine = scannedMachines[i]; if (machine.id == ip) { return machine } } return null; } function getMonkeyIndex(guid) { for (var i = 0; i < monkeys.length; i++) { if (monkeys[i].guid == guid) { return i; } } return -1; } /** * Get a node from its id */ function getNode(id) { for (var i = 0; i < nodes.length; i++) { if (nodes[i].id == id) { return nodes[i]; } } } /** * Get an edge from its id */ function getEdge(id) { for (var i = 0; i < edges.length; i++) { if (edges[i].id == id) { return edges[i]; } } } /** * Verifies whether a node already exist or not */ function nodeExists(id) { return getNode(id) != null; } /** * Verifies whether a link already exist or not */ function edgeExists(link) { for (var i = 0; i < edges.length; i++) { var from = edges[i].from; var to = edges[i].to; var type = edges[i].type; if (from == link[0] && to == link[1] && type == link[2]) { return edges[i]; } } } function removeEdge(link) { for (var i = 0; i < edges.length; i++) { var from = edges[i].from; var to = edges[i].to; var type = edges[i].type; if (from == link[0] && to == link[1] && type == link[2]) { edges.splice(i, 1); return true; } } return false; } /** * Clears the value in the local storage */ function clear(key) { if (localStorage[key]) { delete localStorage[key]; } }; /** /.localStorage Section **/ /** **/ /** ----- **/ /** **/ /** Utilities Section **/ /** * Returns the differences between two arrays */ Array.prototype.diff = function(other) { var diff = []; for (var i = 0; i < this.length; i++) { var obj = this[i]; if (other.indexOf(obj) == -1) { diff.push(obj); } } for (var i = 0; i < other.length; i++) { var obj = other[i]; if (this.indexOf(obj) == -1 && diff.indexOf(obj) == -1) { diff.push(obj); } } return diff; }; /** /.Utilities Section **/ /** **/