diff --git a/README.md b/README.md
index 01ffa2a..b8f6a4b 100644
--- a/README.md
+++ b/README.md
@@ -8,11 +8,11 @@ TinyCheck allows you to easily capture network communications from a smartphone
The idea of TinyCheck emerged in a meeting about stalkerware with a [French women's shelter](https://www.centre-hubertine-auclert.fr). During this meeting we talked about how to easily detect [stalkerware](https://stopstalkerware.org/) without installing very technical apps nor doing forensic analysis on the victim's smartphone. The initial concept was to develop a tiny kiosk device based on Raspberry Pi which can be used by non-tech people to test their smartphones against malicious communications issued by stalkerware or any spyware.
-Of course, TinyCheck can also be used to spot any malicious communications from cybercrime to state-sponsored implants. It allows the end-user to push his own extended Indicators of Compromise via a backend in order to detect some ghosts over the wire.
+Of course, TinyCheck can also be used to spot any malicious communications from cybercrime to state-sponsored implants. It allows the end-user to push their own extended Indicators of Compromise via a backend in order to detect some ghosts over the wire.
If you need more documentation on how to install it, use it and the internals, don't hesitate to take a look at the TinyCheck Wiki.
-If you have any question about the projet, want to contribute or just send your feedback,
don't hesitate to contact us at tinycheck[@]kaspersky[.]com.
+If you have any question about the project, want to contribute or just send your feedback,
don't hesitate to contact us at tinycheck[@]kaspersky[.]com.
### Use cases
diff --git a/analysis/analysis.py b/analysis/analysis.py
index 345e82e..a00d203 100644
--- a/analysis/analysis.py
+++ b/analysis/analysis.py
@@ -16,60 +16,82 @@ import os
containing a capture.pcap file.
"""
-if __name__ == "__main__":
- if len(sys.argv) == 2:
- capture_directory = sys.argv[1]
- if os.path.isdir(capture_directory):
- manager = Manager()
- alerts = manager.dict()
+def analyze(capture_directory,frontend=False):
+ if os.path.isdir(capture_directory):
- def zeekengine(alerts):
- zeek = ZeekEngine(capture_directory)
- zeek.start_zeek()
- alerts["zeek"] = zeek.retrieve_alerts()
+ manager = Manager()
+ alerts = manager.dict()
- # whitelist.json writing.
- with open(os.path.join(capture_directory, "assets/whitelist.json"), "w") as f:
- f.write(json.dumps(zeek.retrieve_whitelist(),
- indent=4, separators=(',', ': ')))
+ def zeekengine(alerts):
+ zeek = ZeekEngine(capture_directory)
+ zeek.start_zeek()
+ alerts["zeek"] = zeek.retrieve_alerts()
- # conns.json writing.
- with open(os.path.join(capture_directory, "assets/conns.json"), "w") as f:
- f.write(json.dumps(zeek.retrieve_conns(),
- indent=4, separators=(',', ': ')))
+ if not os.path.isdir(os.path.join(capture_directory, "assets")):
+ os.mkdir(os.path.join(capture_directory, "assets"))
+ # whitelist.json writing.
+ with open(os.path.join(capture_directory, "assets/whitelist.json"), "w") as f:
+ f.write(json.dumps(zeek.retrieve_whitelist(),
+ indent=4, separators=(',', ': ')))
- def snortengine(alerts):
- suricata = SuricataEngine(capture_directory)
- suricata.start_suricata()
- alerts["suricata"] = suricata.get_alerts()
+ # conns.json writing.
+ with open(os.path.join(capture_directory, "assets/conns.json"), "w") as f:
+ f.write(json.dumps(zeek.retrieve_conns(),
+ indent=4, separators=(',', ': ')))
- # Start the engines.
- p1 = Process(target=zeekengine, args=(alerts,))
- p2 = Process(target=snortengine, args=(alerts,))
- p1.start()
- p2.start()
+ def snortengine(alerts):
+ suricata = SuricataEngine(capture_directory)
+ suricata.start_suricata()
+ alerts["suricata"] = suricata.get_alerts()
- # Wait to their end.
- p1.join()
- p2.join()
+ # Start the engines.
+ p1 = Process(target=zeekengine, args=(alerts,))
+ p2 = Process(target=snortengine, args=(alerts,))
+ p1.start()
+ p2.start()
- # Some formating and alerts.json writing.
- with open(os.path.join(capture_directory, "assets/alerts.json"), "w") as f:
- report = {"high": [], "moderate": [], "low": []}
- for alert in (alerts["zeek"] + alerts["suricata"]):
- if alert["level"] == "High":
- report["high"].append(alert)
- if alert["level"] == "Moderate":
- report["moderate"].append(alert)
- if alert["level"] == "Low":
- report["low"].append(alert)
- f.write(json.dumps(report, indent=4, separators=(',', ': ')))
+ # Wait to their end.
+ p1.join()
+ p2.join()
+
+ # Some formating and alerts.json writing.
+ with open(os.path.join(capture_directory, "assets/alerts.json"), "w") as f:
+ report = {"high": [], "moderate": [], "low": []}
+ for alert in (alerts["zeek"] + alerts["suricata"]):
+ if alert["level"] == "High":
+ report["high"].append(alert)
+ if alert["level"] == "Moderate":
+ report["moderate"].append(alert)
+ if alert["level"] == "Low":
+ report["low"].append(alert)
+ f.write(json.dumps(report, indent=4, separators=(',', ': ')))
+
+ # Generate the report
+ report = Report(capture_directory,frontend)
+ report.generate_report()
- # Generate the report
- report = Report(capture_directory)
- report.generate_report()
- else:
- print("The directory doesn't exist.")
else:
- print("Please specify a capture directory in argument.")
+ print("The directory doesn't exist.")
+
+
+def usage():
+ print("""Usage: python analysis.py [capture_directory]
+ where [capture_directory] is a directory containing a capture.pcap file
+ analysis.py -f starts the analysis in frontend mode intended to be called by the TinyCheck frontend.""")
+
+
+if __name__ == "__main__":
+ if len(sys.argv) == 2: #called manually without frontend
+ analyze(sys.argv[1], False)
+ elif len(sys.argv) == 3:
+ if(sys.argv[1]) == "-f": #frontend mode
+ analyze(sys.argv[2], True)
+ else:
+ usage()
+
+ else:
+ usage()
+
+
+
diff --git a/analysis/classes/report.py b/analysis/classes/report.py
index 9146bb2..8d22680 100644
--- a/analysis/classes/report.py
+++ b/analysis/classes/report.py
@@ -13,7 +13,7 @@ from utils import get_config
class Report(object):
- def __init__(self, capture_directory):
+ def __init__(self, capture_directory, frontend):
self.capture_directory = capture_directory
self.alerts = self.read_json(os.path.join(
capture_directory, "assets/alerts.json"))
@@ -21,10 +21,13 @@ class Report(object):
capture_directory, "assets/whitelist.json"))
self.conns = self.read_json(os.path.join(
capture_directory, "assets/conns.json"))
- self.device = self.read_json(os.path.join(
- capture_directory, "assets/device.json"))
- self.capinfos = self.read_json(os.path.join(
- capture_directory, "assets/capinfos.json"))
+ self.device = None
+ self.capinfos = None
+ if frontend:
+ self.device = self.read_json(os.path.join(
+ capture_directory, "assets/device.json"))
+ self.capinfos = self.read_json(os.path.join(
+ capture_directory, "assets/capinfos.json"))
try:
with open(os.path.join(self.capture_directory, "capture.pcap"), "rb") as f:
self.capture_sha1 = hashlib.sha1(f.read()).hexdigest()
@@ -204,16 +207,18 @@ class Report(object):
"""
header = "