Create a gist now

Instantly share code, notes, and snippets.

@bwall /tracking.js
Last active Feb 15, 2017

What would you like to do?
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.
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