dshield-parser 0.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dshield_parser-0.0.0/PKG-INFO +3 -0
- dshield_parser-0.0.0/README.md +14 -0
- dshield_parser-0.0.0/dshield_parser/__init__.py +1 -0
- dshield_parser-0.0.0/dshield_parser/__main__.py +20 -0
- dshield_parser-0.0.0/dshield_parser/cowrie_processor/__init__.py +1 -0
- dshield_parser-0.0.0/dshield_parser/cowrie_processor/__main__.py +0 -0
- dshield_parser-0.0.0/dshield_parser/cowrie_processor/reports.py +79 -0
- dshield_parser-0.0.0/dshield_parser/firewall_processor/__init__.py +1 -0
- dshield_parser-0.0.0/dshield_parser/firewall_processor/__main__.py +0 -0
- dshield_parser-0.0.0/dshield_parser/firewall_processor/reports.py +79 -0
- dshield_parser-0.0.0/dshield_parser/test/__init__.py +0 -0
- dshield_parser-0.0.0/dshield_parser/test/test_json.py +356 -0
- dshield_parser-0.0.0/dshield_parser/utils/__init__.py +1 -0
- dshield_parser-0.0.0/dshield_parser/utils/__main__.py +0 -0
- dshield_parser-0.0.0/dshield_parser/utils/enrichment.py +458 -0
- dshield_parser-0.0.0/dshield_parser/utils/file_io.py +108 -0
- dshield_parser-0.0.0/dshield_parser/utils/graphs.py +121 -0
- dshield_parser-0.0.0/dshield_parser/utils/json.py +508 -0
- dshield_parser-0.0.0/dshield_parser/utils/ml.py +69 -0
- dshield_parser-0.0.0/dshield_parser/utils/sql.py +204 -0
- dshield_parser-0.0.0/dshield_parser/utils/ssh.py +0 -0
- dshield_parser-0.0.0/dshield_parser/web_processor/__init__.py +1 -0
- dshield_parser-0.0.0/dshield_parser/web_processor/__main__.py +0 -0
- dshield_parser-0.0.0/dshield_parser/web_processor/reports.py +76 -0
- dshield_parser-0.0.0/dshield_parser.egg-info/PKG-INFO +3 -0
- dshield_parser-0.0.0/dshield_parser.egg-info/SOURCES.txt +28 -0
- dshield_parser-0.0.0/dshield_parser.egg-info/dependency_links.txt +1 -0
- dshield_parser-0.0.0/dshield_parser.egg-info/top_level.txt +1 -0
- dshield_parser-0.0.0/pyproject.toml +3 -0
- dshield_parser-0.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# dshield-parser
|
|
2
|
+
Python scripts to parse DShield honeypot (cowrie, web honeypot, iptables firewall) logs
|
|
3
|
+
|
|
4
|
+
# Installing
|
|
5
|
+
The easiest way to install is using pip.
|
|
6
|
+
```
|
|
7
|
+
# it is recommended to use a virtual environment
|
|
8
|
+
# python -m venv /path/to/new/venv
|
|
9
|
+
# /path/to/new/venv/scripts/activate
|
|
10
|
+
|
|
11
|
+
# depending on your system, you may need to replace "pip" with "pip3"
|
|
12
|
+
pip install dshield-parser
|
|
13
|
+
pip install -r https://raw.githubusercontent.com/jslagrew/dshield-parser/main/requirements.txt
|
|
14
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import dshield_parser
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import utils
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
import utils.file_io
|
|
6
|
+
|
|
7
|
+
if __name__ == "__main__":
|
|
8
|
+
if os.path.isfile(sys.argv[0]):
|
|
9
|
+
filesize = os.stat(sys.argv[0])
|
|
10
|
+
filesize_gb = filesize.st_size / (1024 * 1024)
|
|
11
|
+
|
|
12
|
+
#Check if file is greater than 1 GB in size
|
|
13
|
+
if filesize_gb > 1:
|
|
14
|
+
print(f"File is greater than 1 GB ({round(filesize_gb, 2)} GB). Switching to stream mode")
|
|
15
|
+
else:
|
|
16
|
+
"ERROR: filename was expected as an argument."
|
|
17
|
+
|
|
18
|
+
json_data = utils.file_io.read_file_json_stream("cowrie.json.2024-02-14")
|
|
19
|
+
#utils.json.print_json_pretty_stream(json_data)
|
|
20
|
+
utils.json.print_json_keys_stream(json_data)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from dshield_parser.cowrie_processor import *
|
|
File without changes
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import re
|
|
3
|
+
from dshield_parser.utils import json as dshield_json
|
|
4
|
+
|
|
5
|
+
default_datespan = {'start_date': '1970-01-01', 'end_date': '3000-01-01'}
|
|
6
|
+
|
|
7
|
+
def get_top_10_usernames(json_data, datespan=default_datespan):
|
|
8
|
+
return dshield_json.get_top_10("username", json_data, datespan)
|
|
9
|
+
|
|
10
|
+
def get_summary_usernames(json_data, datespan=default_datespan, exclusions=None):
|
|
11
|
+
return dshield_json.get_summary_values("username", json_data, datespan, exclusions)
|
|
12
|
+
|
|
13
|
+
def get_top_10_passwords(json_data, datespan=default_datespan):
|
|
14
|
+
return dshield_json.get_top_10("password", json_data, datespan)
|
|
15
|
+
|
|
16
|
+
def get_summary_src_passwords(json_data, datespan=default_datespan, exclusions=None):
|
|
17
|
+
return dshield_json.get_summary_values("password", json_data, datespan, exclusions)
|
|
18
|
+
|
|
19
|
+
def get_top_10_dst_ports(json_data, datespan=default_datespan):
|
|
20
|
+
return dshield_json.get_top_10("dst_port", json_data, datespan)
|
|
21
|
+
|
|
22
|
+
def get_summary_dst_ports(json_data, datespan=default_datespan, exclusions=None):
|
|
23
|
+
return dshield_json.get_summary_values("dst_port", json_data, datespan, exclusions)
|
|
24
|
+
|
|
25
|
+
#shasum also gets tty files created, not just files uploaded or downloaded to the honeypot
|
|
26
|
+
def get_top_10_shasum(json_data, datespan=default_datespan):
|
|
27
|
+
return dshield_json.get_top_10("shasum", json_data, datespan)
|
|
28
|
+
|
|
29
|
+
#shasum also gets tty files created, not just files uploaded or downloaded to the honeypot
|
|
30
|
+
def get_summary_shasum(json_data, datespan=default_datespan, exclusions=None):
|
|
31
|
+
return dshield_json.get_summary_values("shasum", json_data, datespan, exclusions)
|
|
32
|
+
|
|
33
|
+
def get_top_10_files_created(json_data, datespan=default_datespan):
|
|
34
|
+
created_files = dshield_json.get_top_10("outfile", json_data, datespan)
|
|
35
|
+
updated_created_files = {}
|
|
36
|
+
for key, value in created_files.items():
|
|
37
|
+
hash = re.findall(r".*/(.*)", key)[0]
|
|
38
|
+
updated_created_files[hash] = value
|
|
39
|
+
return updated_created_files
|
|
40
|
+
|
|
41
|
+
def get_summary_files_created(json_data, datespan=default_datespan, exclusions=None):
|
|
42
|
+
created_files = dshield_json.get_summary_values("outfile", json_data, datespan, exclusions)
|
|
43
|
+
updated_created_files = {}
|
|
44
|
+
for key, value in created_files.items():
|
|
45
|
+
hash = re.findall(r".*/(.*)", key)[0]
|
|
46
|
+
updated_created_files[hash] = value
|
|
47
|
+
return updated_created_files
|
|
48
|
+
|
|
49
|
+
def get_all_input(json_data, datespan=default_datespan, exclusions=None):
|
|
50
|
+
return dshield_json.get_json_values("input", json_data, datespan, exclusions)
|
|
51
|
+
|
|
52
|
+
def get_top_10_input(json_data, datespan=default_datespan):
|
|
53
|
+
return dshield_json.get_top_10("input", json_data, datespan)
|
|
54
|
+
|
|
55
|
+
def get_summary_input(json_data, datespan=default_datespan, exclusions=None):
|
|
56
|
+
return dshield_json.get_summary_values("input", json_data, datespan, exclusions)
|
|
57
|
+
|
|
58
|
+
def get_top_10_src_ip(json_data, datespan=default_datespan):
|
|
59
|
+
return dshield_json.get_top_10("src_ip", json_data, datespan)
|
|
60
|
+
|
|
61
|
+
def get_summary_src_ip(json_data, datespan=default_datespan, exclusions=None):
|
|
62
|
+
return dshield_json.get_summary_values("src_ip", json_data, datespan, exclusions)
|
|
63
|
+
|
|
64
|
+
def get_top_10_multiple(fields, json_data, datespan=default_datespan):
|
|
65
|
+
return dshield_json.get_top_10(fields, json_data, datespan)
|
|
66
|
+
|
|
67
|
+
def get_summary_multiple(fields, json_data, datespan=default_datespan, exclusions=None):
|
|
68
|
+
return dshield_json.get_summary_values(fields, json_data, datespan, exclusions)
|
|
69
|
+
|
|
70
|
+
def get_summary_all(json_data, datespan=default_datespan, exclusions=None):
|
|
71
|
+
logging.info("Gathering JSON Keys")
|
|
72
|
+
keys = dshield_json.get_json_keys(json_data)
|
|
73
|
+
logging.info("Completed gathering JSON Keys")
|
|
74
|
+
return keys, dshield_json.get_summary_values(keys, json_data, datespan, exclusions)
|
|
75
|
+
|
|
76
|
+
def get_volume_over_time(json_data, datespan=None):
|
|
77
|
+
if datespan is None:
|
|
78
|
+
datespan = default_datespan
|
|
79
|
+
return dshield_json.get_summary_values("timestamp", json_data, datespan)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from dshield_parser.firewall_processor import *
|
|
File without changes
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from dshield_parser.utils import json as dshield_json
|
|
4
|
+
|
|
5
|
+
default_timespan={"start_time": 0, "end_time": 32516881838}
|
|
6
|
+
|
|
7
|
+
def get_top_10_flags(json_data, timespan=default_timespan):
|
|
8
|
+
return dshield_json.get_top_10("flags", json_data, timespan)
|
|
9
|
+
|
|
10
|
+
def get_summary_flags(json_data, timespan=default_timespan, exclusions=None):
|
|
11
|
+
return dshield_json.get_summary_values("flags", json_data, timespan, exclusions)
|
|
12
|
+
|
|
13
|
+
def get_top_10_src_ips(json_data, timespan=default_timespan):
|
|
14
|
+
return dshield_json.get_top_10("sip", json_data, timespan)
|
|
15
|
+
|
|
16
|
+
def get_summary_src_ips(json_data, timespan=default_timespan, exclusions=None):
|
|
17
|
+
return dshield_json.get_summary_values("sip", json_data, timespan, exclusions)
|
|
18
|
+
|
|
19
|
+
def get_top_10_dst_ips(json_data, timespan=default_timespan):
|
|
20
|
+
return dshield_json.get_top_10("dip", json_data, timespan)
|
|
21
|
+
|
|
22
|
+
def get_summary_dst_ips(json_data, timespan=default_timespan, exclusions=None):
|
|
23
|
+
return dshield_json.get_summary_values("dip", json_data, timespan, exclusions)
|
|
24
|
+
|
|
25
|
+
def get_top_10_proto(json_data, timespan=default_timespan):
|
|
26
|
+
return dshield_json.get_top_10("proto", json_data, timespan)
|
|
27
|
+
|
|
28
|
+
def get_summary_proto(json_data, timespan=default_timespan, exclusions=None):
|
|
29
|
+
return dshield_json.get_summary_values("proto", json_data, timespan, exclusions)
|
|
30
|
+
|
|
31
|
+
def get_top_10_sport(json_data, timespan=default_timespan):
|
|
32
|
+
return dshield_json.get_top_10("sport", json_data, timespan)
|
|
33
|
+
|
|
34
|
+
def get_summary_sport(json_data, timespan=default_timespan, exclusions=None):
|
|
35
|
+
return dshield_json.get_summary_values("sport", json_data, timespan, exclusions)
|
|
36
|
+
|
|
37
|
+
def get_top_10_dport(json_data, timespan=default_timespan):
|
|
38
|
+
return dshield_json.get_top_10("dport", json_data, timespan)
|
|
39
|
+
|
|
40
|
+
def get_summary_dport(json_data, timespan=default_timespan, exclusions=None):
|
|
41
|
+
return dshield_json.get_summary_values("dport", json_data, timespan, exclusions)
|
|
42
|
+
|
|
43
|
+
def get_top_10_version(json_data, timespan=default_timespan):
|
|
44
|
+
return dshield_json.get_top_10("version", json_data, timespan)
|
|
45
|
+
|
|
46
|
+
def get_summary_version(json_data, timespan=default_timespan, exclusions=None):
|
|
47
|
+
return dshield_json.get_summary_values("version", json_data, timespan, exclusions)
|
|
48
|
+
|
|
49
|
+
def get_summary_times(json_data, timespan=default_timespan, exclusions=None):
|
|
50
|
+
return dshield_json.get_summary_values("time", json_data, timespan, exclusions)
|
|
51
|
+
|
|
52
|
+
def get_summary_multiple(fields, json_data, timespan=default_timespan, exclusions=None):
|
|
53
|
+
return dshield_json.get_summary_values(fields, json_data, timespan, exclusions)
|
|
54
|
+
|
|
55
|
+
def get_summary_all(json_data, timespan=default_timespan, exclusions=None):
|
|
56
|
+
keys = dshield_json.get_json_keys(json_data)
|
|
57
|
+
return keys, dshield_json.get_summary_values(keys, json_data, timespan, exclusions)
|
|
58
|
+
|
|
59
|
+
def get_timspan(json_data):
|
|
60
|
+
start_time = ""
|
|
61
|
+
end_time = ""
|
|
62
|
+
logging.info(f"Getting summary times from: '{json_data}'")
|
|
63
|
+
times = get_summary_times(Path(json_data))
|
|
64
|
+
for key, value in times['time'].items():
|
|
65
|
+
if start_time == "":
|
|
66
|
+
start_time = key
|
|
67
|
+
end_time = key
|
|
68
|
+
elif key < start_time:
|
|
69
|
+
start_time = key
|
|
70
|
+
elif key > end_time:
|
|
71
|
+
end_time = key
|
|
72
|
+
logging.info(f"Found start time of: '{start_time}'")
|
|
73
|
+
logging.info(f"Found end time of '{end_time}'")
|
|
74
|
+
return start_time, end_time
|
|
75
|
+
|
|
76
|
+
def get_volume_over_time(json_data, timespan=None):
|
|
77
|
+
if timespan is None:
|
|
78
|
+
timespan = default_timespan
|
|
79
|
+
return dshield_json.get_summary_values("time", json_data, timespan)
|
|
File without changes
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import dshield_parser.utils
|
|
3
|
+
import dshield_parser.cowrie_processor.reports
|
|
4
|
+
import dshield_parser.firewall_processor.reports
|
|
5
|
+
import dshield_parser.web_processor.reports
|
|
6
|
+
import pandas as pd
|
|
7
|
+
#import dshield_parser
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestCowrieTop10Usernames(unittest.TestCase):
|
|
11
|
+
def test_correct(self):
|
|
12
|
+
logfile = "dshield_parser/test/honeypotdata/aws/cowrie.json.2024-02-24"
|
|
13
|
+
top_10 = {'root': 9, 'admin': 4, 'Alphanetworks': 1, 'cpanel': 1, 'default': 1, 'Epuser': 1, 'ftp_nmc': 1, 'GET / HTTP/1.1': 1, 'PCUSER': 1, 'User-Agent: curl/7.64.1': 1}
|
|
14
|
+
self.assertDictEqual(dshield_parser.cowrie_processor.reports.get_top_10_usernames(logfile),
|
|
15
|
+
top_10, msg="Top 10 username value mismatch")
|
|
16
|
+
|
|
17
|
+
class TestCowrieTop10Usernames2(unittest.TestCase):
|
|
18
|
+
def test_correct(self):
|
|
19
|
+
logfile = "dshield_parser/test/honeypotdata/gcp/cowrie.json.2024-06-01"
|
|
20
|
+
top_10 = {'root': 118, 'admin': 39, 'support': 19, 'user': 17, 'telecomadmin': 17, 'ubnt': 11, 'unknown': 8, 'test': 8, 'default': 8, 'operator': 6}
|
|
21
|
+
self.assertDictEqual(dshield_parser.cowrie_processor.reports.get_top_10_usernames(logfile),
|
|
22
|
+
top_10, msg="Top 10 username value mismatch")
|
|
23
|
+
|
|
24
|
+
class TestCowrieSummaryUsernames(unittest.TestCase):
|
|
25
|
+
def test_correct(self):
|
|
26
|
+
logfile = "dshield_parser/test/honeypotdata/aws/cowrie.json.2024-02-24"
|
|
27
|
+
summary_data = {}
|
|
28
|
+
summary_data['username'] = {'root': 9, 'admin': 4, 'Alphanetworks': 1, 'cpanel': 1, 'default': 1, 'Epuser': 1, 'ftp_nmc': 1, 'GET / HTTP/1.1': 1, 'PCUSER': 1, 'User-Agent: curl/7.64.1': 1}
|
|
29
|
+
self.assertDictEqual(dshield_parser.cowrie_processor.reports.get_summary_usernames(logfile),
|
|
30
|
+
summary_data, msg="Summary username value mismatch")
|
|
31
|
+
|
|
32
|
+
class TestCowrieTop10Passwords(unittest.TestCase):
|
|
33
|
+
def test_correct(self):
|
|
34
|
+
logfile = "dshield_parser/test/honeypotdata/aws/cowrie.json.2024-02-24"
|
|
35
|
+
top_10 = {'password': 3, 'admin': 2, '123123': 2, '1111': 2, '0fc0f17d6087680e': 1, 'vizxv': 1, 'juantech': 1, 'Host: 44.204.196.240:23': 1, 'Accept: */*': 1, 'root': 1}
|
|
36
|
+
self.assertDictEqual(dshield_parser.cowrie_processor.reports.get_top_10_passwords(logfile),
|
|
37
|
+
top_10, msg="Top 10 password value mismatch")
|
|
38
|
+
|
|
39
|
+
class TestCowrieSummaryPasswords(unittest.TestCase):
|
|
40
|
+
def test_correct(self):
|
|
41
|
+
logfile = "dshield_parser/test/honeypotdata/aws/cowrie.json.2024-02-24"
|
|
42
|
+
summary_data = {}
|
|
43
|
+
summary_data['password'] = {'0fc0f17d6087680e': 1,
|
|
44
|
+
'696969': 1,
|
|
45
|
+
'Accept: */*': 1,
|
|
46
|
+
'default': 1,
|
|
47
|
+
'Host: 44.204.196.240:23': 1,
|
|
48
|
+
'juantech': 1,
|
|
49
|
+
'root': 1,
|
|
50
|
+
'SYS': 1,
|
|
51
|
+
'tuxalize': 1,
|
|
52
|
+
'userEp': 1,
|
|
53
|
+
'vizxv': 1,
|
|
54
|
+
'wrgn22_dlwbr_dir615': 1,
|
|
55
|
+
'1111': 2,
|
|
56
|
+
'123123': 2,
|
|
57
|
+
'admin': 2,
|
|
58
|
+
'password': 3}
|
|
59
|
+
self.assertDictEqual(dshield_parser.cowrie_processor.reports.get_summary_src_passwords(logfile),
|
|
60
|
+
summary_data, msg="Summary password value mismatch")
|
|
61
|
+
|
|
62
|
+
class TestCowrieTop10Ports(unittest.TestCase):
|
|
63
|
+
def test_correct(self):
|
|
64
|
+
logfile = "dshield_parser/test/honeypotdata/aws/cowrie.json.2024-02-24"
|
|
65
|
+
top_10 = {2222: 7, 2223: 128}
|
|
66
|
+
self.assertDictEqual(dshield_parser.cowrie_processor.reports.get_top_10_dst_ports(logfile),
|
|
67
|
+
top_10, msg="Top 10 ports value mismatch")
|
|
68
|
+
|
|
69
|
+
class TestCowrieSummaryDstPorts(unittest.TestCase):
|
|
70
|
+
def test_correct(self):
|
|
71
|
+
logfile = "dshield_parser/test/honeypotdata/aws/cowrie.json.2024-02-24"
|
|
72
|
+
summary_data = {}
|
|
73
|
+
summary_data['dst_port'] = {2222: 7, 2223: 128}
|
|
74
|
+
self.assertDictEqual(dshield_parser.cowrie_processor.reports.get_summary_dst_ports(logfile),
|
|
75
|
+
summary_data, msg="Summary cowrie destination port value mismatch")
|
|
76
|
+
|
|
77
|
+
class TestCowrieSummaryDstPorts2(unittest.TestCase):
|
|
78
|
+
def test_correct(self):
|
|
79
|
+
logfile = "dshield_parser/test/honeypotdata/gcp/cowrie.json.2024-06-01"
|
|
80
|
+
summary_data = {}
|
|
81
|
+
summary_data['dst_port'] = {2222: 474, 2223: 583, 443: 10, 587: 2, 80: 8}
|
|
82
|
+
self.assertDictEqual(dshield_parser.cowrie_processor.reports.get_summary_dst_ports(logfile),
|
|
83
|
+
summary_data, msg="Summary cowrie destination port value mismatch")
|
|
84
|
+
|
|
85
|
+
class TestCowrieSummaryExclusionDstPorts2(unittest.TestCase):
|
|
86
|
+
def test_correct(self):
|
|
87
|
+
logfile = "dshield_parser/test/honeypotdata/gcp/cowrie.json.2024-06-01"
|
|
88
|
+
summary_data = {}
|
|
89
|
+
summary_data['dst_port'] = {2222: 474, 2223: 583, 443: 10, 80: 8}
|
|
90
|
+
self.assertDictEqual(dshield_parser.cowrie_processor.reports.get_summary_dst_ports(logfile, exclusions={'dst_port': 587}),
|
|
91
|
+
summary_data, msg="Summary cowrie destination port value mismatch")
|
|
92
|
+
|
|
93
|
+
class TestCowrieKeyRetrieval(unittest.TestCase):
|
|
94
|
+
def test_correct(self):
|
|
95
|
+
#cat aws/cowrie.json.2024-02-24| jq keys | sort | uniq| sort -n
|
|
96
|
+
logfile = "dshield_parser/test/honeypotdata/aws/cowrie.json.2024-02-24"
|
|
97
|
+
sorted_keys = dshield_parser.utils.json.get_json_keys(logfile)
|
|
98
|
+
sorted_keys.sort()
|
|
99
|
+
self.assertEqual(sorted_keys,
|
|
100
|
+
[ "arch",
|
|
101
|
+
"compCS",
|
|
102
|
+
"dst_ip",
|
|
103
|
+
"dst_port",
|
|
104
|
+
"duplicate",
|
|
105
|
+
"duration",
|
|
106
|
+
"encCS",
|
|
107
|
+
"eventid",
|
|
108
|
+
"hassh",
|
|
109
|
+
"hasshAlgorithms",
|
|
110
|
+
"input",
|
|
111
|
+
"kexAlgs",
|
|
112
|
+
"keyAlgs",
|
|
113
|
+
"langCS",
|
|
114
|
+
"macCS",
|
|
115
|
+
"message",
|
|
116
|
+
"password",
|
|
117
|
+
"protocol",
|
|
118
|
+
"sensor",
|
|
119
|
+
"session",
|
|
120
|
+
"shasum",
|
|
121
|
+
"size",
|
|
122
|
+
"src_ip",
|
|
123
|
+
"src_port",
|
|
124
|
+
"timestamp",
|
|
125
|
+
"ttylog",
|
|
126
|
+
"username",
|
|
127
|
+
"version"], msg="JSON key value retrieval mismatch")
|
|
128
|
+
|
|
129
|
+
class TestWebhoneypotKeyRetrieval(unittest.TestCase):
|
|
130
|
+
def test_correct(self):
|
|
131
|
+
#cat aws/webhoneypot-2024-02-24.json| jq keys | sort | uniq
|
|
132
|
+
logfile = "dshield_parser/test/honeypotdata/aws/webhoneypot-2024-02-24.json"
|
|
133
|
+
sorted_keys = dshield_parser.utils.json.get_json_keys(logfile)
|
|
134
|
+
sorted_keys.sort()
|
|
135
|
+
self.assertEqual(sorted_keys,
|
|
136
|
+
["data",
|
|
137
|
+
"dip",
|
|
138
|
+
"headers",
|
|
139
|
+
"method",
|
|
140
|
+
"response_id",
|
|
141
|
+
"signature_id",
|
|
142
|
+
"sip",
|
|
143
|
+
"time",
|
|
144
|
+
"url",
|
|
145
|
+
"useragent",
|
|
146
|
+
"version"], msg="JSON key value retrieval mismatch")
|
|
147
|
+
|
|
148
|
+
class TestWebHoneypotTop10URLs(unittest.TestCase):
|
|
149
|
+
def test_correct(self):
|
|
150
|
+
#cat gcp/webhoneypot-2024-06-01.json| jq .url | sort | uniq -c| sort -n
|
|
151
|
+
logfile = "dshield_parser/test/honeypotdata/gcp/webhoneypot-2024-06-01.json"
|
|
152
|
+
top_10 = {"/.env.backup": 257,
|
|
153
|
+
"/.docker/.env": 265,
|
|
154
|
+
"/.c9/metadata/environment/.env": 269,
|
|
155
|
+
"/_static/.env": 273,
|
|
156
|
+
"/.env": 274,
|
|
157
|
+
"/.aws/credentials": 277,
|
|
158
|
+
"/.env_sample": 281,
|
|
159
|
+
"/.env_1": 285,
|
|
160
|
+
"/.env.www": 289,
|
|
161
|
+
"/": 312}
|
|
162
|
+
self.assertDictEqual(dshield_parser.web_processor.reports.get_top_10_url(logfile),
|
|
163
|
+
top_10, msg="Top 10 URLs value mismatch")
|
|
164
|
+
|
|
165
|
+
class TestWebSummaryURLs(unittest.TestCase):
|
|
166
|
+
def test_correct(self):
|
|
167
|
+
#cat aws/webhoneypot-2024-02-24.json | jq .url | sort | uniq -c | sort -n
|
|
168
|
+
logfile = "dshield_parser/test/honeypotdata/aws/webhoneypot-2024-02-24.json "
|
|
169
|
+
summary_data = {}
|
|
170
|
+
summary_data['url'] = {"/manager/text/list": 1,
|
|
171
|
+
"/public/index.php": 1,
|
|
172
|
+
"/ReportServer": 1,
|
|
173
|
+
"/favicon.ico": 2,
|
|
174
|
+
"/goform/set_LimitClient_cfg": 2,
|
|
175
|
+
"/index.php": 9,
|
|
176
|
+
"/.env": 11,
|
|
177
|
+
"/": 18}
|
|
178
|
+
self.assertDictEqual(dshield_parser.web_processor.reports.get_summary_urls(logfile),
|
|
179
|
+
summary_data, msg="Summary URLs value mismatch")
|
|
180
|
+
|
|
181
|
+
class TestWebSummaryURLsExclusion(unittest.TestCase):
|
|
182
|
+
def test_correct(self):
|
|
183
|
+
#cat aws/webhoneypot-2024-02-24.json | jq .url | sort | uniq -c | sort -n
|
|
184
|
+
logfile = "dshield_parser/test/honeypotdata/aws/webhoneypot-2024-02-24.json "
|
|
185
|
+
summary_data = {}
|
|
186
|
+
summary_data['url'] = {"/manager/text/list": 1,
|
|
187
|
+
"/public/index.php": 1,
|
|
188
|
+
"/ReportServer": 1,
|
|
189
|
+
"/favicon.ico": 2,
|
|
190
|
+
"/index.php": 9,
|
|
191
|
+
"/.env": 11,
|
|
192
|
+
"/": 18}
|
|
193
|
+
self.assertDictEqual(dshield_parser.web_processor.reports.get_summary_urls(logfile, exclusions={'url': '/goform/set_LimitClient_cfg'}),
|
|
194
|
+
summary_data, msg="Summary URLs value mismatch")
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class TestWebGetJSONValuesIPExclusion(unittest.TestCase):
|
|
198
|
+
def test_correct(self):
|
|
199
|
+
#cat aws/webhoneypot-2024-02-24.json | jq 'select (.url)' | jq .url | wc -l
|
|
200
|
+
#total of 45 entries
|
|
201
|
+
|
|
202
|
+
#exclude sip of 207.90.244.3
|
|
203
|
+
#cat aws/webhoneypot-2024-02-24.json | jq 'select (.url)' | jq 'select (.sip!="207.90.244.3")' | jq .url | wc -l
|
|
204
|
+
#total of 42 entries
|
|
205
|
+
|
|
206
|
+
logfile = "dshield_parser/test/honeypotdata/aws/webhoneypot-2024-02-24.json "
|
|
207
|
+
self.assertEqual(len(dshield_parser.web_processor.reports.get_all_urls(logfile)),
|
|
208
|
+
45, msg="Summary URLs value mismatch")
|
|
209
|
+
|
|
210
|
+
self.assertEqual(len(dshield_parser.web_processor.reports.get_all_urls(logfile, exclusions={'sip': '207.90.244.3'})),
|
|
211
|
+
42, msg="Summary URLs value mismatch")
|
|
212
|
+
|
|
213
|
+
class TestCowrieJSONValuesIPExclusion(unittest.TestCase):
|
|
214
|
+
def test_correct(self):
|
|
215
|
+
#cat aws/cowrie.json.2024-02-24 | jq 'select (.input)' | jq .input | wc -l
|
|
216
|
+
#total of 61 entries
|
|
217
|
+
|
|
218
|
+
#exclude sip of 213.6.13.197
|
|
219
|
+
#cat aws/cowrie.json.2024-02-24 | jq 'select (.input)' | jq 'select (.src_ip!="213.6.13.197")' |jq .input | wc -l
|
|
220
|
+
#total of 48 entries
|
|
221
|
+
|
|
222
|
+
logfile = "dshield_parser/test/honeypotdata/aws/cowrie.json.2024-02-24"
|
|
223
|
+
self.assertEqual(len(dshield_parser.cowrie_processor.reports.get_all_input(logfile)),
|
|
224
|
+
61, msg="Cowrie Input value mismatch")
|
|
225
|
+
|
|
226
|
+
self.assertEqual(len(dshield_parser.cowrie_processor.reports.get_all_input(logfile, exclusions={'src_ip': '213.6.13.197'})),
|
|
227
|
+
48, msg="Cowrie input value mismatch with set exclusion")
|
|
228
|
+
|
|
229
|
+
class TestFirewallKeyRetrieval(unittest.TestCase):
|
|
230
|
+
def test_correct(self):
|
|
231
|
+
logfile = "dshield_parser/test/honeypotdata/gcp/dshield_firewall_.log"
|
|
232
|
+
sorted_keys = dshield_parser.utils.json.get_json_keys(logfile)
|
|
233
|
+
sorted_keys.sort()
|
|
234
|
+
self.assertEqual(sorted_keys,
|
|
235
|
+
['dip', 'dport', 'flags', 'proto', 'sip', 'sport', 'time', 'version'], msg="JSON key value retrieval mismatch")
|
|
236
|
+
|
|
237
|
+
class TestFirewallKeyLogRetrieval(unittest.TestCase):
|
|
238
|
+
def test_correct(self):
|
|
239
|
+
logfile = "dshield_parser/test/honeypotdata/gcp/dshield_firewall_.log"
|
|
240
|
+
log_data = dshield_parser.utils.json.get_json_values("time", logfile)
|
|
241
|
+
log_data_entry_num = len(log_data)
|
|
242
|
+
self.assertEqual(log_data_entry_num,
|
|
243
|
+
17252, msg="JSON key value retrieval mismatch")
|
|
244
|
+
|
|
245
|
+
class TestFirewallReportsRetrieval(unittest.TestCase):
|
|
246
|
+
def test_correct(self):
|
|
247
|
+
logfile = "dshield_parser/test/honeypotdata/gcp/dshield_firewall_.log"
|
|
248
|
+
self.assertEqual(dshield_parser.firewall_processor.reports.get_top_10_src_ips(logfile),
|
|
249
|
+
{'104.156.155.6': 645,
|
|
250
|
+
'121.182.176.148': 78,
|
|
251
|
+
'148.135.35.230': 95,
|
|
252
|
+
'195.85.205.159': 98,
|
|
253
|
+
'207.180.235.220': 183,
|
|
254
|
+
'62.122.184.51': 122,
|
|
255
|
+
'79.110.62.166': 71,
|
|
256
|
+
'79.110.62.73': 1324,
|
|
257
|
+
'79.110.62.92': 73,
|
|
258
|
+
'79.124.62.74': 125}, msg="Top 10 source IP value mismatch")
|
|
259
|
+
self.assertEqual(dshield_parser.utils.json.get_top_10("sip", logfile),
|
|
260
|
+
{'104.156.155.6': 645,
|
|
261
|
+
'121.182.176.148': 78,
|
|
262
|
+
'148.135.35.230': 95,
|
|
263
|
+
'195.85.205.159': 98,
|
|
264
|
+
'207.180.235.220': 183,
|
|
265
|
+
'62.122.184.51': 122,
|
|
266
|
+
'79.110.62.166': 71,
|
|
267
|
+
'79.110.62.73': 1324,
|
|
268
|
+
'79.110.62.92': 73,
|
|
269
|
+
'79.124.62.74': 125}, msg="Top 10 source IP value mismatch")
|
|
270
|
+
|
|
271
|
+
class TestFirewallSummarySrcIPs(unittest.TestCase):
|
|
272
|
+
def test_correct(self):
|
|
273
|
+
logfile = "dshield_parser/test/honeypotdata/gcp/dshield_firewall_.log"
|
|
274
|
+
self.assertEqual(len(dshield_parser.firewall_processor.reports.get_summary_src_ips(logfile)['sip']),
|
|
275
|
+
4542, msg="Summary source IPs value mismatch. Wrong number of expected values returned.")
|
|
276
|
+
|
|
277
|
+
self.assertEqual(dshield_parser.firewall_processor.reports.get_summary_src_ips(logfile)['sip']['152.89.198.75'],
|
|
278
|
+
17, msg="Summary source IPs value mismatch. Wrong number of occurences returned for IP address.")
|
|
279
|
+
|
|
280
|
+
class TestFirewallSummarySrcIPsExclusion(unittest.TestCase):
|
|
281
|
+
def test_correct(self):
|
|
282
|
+
logfile = "dshield_parser/test/honeypotdata/gcp/dshield_firewall_.log"
|
|
283
|
+
self.assertEqual(len(dshield_parser.firewall_processor.reports.get_summary_src_ips(logfile, exclusions={'sip': '152.89.198.75'})['sip']),
|
|
284
|
+
4541, msg="Summary source IPs value mismatch. Wrong number of expected values returned.")
|
|
285
|
+
|
|
286
|
+
data_with_exclusion = dshield_parser.firewall_processor.reports.get_summary_src_ips(logfile, exclusions={'sip': '152.89.198.75'})['sip']
|
|
287
|
+
self.assertRaises(KeyError, data_with_exclusion.__getitem__, '152.89.198.75')
|
|
288
|
+
|
|
289
|
+
self.assertEqual(data_with_exclusion['147.185.133.120'], 3)
|
|
290
|
+
|
|
291
|
+
#self.assertEqual(len(dshield_parser.firewall_processor.reports.get_summary_src_ips(logfile, exclusions={'sip': {'152.89.198.75', '162.216.150.118'}})['sip']),
|
|
292
|
+
# 4540, msg="Summary source IPs value mismatch. Wrong number of expected values returned.")
|
|
293
|
+
|
|
294
|
+
class TestWebMultipleFields(unittest.TestCase):
|
|
295
|
+
def test_correct(self):
|
|
296
|
+
logfile = "dshield_parser/test/honeypotdata/aws/webhoneypot-2024-02-24.json"
|
|
297
|
+
|
|
298
|
+
url_header_data = dshield_parser.utils.json.get_json_values(["sip", "url", "headers"], logfile)
|
|
299
|
+
|
|
300
|
+
# cat webhoneypot-2024-02-24.json | jq -r '. | [.sip, .url, .headers.["user-agent"]] | @csv' | sort | uniq -c
|
|
301
|
+
|
|
302
|
+
# should have 22 entries
|
|
303
|
+
# cat webhoneypot-2024-02-24.json | jq -r '. | [.sip, .url, .headers.["user-agent"]] | @csv' | sort | uniq -c | wc -l
|
|
304
|
+
|
|
305
|
+
df = pd.DataFrame(url_header_data)
|
|
306
|
+
df["user-agent"] = df["headers"].str['user-agent']
|
|
307
|
+
df = df.drop("headers", axis=1)
|
|
308
|
+
df = df.groupby(df.columns.tolist(),as_index=False, dropna=False).size()
|
|
309
|
+
|
|
310
|
+
#with pd.option_context('display.max_rows', None, 'display.max_columns', None): # more options can be specified also
|
|
311
|
+
# print(df)
|
|
312
|
+
self.assertEqual(len(df), 22)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
class TestCowrieMultipleFields(unittest.TestCase):
|
|
316
|
+
def test_correct(self):
|
|
317
|
+
logfile = "dshield_parser/test/honeypotdata/aws/cowrie.json.2024-02-24"
|
|
318
|
+
|
|
319
|
+
cowrie_data = dshield_parser.utils.json.get_json_values(["src_ip", "dst_port", "input"], logfile)
|
|
320
|
+
|
|
321
|
+
# cat cowrie.json.2024-02-24 | jq -r '. | [.src_ip, .dst_port, .message] | @csv' | sort | uniq -c
|
|
322
|
+
|
|
323
|
+
# should have 180 entries
|
|
324
|
+
# cat cowrie.json.2024-02-24 | jq -r '. | [.src_ip, .dst_port, .message] | @csv' | sort | uniq -c | wc -l
|
|
325
|
+
|
|
326
|
+
df = pd.DataFrame(cowrie_data)
|
|
327
|
+
df = df.groupby(df.columns.tolist(),as_index=False, dropna=False).size()
|
|
328
|
+
|
|
329
|
+
#with pd.option_context('display.max_rows', None, 'display.max_columns', None): # more options can be specified also
|
|
330
|
+
# print(df)
|
|
331
|
+
self.assertEqual(len(df), 180)
|
|
332
|
+
|
|
333
|
+
class TestFirewallMultipleFields(unittest.TestCase):
|
|
334
|
+
def test_correct(self):
|
|
335
|
+
logfile = "dshield_parser/test/honeypotdata/aws/local_copy.log"
|
|
336
|
+
|
|
337
|
+
firewall_data = dshield_parser.utils.json.get_json_values(["sip", "dip", "dport"], logfile)
|
|
338
|
+
|
|
339
|
+
# cat local_copy_2024-02-24.log | sed "s/},/}\\n/$m;P;D" | sed "s/\[/\\n/$m;P;D" | sed "s/\]/\\n/$m;P;D" | awk '{$1=$1};1' | sed -ne '/^{"time/p' | jq -r '. | [.sip, .dip, .dport, .flags] | @csv' | sort | uniq -c
|
|
340
|
+
|
|
341
|
+
# should have 4362 entries
|
|
342
|
+
# cat local_copy_2024-02-24.log | sed "s/},/}\\n/$m;P;D" | sed "s/\[/\\n/$m;P;D" | sed "s/\]/\\n/$m;P;D" | awk '{$1=$1};1' | sed -ne '/^{"time/p' | jq -r '. | [.sip, .dip, .dport, .flags] | @csv' | sort | uniq -c | wc -l
|
|
343
|
+
|
|
344
|
+
df = pd.DataFrame(firewall_data)
|
|
345
|
+
df = df.groupby(df.columns.tolist(),as_index=False, dropna=False).size()
|
|
346
|
+
|
|
347
|
+
#with pd.option_context('display.max_rows', None, 'display.max_columns', None): # more options can be specified also
|
|
348
|
+
# print(df)
|
|
349
|
+
self.assertEqual(len(df), 4362)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
if __name__ == "__main__":
|
|
353
|
+
unittest.main()
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from dshield_parser.utils import *
|
|
File without changes
|