Last active
September 15, 2015 00:01
-
-
Save jmingov/464063c614e7e951e44f to your computer and use it in GitHub Desktop.
My botnet tracking panel converted to reference a static gist as a demonstration. I'm new to nodejs, so feel free to point out any glaring issues.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var blessed = require('blessed'); | |
var contrib = require('blessed-contrib'); | |
var screen = blessed.screen(); | |
var request = require("request"); | |
// You need to install dependencies: | |
// npm install blessed blessed-contrib | |
// Constants | |
var bot_categories = { | |
"Alina": "POS", | |
"Andromeda": "Multi", | |
"Betabot": "Banking", | |
"Blackshades": "RAT", | |
"Citadel": "Banking", | |
"Cythosia": "DDoS", | |
"Dendroid": "RAT", | |
"Dexter": "POS", | |
"EasterJackPOS": "POS", | |
"Ice IX": "Banking", | |
"JackPOS": "POS", | |
"MadnessPro": "DDoS", | |
"njRat": "RAT", | |
"pBot": "Multi", | |
"Pony": "Banking", | |
"Solar": "Multi", | |
"VertexNet": "Multi", | |
"vSkimmer": "POS", | |
"Zeus": "Banking", | |
"Dyre": "Banking", | |
"CryptoWall": "Ransomware", | |
"Cryptolocker": "Ransomware", | |
"XtremeRAT": "RAT", | |
"BlackWorm": "RAT", | |
"DarkComet": "RAT", | |
"DiamondFox": "Multi", | |
"CyberGate": "RAT" | |
}; | |
var bot_colors = { | |
"POS": "red", | |
"Multi": "blue", | |
"Banking": "yellow", | |
"RAT": "white", | |
"DDoS": "cyan", | |
"Ransomware": "magenta" | |
}; | |
var bot_characters = { | |
// POS | |
"Alina": "A", | |
"Dexter": "D", | |
"EasterJackPOS": "E", | |
"JackPOS": "J", | |
"vSkimmer": "V", | |
// Multi-Function | |
"Andromeda": "A", | |
"pBot": "P", | |
"Solar": "S", | |
"VertexNet": "V", | |
"DiamondFox": "D", | |
// Banking | |
"Betabot": "B", | |
"Citadel": "C", | |
"Ice IX": "I", | |
"Pony": "P", | |
"Zeus": "Z", | |
"Dyre": "D", | |
// DDoS | |
"Cythosia": "C", | |
"MadnessPro": "M", | |
// RAT | |
"Blackshades": "B", | |
"Dendroid": "D", | |
"njRat": "N", | |
"XtremeRAT": "X", | |
"BlackWorm": "W", | |
"DarkComet": "C", | |
"CyberGate": "G", | |
// Ransomware | |
"CryptoWall": "W", | |
"Cryptolocker": "L" | |
}; | |
screen.key(['escape', 'q', 'C-c'], function(ch, key) { | |
return process.exit(0); | |
}); | |
var grid = new contrib.grid({rows: 12, cols: 12, screen: screen}); | |
var map = grid.set(4, 0, 8, 8, contrib.map, {label: 'C2 Locations'}); | |
var bar = grid.set(0, 0, 2, 12, contrib.bar, {label: 'Bot Types', barWidth: 12, barSpacing: 12, xOffset: 2, maxHeight: 9}); | |
var barCategories = grid.set(2, 0, 2, 3, contrib.bar, {label: 'Bot Categories', barWidth: 8, barSpacing: 8, xOffset: 2, maxHeight: 9}); | |
var barCountry = grid.set(2, 3, 2, 5, contrib.bar, {label: 'Bot Countries', barWidth: 14, barSpacing: 14, xOffset: 2, maxHeight: 9}); | |
var treeData = {}; | |
var updatedData = {}; | |
var tree = grid.set(2, 8, 10, 4, contrib.tree, {style: {text: 'green', template: { lines: true }}, label: "Explore Data"}); | |
// Dynamic tree portion | |
Object.size = function(obj) { | |
var size = 0, key; | |
for (key in obj) { | |
if (obj.hasOwnProperty(key)) size++; | |
} | |
return size; | |
}; | |
var updated = true; | |
var explorer = { | |
name: '/', | |
extended: true, | |
// Custom function used to recursively determine the node path | |
getPath: function(self){ | |
// If we don't have any parent, we are at tree root, so return the base case | |
if(! self.parent) | |
return ''; | |
// Get the parent node path and add this node name | |
return self.parent.getPath(self.parent)+"|"+self.name; | |
}, | |
// Child generation function | |
children: function(self){ | |
try { | |
var result = {}; | |
var selfPath = self.getPath(self); | |
//console.log(selfPath); | |
var pathParts = selfPath.split("|"); | |
var currentDict = treeData; | |
for (var i = 1; i < pathParts.length; i++) { | |
currentDict = currentDict[pathParts[i]]; | |
} | |
if (updated || !self.childrenContent) { | |
updated = false; | |
var keys = []; | |
for (var c in currentDict){ | |
keys.push(c); | |
} | |
keys.sort(); | |
var temp = []; | |
for (var c in keys) { | |
c = keys[c]; | |
var child_count = Object.size(currentDict[c]); | |
if (child_count > 0) { | |
temp.push({name: c, getPath: self.getPath, extended: false, children: self.children }); | |
} else { | |
temp.push({name: c, getPath: self.getPath, extended: false }); | |
} | |
} | |
for(var key in temp){ | |
result[temp[key].name] = temp[key] | |
} | |
}else{ | |
result = self.childrenContent; | |
} | |
//console.log(result); | |
return result; | |
} | |
catch(e) | |
{ | |
console.log(e); | |
return {} | |
} | |
} | |
}; | |
tree.focus(); | |
tree.setData(explorer); | |
tree.on('select',function(node){ | |
var path = node.getPath(node); | |
if(path == "" || path == "/"){ | |
treeData = updatedData; | |
updated = true; | |
} | |
screen.render(); | |
}); | |
function updateView(){ | |
var url = "https://gist.githubusercontent.com/bwall/afb0339b1c1bcc913030/raw/76bc7a37b138c679032ec8e050a96fcf35c033ec/c2s.json"; | |
request({ | |
url: url, | |
json: true | |
}, function (error, response, body) { | |
if (!error && response.statusCode === 200) { | |
var array_length = body.length; | |
map.clearMarkers(); | |
var bot_type_prevalance = {}; | |
var bot_category_prevalance = {}; | |
var country_prev = {}; | |
var newTreeData = {}; | |
for(var i = 0; i < array_length; i++){ | |
var c2 = body[i]; | |
// Add tree data | |
if(!(bot_categories[c2.bot_type] in newTreeData)){ | |
newTreeData[bot_categories[c2.bot_type]] = {}; | |
} | |
if(!(c2.bot_type in newTreeData[bot_categories[c2.bot_type]])) { | |
newTreeData[bot_categories[c2.bot_type]][c2.bot_type] = {}; | |
} | |
var bot_key = c2.uri + " " + c2.ip; | |
if(!(bot_key in newTreeData[bot_categories[c2.bot_type]][c2.bot_type])) { | |
newTreeData[bot_categories[c2.bot_type]][c2.bot_type][bot_key] = {}; | |
} | |
// Add map markers | |
map.addMarker({ | |
"lon": c2.lng, | |
"lat": c2.lat, | |
"color": bot_colors[bot_categories[c2.bot_type]], | |
"char": bot_characters[c2.bot_type] | |
}); | |
// Gather country stats | |
if(c2.country in country_prev){ | |
country_prev[c2.country]++; | |
} else { | |
country_prev[c2.country] = 1; | |
} | |
// Gather bot type stats | |
if(c2.bot_type in bot_type_prevalance){ | |
bot_type_prevalance[c2.bot_type]++; | |
} else { | |
bot_type_prevalance[c2.bot_type] = 1; | |
} | |
// Gather bot category stats | |
if(bot_categories[c2.bot_type] in bot_category_prevalance){ | |
bot_category_prevalance[bot_categories[c2.bot_type]]++; | |
} else { | |
bot_category_prevalance[bot_categories[c2.bot_type]] = 1; | |
} | |
} | |
// Render tree data | |
updatedData = newTreeData; | |
// Render bot country stats | |
var tuples = []; | |
for (var key in country_prev){ | |
tuples.push([key, country_prev[key]]); | |
} | |
tuples.sort(function(a, b) { | |
a = a[1]; | |
b = b[1]; | |
return a > b ? -1 : (a < b ? 1 : 0); | |
}); | |
var array_keys = new Array(); | |
var array_values = new Array(); | |
for (var i = 0; i < tuples.length; i++) { | |
array_keys.push(tuples[i][0]); | |
array_values.push(tuples[i][1]); | |
} | |
barCountry.setData({titles: array_keys, data: array_values}); | |
// Render bot type stats | |
var tuples = []; | |
for (var key in bot_type_prevalance){ | |
tuples.push([key, bot_type_prevalance[key]]); | |
} | |
tuples.sort(function(a, b) { | |
a = a[1]; | |
b = b[1]; | |
return a > b ? -1 : (a < b ? 1 : 0); | |
}); | |
var array_keys = new Array(); | |
var array_values = new Array(); | |
for (var i = 0; i < tuples.length; i++) { | |
array_keys.push(tuples[i][0]); | |
array_values.push(tuples[i][1]); | |
} | |
bar.setData({titles: array_keys, data: array_values}); | |
// Render bot category stats | |
var tuples = []; | |
for (var key in bot_category_prevalance){ | |
tuples.push([key, bot_category_prevalance[key]]); | |
} | |
tuples.sort(function(a, b) { | |
a = a[1]; | |
b = b[1]; | |
return a > b ? -1 : (a < b ? 1 : 0); | |
}); | |
var array_keys = new Array(); | |
var array_values = new Array(); | |
for (var i = 0; i < tuples.length; i++) { | |
array_keys.push(tuples[i][0]); | |
array_values.push(tuples[i][1]); | |
} | |
barCategories.setData({titles: array_keys, data: array_values}); | |
tree.focus(); | |
screen.render(); | |
} | |
}); | |
} | |
updateView(); | |
setInterval(updateView, 60000); | |
screen.render(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment