diff --git a/analyzers/JoeSandbox/JoeSandbox_File_Analysis_Inet.html b/analyzers/JoeSandbox/JoeSandbox_File_Analysis_Inet.html new file mode 100644 index 000000000..35d56b32e --- /dev/null +++ b/analyzers/JoeSandbox/JoeSandbox_File_Analysis_Inet.html @@ -0,0 +1,209 @@ +
+ + + +
+
+ General Information +
+
+ +

Joe Sandbox

+
+
+
Version
+
{{content.version}}
+
+
+
Arch
+
{{content.arch}}
+
+
+
System
+
{{content.system}}
+
+
+
Cookbook
+
{{content.cookbook}}
+
+
+
Start date and time
+
{{content.startdate}} {{content.starttime}} (Joe Sandbox time)
+
+
+

File information

+
+
+
FileType
+
{{content.filetype}}
+
+
+
{{k}}
+
{{v}}
+
+ +
+
+ +
+
+ Analysis +
+
+ +
+

Signatures

+
+
+
{{l}}
+
+
+
{{content.signatures.signare}}
+
+
+
+ No suspicious signature reported +
+
+
+

Remote connections

+
+
+
+
domains
+
+
{{e.ip}}
+
{{e.name}}
+
+
+ +
+
IP addresses
+
+
+ {{v.ip}} +
+
+
+
+ + + + + {{ip.$}} +
+
+ {{ip}} +
+
+
+
+
+
+ +
+

Dropped files

+
+
+
{{f.name}}
+
+
{{k}}
+
{{v}}
+
+
+
+ No dropped file reported +
+
+ +
+
+

Confidence

+
+
+
Score
+
{{content.confidence.score}}/{{content.confidence.maxscore}}
+
+
+
+
+ +
+

Maliciousness

+
+
+
Score
+
{{content.detection.score}}/{{content.detection.maxscore}}
+
+
+ + + Clean + + + Malicious + + + Suspicious + + +
+
+
+
+
+
+ +
+
+ Images +
+
+
+
+

+ + {{index||0}} + +

+
+ +
+
+
+
+ +
+
+ Reports +
+
+
+
HTML report
+
{{content.htmlreport}}
+
+
+
PDF report
+
{{content.pdfreport}}
+
+
+
+ +
+ + + +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
+ diff --git a/analyzers/JoeSandbox/JoeSandbox_File_Analysis_Inet.json b/analyzers/JoeSandbox/JoeSandbox_File_Analysis_Inet.json index 44ed2888a..c6780464a 100644 --- a/analyzers/JoeSandbox/JoeSandbox_File_Analysis_Inet.json +++ b/analyzers/JoeSandbox/JoeSandbox_File_Analysis_Inet.json @@ -1,6 +1,6 @@ { "name": "JoeSandbox_File_Analysis_Inet", - "version": "2.0", + "version": "3.0", "author": "CERT-BDF", "url": "https://github.com/TheHive-Project/Cortex-Analyzers", "license": "AGPL-V3", @@ -41,6 +41,47 @@ "multi": false, "required": true, "defaultValue": 30 + }, + { + "name": "HTML_report", + "description": "Download HTML report", + "type": "boolean", + "multi": false, + "required": true, + "defaultValue": false + }, + { + "name": "images", + "description": "Allow images in the report", + "type": "boolean", + "multi": false, + "required": true, + "defaultValue": false + }, + { + "name": "observables", + "description": "Creat observables form report", + "type": "boolean", + "multi": false, + "required": true, + "defaultValue": false + } + ], + "registration_required": true, + "subscription_required": true, + + "screenshots": [ + { + "path": "assets/HTML_report.png", + "caption": "EmlParser: HTML report" + }, + { + "path": "assets/images_preview.png", + "caption": "EmlParser: images preview" + }, + { + "path": "assets/IP_URL.png", + "caption": "EmlParser: IP and URL" } ] } diff --git a/analyzers/JoeSandbox/JoeSandbox_File_Analysis_Noinet.html b/analyzers/JoeSandbox/JoeSandbox_File_Analysis_Noinet.html new file mode 100644 index 000000000..f981b63a9 --- /dev/null +++ b/analyzers/JoeSandbox/JoeSandbox_File_Analysis_Noinet.html @@ -0,0 +1,195 @@ +
+ + + +
+
+ General Information +
+
+ +

Joe Sandbox

+
+
+
Version
+
{{content.version}}
+
+
+
Arch
+
{{content.arch}}
+
+
+
System
+
{{content.system}}
+
+
+
Cookbook
+
{{content.cookbook}}
+
+
+
Start date and time
+
{{content.startdate}} {{content.starttime}} (Joe Sandbox time)
+
+
+

File information

+
+
+
FileType
+
{{content.filetype}}
+
+
+
{{k}}
+
{{v}}
+
+ +
+
+ +
+
+ Analysis +
+
+ +
+

Signatures

+
+
+
{{l}}
+
+
+
{{content.signatures.signare}}
+
+
+
+ No suspicious signature reported +
+
+
+

Remote connections

+
+
+
+
domains
+
+
{{e.ip}}
+
{{e.name}}
+
+
+ +
+
IP addresses
+
+
{{ip}}
+
+
+
+
+
+ +
+

Dropped files

+
+
+
{{f.name}}
+
+
{{k}}
+
{{v}}
+
+
+
+ No dropped file reported +
+
+ +
+
+

Confidence

+
+
+
Score
+
{{content.confidence.score}}/{{content.confidence.maxscore}}
+
+
+
+
+ +
+

Maliciousness

+
+
+
Score
+
{{content.detection.score}}/{{content.detection.maxscore}}
+
+
+ + + Clean + + + Malicious + + + Suspicious + + +
+
+
+
+
+
+ +
+
+ Images +
+
+
+
+

+ + {{index||0}} + +

+
+ +
+
+
+
+ +
+
+ Reports +
+
+
+
HTML report
+
{{content.htmlreport}}
+
+
+
PDF report
+
{{content.pdfreport}}
+
+
+
+ +
+ + + +
+
+ {{(artifact.data || artifact.attachment.name) | fang}} +
+
+ {{content.errorMessage}} +
+
+ diff --git a/analyzers/JoeSandbox/JoeSandbox_File_Analysis_Noinet.json b/analyzers/JoeSandbox/JoeSandbox_File_Analysis_Noinet.json index d18c8e7ef..dbb21eae0 100644 --- a/analyzers/JoeSandbox/JoeSandbox_File_Analysis_Noinet.json +++ b/analyzers/JoeSandbox/JoeSandbox_File_Analysis_Noinet.json @@ -1,6 +1,6 @@ { "name": "JoeSandbox_File_Analysis_Noinet", - "version": "2.0", + "version": "3.0", "author": "CERT-BDF", "url": "https://github.com/TheHive-Project/Cortex-Analyzers", "license": "AGPL-V3", @@ -41,6 +41,43 @@ "multi": false, "required": true, "defaultValue": 30 + }, + { + "name": "HTML_report", + "description": "Download HTML report", + "type": "boolean", + "multi": false, + "required": true, + "defaultValue": false + }, + { + "name": "images", + "description": "Allow images in the report", + "type": "boolean", + "multi": false, + "required": true, + "defaultValue": false + }, + { + "name": "observables", + "description": "Creat observables form report", + "type": "boolean", + "multi": false, + "required": true, + "defaultValue": false + } + ], + "registration_required": true, + "subscription_required": true, + + "screenshots": [ + { + "path": "assets/HTML_report.png", + "caption": "EmlParser: HTML report" + }, + { + "path": "assets/images_preview.png", + "caption": "EmlParser: images preview" } - ] + ] } diff --git a/analyzers/JoeSandbox/README.md b/analyzers/JoeSandbox/README.md new file mode 100644 index 000000000..35869adac --- /dev/null +++ b/analyzers/JoeSandbox/README.md @@ -0,0 +1,12 @@ +### Joe SandBox + +With the version 3.0 this analyzer allow you to have: +- the HTML report as an observable +- the screenshot from Joe Sandbox in the analysis report +- IP and URL as observable + + +This analyzer has 3 flavors: +- URL analysis +- File analysis inet +- File analysis noinet diff --git a/analyzers/JoeSandbox/assets/HTML_report.png b/analyzers/JoeSandbox/assets/HTML_report.png new file mode 100644 index 000000000..9b195cf72 Binary files /dev/null and b/analyzers/JoeSandbox/assets/HTML_report.png differ diff --git a/analyzers/JoeSandbox/assets/IP_URL.png b/analyzers/JoeSandbox/assets/IP_URL.png new file mode 100644 index 000000000..a6a8d25d0 Binary files /dev/null and b/analyzers/JoeSandbox/assets/IP_URL.png differ diff --git a/analyzers/JoeSandbox/assets/images_preview.png b/analyzers/JoeSandbox/assets/images_preview.png new file mode 100644 index 000000000..037c0ff69 Binary files /dev/null and b/analyzers/JoeSandbox/assets/images_preview.png differ diff --git a/analyzers/JoeSandbox/joesandbox_analyzer.py b/analyzers/JoeSandbox/joesandbox_analyzer.py index 6da866a6c..d2543d2cf 100755 --- a/analyzers/JoeSandbox/joesandbox_analyzer.py +++ b/analyzers/JoeSandbox/joesandbox_analyzer.py @@ -3,12 +3,30 @@ from cortexutils.analyzer import Analyzer +import zipfile +import os +import base64 import io import requests import time import json from jbxapi import JoeSandbox +def get_files(folder): + # function to get all files in a folder sorted + + # get the path of the files + files = [f"{file}" for file in os.listdir(folder)] + # split . + for i in range(len(files)): + files[i]=files[i].split('.') + # sort by numerically + files.sort(key=lambda x: int(x[0])) + # merge /. + for i in range(len(files)): + files[i]=folder+"/"+files[i][0]+"."+files[i][1] + return files + class JoeSandboxAnalyzer(Analyzer): def __init__(self): @@ -25,6 +43,9 @@ def __init__(self): ) self.analysistimeout = self.get_param("config.analysistimeout", 30 * 60, None) self.networktimeout = self.get_param("config.networktimeout", 30, None) + self.images = self.get_param("config.images", False, None) + self.HTML_report = self.get_param("config.HTML_report", False, None) + self.observables = self.get_param("config.observables", False, None) self.joe = JoeSandbox(apikey, self.url, verify_ssl=False, accept_tac=True) def summary(self, raw): @@ -49,6 +70,38 @@ def summary(self, raw): taxonomies.append(self.build_taxonomy(level, namespace, predicate, value)) return {"taxonomies": taxonomies} + def artifacts(self, raw): + artifacts= [] + + if self.observables: + #IP + if self.analysis['contacted']['ips']: + for i in self.analysis['contacted']['ips']['ip']: + if(i['$']!='unknown'): + #print('ip ',str(i['$'])) + artifacts.append(self.build_artifact('ip',str(i['$']))) + + #URL + if self.analysis['contacted']['domains']: + for i in self.analysis['contacted']['domains']['domain']: + if(i['ip']!="unknown"): + #print('ip ',str(i['ip'])) + artifacts.append(self.build_artifact('ip',str(i['ip']))) + #print('url',str(i['name'])) + artifacts.append(self.build_artifact('url',str(i['name']))) + + #HTML report + if self.HTML_report: + if self.webid: + webid = self.webid + response = self.joe.analysis_download(webid, "html", run=0) + with open('/tmp/'+str(response[0]), 'wb') as the_file: + the_file.write(response[1]) + artifacts.append(self.build_artifact('file',"/tmp/"+str(response[0]))) + os.remove('/tmp/'+str(response[0])) + + return artifacts + def run(self): Analyzer.run(self) @@ -79,26 +132,55 @@ def run(self): while not finished and tries <= self.analysistimeout / 60: time.sleep(60) response = self.joe.submission_info(submission_id) - webid = response["analyses"][0]["webid"] + self.webid = response["analyses"][0]["webid"] if response["status"] == "finished": finished = True tries += 1 if not finished: self.error("JoeSandbox analysis timed out") # Download the report - response = self.joe.analysis_download(webid, "irjsonfixed", run=0) - analysis = json.loads(response[1].decode("utf-8")).get("analysis", None) - if analysis: - analysis["htmlreport"] = ( - self.url + "analysis/" + str(analysis["id"]) + "/0/html" + response = self.joe.analysis_download(self.webid, "irjsonfixed", run=0) + self.analysis = json.loads(response[1].decode("utf-8")).get("analysis", None) + + if self.images: + # Download images + zip_images = self.joe.analysis_download(self.webid, "shoots", run=0) + zip_location = "/tmp/"+str(zip_images[0]) + zip_folder = "/tmp/images/"+str(zip_images[0]) + # write ziped images in /tmp + with open(zip_location, 'wb') as file: + file.write(zip_images[1]) + if not os.path.exists("/tmp/images/"): + os.mkdir(path="/tmp/images/", mode = 0o744) + if not os.path.exists(zip_folder): + os.mkdir(path=zip_folder, mode = 0o744) + # unzip images + with zipfile.ZipFile(zip_location) as z: + z.extractall(path=zip_folder) + # remove ziped images (not needed anymore) + os.remove(zip_location) + # put image in json + images=[] + for f in get_files(zip_folder): + with open(str(f), mode='rb') as file: + images.append( base64.encodebytes(file.read()).decode('utf-8') ) + os.remove(f) + self.analysis["images"] = images + # remove not needed files + os.rmdir(zip_folder) + + if self.analysis: + self.analysis["htmlreport"] = ( + self.url + "analysis/" + str(self.analysis["id"]) + "/0/html" ) - analysis["pdfreport"] = ( - self.url + "analysis/" + str(analysis["id"]) + "/0/pdf" + self.analysis["pdfreport"] = ( + self.url + "analysis/" + str(self.analysis["id"]) + "/0/pdf" ) - self.report(analysis) + self.report(self.analysis) else: self.error("Invalid output") if __name__ == "__main__": JoeSandboxAnalyzer().run() +