Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • Pavel.Valach/warden
1 result
Show changes
Commits on Source (20)
Showing
with 435 additions and 120 deletions
--- ---
server_admin: "{{ root@inventory_hostname }}" server_admin: "{{ root@inventory_hostname }}"
warden_filer_bin_path: /opt/warden-filer warden_filer_bin_path: /opt/warden-filer
warden_filer_lib_path: /var/lib/warden_filer
warden_filer_run_path: /run/warden_filer
warden_client_cert_path: /etc/ssl/certs/warden.cert.pem warden_client_cert_path: /etc/ssl/certs/warden.cert.pem
warden_client_key_path: /etc/ssl/private/warden.key.pem warden_client_key_path: /etc/ssl/private/warden.key.pem
warden_client_id_store: /var/lib/warden_filer/warden_filer.id warden_client_id_store: /var/lib/warden_filer/warden_filer.id
......
--- ---
- name: Checkout Warden repository - name: Checkout Warden repository
git: git:
repo: https://homeproj.cesnet.cz/git/warden.git/ repo: https://gitlab.cesnet.cz/713/warden/warden.git
version: warden-client-3.0-beta3 version: warden-client-3.0-beta3
dest: /tmp/warden_client_repository dest: /tmp/warden_client_repository
- name: Create bin dir for warden_filer
file:
path: "{{ warden_filer_bin_path }}"
state: directory
owner: root
group: root
mode: "755"
- name: Create lib and run dir for warden_filer
file:
path: "{{ item }}"
state: directory
owner: "{{ warden_filer_uid }}"
group: "{{ warden_filer_gid }}"
mode: "755"
with_items:
- "{{ warden_filer_lib_path }}"
- "{{ warden_filer_run_path }}"
- name: Install Filer binaries - name: Install Filer binaries
copy: copy:
src: "/tmp/warden_client_repository/{{ src }}" remote_src: true
dest: "{{ warden_filer_bin_path }}/{{ dest }}" src: "/tmp/warden_client_repository/{{ item.src }}"
dest: "{{ warden_filer_bin_path }}/{{ item.dest }}"
mode: "755"
with_items: with_items:
- src: warden_client/warden_client.py - src: warden_client/warden_client.py
dest: warden_client.py dest: warden_client.py
...@@ -17,15 +38,26 @@ ...@@ -17,15 +38,26 @@
- src: warden_filer/check_file_count - src: warden_filer/check_file_count
dest: check_file_count dest: check_file_count
- name: Link Filer binary to /usr/local/bin
file:
src: "{{ warden_filer_bin_path }}/warden_filer.py"
dest: "/usr/local/bin/warden_filer.py"
state: link
owner: root
group: root
mode: "755"
- name: Install Warden Filer config - name: Install Warden Filer config
template: template:
src: "{{ item }}" src: "{{ item }}"
dest: "/{{ item }}" dest: "/{{ item }}"
with_items: with_items:
- etc/warden_filer.cfg - etc/warden_filer.cfg
- etc/defaults/warden_filer_receiver - etc/default/warden_filer_receiver
- name: Install Warden Filer init script - name: Install Warden Filer init script
copy: copy:
remote_src: true
src: /tmp/warden_client_repository/warden_filer/warden_filer_receiver src: /tmp/warden_client_repository/warden_filer/warden_filer_receiver
dest: /etc/init.d/warden_filer_receiver dest: /etc/init.d/warden_filer_receiver
mode: "755"
--- ---
- name: Checkout Warden repository - name: Checkout Warden repository
git: git:
repo: https://homeproj.cesnet.cz/git/warden.git/ repo: https://gitlab.cesnet.cz/713/warden/warden.git
version: warden-server-3.0-beta3 version: warden-server-3.0-beta3
dest: /tmp/warden_server_repository dest: /tmp/warden_server_repository
......
...@@ -22,10 +22,7 @@ def main(args): ...@@ -22,10 +22,7 @@ def main(args):
banners = [{'name': banner_name_en, 'database' : "Database Size:", 'events' : "Number of Events:", 'senders' : "Number of Senders:", 'receivers' : "Number of Receivers:", 'created' : "Banner Created:"}, {'name': banner_name_cz, 'database' : "Velikost databáze:", 'events' : "Suma všech událostí:", 'senders' : "Odesílající klienti:", 'receivers' : "Přijímající klienti:", 'created' : "Banner vytvořen:"}] banners = [{'name': banner_name_en, 'database' : "Database Size:", 'events' : "Number of Events:", 'senders' : "Number of Senders:", 'receivers' : "Number of Receivers:", 'created' : "Banner Created:"}, {'name': banner_name_cz, 'database' : "Velikost databáze:", 'events' : "Suma všech událostí:", 'senders' : "Odesílající klienti:", 'receivers' : "Přijímající klienti:", 'created' : "Banner vytvořen:"}]
# We have DB credentials # We have DB credentials
user = "warden" host, database, user, password = sys.argv[1:]
password = "w4rd3n&u53r"
database = "warden3"
host = "localhost"
db = MySQLdb.connect(host = host, user = user, passwd = password, db = database) db = MySQLdb.connect(host = host, user = user, passwd = password, db = database)
cursor = db.cursor() cursor = db.cursor()
......
...@@ -36,14 +36,11 @@ B. Configuration ...@@ -36,14 +36,11 @@ B. Configuration
4. Setup backend call (warden-map.py) in a crontab. 4. Setup backend call (warden-map.py) in a crontab.
NOTE: Please make sure you will have stored warden-map.json file NOTE: Please make sure you will have stored warden-map.json file
in the fronted folder. in the frontend folder.
EXAMPLE: ./warden-map.py --events 100 \ EXAMPLE: ./warden-map.py --client cz.cesnet.warden.map \
--client cz.cesnet.warden.map \
--key certs/key.pem \ --key certs/key.pem \
--cert certs/cert.pem \ --cert certs/cert.pem \
--cacert certs/cacert.pem \ --output ../frontend/
--secret SeCreT \
--output ../fronted/
5. Enjoy your map. 5. Enjoy your map.
......
...@@ -6,86 +6,83 @@ ...@@ -6,86 +6,83 @@
# Copyright (C) 2016 Cesnet z.s.p.o # Copyright (C) 2016 Cesnet z.s.p.o
# Use of this source is governed by a 3-clause BSD-style license, see LICENSE file. # Use of this source is governed by a 3-clause BSD-style license, see LICENSE file.
import json
import codecs
import time
import argparse
import GeoIP
import requests
def getLastEvents(events, client, key, cert, cacert, secret): def getLastEvents(client, key, cert):
try: res = requests.post(
ses = Session() 'https://warden-hub.cesnet.cz/warden3/getEvents?client=%s' % (client,),
req = Request('POST', 'https://warden-hub.cesnet.cz/warden3/getEvents?client='+ client + ('&secret='+ secret if secret else "")+'&count=' + events) cert=(cert, key)
pre = req.prepare() )
res = ses.send(pre, cert = (cert, key), verify=cacert)
except requests.exceptions.RequestException as error:
print error
sys.exit(1)
data = res.json() data = res.json()
i = 0 i = 0
eventsList = [] eventsList = []
for p in data['events']: for p in data['events']:
event = {} event = {}
if i < events: for key, value in { 'event': 'Category', 'time': 'DetectTime', 'origin': 'Source', 'destination': 'Target'}.items():
for key, value in { 'event': 'Category', 'time': 'DetectTime', 'origin': 'Source', 'destination': 'Target'}.iteritems(): if value in p:
if value in p: if (key == 'origin') or (key == 'destination'):
if (key == 'origin') or (key == 'destination'): event[key] = {}
event[key] = {} if 'IP4' in p[value][0]:
if 'IP4' in p[value][0]: event[key]['ip'] = p[value][0]['IP4'][0]
event[key]['ip'] = p[value][0]['IP4']
else:
event[key] = {}
elif (key == 'event'):
event[key] = ', '.join(p[value])
else: else:
event[key] = p[value]
else:
if (key == 'origin') or (key == 'destination'):
event[key] = {} event[key] = {}
else: elif (key == 'event'):
event[key] = {} event[key] = ', '.join(p[value])
if 'ip' in event['origin']: else:
eventsList.append(event) event[key] = p[value]
i += 1 else:
else: if (key == 'origin') or (key == 'destination'):
break event[key] = {}
else:
event[key] = {}
if 'ip' in event['origin']:
eventsList.append(event)
i += 1
return eventsList return eventsList
def getGeolocation(ip): def getGeolocation(ip, db):
try:
response = requests.get('http://freegeoip.net/json/' + str(ip[0]))
except requests.exceptions.RequestException as error:
print error
sys.exit(1)
try: data = db.record_by_addr(ip)
json_data = json.loads(response.text)
except ValueError as error:
print error
sys.exit(1)
return {'latitude': json_data['latitude'], 'longitude': json_data['longitude'], 'country_name': json_data['country_name'], 'city': json_data['city']} if not data:
return {}
else:
return {
'latitude': data['latitude'],
'longitude': data['longitude'],
'country_name': data['country_name'] if data['country_name'] else None,
'city': data['city'] if data['city'] else None
}
def main(args): def main(args):
events = args.events[0]
client = args.client[0] client = args.client[0]
key = args.key[0] key = args.key[0]
cert = args.cert[0] cert = args.cert[0]
cacert = args.cacert[0]
secret = args.secret[0]
if args.output is not None: if args.output is not None:
path = args.output[0] + 'warden-map.json' path = args.output[0] + 'warden-map.json'
else: else:
path = 'warden-map.json' path = 'warden-map.json'
wardenEvents = getLastEvents(events, client, key, cert, cacert, secret) db = GeoIP.open("GeoLiteCity.dat", GeoIP.GEOIP_MEMORY_CACHE)
db.set_charset(GeoIP.GEOIP_CHARSET_UTF8)
wardenEvents = getLastEvents(client, key, cert)
for p in wardenEvents: for p in wardenEvents:
for target in {'origin', 'destination'}: for target in {'origin', 'destination'}:
geoData = {} geoData = {}
if 'ip' in p[target]: if 'ip' in p[target]:
geoData = getGeolocation(p[target]['ip']) geoData = getGeolocation(p[target]['ip'], db)
for value in {'latitude', 'longitude', 'country_name', 'city'}: for value in {'latitude', 'longitude', 'country_name', 'city'}:
if value in geoData: if value in geoData:
if not geoData[value]: if not geoData[value]:
...@@ -102,22 +99,13 @@ def main(args): ...@@ -102,22 +99,13 @@ def main(args):
p[target]['latitude'] = 49.743 p[target]['latitude'] = 49.743
p[target]['longitude'] = 15.338 p[target]['longitude'] = 15.338
try: wardenEvents.append(int(time.time()));
with open(path, 'w') as outfile:
json.dump(wardenEvents, outfile)
except IOError:
print "Error: File does not appear to exist."
sys.exit(1)
return 0 with open(path, 'w') as outfile:
json.dump(wardenEvents, outfile)
if __name__ == '__main__':
import sys
import json
from requests import Request, Session
import requests
import argparse
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Creates warden-map.json for warden-map.html frontend.', parser = argparse.ArgumentParser(description='Creates warden-map.json for warden-map.html frontend.',
formatter_class=lambda prog: argparse.HelpFormatter(prog,max_help_position=30)) formatter_class=lambda prog: argparse.HelpFormatter(prog,max_help_position=30))
...@@ -126,18 +114,12 @@ if __name__ == '__main__': ...@@ -126,18 +114,12 @@ if __name__ == '__main__':
requiredNamed = parser.add_argument_group('required arguments') requiredNamed = parser.add_argument_group('required arguments')
requiredNamed.add_argument('--events', metavar='<number>', type=str, required=True,
nargs=1, help='count of events for a map')
requiredNamed.add_argument('--client', metavar='<org.ex.cl>', type=str, required=True, requiredNamed.add_argument('--client', metavar='<org.ex.cl>', type=str, required=True,
nargs=1, help='client name') nargs=1, help='client name')
requiredNamed.add_argument('--key', metavar='path/key.pem', type=str, required=True, requiredNamed.add_argument('--key', metavar='path/key.pem', type=str, required=True,
nargs=1, help='SSL key for a client') nargs=1, help='SSL key for a client')
requiredNamed.add_argument('--cert', metavar='path/cert.pem', type=str, required=True, requiredNamed.add_argument('--cert', metavar='path/cert.pem', type=str, required=True,
nargs=1, help='SSL cert for a client') nargs=1, help='SSL cert for a client')
requiredNamed.add_argument('--cacert', metavar='path/cacert.pem', type=str, required=True,
nargs=1, help='SSL cacert for a client')
requiredNamed.add_argument('--secret', metavar='<SeCreT>', type=str, required=True,
nargs=1, help='secret key for a client')
args = parser.parse_args() args = parser.parse_args()
main(args) main(args)
...@@ -11,6 +11,10 @@ ...@@ -11,6 +11,10 @@
body { body {
font-family: 'Oswald', sans-serif; font-family: 'Oswald', sans-serif;
background: #00253D;
border: 0px;
padding: 0px;
margin: 0px;
} }
h2 { h2 {
...@@ -22,7 +26,7 @@ h2 { ...@@ -22,7 +26,7 @@ h2 {
} }
#country { #country {
color: #0062a2; color: #0062a2; /* Cesnet blue */
font-weight: bold; font-weight: bold;
} }
...@@ -35,25 +39,29 @@ table { ...@@ -35,25 +39,29 @@ table {
} }
table th { table th {
color: #0062a2; color: #0062a2; /* Cesnet blue */
padding: 0; padding: 0;
} }
table td { table td {
color: #4b4d4a; color: #4b4d4a; /* Greenish gray */
padding: 0; padding: 0;
} }
#container { #container {
overflow: hidden; overflow: hidden;
border: 2px solid #0062a2; /* border: 2px solid #0062a2;
border-radius: 5px; border: 0px;
background: white; padding: 0px;
margin: 0px;
border-radius: 5px;*/
position: relative; position: relative;
width: 1280px; /* width: 1280px;
height: 720px; height: 720px;*/
max-width: 100%; max-width: 100%;
max-height: 100% max-height: 100%
width: 100%;
height: 100vh;*/
} }
.zoom-button { .zoom-button {
...@@ -77,3 +85,54 @@ table td { ...@@ -77,3 +85,54 @@ table td {
padding: 10px; padding: 10px;
color: #0062a2; color: #0062a2;
} }
#warden-logo {
position: absolute;
top: 30px;
left: 30px;
background: white;
padding: 10px;
border-radius: 10px;
width: 240px;
height: 92px;
text-align: center;
}
#cesnet-logo {
position: absolute;
top: 30px;
right: 30px;
background: white;
padding: 10px;
border-radius: 10px;
width: 240px;
height: 92px;
text-align: center;
}
#legend-box {
position: absolute;
bottom: 30px;
left: 30px;
background-color: rgba(0,0,0,0.3);
color: white;
padding: 10px;
border-radius: 10px;
/*width: 240px;
height: 92px;
text-align: center;*/
}
#heading {
position: absolute;
top: 30px;
left: 50%;
width: 40em;
height: 92px;
margin-left: -20em;
font-size: xx-large;
color: white;
text-align: center;
vertical-align: middle;
line-height: 92px;
}
...@@ -205,20 +205,197 @@ Zoom.prototype._getNextScale = function(direction) { ...@@ -205,20 +205,197 @@ Zoom.prototype._getNextScale = function(direction) {
return scaleSet[shift]; return scaleSet[shift];
}; };
function defaults(obj) {
Array.prototype.slice.call(arguments, 1).forEach(function(source) {
if (source) {
for (var prop in source) {
// Deep copy if property not set
if (obj[prop] == null) {
if (typeof source[prop] == 'function') {
obj[prop] = source[prop];
}
else {
obj[prop] = JSON.parse(JSON.stringify(source[prop]));
}
}
}
}
});
return obj;
}
function val( datumValue, optionsValue, context ) {
if ( typeof context === 'undefined' ) {
context = optionsValue;
optionsValues = undefined;
}
var value = typeof datumValue !== 'undefined' ? datumValue : optionsValue;
if (typeof value === 'undefined') {
return null;
}
if ( typeof value === 'function' ) {
var fnContext = [context];
if ( context.geography ) {
fnContext = [context.geography, context.data];
}
return value.apply(null, fnContext);
}
else {
return value;
}
}
var cat_color = {
"Abusive": "MediumPurple",
"Malware": "Red",
"Recon": "LightSlateGray",
"Attempt": "GhostWhite",
"Intrusion": "DarkTurquoise",
"Availability": "HotPink",
"Information": "PaleTurquoise",
"Fraud": "Yellow",
"Vulnerable": "DarkGoldenRod",
"Anomaly": "Brown",
"Other": "Green"
}
var cat_desc = {
"Abusive": "spam",
"Malware": "virus, worm, trojan, malware",
"Recon": "scanning, sniffing",
"Attempt": "bruteforce, exploitation attempt",
"Intrusion": "botnet, successful exploit",
"Availability": "(D)DOS",
"Information": "wiretapping, spoofing, hijacking",
"Fraud": "phishing, scam",
"Vulnerable": "open for abuse",
"Anomaly": "unusual traffic",
"Other": "unknown/unidentified"
}
function handleArcs (layer, data, options) {
var self = this,
svg = this.svg;
if ( !data || (data && !data.slice) ) {
throw "Datamaps Error - arcs must be an array";
}
// For some reason arc options were put in an `options` object instead of the parent arc
// I don't like this, so to match bubbles and other plugins I'm moving it
// This is to keep backwards compatability
for ( var i = 0; i < data.length; i++ ) {
data[i] = defaults(data[i], data[i].options);
delete data[i].options;
}
if ( typeof options === "undefined" ) {
options = defaultOptions.arcConfig;
}
var arcs = layer.selectAll('path.datamaps-arc').data( data, JSON.stringify );
var path = d3.geo.path()
.projection(self.projection);
arcs
.enter()
.append('svg:path')
.attr('class', 'datamaps-arc')
.style('stroke-linecap', 'round')
.style('stroke', function(datum) {
/* return val(datum.strokeColor, options.strokeColor, datum);*/
for (cat in cat_color) {
if (datum.event.startsWith(cat)) {
return cat_color[cat];
}
}
return "Green";
})
.style('fill', 'none')
.style('stroke-width', function(datum) {
return val(datum.strokeWidth, options.strokeWidth, datum);
})
.attr('d', function(datum) {
var originXY, destXY;
originXY = self.latLngToXY(val(datum.origin.latitude, datum), val(datum.origin.longitude, datum))
destXY = self.latLngToXY(val(datum.destination.latitude, datum), val(datum.destination.longitude, datum));
var midXY = [ (originXY[0] + destXY[0]) / 2, (originXY[1] + destXY[1]) / 2];
if (options.greatArc) {
// TODO: Move this to inside `if` clause when setting attr `d`
var greatArc = d3.geo.greatArc()
.source(function(d) { return [val(d.origin.longitude, d), val(d.origin.latitude, d)]; })
.target(function(d) { return [val(d.destination.longitude, d), val(d.destination.latitude, d)]; });
return path(greatArc(datum))
}
var sharpness = val(datum.arcSharpness, options.arcSharpness, datum);
return "M" + originXY[0] + ',' + originXY[1] + "S" + (midXY[0] + (50 * sharpness)) + "," + (midXY[1] - (75 * sharpness)) + "," + destXY[0] + "," + destXY[1];
})
.attr('data-info', function(datum) {
return JSON.stringify(datum);
})
.on('mouseover', function ( datum ) {
var $this = d3.select(this);
if (options.popupOnHover) {
self.updatePopup($this, datum, options, svg);
}
})
.on('mouseout', function ( datum ) {
var $this = d3.select(this);
d3.selectAll('.datamaps-hoverover').style('display', 'none');
})
.transition()
.style('fill', function(datum, i) {
/*
Thank you Jake Archibald, this is awesome.
Source: http://jakearchibald.com/2013/animated-line-drawing-svg/
*/
var length = this.getTotalLength();
this.style.transition = this.style.WebkitTransition = 'none';
this.style.strokeDasharray = length + ' ' + length;
this.style.strokeDashoffset = length;
this.getBoundingClientRect();
this.style.transition = this.style.WebkitTransition = 'stroke-dashoffset ' + val(datum.animationSpeed, options.animationSpeed, datum) + 'ms ' + datum.delay*1000 + 'ms ease-out';
this.style.strokeDashoffset = '0';
return 'none';
});
arcs.exit()
.transition()
.duration(1000)
.style('opacity', 0)
.remove();
}
var main_data = [];
var prev_data = 0;
// Configuration of datamap canvas // Configuration of datamap canvas
// Futher reading can be found at https://datamaps.github.io/ // Futher reading can be found at https://datamaps.github.io/
function Datamap() { function Datamap() {
this.$container = $("#container"); this.$container = $("#container");
this.instance = new Datamaps({ instance = this.instance = new Datamaps({
scope: 'world', scope: 'world',
element: this.$container.get(0), element: this.$container.get(0),
done: this._handleMapReady.bind(this), done: this._handleMapReady.bind(this),
projection: 'mercator', projection: 'mercator',
fills: { fills: {
defaultFill: '#dcdcda' /*defaultFill: '#454545'*/
defaultFill: 'black'
}, },
geographyConfig: { geographyConfig: {
borderColor: '#fdfdfd', hideAntarctica: true,
borderColor: '#0062a2',
highlightFillColor: '#4b4d4a', highlightFillColor: '#4b4d4a',
highlightBorderColor: '#fdfdfd', highlightBorderColor: '#fdfdfd',
popupOnHover: true, popupOnHover: true,
...@@ -226,18 +403,18 @@ function Datamap() { ...@@ -226,18 +403,18 @@ function Datamap() {
return '<div class="hoverinfo" id="country">' + geography.properties.name + '</div>'; return '<div class="hoverinfo" id="country">' + geography.properties.name + '</div>';
}, },
}, },
arcConfig: { ph_arcConfig: {
strokeColor: '#0062a2', strokeColor: '#0062a2',
strokeWidth: 1, strokeWidth: 2,
arcSharpness: 5, arcSharpness: 2, /* 5 */
animationSpeed: 4000, // Milliseconds animationSpeed: 3000, // Milliseconds
popupOnHover: true, popupOnHover: true,
// Case with latitude and longitude // Case with latitude and longitude
popupTemplate: function(geography, data) { popupTemplate: function(geography, data) {
if ( ( data.origin && data.destination ) && data.origin.latitude && data.origin.longitude && data.destination.latitude && data.destination.longitude ) { if ( ( data.origin && data.destination ) && data.origin.latitude && data.origin.longitude && data.destination.latitude && data.destination.longitude ) {
// Content of info table // Content of info table
str = '<div class="hoverinfo"><table id="event"><tr><th>Warden Event</th></tr><tr><td>Type</td><td>'+ JSON.stringify(data.event) +'</td></tr><tr><td>Detect Time</td><td>'+ JSON.stringify(data.time) +'</td></tr><tr><th>Event origin</th></tr><tr><td>IP</td><td>' + JSON.stringify(data.origin.ip) + '</td></tr><tr><td>City & Country</td><td>' + JSON.stringify(data.origin.city) + ',&nbsp;' + JSON.stringify(data.origin.country_name) + '</td></tr><tr><td>GPS</td><td>' + JSON.stringify(data.origin.latitude) + ',&nbsp;' + JSON.stringify(data.origin.longitude) + '</td></tr><tr><th>Event Destination</th></tr><tr><td>IP</td><td>' + JSON.stringify(data.destination.ip) + '</td></tr><tr><td>City & Country</td><td>' + JSON.stringify(data.destination.city) + ',&nbsp;' + JSON.stringify(data.destination.country_name) + '</td></tr><tr><td>GPS</td><td>' + JSON.stringify(data.destination.latitude) + ',&nbsp;' + JSON.stringify(data.destination.longitude) + '</td></tr></table></div>'; str = '<div class="hoverinfo"><table id="event"><tr><th>Warden Event</th></tr><tr><td>Type</td><td>'+ JSON.stringify(data.event) +'</td></tr><tr><td>Detect Time</td><td>'+ JSON.stringify(data.time) +'</td></tr><tr><th>Event origin</th></tr><tr><td>IP</td><td>' + JSON.stringify(data.origin.ip) + '</td></tr><tr><td>City & Country</td><td>' + JSON.stringify(data.origin.city) + ',&nbsp;' + JSON.stringify(data.origin.country_name) + '</td></tr><tr><td>GPS</td><td>' + JSON.stringify(data.origin.latitude) + ',&nbsp;' + JSON.stringify(data.origin.longitude) + '</td></tr><tr><th>Event Destination</th></tr><tr><td>IP</td><td>' + JSON.stringify(data.destination.ip) + '</td></tr><tr><td>City & Country</td><td>' + JSON.stringify(data.destination.city) + ',&nbsp;' + JSON.stringify(data.destination.country_name) + '</td></tr><tr><td>GPS</td><td>' + JSON.stringify(data.destination.latitude) + ',&nbsp;' + JSON.stringify(data.destination.longitude) + '</td></tr></table></div>';
return str.replace(/"/g,""); return str.replace(/&quot;/g,"");
} }
// Missing information // Missing information
else { else {
...@@ -246,15 +423,48 @@ function Datamap() { ...@@ -246,15 +423,48 @@ function Datamap() {
} }
} }
}); });
var instance = this.instance;
// Link to a json file with information for drawing.
// NOTE: Change path if you separate backend and fronend!
d3.json("./warden-map.json", function(error, data) {
instance.arc(data);
});
};
legend_data = d3.select("#legend")
.selectAll("li")
.data(Object.keys(cat_color).sort())
.enter()
.append("li")
.append("span")
.style("color", function(datum) { return cat_color[datum]})
.text(function(datum) { return datum; })
.append("span")
.text(function(datum) { return "" + cat_desc[datum]})
.style("color", "white");
instance.addPlugin('ph_arc', handleArcs);
setInterval(function(){
d3.json("./warden-map.json", function(error, data) {
if (data) {
var cur_data = data.pop()
var cur_time = new Date().getTime();
if (cur_data != prev_data) {
prev_data = cur_data;
for (var i=0; i<data.length; i++) {
data[i].arrivalTime = cur_time;
data[i].delay = i/data.length;
}
main_data = main_data.concat(data);
}
}
var trimmed_data = [];
for (var i=0; i<main_data.length; i++) {
if (main_data[i].arrivalTime + 3500 > cur_time) {
trimmed_data.push(main_data[i]);
}
}
main_data = trimmed_data;
trimmed_data = cur_time = cur_data = error = data = null;
instance.ph_arc(main_data);
});
}, 1000);
};
Datamap.prototype._handleMapReady = function(datamap) { Datamap.prototype._handleMapReady = function(datamap) {
this.zoom = new Zoom({ this.zoom = new Zoom({
......
...@@ -20,9 +20,10 @@ ...@@ -20,9 +20,10 @@
<script src="https://d3js.org/d3.v3.min.js"></script> <script src="https://d3js.org/d3.v3.min.js"></script>
<script src="https://d3js.org/topojson.v1.min.js"></script> <script src="https://d3js.org/topojson.v1.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="./js/datamaps.world.hires.min.js"></script> <script src="./js/datamaps.world.min.js"></script>
<script src="./js/warden-map.js"></script> <script src="./js/warden-map.js"></script>
<!--
<h2>Warden Map</h2> <h2>Warden Map</h2>
<div id="tools"> <div id="tools">
<button class="zoom-button" data-zoom="reset">&#x2302</button> <button class="zoom-button" data-zoom="reset">&#x2302</button>
...@@ -30,7 +31,15 @@ ...@@ -30,7 +31,15 @@
<button class="zoom-button" data-zoom="in">+</button> <button class="zoom-button" data-zoom="in">+</button>
<div id="zoom-info"></div> <div id="zoom-info"></div>
</div> </div>
-->
<div id="container"></div> <div id="container"></div>
<div id="heading">Attacks, detected in CESNET network<br/>
SABU - Sharing and Analysis of Security Events
</div>
<div id="legend-box">
<p><b>Reported to Warden right <i>now</i>.</b></p>
<ul id="legend"></ul>
</div>
<!-- Draw datamap into id="container" --> <!-- Draw datamap into id="container" -->
<script>new Datamap();</script> <script>new Datamap();</script>
......
...@@ -53,7 +53,7 @@ C.1. Event description format ...@@ -53,7 +53,7 @@ C.1. Event description format
IDEA - Intrusion Detection Extensible Alert, flexible extensible format IDEA - Intrusion Detection Extensible Alert, flexible extensible format
for security events, see: for security events, see:
https://csirt.cesnet.cz/IDEA https://idea.cesnet.cz/
C.2. Event serial ID C.2. Event serial ID
......
...@@ -470,6 +470,18 @@ def get_configs(): ...@@ -470,6 +470,18 @@ def get_configs():
def get_uid_gid(str_id, get_nam_func):
if str_id:
try:
id = int(str_id)
except ValueError:
id = get_nam_func(str_id)[2]
else:
id = None
return id
if __name__ == "__main__": if __name__ == "__main__":
args = get_args() args = get_args()
...@@ -482,12 +494,17 @@ if __name__ == "__main__": ...@@ -482,12 +494,17 @@ if __name__ == "__main__":
try: try:
if args.daemon: if args.daemon:
from pwd import getpwnam
from grp import getgrnam
uid = get_uid_gid(fconfig.get("uid"), getpwnam)
gid = get_uid_gid(fconfig.get("gid"), getgrnam)
daemonize( daemonize(
work_dir = fconfig.get("work_dir", "."), work_dir = fconfig.get("work_dir", "."),
chroot_dir = fconfig.get("chroot_dir"), chroot_dir = fconfig.get("chroot_dir"),
umask = fconfig.get("umask"), umask = fconfig.get("umask"),
uid = fconfig.get("uid"), uid = uid,
gid = fconfig.get("gid"), gid = gid,
pidfile = args.pid_file, pidfile = args.pid_file,
files_preserve = get_logger_files(wclient.logger), files_preserve = get_logger_files(wclient.logger),
signals = { signals = {
......
...@@ -23,9 +23,6 @@ import subprocess ...@@ -23,9 +23,6 @@ import subprocess
import shlex import shlex
import tempfile import tempfile
import M2Crypto import M2Crypto
# *ph* server vulnerable to logjam, local openssl too new, use hammer to disable Diffie-Helmann
import ssl
ssl._DEFAULT_CIPHERS += ":!DH"
import ejbcaws import ejbcaws
...@@ -253,7 +250,13 @@ class EjbcaRegistry(OpenSSLRegistry): ...@@ -253,7 +250,13 @@ class EjbcaRegistry(OpenSSLRegistry):
subjectDN = self.subject_dn_template % client.name subjectDN = self.subject_dn_template % client.name
) )
edata["subjectAltName"] = ",".join(("RFC822NAME=%s" % a for a in client.admins)) edata["subjectAltName"] = ",".join(("RFC822NAME=%s" % a for a in client.admins))
edata["status"] = self.status_str_to_ejbca.get(client.status, edata["status"]) try:
edata["status"] = self.status_str_to_ejbca.get(client.status)
except KeyError:
# Unknown status - either came from EJBCA and translated to
# "Other", or something wrong came in later. Let's just
# keep original EJBCA status unchanged.
pass
if client.pwd: if client.pwd:
edata["password"] = client.pwd edata["password"] = client.pwd
edata["clearPwd"] = True edata["clearPwd"] = True
......
...@@ -8,11 +8,15 @@ import sys ...@@ -8,11 +8,15 @@ import sys
import warnings import warnings
from os import path from os import path
from copy import deepcopy from copy import deepcopy
import unittest2 as unittest
import MySQLdb as my import MySQLdb as my
from warden_server import build_server from warden_server import build_server
import warden_server import warden_server
if sys.version_info >= (3, 10):
import unittest
else:
import unittest2 as unittest
if sys.version_info[0] >= 3: if sys.version_info[0] >= 3:
from io import StringIO from io import StringIO
else: else:
...@@ -408,8 +412,9 @@ def init_user(): ...@@ -408,8 +412,9 @@ def init_user():
conn = None conn = None
try: try:
conn = my.connect(user='root', passwd=getpass.getpass('Enter MySQL Root password:')) conn = my.connect(user='root', passwd=getpass.getpass('Enter MySQL Root password:'))
with conn as cur: # Not a canonical connector implementation, for sure with conn.cursor() as cur:
cur.execute("GRANT SELECT, INSERT, UPDATE, CREATE, DELETE, DROP ON *.* TO %s@'localhost' IDENTIFIED BY %s", (USER, PASSWORD)) cur.execute("CREATE USER IF NOT EXISTS %s@'localhost' IDENTIFIED BY %s", (USER, PASSWORD))
cur.execute("GRANT SELECT, INSERT, UPDATE, CREATE, DELETE, DROP ON *.* TO %s@'localhost'", (USER,))
conn.commit() conn.commit()
print("DB User set up successfuly") print("DB User set up successfuly")
except my.OperationalError as ex: except my.OperationalError as ex:
......
...@@ -493,7 +493,7 @@ class MySQL(ObjectBase): ...@@ -493,7 +493,7 @@ class MySQL(ObjectBase):
with io.open(tagmap_filename, "r", encoding="utf-8") as tagmap_fd: with io.open(tagmap_filename, "r", encoding="utf-8") as tagmap_fd:
self.tagmap = json.load(tagmap_fd) self.tagmap = json.load(tagmap_fd)
self.tagmap_other = self.catmap["Other"] # Catch error soon, avoid lookup later self.tagmap_other = self.tagmap["Other"] # Catch error soon, avoid lookup later
self.con = None self.con = None
...@@ -714,10 +714,11 @@ class MySQL(ObjectBase): ...@@ -714,10 +714,11 @@ class MySQL(ObjectBase):
if group or nogroup: if group or nogroup:
subquery = [] subquery = []
for name in (group or nogroup): for name in (group or nogroup):
subquery.append("c.name = %s") # exact client escaped_name = name.replace('&', '&&').replace("_", "&_").replace("%", "&%") # escape for LIKE
subquery.append("c.name = %s") # exact client
params.append(name) params.append(name)
subquery.append("c.name LIKE %s") # whole subtree subquery.append("c.name LIKE CONCAT(%s, '.%%') ESCAPE '&'") # whole subtree
params.append(name + ".%") params.append(escaped_name)
query.append(" AND %s (%s)" % (self._get_not(group), " OR ".join(subquery))) query.append(" AND %s (%s)" % (self._get_not(group), " OR ".join(subquery)))
...@@ -1095,6 +1096,7 @@ class WardenHandler(ObjectBase): ...@@ -1095,6 +1096,7 @@ class WardenHandler(ObjectBase):
if self.get_events_limit: if self.get_events_limit:
count = min(count, self.get_events_limit) count = min(count, self.get_events_limit)
count = max(0, count)
res = self.db.fetch_events(self.req.client, id, count, cat, nocat, tag, notag, group, nogroup) res = self.db.fetch_events(self.req.client, id, count, cat, nocat, tag, notag, group, nogroup)
......