mirror of
https://github.com/telekom-security/tpotce.git
synced 2025-07-03 21:42:13 +00:00
1057 lines
30 KiB
Python
1057 lines
30 KiB
Python
![]() |
import json
|
||
|
|
||
|
import numpy as np
|
||
|
from django.contrib.auth.decorators import permission_required
|
||
|
from django.shortcuts import render, redirect
|
||
|
from django.conf import settings
|
||
|
from django.http import JsonResponse, HttpResponse, HttpResponseRedirect
|
||
|
|
||
|
from django.db import connection
|
||
|
|
||
|
import CollectorAPI.models
|
||
|
import CollectorAPI.views as api_views
|
||
|
import CollectorAPI.reports
|
||
|
|
||
|
from .forms import GenerateAdvReport
|
||
|
|
||
|
|
||
|
import csv
|
||
|
|
||
|
from ipwhois import IPWhois
|
||
|
import datetime
|
||
|
UNKNOWN_color = '#aaaaaa'
|
||
|
OTHER_color = '#6272fc'
|
||
|
BG_color = '#fc6265'
|
||
|
TARGET_color = '#fcbc62'
|
||
|
|
||
|
CITY_colors = [
|
||
|
"#ffa6a6",
|
||
|
"#e605ff",
|
||
|
"#ffdda6",
|
||
|
"#05f7ff",
|
||
|
"#f9ffa6",
|
||
|
"#ffa305",
|
||
|
"#acffa6",
|
||
|
"#ffa6f3",
|
||
|
"#a6f9ff",
|
||
|
"#dea6ff",
|
||
|
"#a6beff",
|
||
|
"#ffa6b6",
|
||
|
"#8aff05",
|
||
|
"#1e05ff",
|
||
|
"#ff051e"
|
||
|
]
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
class Echo:
|
||
|
"""An object that implements just the write method of the file-like
|
||
|
interface.
|
||
|
"""
|
||
|
def write(self, value):
|
||
|
"""Write the value by returning it, instead of storing in a buffer."""
|
||
|
return value
|
||
|
|
||
|
# Create your views here.
|
||
|
|
||
|
|
||
|
def convert_date(date_str):
|
||
|
if len(date_str) == 0 or date_str == "none":
|
||
|
return "none"
|
||
|
|
||
|
day, month, year = date_str.split('.')
|
||
|
if len(day) > 2:
|
||
|
raise Exception('Invalid date')
|
||
|
if len(month) > 2:
|
||
|
raise Exception('Invalid date')
|
||
|
if (len(year)) > 4:
|
||
|
raise Exception('Invalid date')
|
||
|
|
||
|
a = f'{year}-{month}-{day}'
|
||
|
return a
|
||
|
|
||
|
|
||
|
def index(request):
|
||
|
"""
|
||
|
View for /
|
||
|
:param request:
|
||
|
:return:
|
||
|
"""
|
||
|
|
||
|
if not request.user.is_authenticated:
|
||
|
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
|
||
|
query_servers = 'SELECT * FROM \"CollectorAPI_honeypotserver\" ORDER BY last_input DESC;'
|
||
|
|
||
|
with connection.cursor() as cursor:
|
||
|
|
||
|
cursor.execute(query_servers)
|
||
|
servers = cursor.fetchall()
|
||
|
|
||
|
context = {
|
||
|
'servers': servers,
|
||
|
}
|
||
|
|
||
|
return render(request, 'home.html', context)
|
||
|
|
||
|
|
||
|
def reports(request):
|
||
|
if not request.user.is_authenticated:
|
||
|
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
|
||
|
|
||
|
context = {}
|
||
|
return render(request, 'report.html', context)
|
||
|
|
||
|
|
||
|
@permission_required('CollectorAPI.adv_reports')
|
||
|
def reports_adv(request):
|
||
|
if not request.user.is_authenticated:
|
||
|
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
|
||
|
if request.method == 'POST':
|
||
|
# create a form instance and populate it with data from the request:
|
||
|
form = GenerateAdvReport(request.POST)
|
||
|
if form.is_valid():
|
||
|
from_date = form.cleaned_data['from_date']
|
||
|
to_date = form.cleaned_data['to_date']
|
||
|
affected_honeys = form.cleaned_data['affected_honeys']
|
||
|
attacker_countries = form.cleaned_data['attacker_countries']
|
||
|
output = CollectorAPI.reports.gen_report(from_date, to_date, affected_honeys, attacker_countries)
|
||
|
output = json.loads(output)
|
||
|
print(output)
|
||
|
filename = 'report'
|
||
|
response = HttpResponse(
|
||
|
content_type='text/csv',
|
||
|
headers={'Content-Disposition': 'attachment; filename="' + filename + '.csv"'},
|
||
|
)
|
||
|
|
||
|
writer = csv.writer(response)
|
||
|
for ip in output:
|
||
|
ip = [ip]
|
||
|
writer.writerow(ip)
|
||
|
return response
|
||
|
|
||
|
else:
|
||
|
form = GenerateAdvReport()
|
||
|
|
||
|
if 'r' in request.GET:
|
||
|
r = int(request.GET['r'])
|
||
|
|
||
|
try:
|
||
|
obj = CollectorAPI.models.HoneypotReportsStorage.objects.get(id=r)
|
||
|
except CollectorAPI.models.HoneypotReportsStorage.DoesNotExist:
|
||
|
return JsonResponse({'error': f'No such report'})
|
||
|
output = json.loads(obj.data)
|
||
|
filename = 'report'
|
||
|
response = HttpResponse(
|
||
|
content_type='text/csv',
|
||
|
headers={'Content-Disposition': 'attachment; filename="' + filename + '.csv"'},
|
||
|
)
|
||
|
|
||
|
writer = csv.writer(response)
|
||
|
for ip in output:
|
||
|
ip = [ip]
|
||
|
writer.writerow(ip)
|
||
|
return response
|
||
|
|
||
|
|
||
|
honeys = CollectorAPI.models.HoneyPotServer.objects.all()
|
||
|
honeys_clean = {}
|
||
|
for honey in honeys:
|
||
|
honeys_clean[honey.id] = honey.name
|
||
|
|
||
|
reports = CollectorAPI.models.HoneypotReportsStorage.objects.all().order_by('from_date')
|
||
|
clean_reports = []
|
||
|
for report in reports:
|
||
|
honey_to_servers = []
|
||
|
afected_shit = json.loads(report.affected_honeys)
|
||
|
for afected_shit_sub in afected_shit:
|
||
|
honey_to_servers.append(honeys_clean[int(afected_shit_sub)])
|
||
|
clean_reports.append({
|
||
|
'id': report.id,
|
||
|
'from_date': report.from_date,
|
||
|
'to_date': report.to_date,
|
||
|
'affected_honeys': honey_to_servers,
|
||
|
'countries': json.loads(report.countries)
|
||
|
})
|
||
|
|
||
|
return render(request, 'report_adv.html', {'form': form, 'reports': clean_reports, 'servers': honeys_clean})
|
||
|
|
||
|
|
||
|
def get_report_ips_csv(request):
|
||
|
'''
|
||
|
Function to export reports as CSV
|
||
|
:param request:
|
||
|
:return:
|
||
|
'''
|
||
|
|
||
|
if not request.user.is_authenticated:
|
||
|
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
|
||
|
|
||
|
days = 0
|
||
|
limit = 0
|
||
|
ISO = 'any'
|
||
|
no_count = True
|
||
|
country = True
|
||
|
city = True
|
||
|
if 'no_count' in request.GET:
|
||
|
no_count = False
|
||
|
country = False
|
||
|
city = False
|
||
|
|
||
|
if 'days' in request.GET:
|
||
|
days = int(request.GET['days'])
|
||
|
|
||
|
if 'limit' in request.GET:
|
||
|
limit = int(request.GET['limit'])
|
||
|
|
||
|
if 'iso' in request.GET:
|
||
|
ISO = request.GET['iso']
|
||
|
|
||
|
ips = api_views.gen_attack_ips(days, limit, ISO, no_count, country, city)
|
||
|
|
||
|
filename = 'attackers_for_days_' + str(days) + '_from_' + ISO
|
||
|
if no_count:
|
||
|
filename = filename + '_with_stats'
|
||
|
# Create the HttpResponse object with the appropriate CSV header.
|
||
|
response = HttpResponse(
|
||
|
content_type='text/csv',
|
||
|
headers={'Content-Disposition': 'attachment; filename="' + filename + '.csv"'},
|
||
|
)
|
||
|
|
||
|
writer = csv.writer(response)
|
||
|
for ip in ips:
|
||
|
if no_count:
|
||
|
try:
|
||
|
obj = IPWhois(ip[0])
|
||
|
res = obj.lookup_whois()
|
||
|
ip_print = ip + (res["nets"][0]['name'],)
|
||
|
except Exception as e:
|
||
|
print(e)
|
||
|
ip_print = ip + (e,)
|
||
|
|
||
|
ip = ip_print
|
||
|
writer.writerow(ip)
|
||
|
|
||
|
return response
|
||
|
|
||
|
|
||
|
def get_report_ips_json(request):
|
||
|
if not request.user.is_authenticated:
|
||
|
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
|
||
|
|
||
|
days = 0
|
||
|
limit = 0
|
||
|
ISO = 'any'
|
||
|
no_count = True
|
||
|
if 'no_count' in request.GET:
|
||
|
no_count = False
|
||
|
|
||
|
if 'days' in request.GET:
|
||
|
days = int(request.GET['days'])
|
||
|
|
||
|
if 'limit' in request.GET:
|
||
|
limit = int(request.GET['limit'])
|
||
|
|
||
|
if 'iso' in request.GET:
|
||
|
ISO = request.GET['iso']
|
||
|
|
||
|
ips = api_views.gen_attack_ips(days, limit, ISO, no_count)
|
||
|
filename = 'attackers_for_days_' + str(days) + '_from_' + ISO
|
||
|
if no_count:
|
||
|
filename = filename + '_with_stats'
|
||
|
# Create the HttpResponse object with the appropriate CSV header.
|
||
|
response = HttpResponse(json.dumps(ips), content_type="application/json")
|
||
|
response['Content-Disposition'] = 'attachment; filename=' + filename + '.json'
|
||
|
|
||
|
return response
|
||
|
|
||
|
|
||
|
def get_report_agregated_per_server_csv(request):
|
||
|
|
||
|
if not request.user.is_authenticated:
|
||
|
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
|
||
|
|
||
|
filter = '24h_all'
|
||
|
if 'filter' in request.GET:
|
||
|
filter = request.GET['filter']
|
||
|
|
||
|
target_targets = ['24h_all', '7d_all', '30d_all', '24h_bg', '7d_bg', '30d_bg']
|
||
|
|
||
|
if filter not in target_targets:
|
||
|
return JsonResponse({'error': f'I see you try to be a hacker!!!'})
|
||
|
|
||
|
data = CollectorAPI.models.HoneypotAgregatePerServer.objects.get(data_id=filter)
|
||
|
servers = CollectorAPI.models.HoneyPotServer.objects.all()
|
||
|
|
||
|
servers_output = []
|
||
|
json_data = json.dumps(data.data)
|
||
|
data_array = json.loads(json_data)
|
||
|
build_top = 0
|
||
|
print(data_array)
|
||
|
for server in servers:
|
||
|
if str(server.id) not in data_array:
|
||
|
continue
|
||
|
# check if we have top row with info
|
||
|
if build_top < 1:
|
||
|
json_int = json.dumps(data_array[str(server.id)]['data'])
|
||
|
data_int = json.loads(json_int)
|
||
|
top_row = ['name', 'ip']
|
||
|
for id, count in data_int.items():
|
||
|
if id == '01_comult':
|
||
|
top_row.append('Total')
|
||
|
else:
|
||
|
top_row.append(id)
|
||
|
build_top = 1
|
||
|
servers_output.append(top_row)
|
||
|
|
||
|
row = [server.name, server.ip]
|
||
|
json_int = json.dumps(data_array[str(server.id)]['data'])
|
||
|
data_int = json.loads(json_int)
|
||
|
for id, count in data_int.items():
|
||
|
row.append(count)
|
||
|
servers_output.append(row)
|
||
|
|
||
|
filename = 'per_server_' + str(filter)
|
||
|
response = HttpResponse(
|
||
|
content_type='text/csv',
|
||
|
headers={'Content-Disposition': 'attachment; filename="' + filename + '.csv"'},
|
||
|
)
|
||
|
writer = csv.writer(response)
|
||
|
for server in servers_output:
|
||
|
writer.writerow(server)
|
||
|
return response
|
||
|
|
||
|
|
||
|
@permission_required('CollectorAPI.graphs')
|
||
|
def graphs(request):
|
||
|
|
||
|
if not request.user.is_authenticated:
|
||
|
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
|
||
|
|
||
|
return render(request, 'graphs.html')
|
||
|
|
||
|
|
||
|
@permission_required('CollectorAPI.graphs')
|
||
|
def attack_graph(request, start_date="none", end_date="none", min_attacks=0, global_ip="none", bg_only=0):
|
||
|
|
||
|
if not request.user.is_authenticated:
|
||
|
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
|
||
|
|
||
|
bg_only = not not bg_only
|
||
|
|
||
|
try:
|
||
|
start_date = convert_date(start_date)
|
||
|
except Exception as e:
|
||
|
return JsonResponse({'error': f'Issue with start_date {e}'})
|
||
|
try:
|
||
|
end_date = convert_date(end_date)
|
||
|
except Exception as e:
|
||
|
return JsonResponse({'error': f'Issue with end_date {e}'})
|
||
|
|
||
|
query = None
|
||
|
if bg_only:
|
||
|
query = """
|
||
|
select
|
||
|
src_ip,
|
||
|
servers.name,
|
||
|
count(*) "value",
|
||
|
city_name
|
||
|
from "CollectorAPI_honeypotinfo" as info
|
||
|
"""
|
||
|
else:
|
||
|
query = """
|
||
|
select
|
||
|
src_ip,
|
||
|
servers.name,
|
||
|
count(*) "value",
|
||
|
"countryISO" = 'BG'
|
||
|
from "CollectorAPI_honeypotinfo" as info"""
|
||
|
|
||
|
query += """
|
||
|
inner join "CollectorAPI_honeypotserver" as servers on info.server_id_id = servers.id
|
||
|
"""
|
||
|
|
||
|
conditions = []
|
||
|
arguments = []
|
||
|
if global_ip != "none":
|
||
|
conditions.append("src_ip = %s")
|
||
|
arguments.append(global_ip)
|
||
|
|
||
|
if start_date != "none":
|
||
|
conditions.append("event_timestamp >= %s")
|
||
|
arguments.append(start_date)
|
||
|
|
||
|
if end_date != "none":
|
||
|
conditions.append("event_timestamp <= %s")
|
||
|
arguments.append(end_date)
|
||
|
|
||
|
if bg_only:
|
||
|
conditions.append('"countryISO" = %s')
|
||
|
arguments.append("BG")
|
||
|
|
||
|
if len(conditions) != 0:
|
||
|
query += """
|
||
|
where
|
||
|
""" + " and ".join(conditions)
|
||
|
|
||
|
if bg_only:
|
||
|
query += """
|
||
|
group by
|
||
|
src_ip,
|
||
|
servers.name,
|
||
|
city_name
|
||
|
"""
|
||
|
else:
|
||
|
query += """
|
||
|
group by
|
||
|
src_ip,
|
||
|
servers.name,
|
||
|
"countryISO" = 'BG'
|
||
|
"""
|
||
|
|
||
|
if min_attacks != 0:
|
||
|
query += " having count('*') > %s"
|
||
|
arguments.append(min_attacks)
|
||
|
|
||
|
query += """
|
||
|
order by value desc
|
||
|
"""
|
||
|
print(query)
|
||
|
with connection.cursor() as cursor:
|
||
|
cursor.execute(query, arguments)
|
||
|
rows = cursor.fetchall()
|
||
|
|
||
|
def loc_name(loc):
|
||
|
if loc is None:
|
||
|
return 'Unknown'
|
||
|
|
||
|
if type(loc) is bool:
|
||
|
if loc:
|
||
|
return "Bulgaria"
|
||
|
else:
|
||
|
return "Foreign"
|
||
|
return loc
|
||
|
|
||
|
links = []
|
||
|
rows = [[r[0] + f' ({loc_name(r[3])})', r[1], r[2], r[3]]
|
||
|
for r in rows]
|
||
|
for r in rows:
|
||
|
links.append({'source': r[0], 'target': r[1], 'value': r[2]})
|
||
|
ips = set()
|
||
|
ip2color = {}
|
||
|
|
||
|
if bg_only:
|
||
|
city2color = {}
|
||
|
available_colors = CITY_colors.copy()
|
||
|
|
||
|
for r in rows:
|
||
|
city = r[3] if r[3] is not None else "Unknown"
|
||
|
source = r[0]
|
||
|
target = r[1]
|
||
|
|
||
|
ips.add(source)
|
||
|
ips.add(target)
|
||
|
|
||
|
if target not in ip2color:
|
||
|
ip2color[target] = {
|
||
|
'color': TARGET_color
|
||
|
}
|
||
|
if source not in ip2color:
|
||
|
if city not in city2color:
|
||
|
if city == "Unknown":
|
||
|
city2color[city] = UNKNOWN_color
|
||
|
if len(available_colors) > 0:
|
||
|
city2color[city] = available_colors.pop()
|
||
|
else:
|
||
|
city2color[city] = BG_color
|
||
|
ip2color[source] = {
|
||
|
'color': city2color[city]
|
||
|
}
|
||
|
location2color = city2color
|
||
|
else:
|
||
|
for r in rows:
|
||
|
loc = r[3] if r[3] is not None else "Unknown"
|
||
|
|
||
|
ips.add(r[1])
|
||
|
ips.add(r[0])
|
||
|
|
||
|
if r[1] not in ip2color:
|
||
|
ip2color[r[1]] = {
|
||
|
'color': TARGET_color
|
||
|
}
|
||
|
if r[0] not in ip2color:
|
||
|
if loc == "Unknown":
|
||
|
ip2color[r[0]] = {
|
||
|
'color': UNKNOWN_color
|
||
|
}
|
||
|
elif r[3]:
|
||
|
ip2color[r[0]] = {
|
||
|
'color': BG_color
|
||
|
}
|
||
|
else:
|
||
|
ip2color[r[0]] = {
|
||
|
'color': OTHER_color
|
||
|
}
|
||
|
|
||
|
location2color = {
|
||
|
'Bulgaria': BG_color,
|
||
|
'Other': OTHER_color
|
||
|
}
|
||
|
vertices = [{'name': v, 'itemStyle': ip2color[v]} for v in ips]
|
||
|
print(ip2color)
|
||
|
return JsonResponse({'vertices': vertices,
|
||
|
'links': links,
|
||
|
'location2color': location2color})
|
||
|
|
||
|
|
||
|
@permission_required('CollectorAPI.graphs')
|
||
|
def attack_trend(request, start_date="none", end_date="none", resolution='day', global_ip="none", bg_only=0):
|
||
|
if not request.user.is_authenticated:
|
||
|
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
|
||
|
|
||
|
try:
|
||
|
start_date = convert_date(start_date)
|
||
|
except Exception as e:
|
||
|
return JsonResponse({'error': f'Issue with start_date {e}'})
|
||
|
try:
|
||
|
end_date = convert_date(end_date)
|
||
|
except Exception as e:
|
||
|
return JsonResponse({'error': f'Issue with end_date {e}'})
|
||
|
|
||
|
if resolution not in ['hour', 'day', 'week']:
|
||
|
return JsonResponse({'error': 'Unknown resolution ' + resolution})
|
||
|
|
||
|
if resolution == 'hour':
|
||
|
time_step = 3600.0
|
||
|
elif resolution == 'day':
|
||
|
time_step = 3600.0*24
|
||
|
elif resolution == 'week':
|
||
|
time_step = 3600.0*24*7
|
||
|
else:
|
||
|
return JsonResponse({'error': 'Unknown resolution ' + resolution})
|
||
|
|
||
|
query = "select count(*) \"value\", date_trunc(%s, event_timestamp) timepoint from \"CollectorAPI_honeypotinfo\""
|
||
|
conditions = []
|
||
|
arguments = [resolution]
|
||
|
if start_date != "none":
|
||
|
conditions.append(" event_timestamp >= %s ")
|
||
|
arguments.append(start_date)
|
||
|
if end_date != "none":
|
||
|
conditions.append(" event_timestamp <= %s ")
|
||
|
arguments.append(end_date)
|
||
|
|
||
|
if global_ip != "none":
|
||
|
conditions.append(" src_ip = %s")
|
||
|
arguments.append(global_ip)
|
||
|
|
||
|
if bg_only:
|
||
|
conditions.append(" \"countryISO\" = 'BG'")
|
||
|
|
||
|
if len(conditions) != 0:
|
||
|
query += " where " + " and ".join(conditions)
|
||
|
|
||
|
query += " group by timepoint order by timepoint asc"
|
||
|
print(query)
|
||
|
with connection.cursor() as cursor:
|
||
|
cursor.execute(query, arguments)
|
||
|
rows = cursor.fetchall()
|
||
|
|
||
|
if len(rows) < 3:
|
||
|
return JsonResponse({'error': f'Insufficient data for regression analysis for start \
|
||
|
{start_date} end {end_date} and resolution {resolution}'})
|
||
|
data = np.zeros((len(rows), 2))
|
||
|
|
||
|
for i, r in enumerate(rows):
|
||
|
data[i, :] = [(r[1] - rows[0][1]).total_seconds()/time_step, r[0]]
|
||
|
|
||
|
n = data.shape[0]
|
||
|
# The growth model is y = a*x + b
|
||
|
# From this the formula for a will be a = \frac{\sum_i (x_i - \mu_x)(y_i - \mu_i)}{\sum_i (x - \mu_x)^2}
|
||
|
# Having a calculated, b = \mu_y - a \mu_x
|
||
|
a = np.sum(np.prod(data - np.mean(data, axis=0)[None], axis=1))/np.sum((data[:, 0] - np.mean(data[:, 0]))**2)
|
||
|
b = np.mean(data[:, 1]) - a*np.mean(data[:, 0])
|
||
|
|
||
|
# Since the parameters are calculated, the confidence interval of the slope should be calculated
|
||
|
# according to \sigma_a = \sqrt{\frac{\sum_i (y_i - a x_i - b)^2}{(n-2)\sum_i (x_i - \mu_x)^2}}
|
||
|
sigma_a = np.sqrt(np.sum((data[:, 1] - (a * data[:, 0] + b))**2) /
|
||
|
((n - 2) * np.sum((data[:, 0] - np.mean(data[:, 0]))**2))
|
||
|
)
|
||
|
|
||
|
return JsonResponse({'a': a, 'b': b,
|
||
|
'data': data.tolist(),
|
||
|
'max_x': np.max(data[:, 0]),
|
||
|
'first_attack': rows[0][1].strftime("%d %b %Y %H:%m:%S %Z"),
|
||
|
'sigma_a': sigma_a})
|
||
|
|
||
|
|
||
|
@permission_required('CollectorAPI.graphs')
|
||
|
def multi_target(request, ip):
|
||
|
|
||
|
if not request.user.is_authenticated:
|
||
|
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
|
||
|
|
||
|
if len(ip) == 0:
|
||
|
return JsonResponse({'error': 'Invalid IP'})
|
||
|
|
||
|
query = """select
|
||
|
min(info.event_timestamp) + (max(info.event_timestamp) - min(info.event_timestamp)) / 2 "x",
|
||
|
count(*) "y",
|
||
|
info.type,
|
||
|
server.name
|
||
|
from
|
||
|
"CollectorAPI_honeypotinfo" as info
|
||
|
inner join "CollectorAPI_honeypotserver" as server
|
||
|
on info.server_id_id = server.id
|
||
|
where
|
||
|
info.src_ip = %s
|
||
|
group by
|
||
|
info.type, server.name, date_trunc('hour', info.event_timestamp)
|
||
|
order by
|
||
|
server.name, info.type, "x" """
|
||
|
|
||
|
with connection.cursor() as cursor:
|
||
|
cursor.execute(query, [ip])
|
||
|
rows = cursor.fetchall()
|
||
|
|
||
|
result = {}
|
||
|
attack_start = None
|
||
|
attack_end = None
|
||
|
|
||
|
max_attacks = None
|
||
|
|
||
|
for row in rows:
|
||
|
if attack_start is None:
|
||
|
attack_start = row[0]
|
||
|
else:
|
||
|
attack_start = min(row[0], attack_start)
|
||
|
|
||
|
if attack_end is None:
|
||
|
attack_end = row[0]
|
||
|
else:
|
||
|
attack_end = max(row[0], attack_end)
|
||
|
|
||
|
if max_attacks is None:
|
||
|
max_attacks = row[1]
|
||
|
else:
|
||
|
max_attacks = max(max_attacks, row[1])
|
||
|
|
||
|
if row[3] not in result:
|
||
|
result[row[3]] = {}
|
||
|
if row[2] not in result[row[3]]:
|
||
|
result[row[3]][row[2]] = []
|
||
|
result[row[3]][row[2]].append([row[0].strftime("%d %b %Y %H:%m:%S %Z"), row[1]])
|
||
|
|
||
|
return JsonResponse({'data': result,
|
||
|
'attack_start': attack_start.strftime("%d %b %Y %H:%m:%S %Z"),
|
||
|
'attack_end': attack_end.strftime("%d %b %Y %H:%m:%S %Z"),
|
||
|
'max_attacks': max_attacks})
|
||
|
|
||
|
|
||
|
@permission_required('CollectorAPI.graphs')
|
||
|
def multi_target_summary(request, ip):
|
||
|
|
||
|
if not request.user.is_authenticated:
|
||
|
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
|
||
|
|
||
|
if len(ip) == 0:
|
||
|
return JsonResponse({'error': 'Invalid IP'})
|
||
|
|
||
|
query = """
|
||
|
select
|
||
|
date_trunc('day', event_timestamp) "day",
|
||
|
server.name "name",
|
||
|
count(*) "value",
|
||
|
info.type
|
||
|
from "CollectorAPI_honeypotinfo" as info
|
||
|
inner join "CollectorAPI_honeypotserver" as server
|
||
|
on info.server_id_id = server.id
|
||
|
where src_ip = %s
|
||
|
group by server.name, day, info.type;
|
||
|
"""
|
||
|
with connection.cursor() as cursor:
|
||
|
cursor.execute(query, [ip])
|
||
|
rows = cursor.fetchall()
|
||
|
|
||
|
max_attacks = None
|
||
|
data = {}
|
||
|
for row in rows:
|
||
|
if max_attacks is None:
|
||
|
max_attacks = row[2]
|
||
|
else:
|
||
|
max_attacks = max(max_attacks, row[2])
|
||
|
|
||
|
for row in rows:
|
||
|
if row[3] not in data:
|
||
|
data[row[3]] = []
|
||
|
data[row[3]].append([row[0].strftime("%d %b %Y"), row[1], float(row[2]) * 100.0 / float(max_attacks)])
|
||
|
|
||
|
return JsonResponse({
|
||
|
'data': data
|
||
|
})
|
||
|
|
||
|
|
||
|
@permission_required('CollectorAPI.tables')
|
||
|
def tables(request):
|
||
|
if not request.user.is_authenticated:
|
||
|
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
|
||
|
|
||
|
return render(request, 'tables.html')
|
||
|
|
||
|
|
||
|
@permission_required('CollectorAPI.tables')
|
||
|
def table_daily(request, date):
|
||
|
psql_date = convert_date(date)
|
||
|
query_targets = """
|
||
|
select "name", "id" from "CollectorAPI_honeypotserver"
|
||
|
"""
|
||
|
|
||
|
query_per_ip = """
|
||
|
select count(*) "attacks", src_ip from "CollectorAPI_honeypotinfo"
|
||
|
where
|
||
|
"countryISO" = 'BG'
|
||
|
and event_timestamp >= %s
|
||
|
and event_timestamp <= (%s::date + interval '1d')
|
||
|
and server_id_id = %s
|
||
|
group by
|
||
|
src_ip
|
||
|
order by
|
||
|
attacks desc
|
||
|
"""
|
||
|
query_bg = """
|
||
|
select count(*) from "CollectorAPI_honeypotinfo"
|
||
|
where
|
||
|
"countryISO" = 'BG'
|
||
|
and event_timestamp >= %s
|
||
|
and event_timestamp <= (%s::date + interval '1d')
|
||
|
and server_id_id = %s
|
||
|
"""
|
||
|
query_all = """
|
||
|
select count(*) from "CollectorAPI_honeypotinfo"
|
||
|
where
|
||
|
event_timestamp >= %s
|
||
|
and event_timestamp <= (%s::date + interval '1d')
|
||
|
and server_id_id = %s
|
||
|
"""
|
||
|
|
||
|
with connection.cursor() as cursor:
|
||
|
cursor.execute(query_targets)
|
||
|
servers = cursor.fetchall()
|
||
|
|
||
|
table_data = {}
|
||
|
for name, s_id in servers:
|
||
|
with connection.cursor() as cursor:
|
||
|
cursor.execute(query_per_ip, [psql_date, psql_date, s_id])
|
||
|
top_ips = cursor.fetchall()
|
||
|
|
||
|
with connection.cursor() as cursor:
|
||
|
cursor.execute(query_bg, [psql_date, psql_date, s_id])
|
||
|
bg_attacks = cursor.fetchall()
|
||
|
|
||
|
with connection.cursor() as cursor:
|
||
|
cursor.execute(query_all, [psql_date, psql_date, s_id])
|
||
|
all_attacks = cursor.fetchall()
|
||
|
|
||
|
if len(top_ips) == 0:
|
||
|
continue
|
||
|
|
||
|
table_data[name] = {
|
||
|
'rest_top_ips': top_ips[1:],
|
||
|
'bg_attacks': bg_attacks[0][0],
|
||
|
'all_attacks': all_attacks[0][0],
|
||
|
'top_ip': top_ips[0][1],
|
||
|
'top_count': top_ips[0][0]
|
||
|
}
|
||
|
context = {'table_data': table_data,
|
||
|
'date': date,
|
||
|
'has_data': len(table_data) != 0}
|
||
|
return render(request, 'table_daily.html', context=context)
|
||
|
|
||
|
|
||
|
@permission_required('CollectorAPI.tables')
|
||
|
def table_simple(request, date):
|
||
|
|
||
|
if not request.user.is_authenticated:
|
||
|
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
|
||
|
|
||
|
def process_rows(rows):
|
||
|
processed = {}
|
||
|
for row in rows:
|
||
|
if row[1] not in processed:
|
||
|
processed[row[1]] = {
|
||
|
'domestic': 0,
|
||
|
'total': 0
|
||
|
}
|
||
|
if row[2]:
|
||
|
processed[row[1]]['domestic'] = row[0]
|
||
|
processed[row[1]]['total'] += row[0]
|
||
|
return processed
|
||
|
|
||
|
psql_date = convert_date(date)
|
||
|
|
||
|
query24h = """
|
||
|
select count(*) "attacks", server.name, info."countryISO" = 'BG' as domestic from "CollectorAPI_honeypotinfo" as info
|
||
|
inner join "CollectorAPI_honeypotserver" as server
|
||
|
on info.server_id_id = server.id
|
||
|
where
|
||
|
event_timestamp <= (%s::date + interval '1d')
|
||
|
and event_timestamp >= %s::date
|
||
|
group by
|
||
|
server.name,
|
||
|
domestic
|
||
|
order by
|
||
|
server.name,
|
||
|
domestic,
|
||
|
attacks desc
|
||
|
"""
|
||
|
|
||
|
query7d = """
|
||
|
select count(*) "attacks", server.name, info."countryISO" = 'BG' as domestic from "CollectorAPI_honeypotinfo" as info
|
||
|
inner join "CollectorAPI_honeypotserver" as server
|
||
|
on info.server_id_id = server.id
|
||
|
where
|
||
|
event_timestamp <= (%s::date + interval '1d')
|
||
|
and event_timestamp >= (%s::date - interval '6d')
|
||
|
group by
|
||
|
server.name,
|
||
|
domestic
|
||
|
order by
|
||
|
server.name,
|
||
|
domestic,
|
||
|
attacks desc
|
||
|
"""
|
||
|
|
||
|
query30d = """
|
||
|
select count(*) "attacks", server.name, info."countryISO" = 'BG' as domestic from "CollectorAPI_honeypotinfo" as info
|
||
|
inner join "CollectorAPI_honeypotserver" as server
|
||
|
on info.server_id_id = server.id
|
||
|
where
|
||
|
event_timestamp <= (%s::date + interval '1d')
|
||
|
and event_timestamp >= (%s::date - interval '29d')
|
||
|
group by
|
||
|
server.name,
|
||
|
domestic
|
||
|
order by
|
||
|
server.name,
|
||
|
domestic,
|
||
|
attacks desc
|
||
|
"""
|
||
|
|
||
|
query24h_date = """
|
||
|
select %s::date, (%s::date + interval '1d');
|
||
|
"""
|
||
|
query7d_date = """
|
||
|
select (%s::date - interval '6d'), (%s::date + interval '1d');
|
||
|
"""
|
||
|
query30d_date = """
|
||
|
select (%s::date - interval '29d'), (%s::date + interval '1d');
|
||
|
"""
|
||
|
|
||
|
with connection.cursor() as cursor:
|
||
|
cursor.execute(query24h, [psql_date, psql_date])
|
||
|
summary24h = process_rows(cursor.fetchall())
|
||
|
|
||
|
with connection.cursor() as cursor:
|
||
|
cursor.execute(query7d, [psql_date, psql_date])
|
||
|
summary7d = process_rows(cursor.fetchall())
|
||
|
|
||
|
with connection.cursor() as cursor:
|
||
|
cursor.execute(query30d, [psql_date, psql_date])
|
||
|
summary30d = process_rows(cursor.fetchall())
|
||
|
|
||
|
with connection.cursor() as cursor:
|
||
|
cursor.execute(query24h_date, [psql_date, psql_date])
|
||
|
rows = cursor.fetchall()
|
||
|
date24h = {
|
||
|
'start': rows[0][0].strftime("%d %b %Y"),
|
||
|
'end': rows[0][1].strftime("%d %b %Y")
|
||
|
}
|
||
|
|
||
|
with connection.cursor() as cursor:
|
||
|
cursor.execute(query7d_date, [psql_date, psql_date])
|
||
|
rows = cursor.fetchall()
|
||
|
date7d = {
|
||
|
'start': rows[0][0].strftime("%d %b %Y"),
|
||
|
'end': rows[0][1].strftime("%d %b %Y")
|
||
|
}
|
||
|
|
||
|
with connection.cursor() as cursor:
|
||
|
cursor.execute(query30d_date, [psql_date, psql_date])
|
||
|
rows = cursor.fetchall()
|
||
|
date30d = {
|
||
|
'start': rows[0][0].strftime("%d %b %Y"),
|
||
|
'end': rows[0][1].strftime("%d %b %Y")
|
||
|
}
|
||
|
|
||
|
total = {
|
||
|
'summary24h': {
|
||
|
'domestic': 0,
|
||
|
'total': 0
|
||
|
},
|
||
|
'summary7d': {
|
||
|
'domestic': 0,
|
||
|
'total': 0
|
||
|
},
|
||
|
'summary30d': {
|
||
|
'domestic': 0,
|
||
|
'total': 0
|
||
|
}
|
||
|
}
|
||
|
all_targets = set(
|
||
|
list(summary24h.keys()) +
|
||
|
list(summary7d.keys()) +
|
||
|
list(summary30d.keys())
|
||
|
)
|
||
|
|
||
|
for k in summary24h:
|
||
|
all_targets.add(k)
|
||
|
|
||
|
for k in summary24h:
|
||
|
total['summary24h']['domestic'] += summary24h[k]['domestic']
|
||
|
total['summary24h']['total'] += summary24h[k]['total']
|
||
|
|
||
|
for k in summary7d:
|
||
|
total['summary7d']['domestic'] += summary7d[k]['domestic']
|
||
|
total['summary7d']['total'] += summary7d[k]['total']
|
||
|
|
||
|
for k in summary30d:
|
||
|
total['summary30d']['domestic'] += summary30d[k]['domestic']
|
||
|
total['summary30d']['total'] += summary30d[k]['total']
|
||
|
|
||
|
context = {'summary24h': summary24h,
|
||
|
'summary7d': summary7d,
|
||
|
'summary30d': summary30d,
|
||
|
'total': total,
|
||
|
'all_targets': list(all_targets),
|
||
|
'date24h': date24h,
|
||
|
'date7d': date7d,
|
||
|
'date30d': date30d}
|
||
|
|
||
|
return render(request, "table_simple.html", context=context)
|
||
|
|
||
|
|
||
|
@permission_required('CollectorAPI.tables')
|
||
|
def table_details(request, start, end, res):
|
||
|
|
||
|
if not request.user.is_authenticated:
|
||
|
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
|
||
|
|
||
|
psql_start = convert_date(start)
|
||
|
psql_end = convert_date(end)
|
||
|
|
||
|
query = """
|
||
|
select
|
||
|
count(*) "attacks",
|
||
|
count(distinct(info.src_ip)) "ips",
|
||
|
info."countryISO" = 'BG' "domestic",
|
||
|
server.name,
|
||
|
date_trunc(%s, info.event_timestamp) "event_date"
|
||
|
from "CollectorAPI_honeypotinfo" as info
|
||
|
inner join "CollectorAPI_honeypotserver" as server
|
||
|
on info.server_id_id = server.id
|
||
|
where
|
||
|
info.event_timestamp >= %s
|
||
|
and info.event_timestamp <= %s
|
||
|
group by
|
||
|
domestic,
|
||
|
server.name,
|
||
|
event_date
|
||
|
"""
|
||
|
with connection.cursor() as cursor:
|
||
|
cursor.execute(query, [res, psql_start, psql_end])
|
||
|
rows = cursor.fetchall()
|
||
|
|
||
|
time_points = set()
|
||
|
targets = set()
|
||
|
|
||
|
data = {}
|
||
|
total_over_time = {}
|
||
|
total_over_targets = {}
|
||
|
total = {
|
||
|
'bg': {
|
||
|
'attacks': 0,
|
||
|
'ips': 0
|
||
|
},
|
||
|
'all': {
|
||
|
'attacks': 0,
|
||
|
'ips': 0
|
||
|
}
|
||
|
}
|
||
|
for row in rows:
|
||
|
time_point = row[4].strftime("%d %b %Y")
|
||
|
server = row[3]
|
||
|
domestic = not not row[2]
|
||
|
ips = row[1]
|
||
|
attacks = row[0]
|
||
|
|
||
|
time_points.add(row[4])
|
||
|
targets.add(server)
|
||
|
|
||
|
if time_point not in data:
|
||
|
data[time_point] = {}
|
||
|
if server not in data[time_point]:
|
||
|
data[time_point][server] = {
|
||
|
'bg': {
|
||
|
'attacks': 0,
|
||
|
'ips': 0
|
||
|
},
|
||
|
'all': {
|
||
|
'attacks': 0,
|
||
|
'ips': 0
|
||
|
}
|
||
|
}
|
||
|
if domestic:
|
||
|
data[time_point][server]['bg']['attacks'] = attacks
|
||
|
data[time_point][server]['bg']['ips'] = ips
|
||
|
data[time_point][server]['all']['attacks'] += attacks
|
||
|
data[time_point][server]['all']['ips'] += ips
|
||
|
|
||
|
if time_point not in total_over_targets:
|
||
|
total_over_targets[time_point] = {
|
||
|
'bg': {
|
||
|
'attacks': 0,
|
||
|
'ips': 0
|
||
|
},
|
||
|
'all': {
|
||
|
'attacks': 0,
|
||
|
'ips': 0
|
||
|
}
|
||
|
}
|
||
|
if domestic:
|
||
|
total_over_targets[time_point]['bg']['attacks'] += attacks
|
||
|
total_over_targets[time_point]['bg']['ips'] += ips
|
||
|
total_over_targets[time_point]['all']['attacks'] += attacks
|
||
|
total_over_targets[time_point]['all']['ips'] += ips
|
||
|
|
||
|
if server not in total_over_time:
|
||
|
total_over_time[server] = {
|
||
|
'bg': {
|
||
|
'attacks': 0,
|
||
|
'ips': 0
|
||
|
},
|
||
|
'all': {
|
||
|
'attacks': 0,
|
||
|
'ips': 0
|
||
|
}
|
||
|
}
|
||
|
if domestic:
|
||
|
total_over_time[server]['bg']['attacks'] += attacks
|
||
|
total_over_time[server]['bg']['ips'] += ips
|
||
|
total_over_time[server]['all']['attacks'] += attacks
|
||
|
total_over_time[server]['all']['ips'] += ips
|
||
|
if domestic:
|
||
|
total['bg']['attacks'] += attacks
|
||
|
total['bg']['ips'] += ips
|
||
|
total['all']['attacks'] += attacks
|
||
|
total['all']['ips'] += ips
|
||
|
|
||
|
context = {
|
||
|
'time_points': [d.strftime("%d %b %Y") for d in sorted(list(time_points))],
|
||
|
'targets': sorted(list(targets)),
|
||
|
'data': data,
|
||
|
'total_over_time': total_over_time,
|
||
|
'total_over_targets': total_over_targets,
|
||
|
'total': total
|
||
|
}
|
||
|
|
||
|
return render(request, "table_details.html", context=context)
|