From 40971404f3dc7c68158f7e721133a4d0dfe43e18 Mon Sep 17 00:00:00 2001 From: lcwiklinski-r7 Date: Thu, 6 Feb 2025 13:01:23 +0100 Subject: [PATCH] [SOAR-18821] joe sandbox issue with passing a sample (#3077) (#3078) * Updated parameters and bumped SDK * Refreshing the plugin * Linting the unit test --- plugins/joe_sandbox/.CHECKSUM | 8 +- plugins/joe_sandbox/Dockerfile | 2 +- plugins/joe_sandbox/bin/icon_joe_sandbox | 2 +- plugins/joe_sandbox/help.md | 148 +++++++++--------- .../actions/get_submitted_info/action.py | 2 +- .../actions/submit_cookbook/action.py | 8 +- .../actions/submit_sample/action.py | 19 ++- .../actions/submit_sample/schema.py | 15 +- plugins/joe_sandbox/plugin.spec.yaml | 28 +++- plugins/joe_sandbox/setup.py | 2 +- plugins/joe_sandbox/unit_test/mock.py | 6 + .../responses/chunked_sample.json.resp | 6 + .../responses/get_submitted_info.json.resp | 57 +++++++ .../responses/submit_sample.json.resp | 5 + .../unit_test/test_get_submitted_info.py | 88 +++++++++++ .../unit_test/test_submit_cookbook.py | 27 ++++ .../unit_test/test_submit_sample.py | 30 ++++ 17 files changed, 345 insertions(+), 108 deletions(-) create mode 100644 plugins/joe_sandbox/unit_test/responses/chunked_sample.json.resp create mode 100644 plugins/joe_sandbox/unit_test/responses/get_submitted_info.json.resp create mode 100644 plugins/joe_sandbox/unit_test/responses/submit_sample.json.resp create mode 100644 plugins/joe_sandbox/unit_test/test_get_submitted_info.py create mode 100644 plugins/joe_sandbox/unit_test/test_submit_cookbook.py create mode 100644 plugins/joe_sandbox/unit_test/test_submit_sample.py diff --git a/plugins/joe_sandbox/.CHECKSUM b/plugins/joe_sandbox/.CHECKSUM index b4a8022a65..a9126bcf48 100644 --- a/plugins/joe_sandbox/.CHECKSUM +++ b/plugins/joe_sandbox/.CHECKSUM @@ -1,7 +1,7 @@ { - "spec": "7c44d7ec555d0bf72ad65e02bb277cbc", - "manifest": "c6ce22bd383963cc96f5c7e9fe92d071", - "setup": "f0407b136e81ef2ace16e53ffdbc7ff8", + "spec": "5cfed2d6030225802d6a71f1920dc882", + "manifest": "cd604b540e9eb0b4cfa625072c405fe0", + "setup": "8bcad3fda51df4fbbce75c43dfc14a61", "schemas": [ { "identifier": "check_server_status/schema.py", @@ -57,7 +57,7 @@ }, { "identifier": "submit_sample/schema.py", - "hash": "1d67d8122b794bf07aab8d4e8278a4ae" + "hash": "a7bfbeee4afc2b28a6fd209db9ef0fac" }, { "identifier": "submit_sample_url/schema.py", diff --git a/plugins/joe_sandbox/Dockerfile b/plugins/joe_sandbox/Dockerfile index 5cb724ab04..f14c0e7af2 100755 --- a/plugins/joe_sandbox/Dockerfile +++ b/plugins/joe_sandbox/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=linux/amd64 rapid7/insightconnect-python-3-slim-plugin:5.4.4 +FROM --platform=linux/amd64 rapid7/insightconnect-python-3-slim-plugin:6.2.4 LABEL organization=rapid7 LABEL sdk=python diff --git a/plugins/joe_sandbox/bin/icon_joe_sandbox b/plugins/joe_sandbox/bin/icon_joe_sandbox index 82675358b8..91c05855ea 100755 --- a/plugins/joe_sandbox/bin/icon_joe_sandbox +++ b/plugins/joe_sandbox/bin/icon_joe_sandbox @@ -6,7 +6,7 @@ from sys import argv Name = "Joe Sandbox" Vendor = "rapid7" -Version = "2.0.0" +Version = "3.0.0" Description = "Joe Sandbox Cloud executes files and URLs fully automated in a controlled environment and monitors the behavior of applications and the operating system for suspicious activities" diff --git a/plugins/joe_sandbox/help.md b/plugins/joe_sandbox/help.md index ae04d84817..68f2510cf5 100644 --- a/plugins/joe_sandbox/help.md +++ b/plugins/joe_sandbox/help.md @@ -3,31 +3,31 @@ Joe Sandbox Cloud executes files and URLs fully automated in a controlled environment and monitors the behavior of applications and the operating system for suspicious activities # Key Features - -* Submit samples and URLs for sandbox analysis -* Search, list, get, download, and delete analyses + +* Submit samples and URLs for sandbox analysis +* Search, list, get, download, and delete analyses * Get, list, and manage server and user info # Requirements - -* API Key + +* API Key * Sandbox server (if not using cloud) # Supported Product Versions - + * Joe Sandbox API v2 # Documentation ## Setup - + The connection configuration accepts the following parameters: -|Name|Type|Default|Required|Description|Enum|Example| -| :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|api_key|credential_secret_key|None|True|API key generated for Joe Sandbox user|None|8e8786182c66e8bc2abdab9198f1385691987bfe2a4917be1268e915e457dbc5| -|url|string|https://jbxcloud.joesecurity.org/api|False|API URL of the Joe Sandbox instance. Default is for Joe Sandbox Cloud. On-premise installations use the following URL format http://example.com/joesandbox/index.php/api|None|http://example.com/joesandbox/index.php/api| - +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|api_key|credential_secret_key|None|True|API key generated for Joe Sandbox user|None|8e8786182c66e8bc2abdab9198f1385691987bfe2a4917be1268e915e457dbc5|None|None| +|url|string|https://jbxcloud.joesecurity.org/api|False|API URL of the Joe Sandbox instance. Default is for Joe Sandbox Cloud. On-premise installations use the following URL format http://example.com/joesandbox/index.php/api|None|http://example.com/joesandbox/index.php/api|None|None| + Example input: ``` @@ -43,7 +43,7 @@ Example input: #### Check Server Status - + This action is used to check if Joe Sandbox is online or in maintenance mode ##### Input @@ -65,14 +65,14 @@ Example output: ``` #### Delete Analysis - + This action is used to delete an analysis ##### Input -|Name|Type|Default|Required|Description|Enum|Example| -| :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|webid|string|None|True|The web ID of the analysis|None|10001| +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|webid|string|None|True|The web ID of the analysis|None|10001|None|None| Example input: @@ -97,16 +97,16 @@ Example output: ``` #### Download Analysis - + This action is used to download a resource for an analysis. This can be a full report, binaries, screenshots, etc ##### Input -|Name|Type|Default|Required|Description|Enum|Example| -| :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|run|integer|None|False|The number of the run. If not specified, Joe Sandbox will choose one automatically|None|1| -|type|string|html|False|The report type|["bins", "binstrings", "classhtml", "classxml", "clusterxml", "cookbook", "executive", "graphreports", "html", "ida", "irjson", "irjsonfixed", "irxml", "ishots", "json", "jsonfixed", "lighthtml", "lightjson", "lightjsonfixed", "lightxml", "maec", "memdumps", "memstrings", "misp", "openioc", "pcap", "pcapslim", "pdf", "sample", "shoots", "unpack", "unpackpe", "xml", "yara"]|pdf| -|webid|string|None|True|The web ID of the analysis|None|10001| +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|run|integer|None|False|The number of the run. If not specified, Joe Sandbox will choose one automatically|None|1|None|None| +|type|string|html|False|The report type|["bins", "binstrings", "classhtml", "classxml", "clusterxml", "cookbook", "executive", "graphreports", "html", "ida", "irjson", "irjsonfixed", "irxml", "ishots", "json", "jsonfixed", "lighthtml", "lightjson", "lightjsonfixed", "lightxml", "maec", "memdumps", "memstrings", "misp", "openioc", "pcap", "pcapslim", "pdf", "sample", "shoots", "unpack", "unpackpe", "xml", "yara"]|pdf|None|None| +|webid|string|None|True|The web ID of the analysis|None|10001|None|None| Example input: @@ -135,7 +135,7 @@ Example output: ``` #### Get Account Info - + This action is used to query information about Joe Sandbox user account ##### Input @@ -170,14 +170,14 @@ Example output: ``` #### Get Analysis Info - + This action is used to show the status and most important attributes of an analysis ##### Input -|Name|Type|Default|Required|Description|Enum|Example| -| :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|webid|string|None|True|The web ID of the analysis|None|10001| +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|webid|string|None|True|The web ID of the analysis|None|10001|None|None| Example input: @@ -226,7 +226,7 @@ Example output: ``` #### Get Server Info - + This action is used to query information about the server ##### Input @@ -248,14 +248,14 @@ Example output: ``` #### Get Submitted Info - + This action is used to show the status and info of submission ##### Input -|Name|Type|Default|Required|Description|Enum|Example| -| :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|submission_id|string|None|True|Submission ID from analysis|None|1001| +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|submission_id|string|None|True|Submission ID from analysis|None|1001|None|None| Example input: @@ -280,7 +280,7 @@ Example output: ``` #### List Analyses - + This action is used to fetch a list of all analyses ##### Input @@ -306,7 +306,7 @@ Example output: ``` #### List Countries - + This action is used to retrieve a list of localized internet anonymization countries ##### Input @@ -335,7 +335,7 @@ Example output: ``` #### List Languages and Locales - + This action is used to retrieve a list of available keyboard layouts for Windows analyzers ##### Input @@ -364,7 +364,7 @@ Example output: ``` #### List Systems - + This action is used to retrieve a list of systems on the server ##### Input @@ -393,15 +393,15 @@ Example output: ``` #### Search Analysis - + This action is used to lists the web IDs of the analyses that match the given query. Searches in MD5, SHA1, SHA256, filename, cookbook name, comment, URL and report ID ##### Input -|Name|Type|Default|Required|Description|Enum|Example| -| :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|query|string|None|True|String to search for|None|44d88612fea8a8f36de82e1278abb02f| +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|query|string|None|True|String to search for|None|44d88612fea8a8f36de82e1278abb02f|None|None| Example input: @@ -430,16 +430,16 @@ Example output: ``` #### Submit Cookbook - + This action is used to submit a cookbook for analysis and return the associated web IDs for the cookbook ##### Input -|Name|Type|Default|Required|Description|Enum|Example| -| :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|additional_parameters|object|None|False|Additional parameters for Joe Sandbox Cloud, described in more detail in the API documentation. All boolean parameters should be set to 1 or 0. Parameter `accept-tac` will always be set to 1|None|{ "accept-tac": 1, "url-reputation": 0, "export-to-jbxview": 1, "delete-after-days": 30 }| -|cookbook|bytes|None|True|Cookbook to be uploaded together with the sample|None|TVqQAAMAAAAEAAAA//8AALgAAAAAAA...| -|parameters|object|None|False|Custom sandbox parameters, described in more detail in the API documentation. All boolean parameters should be set to 1 or 0|None|{ "comments": "Enabled hybrid code analysis for sample", "hybrid-code-analysis": 1 }| +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|additional_parameters|object|None|False|Additional parameters for Joe Sandbox Cloud, described in more detail in the API documentation. All boolean parameters should be set to 1 or 0. Parameter `accept-tac` will always be set to 1|None|{ "accept-tac": 1, "url-reputation": 0, "export-to-jbxview": 1, "delete-after-days": 30 }|None|None| +|cookbook|bytes|None|True|Cookbook to be uploaded together with the sample|None|TVqQAAMAAAAEAAAA//8AALgAAAAAAA...|None|None| +|parameters|object|None|False|Custom sandbox parameters, described in more detail in the API documentation. All boolean parameters should be set to 1 or 0|None|{ "comments": "Enabled hybrid code analysis for sample", "hybrid-code-analysis": 1 }|None|None| Example input: @@ -474,18 +474,18 @@ Example output: ``` #### Submit Sample - + This action is used to submit a sample for analysis and return the associated web IDs for the sample ##### Input -|Name|Type|Default|Required|Description|Enum|Example| -| :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|additional_parameters|object|None|False|Additional parameters for Joe Sandbox Cloud, described in more detail in the API documentation. All boolean parameters should be set to 1 or 0. Parameter `accept-tac` will always be set to 1|None|{ "accept-tac": 1, "url-reputation": 0, "export-to-jbxview": 1, "delete-after-days": 30 }| -|cookbook|bytes|None|False|Cookbook to be uploaded together with the sample|None|TVqQAAMAAAAEAAAA//8AALgAAAAAAA...| -|filename|string|None|False|Used to give Joe Sandbox a hint at what file type is being uploaded. File extension (eg .txt, .zip) required|None|example.jpg| -|parameters|object|None|False|Custom sandbox parameters, described in more detail in the API documentation. All boolean parameters should be set to 1 or 0. In case the `cookbook` option is used, most other options are silently ignored since they can be specified inside the cookbook|None|{ "comments": "Enabled hybrid code analysis for sample", "hybrid-code-analysis": 1 }| -|sample|bytes|None|True|The sample to submit|None|TVqQAAMAAAAEAAAA//8AALgAAAAAAA...| +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|additional_parameters|object|None|False|Additional parameters for Joe Sandbox Cloud, described in more detail in the API documentation. All boolean parameters should be set to 1 or 0. Parameter `accept-tac` will always be set to 1|None|{ "accept-tac": 1, "url-reputation": 0, "export-to-jbxview": 1, "delete-after-days": 30 }|None|None| +|cookbook|bytes|None|False|Cookbook to be uploaded together with the sample|None|TVqQAAMAAAAEAAAA//8AALgAAAAAAA...|None|None| +|filename|string|None|False|Used to give Joe Sandbox a hint at what file type is being uploaded. File extension (eg .txt, .zip) required|None|example.jpg|None|None| +|parameters|object|None|False|Custom sandbox parameters, described in more detail in the API documentation. All boolean parameters should be set to 1 or 0. In case the `cookbook` option is used, most other options are silently ignored since they can be specified inside the cookbook|None|{ "comments": "Enabled hybrid code analysis for sample", "hybrid-code-analysis": 1 }|None|None| +|sample|bytes|None|True|The sample to submit|None|TVqQAAMAAAAEAAAA//8AALgAAAAAAA...|None|None| Example input: @@ -511,30 +511,27 @@ Example input: |Name|Type|Required|Description|Example| | :--- | :--- | :--- | :--- | :--- | -|webids|[]string|True|Web IDs associated with the sample|["1234567", "7654321"]| +|submission_id|string|True|Submission ID associated with the sample|1234567| Example output: ``` { - "webids": [ - "1234567", - "7654321" - ] + "submission_id": 1234567 } ``` #### Submit Sample URL - + This action is used to submit a sample at a given URL for analysis and return the associated web IDs for the sample ##### Input -|Name|Type|Default|Required|Description|Enum|Example| -| :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|additional_parameters|object|None|False|Additional parameters for Joe Sandbox Cloud, described in more detail in the API documentation. All boolean parameters should be set to 1 or 0. Parameter `accept-tac` will always be set to 1|None|{ "accept-tac": 1, "url-reputation": 0, "export-to-jbxview": 1, "delete-after-days": 30 }| -|parameters|object|None|False|Custom sandbox parameters, described in more detail in the API documentation. All boolean parameters should be set to 1 or 0|None|{ "comments": "Enabled hybrid code analysis for sample", "hybrid-code-analysis": 1 }| -|sample_url|string|None|True|The URL of a sample to submit|None|https://example.com| +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|additional_parameters|object|None|False|Additional parameters for Joe Sandbox Cloud, described in more detail in the API documentation. All boolean parameters should be set to 1 or 0. Parameter `accept-tac` will always be set to 1|None|{ "accept-tac": 1, "url-reputation": 0, "export-to-jbxview": 1, "delete-after-days": 30 }|None|None| +|parameters|object|None|False|Custom sandbox parameters, described in more detail in the API documentation. All boolean parameters should be set to 1 or 0|None|{ "comments": "Enabled hybrid code analysis for sample", "hybrid-code-analysis": 1 }|None|None| +|sample_url|string|None|True|The URL of a sample to submit|None|https://example.com|None|None| Example input: @@ -569,16 +566,16 @@ Example output: ``` #### Submit URL - + This action is used to submit a website for analysis and return the associated web IDs for the sample ##### Input -|Name|Type|Default|Required|Description|Enum|Example| -| :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|additional_parameters|object|None|False|Additional parameters for Joe Sandbox Cloud, described in more detail in the API documentation. All boolean parameters should be set to 1 or 0. Parameter `accept-tac` will always be set to 1|None|{ "accept-tac": 1, "url-reputation": 0, "export-to-jbxview": 1, "delete-after-days": 30 }| -|parameters|object|None|False|Custom sandbox parameters, described in more detail in the API documentation. All boolean parameters should be set to 1 or 0|None|{ "comments": "Enabled hybrid code analysis for sample", "hybrid-code-analysis": 1 }| -|url|string|None|True|The URL of a website to submit|None|https://example.com| +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|additional_parameters|object|None|False|Additional parameters for Joe Sandbox Cloud, described in more detail in the API documentation. All boolean parameters should be set to 1 or 0. Parameter `accept-tac` will always be set to 1|None|{ "accept-tac": 1, "url-reputation": 0, "export-to-jbxview": 1, "delete-after-days": 30 }|None|None| +|parameters|object|None|False|Custom sandbox parameters, described in more detail in the API documentation. All boolean parameters should be set to 1 or 0|None|{ "comments": "Enabled hybrid code analysis for sample", "hybrid-code-analysis": 1 }|None|None| +|url|string|None|True|The URL of a website to submit|None|https://example.com|None|None| Example input: @@ -611,11 +608,9 @@ Example output: "submission_id": 1001 } ``` - ### Triggers *This plugin does not contain any triggers.* - ### Tasks *This plugin does not contain any tasks.* @@ -705,14 +700,15 @@ Example output: ## Troubleshooting -*There is no troubleshooting for this plugin.* +*This plugin does not contain a troubleshooting.* # Version History +* 3.0.0 - Buffering encoded strings and fixing issues related to the actions | Updated SDK to 6.2.4 version * 2.0.0 - Update `jbxapi` dependency | `List Keyboard Layouts` - Renamed to `List Languages and Locales` | Updated SDK | `Get Submitted Info` - New action * 1.0.4 - Add extra optional input for Submit Sample action * 1.0.3 - Add example inputs -* 1.0.2 - Fix misspelling in error message | Remove generic "automation" keyword +* 1.0.2 - Fix misspelling in error message | Remove generic 'automation' keyword * 1.0.1 - New spec and help.md format for the Extension Library * 1.0.0 - Initial plugin diff --git a/plugins/joe_sandbox/icon_joe_sandbox/actions/get_submitted_info/action.py b/plugins/joe_sandbox/icon_joe_sandbox/actions/get_submitted_info/action.py index b6ab0c9576..71a2b188c7 100644 --- a/plugins/joe_sandbox/icon_joe_sandbox/actions/get_submitted_info/action.py +++ b/plugins/joe_sandbox/icon_joe_sandbox/actions/get_submitted_info/action.py @@ -8,7 +8,7 @@ class GetSubmittedInfo(insightconnect_plugin_runtime.Action): def __init__(self): super(self.__class__, self).__init__( - name="get_submission_info", + name="get_submitted_info", description=Component.DESCRIPTION, input=GetSubmittedInfoInput(), output=GetSubmittedInfoOutput(), diff --git a/plugins/joe_sandbox/icon_joe_sandbox/actions/submit_cookbook/action.py b/plugins/joe_sandbox/icon_joe_sandbox/actions/submit_cookbook/action.py index 5d0133abf6..d049320974 100755 --- a/plugins/joe_sandbox/icon_joe_sandbox/actions/submit_cookbook/action.py +++ b/plugins/joe_sandbox/icon_joe_sandbox/actions/submit_cookbook/action.py @@ -1,3 +1,5 @@ +from io import BytesIO + import insightconnect_plugin_runtime from .schema import SubmitCookbookInput, SubmitCookbookOutput, Input, Output, Component @@ -26,7 +28,7 @@ def run(self, params={}): additional_parameters.update({"accept-tac": 1}) try: - cookbook_bytes = b64decode(cookbook) if cookbook else None + cookbook_bytes = BytesIO(b64decode(cookbook)) if cookbook else None except binascii.Error: raise PluginException( cause='Unable to decode base64 input for "cookbook". ', @@ -34,7 +36,7 @@ def run(self, params={}): ) try: - webids = self.connection.api.submit_cookbook(cookbook_bytes, parameters, additional_parameters) + submission_id = self.connection.api.submit_cookbook(cookbook_bytes, parameters, additional_parameters) except jbxapi.MissingParameterError as error: raise ConnectionTestException( cause=f"An error occurred: {error}", @@ -48,4 +50,4 @@ def run(self, params={}): assistance="If the issue persists please contact support.", ) - return {Output.SUBMISSION_ID: webids.get("submission_id")} + return {Output.SUBMISSION_ID: submission_id.get("submission_id")} diff --git a/plugins/joe_sandbox/icon_joe_sandbox/actions/submit_sample/action.py b/plugins/joe_sandbox/icon_joe_sandbox/actions/submit_sample/action.py index e03a90810c..20cda2ea9d 100755 --- a/plugins/joe_sandbox/icon_joe_sandbox/actions/submit_sample/action.py +++ b/plugins/joe_sandbox/icon_joe_sandbox/actions/submit_sample/action.py @@ -1,3 +1,5 @@ +from io import BytesIO + import insightconnect_plugin_runtime from .schema import SubmitSampleInput, SubmitSampleOutput, Input, Output, Component @@ -28,7 +30,7 @@ def run(self, params={}): if "hybrid-decompilation" not in additional_parameters: additional_parameters.update({"hybrid-decompilation": 0}) try: - sample_bytes = b64decode(sample) + sample_bytes = BytesIO(b64decode(sample)) except binascii.Error: raise PluginException( cause='Unable to decode base64 input for "sample". ', @@ -36,7 +38,7 @@ def run(self, params={}): ) try: - cookbook_bytes = b64decode(cookbook) if cookbook else None + cookbook_bytes = BytesIO(b64decode(cookbook)) if cookbook else None except binascii.Error: raise PluginException( cause='Unable to decode base64 input for "cookbook". ', @@ -45,8 +47,15 @@ def run(self, params={}): if filename: sample_tuple = (filename, sample_bytes) - webids = self.connection.api.submit_sample(sample_tuple, cookbook_bytes, parameters, additional_parameters) + submission_id = self.connection.api.submit_sample( + sample_tuple, cookbook_bytes, parameters, additional_parameters + ) else: - webids = self.connection.api.submit_sample(sample_bytes, cookbook_bytes, parameters, additional_parameters) + submission_id = self.connection.api.submit_sample( + sample_bytes, cookbook_bytes, parameters, additional_parameters + ) + + submission_id_object = submission_id.get("submission_id") + self.logger.info(f"submission_id {submission_id_object}") - return {Output.WEBIDS: webids} + return {Output.SUBMISSION_ID: submission_id_object} diff --git a/plugins/joe_sandbox/icon_joe_sandbox/actions/submit_sample/schema.py b/plugins/joe_sandbox/icon_joe_sandbox/actions/submit_sample/schema.py index 27dedca2a3..141081eea9 100755 --- a/plugins/joe_sandbox/icon_joe_sandbox/actions/submit_sample/schema.py +++ b/plugins/joe_sandbox/icon_joe_sandbox/actions/submit_sample/schema.py @@ -16,7 +16,7 @@ class Input: class Output: - WEBIDS = "webids" + SUBMISSION_ID = "submission_id" class SubmitSampleInput(insightconnect_plugin_runtime.Input): @@ -77,18 +77,15 @@ class SubmitSampleOutput(insightconnect_plugin_runtime.Output): "type": "object", "title": "Variables", "properties": { - "webids": { - "type": "array", - "title": "Web IDs", - "description": "Web IDs associated with the sample", - "items": { - "type": "string" - }, + "submission_id": { + "type": "string", + "title": "Submission ID", + "description": "Submission ID associated with the sample", "order": 1 } }, "required": [ - "webids" + "submission_id" ], "definitions": {} } diff --git a/plugins/joe_sandbox/plugin.spec.yaml b/plugins/joe_sandbox/plugin.spec.yaml index 00e3d42de6..58c18118ec 100644 --- a/plugins/joe_sandbox/plugin.spec.yaml +++ b/plugins/joe_sandbox/plugin.spec.yaml @@ -6,13 +6,13 @@ title: Joe Sandbox description: Joe Sandbox Cloud executes files and URLs fully automated in a controlled environment and monitors the behavior of applications and the operating system for suspicious activities -version: 2.0.0 +version: 3.0.0 supported_versions: ['Joe Sandbox API v2'] connection_version: 2 requirements: ["API Key", "Sandbox server (if not using cloud)"] sdk: type: slim - version: 5.4.4 + version: 6.2.4 user: nobody vendor: rapid7 support: community @@ -34,6 +34,20 @@ hub_tags: use_cases: [application_management, cloud_security, reporting_and_analytics] keywords: [sandbox, malware, analysis] features: [sandbox, analysis] +version_history: + - "3.0.0 - Buffering encoded strings and fixing issues related to the actions | Updated SDK to 6.2.4 version" + - "2.0.0 - Update `jbxapi` dependency | `List Keyboard Layouts` - Renamed to `List Languages and Locales` | Updated SDK | `Get Submitted Info` - New action" + - "1.0.4 - Add extra optional input for Submit Sample action" + - "1.0.3 - Add example inputs" + - "1.0.2 - Fix misspelling in error message | Remove generic 'automation' keyword" + - "1.0.1 - New spec and help.md format for the Extension Library" + - "1.0.0 - Initial plugin" +links: + - "[Joe Sandbox](https://www.joesecurity.org)" +references: + - "[Joe Sandbox API](https://jbxcloud.joesecurity.org/userguide?sphinxurl=usage%2Fwebapi.html)" + - "[Joe Sandbox API wrapper](https://github.com/joesecurity/jbxapi)" + - "[Report formats](https://jbxcloud.joesecurity.org/userguide?sphinxurl=usage/reportformats.html)" types: system: name: @@ -338,11 +352,11 @@ actions: required: false example: '{ "accept-tac": 1, "url-reputation": 0, "export-to-jbxview": 1, "delete-after-days": 30 }' output: - webids: - title: Web IDs - description: Web IDs associated with the sample - type: "[]string" - example: ["1234567", "7654321"] + submission_id: + title: Submission ID + description: Submission ID associated with the sample + type: string + example: "1234567" required: true submit_sample_url: title: Submit Sample URL diff --git a/plugins/joe_sandbox/setup.py b/plugins/joe_sandbox/setup.py index 0e86a735a7..923727b1cd 100755 --- a/plugins/joe_sandbox/setup.py +++ b/plugins/joe_sandbox/setup.py @@ -3,7 +3,7 @@ setup(name="joe_sandbox-rapid7-plugin", - version="2.0.0", + version="3.0.0", description="Joe Sandbox Cloud executes files and URLs fully automated in a controlled environment and monitors the behavior of applications and the operating system for suspicious activities", author="rapid7", author_email="", diff --git a/plugins/joe_sandbox/unit_test/mock.py b/plugins/joe_sandbox/unit_test/mock.py index 0e248f2852..550937c413 100644 --- a/plugins/joe_sandbox/unit_test/mock.py +++ b/plugins/joe_sandbox/unit_test/mock.py @@ -57,6 +57,12 @@ def mock_conditions(url: str, status_code: int) -> MockResponse: return MockResponse("get_server_info", status_code) if url == "https://example.com/v2/submission/info": return MockResponse("get_submitted_info", status_code) + if url == "https://example.com/v2/submission/new": + return MockResponse("submit_sample", status_code) + if url == "https://example.com/v2/submission/chunked-sample": + return MockResponse("chunked_sample", status_code) + if url == "https://example.com/v2/submission/info": + return MockResponse("get_submitted_info", status_code) if url == "https://example.com/v2/analysis/list": return MockResponse("list_analysis", status_code) if url == "https://example.com/v2/server/lia_countries": diff --git a/plugins/joe_sandbox/unit_test/responses/chunked_sample.json.resp b/plugins/joe_sandbox/unit_test/responses/chunked_sample.json.resp new file mode 100644 index 0000000000..c93893f42c --- /dev/null +++ b/plugins/joe_sandbox/unit_test/responses/chunked_sample.json.resp @@ -0,0 +1,6 @@ +{ + "data": { + "apikey": "abcdef", + "submission_id": "12345" + } +} diff --git a/plugins/joe_sandbox/unit_test/responses/get_submitted_info.json.resp b/plugins/joe_sandbox/unit_test/responses/get_submitted_info.json.resp new file mode 100644 index 0000000000..9494a78b03 --- /dev/null +++ b/plugins/joe_sandbox/unit_test/responses/get_submitted_info.json.resp @@ -0,0 +1,57 @@ +{ + "data": { + "submission_info": { + "analyses": [ + { + "analysisid": "1111", + "classification": "", + "comments": "", + "detection": "clean", + "duration": 595, + "encrypted": false, + "filename": "test.csv", + "has_malwareconfig": false, + "md5": "df7761075b3e745e58ae6c9607721d04", + "runs": [ + { + "detection": "clean", + "error": null, + "score": 0, + "sigma": false, + "suricata": false, + "system": "w10x64_21h1_office", + "yara": false + }, + { + "detection": "clean", + "error": null, + "score": 0, + "sigma": false, + "suricata": false, + "system": "w7x64_office", + "yara": false + } + ], + "score": 0, + "scriptname": "default.jbs", + "sha1": "111", + "sha256": "1111", + "status": "finished", + "tags": [], + "threatname": "", + "time": "2025-02-04T15:44:08+01:00", + "webid": "1111" + } + ], + "most_relevant_analysis": { + "detection": "clean", + "score": 0, + "webid": "1111" + }, + "name": "test.csv", + "status": "finished", + "submission_id": "12345", + "time": "2025-02-04T15:44:06+01:00" + } + } +} diff --git a/plugins/joe_sandbox/unit_test/responses/submit_sample.json.resp b/plugins/joe_sandbox/unit_test/responses/submit_sample.json.resp new file mode 100644 index 0000000000..fe52f8002f --- /dev/null +++ b/plugins/joe_sandbox/unit_test/responses/submit_sample.json.resp @@ -0,0 +1,5 @@ +{ + "data": { + "submission_id": "12345" + } +} diff --git a/plugins/joe_sandbox/unit_test/test_get_submitted_info.py b/plugins/joe_sandbox/unit_test/test_get_submitted_info.py new file mode 100644 index 0000000000..aceb81a073 --- /dev/null +++ b/plugins/joe_sandbox/unit_test/test_get_submitted_info.py @@ -0,0 +1,88 @@ +import sys +import os + +sys.path.append(os.path.abspath("../")) + +from unittest import TestCase +from unittest.mock import patch +from icon_joe_sandbox.actions.get_submitted_info.action import GetSubmittedInfo +from icon_joe_sandbox.actions.get_submitted_info.schema import Input, Output +from jsonschema import validate +from mock import Util, mock_request_200, mocked_request, MagicMock + + +class TestGetSubmittedInfo(TestCase): + @patch("requests.request", side_effect=mock_request_200) + def setUp(self, mock_client) -> None: + self.action = Util.default_connector(GetSubmittedInfo()) + self.params = {Input.SUBMISSION_ID: "12345"} + + @patch("requests.request", side_effect=mock_request_200) + def test_get_submitted_info(self, mock_get) -> None: + mocked_request(mock_get) + response = self.action.run(self.params) + expected = { + Output.SUBMISSION_INFO: { + "submission_info": { + "analyses": [ + { + "analysisid": "1111", + "classification": "", + "comments": "", + "detection": "clean", + "duration": 595, + "encrypted": False, + "filename": "test.csv", + "has_malwareconfig": False, + "md5": "df7761075b3e745e58ae6c9607721d04", + "runs": [ + { + "detection": "clean", + "error": None, + "score": 0, + "sigma": False, + "suricata": False, + "system": "w10x64_21h1_office", + "yara": False, + }, + { + "detection": "clean", + "error": None, + "score": 0, + "sigma": False, + "suricata": False, + "system": "w7x64_office", + "yara": False, + }, + ], + "score": 0, + "scriptname": "default.jbs", + "sha1": "111", + "sha256": "1111", + "status": "finished", + "tags": [], + "threatname": "", + "time": "2025-02-04T15:44:08+01:00", + "webid": "1111", + } + ], + "most_relevant_analysis": { + "detection": "clean", + "score": 0, + "webid": "1111", + }, + "name": "test.csv", + "status": "finished", + "submission_id": "12345", + "time": "2025-02-04T15:44:06+01:00", + }, + "most_relevant_analysis": { + "webid": "running", + "detection": "running", + "score": "running", + }, + } + } + + validate(response, self.action.output.schema) + self.assertEqual(response, expected) diff --git a/plugins/joe_sandbox/unit_test/test_submit_cookbook.py b/plugins/joe_sandbox/unit_test/test_submit_cookbook.py new file mode 100644 index 0000000000..109f1f7708 --- /dev/null +++ b/plugins/joe_sandbox/unit_test/test_submit_cookbook.py @@ -0,0 +1,27 @@ +import sys +import os + +sys.path.append(os.path.abspath("../")) + +from unittest import TestCase +from unittest.mock import patch +from icon_joe_sandbox.actions.submit_cookbook.action import SubmitCookbook +from icon_joe_sandbox.actions.submit_cookbook.schema import Input, Output +from jsonschema import validate +from mock import Util, mock_request_200, mocked_request, MagicMock + + +class TestSubmitCookbook(TestCase): + @patch("requests.request", side_effect=mock_request_200) + def setUp(self, mock_client) -> None: + self.action = Util.default_connector(SubmitCookbook()) + self.params = {Input.COOKBOOK: "VGVzdA=="} + + @patch("requests.request", side_effect=mock_request_200) + def test_submit_cookbook(self, mock_get) -> None: + mocked_request(mock_get) + response = self.action.run(self.params) + expected = {Output.SUBMISSION_ID: "12345"} + + validate(response, self.action.output.schema) + self.assertEqual(response, expected) diff --git a/plugins/joe_sandbox/unit_test/test_submit_sample.py b/plugins/joe_sandbox/unit_test/test_submit_sample.py new file mode 100644 index 0000000000..c9e9e93796 --- /dev/null +++ b/plugins/joe_sandbox/unit_test/test_submit_sample.py @@ -0,0 +1,30 @@ +import sys +import os + +sys.path.append(os.path.abspath("../")) + +from unittest import TestCase +from unittest.mock import patch +from icon_joe_sandbox.actions.submit_sample.action import SubmitSample +from icon_joe_sandbox.actions.submit_sample.schema import Input, Output +from jsonschema import validate +from mock import Util, mock_request_200, mocked_request, MagicMock + + +class TestSubmitSample(TestCase): + @patch("requests.request", side_effect=mock_request_200) + def setUp(self, mock_client) -> None: + self.action = Util.default_connector(SubmitSample()) + self.params = { + Input.FILENAME: "test.csv", + Input.SAMPLE: "VGVzdA==", + } + + @patch("requests.request", side_effect=mock_request_200) + def test_submit_sample(self, mock_get: MagicMock) -> None: + mocked_request(mock_get) + response = self.action.run(self.params) + expected = {Output.SUBMISSION_ID: "12345"} + + validate(response, self.action.output.schema) + self.assertEqual(response, expected)