From f17f067fb9be26f44147e4a4b2703426ac15fc91 Mon Sep 17 00:00:00 2001 From: garanews Date: Mon, 5 Oct 2020 12:11:44 +0200 Subject: [PATCH 01/25] Update URLhaus_analyzer.py --- analyzers/URLhaus/URLhaus_analyzer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/analyzers/URLhaus/URLhaus_analyzer.py b/analyzers/URLhaus/URLhaus_analyzer.py index 2bf5f2276..e68bd4887 100755 --- a/analyzers/URLhaus/URLhaus_analyzer.py +++ b/analyzers/URLhaus/URLhaus_analyzer.py @@ -35,7 +35,8 @@ def summary(self, raw): namespace = "URLhaus" if raw['query_status'] == 'no_results' \ - or raw['query_status'] == 'ok' and raw['md5_hash'] == None and raw['sha256_hash'] == None: + or (raw['query_status'] == 'ok' and not raw.get('md5_hash', None) \ + and not raw.get('sha256_hash', None)): taxonomies.append(self.build_taxonomy( 'info', namespace, From ee2e589616594f5b2841695ba45db68724238a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leonard?= Date: Thu, 15 Oct 2020 15:25:04 +0200 Subject: [PATCH 02/25] #882 build and push report-templates package on new server --- .drone.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index c9409745c..61cf07270 100644 --- a/.drone.yml +++ b/.drone.yml @@ -57,6 +57,14 @@ steps: when: event: [tag] + - name: build report-templates zip package + image: thehiveproject/neurons-build-report-templates + when: + event: [tag] + + +# Bintray will not be used anymore. We keep it until Feb 21 + - name: upload catalogs to bintray image: thehiveproject/drone-bintray settings: @@ -91,7 +99,8 @@ steps: when: event: [tag] - - name: upload catalogs to package server + + - name: upload catalogs and report-templates package to package server image: appleboy/drone-scp settings: host: {from_secret: package_host} @@ -103,6 +112,7 @@ steps: - analyzers/analyzers-stable.json - responders/responders.json - responders/responders-stable.json + - report-templates.zip strip_components: 1 when: event: [tag] @@ -112,6 +122,8 @@ steps: when: branch: [develop] + +# Bintray will not be used anymore. We keep it until Feb 21 - name: upload devel catalogs to bintray image: thehiveproject/drone-bintray settings: From 09c3f39e453ff12f7bd12ee49e81cef8dc095db7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leonard?= Date: Fri, 16 Oct 2020 12:08:11 +0200 Subject: [PATCH 03/25] #882 improve process --- .drone.yml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 61cf07270..495585ff8 100644 --- a/.drone.yml +++ b/.drone.yml @@ -99,6 +99,30 @@ steps: when: event: [tag] + - name: upload report-templates to bintray + image: thehiveproject/drone-bintray + settings: + user: {from_secret: bintray_user} + key: {from_secret: bintray_key} + subject: thehive-project + package: report-templates + version: latest + override: 1 + publish: 1 + commands: + - | + export PLUGIN_USER + export PLUGIN_KEY + export PLUGIN_SUBJECT + export PLUGIN_PACKAGE + export PLUGIN_VERSION + export PLUGIN_OVERRIDE + export PLUGIN_PUBLISH + upload \ + --file analyzers/report-templates.zip \ + --repo binary + when: + event: [tag] - name: upload catalogs and report-templates package to package server image: appleboy/drone-scp @@ -112,7 +136,7 @@ steps: - analyzers/analyzers-stable.json - responders/responders.json - responders/responders-stable.json - - report-templates.zip + - analyzers/report-templates.zip strip_components: 1 when: event: [tag] From 00a5ced3cb7f53fb109f7ad352bb8e2cfdd427d5 Mon Sep 17 00:00:00 2001 From: garanews Date: Tue, 20 Oct 2020 11:48:21 +0200 Subject: [PATCH 04/25] edit shebang for python3 edit shebang for python3 --- analyzers/MISPWarningLists/warninglists_create_db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analyzers/MISPWarningLists/warninglists_create_db.py b/analyzers/MISPWarningLists/warninglists_create_db.py index 663b19f0b..3d43dca4d 100755 --- a/analyzers/MISPWarningLists/warninglists_create_db.py +++ b/analyzers/MISPWarningLists/warninglists_create_db.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # coding: utf-8 import re From 06e06b37a31ee24341b6ae278880eb103b980717 Mon Sep 17 00:00:00 2001 From: garanews Date: Tue, 20 Oct 2020 11:52:21 +0200 Subject: [PATCH 05/25] added tqdm in requirements tqdm is used warninglists_create_db.py --- analyzers/MISPWarningLists/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/analyzers/MISPWarningLists/requirements.txt b/analyzers/MISPWarningLists/requirements.txt index 10975ab77..16edc58c8 100644 --- a/analyzers/MISPWarningLists/requirements.txt +++ b/analyzers/MISPWarningLists/requirements.txt @@ -4,3 +4,4 @@ ipaddress tld sqlalchemy psycopg2-binary +tqdm From 677c830713eeaaaf45c9afd4011b852271224e5c Mon Sep 17 00:00:00 2001 From: staf711 <40694301+staf711@users.noreply.github.com> Date: Tue, 20 Oct 2020 20:52:55 +0300 Subject: [PATCH 06/25] =?UTF-8?q?=D1=84=D0=B2=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Block_ip.py | 51 ++++++++++++++ ...aloAltoNGFW_block_external_IP_address.json | 55 +++++++++++++++ .../README.md | 21 ++++++ .../Block_domain.py | 51 ++++++++++++++ .../PaloAltoNGFW_block_external_domain.json | 55 +++++++++++++++ .../README.md | 21 ++++++ .../Block_port.py | 54 +++++++++++++++ .../PaloAltoNGFW_block_external_port.json | 55 +++++++++++++++ .../README.md | 23 +++++++ .../Block_url.py | 46 +++++++++++++ .../PaloAltoNGFW_block_external_url.json | 55 +++++++++++++++ .../PaloAltoNGFW_block_external_url/README.md | 19 ++++++ .../Block_ip.py | 51 ++++++++++++++ ...aloAltoNGFW_block_internal_IP_address.json | 55 +++++++++++++++ .../README.md | 21 ++++++ .../Block_domain.py | 51 ++++++++++++++ .../PaloAltoNGFW_block_internal_domain.json | 55 +++++++++++++++ .../README.md | 21 ++++++ .../Block_port.py | 54 +++++++++++++++ .../PaloAltoNGFW_block_internal_port.json | 55 +++++++++++++++ .../README.md | 23 +++++++ .../Block_url.py | 46 +++++++++++++ .../PaloAltoNGFW_block_internal_url.json | 55 +++++++++++++++ .../PaloAltoNGFW_block_internal_url/README.md | 21 ++++++ .../PaloAltoNGFW_unblock_domain.json | 62 +++++++++++++++++ .../PaloAltoNGFW_unblock_domain/README.md | 18 +++++ .../Unblock_domain.py | 61 +++++++++++++++++ .../PaloAltoNGFW_unblock_ip.json | 62 +++++++++++++++++ responders/PaloAltoNGFW_unblock_ip/README.md | 18 +++++ .../PaloAltoNGFW_unblock_ip/Unblock_ip.py | 61 +++++++++++++++++ .../.Unblock_port.py.swp | Bin 0 -> 12288 bytes .../PaloAltoNGFW_unblock_port.json | 62 +++++++++++++++++ .../PaloAltoNGFW_unblock_port/README.md | 19 ++++++ .../PaloAltoNGFW_unblock_port/Unblock_port.py | 63 ++++++++++++++++++ 34 files changed, 1440 insertions(+) create mode 100644 responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py create mode 100644 responders/PaloAltoNGFW_block_external_IP_address/PaloAltoNGFW_block_external_IP_address.json create mode 100644 responders/PaloAltoNGFW_block_external_IP_address/README.md create mode 100644 responders/PaloAltoNGFW_block_external_domain/Block_domain.py create mode 100644 responders/PaloAltoNGFW_block_external_domain/PaloAltoNGFW_block_external_domain.json create mode 100644 responders/PaloAltoNGFW_block_external_domain/README.md create mode 100644 responders/PaloAltoNGFW_block_external_port/Block_port.py create mode 100644 responders/PaloAltoNGFW_block_external_port/PaloAltoNGFW_block_external_port.json create mode 100644 responders/PaloAltoNGFW_block_external_port/README.md create mode 100644 responders/PaloAltoNGFW_block_external_url/Block_url.py create mode 100644 responders/PaloAltoNGFW_block_external_url/PaloAltoNGFW_block_external_url.json create mode 100644 responders/PaloAltoNGFW_block_external_url/README.md create mode 100644 responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py create mode 100644 responders/PaloAltoNGFW_block_internal_IP_address/PaloAltoNGFW_block_internal_IP_address.json create mode 100644 responders/PaloAltoNGFW_block_internal_IP_address/README.md create mode 100644 responders/PaloAltoNGFW_block_internal_domain/Block_domain.py create mode 100644 responders/PaloAltoNGFW_block_internal_domain/PaloAltoNGFW_block_internal_domain.json create mode 100644 responders/PaloAltoNGFW_block_internal_domain/README.md create mode 100644 responders/PaloAltoNGFW_block_internal_port/Block_port.py create mode 100644 responders/PaloAltoNGFW_block_internal_port/PaloAltoNGFW_block_internal_port.json create mode 100644 responders/PaloAltoNGFW_block_internal_port/README.md create mode 100644 responders/PaloAltoNGFW_block_internal_url/Block_url.py create mode 100644 responders/PaloAltoNGFW_block_internal_url/PaloAltoNGFW_block_internal_url.json create mode 100644 responders/PaloAltoNGFW_block_internal_url/README.md create mode 100644 responders/PaloAltoNGFW_unblock_domain/PaloAltoNGFW_unblock_domain.json create mode 100644 responders/PaloAltoNGFW_unblock_domain/README.md create mode 100644 responders/PaloAltoNGFW_unblock_domain/Unblock_domain.py create mode 100644 responders/PaloAltoNGFW_unblock_ip/PaloAltoNGFW_unblock_ip.json create mode 100644 responders/PaloAltoNGFW_unblock_ip/README.md create mode 100644 responders/PaloAltoNGFW_unblock_ip/Unblock_ip.py create mode 100644 responders/PaloAltoNGFW_unblock_port/.Unblock_port.py.swp create mode 100644 responders/PaloAltoNGFW_unblock_port/PaloAltoNGFW_unblock_port.json create mode 100644 responders/PaloAltoNGFW_unblock_port/README.md create mode 100644 responders/PaloAltoNGFW_unblock_port/Unblock_port.py diff --git a/responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py b/responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py new file mode 100644 index 000000000..da280475c --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Block_ip(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_external_Address_Group = self.get_param('config.name_external_Address_Group') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'ip' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressObject.refreshall(fw) + if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): + new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked ip address") + fw.add(new_ioc_object) + new_ioc_object.create() + panos.objects.AddressGroup.refreshall(fw) + block_list = fw.find(self.name_external_Address_Group, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc not in ioc_list: + ioc_list.append(ioc) + temp1 = panos.objects.AddressGroup(self.name_external_Address_Group, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Block_ip().run() diff --git a/responders/PaloAltoNGFW_block_external_IP_address/PaloAltoNGFW_block_external_IP_address.json b/responders/PaloAltoNGFW_block_external_IP_address/PaloAltoNGFW_block_external_IP_address.json new file mode 100644 index 000000000..761727b33 --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_IP_address/PaloAltoNGFW_block_external_IP_address.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_block_external_IP_address", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Block external IP address", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_block_external_IP_address/Block_ip.py", + "baseConfig": "PaloAltoNGFW_block_external_IP_address", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_external_Address_Group", + "description": "name_external_Address_Group", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_block_external_IP_address/README.md b/responders/PaloAltoNGFW_block_external_IP_address/README.md new file mode 100644 index 000000000..e58e9dd68 --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_IP_address/README.md @@ -0,0 +1,21 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_Address_Group". +https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added AddressObject. +3. if ioc not in AddressObject, will add +4. if ioc in AddressObject, next step +5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_external_domain/Block_domain.py b/responders/PaloAltoNGFW_block_external_domain/Block_domain.py new file mode 100644 index 000000000..b1557d77f --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_domain/Block_domain.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Block_domain(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_external_Address_Group_for_domain = self.get_param('config.name_external_Address_Group') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'hostname' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressObject.refreshall(fw) + if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): + new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked fqdn",type="fqdn") + fw.add(new_ioc_object) + new_ioc_object.create() + panos.objects.AddressGroup.refreshall(fw) + block_list = fw.find(self.name_external_Address_Group_for_domain, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc not in ioc_list: + ioc_list.append(ioc) + temp1 = panos.objects.AddressGroup(self.name_external_Address_Group_for_domain, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Block_domain().run() diff --git a/responders/PaloAltoNGFW_block_external_domain/PaloAltoNGFW_block_external_domain.json b/responders/PaloAltoNGFW_block_external_domain/PaloAltoNGFW_block_external_domain.json new file mode 100644 index 000000000..28de7ece6 --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_domain/PaloAltoNGFW_block_external_domain.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_block_external_domain", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Block external domain", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_block_external_domain/Block_domain.py", + "baseConfig": "PaloAltoNGFW_block_external_domain", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_external_Address_Group", + "description": "name_external_Address_Group_for_domain", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_block_external_domain/README.md b/responders/PaloAltoNGFW_block_external_domain/README.md new file mode 100644 index 000000000..dfa67ff6d --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_domain/README.md @@ -0,0 +1,21 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_Address_Group". +https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added AddressObject. +3. if ioc not in AddressObject, will add +4. if ioc in AddressObject, next step +5. checks if there is already a blocking list (Address_Group), if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_external_port/Block_port.py b/responders/PaloAltoNGFW_block_external_port/Block_port.py new file mode 100644 index 000000000..6f1a919bc --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_port/Block_port.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects +import re +class Block_port(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_external_Service_Group = self.get_param('config.name_external_Service_Group') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + data_list=[] + data=None + for i in response.json().get("artifacts"): + if "'port'," in str(i): + ioc = i.get("data") + data_list.append(i.get("data")) + elif "'protocol'," in str(i): + ioc = i.get("data") + data_list.append(i.get("data")) + data=" ".join(data_list) + protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(data)); port="".join(port) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.ServiceObject.refreshall(fw) + if port not in str(fw.find(port, panos.objects.ServiceObject)): + new_port_object = panos.objects.ServiceObject(port, protocol, description="Blocked port",destination_port=port) + fw.add(new_port_object) + new_port_object.create() + + + panos.objects.ServiceGroup.refreshall(fw) + block_list = fw.find(self.name_external_Service_Group, panos.objects.ServiceGroup) + port_list = block_list.about().get('value') + if port not in port_list: + port_list.append(port) + temp1 = panos.objects.ServiceGroup(self.name_external_Service_Group, value=port_list) + fw.add(temp1) + temp1.apply() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Block_port().run() diff --git a/responders/PaloAltoNGFW_block_external_port/PaloAltoNGFW_block_external_port.json b/responders/PaloAltoNGFW_block_external_port/PaloAltoNGFW_block_external_port.json new file mode 100644 index 000000000..540be6dc7 --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_port/PaloAltoNGFW_block_external_port.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_block_external_port", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Block external port", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_block_external_port/Block_port.py", + "baseConfig": "PaloAltoNGFW_block_external_port", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_external_Service_Group", + "description": "name_external_Service_Group", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_block_external_port/README.md b/responders/PaloAltoNGFW_block_external_port/README.md new file mode 100644 index 000000000..9b84128e4 --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_port/README.md @@ -0,0 +1,23 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_Service_Group". + +First: you need add field "port" and "protocol" to "Observable types management" in the hive. +or you can change script and call your field names + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added Service_Group. +3. if ioc not in Service_Group, will add field port and protocol +4. if ioc in Service_Group, next step +5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_external_url/Block_url.py b/responders/PaloAltoNGFW_block_external_url/Block_url.py new file mode 100644 index 000000000..33eb834ad --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_url/Block_url.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Block_url(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_external_URL_category = self.get_param('config.name_external_URL_category') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'url' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.CustomUrlCategory.refreshall(fw) + block_list = fw.find(self.name_external_URL_category, panos.objects.CustomUrlCategory) + ioc_list = block_list.about().get('url_value') + if ioc not in ioc_list: + ioc_list.append(ioc) + temp1 = panos.objects.CustomUrlCategory(self.name_external_URL_category, url_value=ioc_list) + fw.add(temp1) + temp1.create() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Block_url().run() diff --git a/responders/PaloAltoNGFW_block_external_url/PaloAltoNGFW_block_external_url.json b/responders/PaloAltoNGFW_block_external_url/PaloAltoNGFW_block_external_url.json new file mode 100644 index 000000000..fbeee7697 --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_url/PaloAltoNGFW_block_external_url.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_block_external_url", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Block external domain", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_block_external_url/Block_url.py", + "baseConfig": "PaloAltoNGFW_block_external_url", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_external_URL_category", + "description": "name_external_URL_category", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_block_external_url/README.md b/responders/PaloAltoNGFW_block_external_url/README.md new file mode 100644 index 000000000..a97c170ef --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_url/README.md @@ -0,0 +1,19 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_URL_category". + + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added URL_category. +3. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py b/responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py new file mode 100644 index 000000000..6a0db4d52 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Block_ip(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_Address_Group = self.get_param('config.name_internal_Address_Group') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'ip' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressObject.refreshall(fw) + if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): + new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked ip address") + fw.add(new_ioc_object) + new_ioc_object.create() + panos.objects.AddressGroup.refreshall(fw) + block_list = fw.find(self.name_internal_Address_Group, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc not in ioc_list: + ioc_list.append(ioc) + temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Block_ip().run() diff --git a/responders/PaloAltoNGFW_block_internal_IP_address/PaloAltoNGFW_block_internal_IP_address.json b/responders/PaloAltoNGFW_block_internal_IP_address/PaloAltoNGFW_block_internal_IP_address.json new file mode 100644 index 000000000..36ef81cd9 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_IP_address/PaloAltoNGFW_block_internal_IP_address.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_block_internal_IP_address", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Block internal IP address", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_block_internal_IP_address/Block_ip.py", + "baseConfig": "PaloAltoNGFW_block_internal_IP_address", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_internal_Address_Group", + "description": "name_internal_Address_Group", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_block_internal_IP_address/README.md b/responders/PaloAltoNGFW_block_internal_IP_address/README.md new file mode 100644 index 000000000..e58e9dd68 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_IP_address/README.md @@ -0,0 +1,21 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_Address_Group". +https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added AddressObject. +3. if ioc not in AddressObject, will add +4. if ioc in AddressObject, next step +5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_domain/Block_domain.py b/responders/PaloAltoNGFW_block_internal_domain/Block_domain.py new file mode 100644 index 000000000..cb1d1ce96 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_domain/Block_domain.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Block_domain(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_Address_Group_for_domain = self.get_param('config.name_internal_Address_Group') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'hostname' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressObject.refreshall(fw) + if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): + new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked fqdn",type="fqdn") + fw.add(new_ioc_object) + new_ioc_object.create() + panos.objects.AddressGroup.refreshall(fw) + block_list = fw.find(self.name_internal_Address_Group_for_domain, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc not in ioc_list: + ioc_list.append(ioc) + temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group_for_domain, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Block_domain().run() diff --git a/responders/PaloAltoNGFW_block_internal_domain/PaloAltoNGFW_block_internal_domain.json b/responders/PaloAltoNGFW_block_internal_domain/PaloAltoNGFW_block_internal_domain.json new file mode 100644 index 000000000..e52db2720 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_domain/PaloAltoNGFW_block_internal_domain.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_block_internal_domain", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Block internal domain", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_block_internal_domain/Block_domain.py", + "baseConfig": "PaloAltoNGFW_block_internal_domain", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_internal_Address_Group", + "description": "name_internal_Address_Group_for_domain", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_block_internal_domain/README.md b/responders/PaloAltoNGFW_block_internal_domain/README.md new file mode 100644 index 000000000..bda74a5f2 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_domain/README.md @@ -0,0 +1,21 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Address_Group_for_domain". +https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added AddressObject. +3. if ioc not in AddressObject, will add +4. if ioc in AddressObject, next step +5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_port/Block_port.py b/responders/PaloAltoNGFW_block_internal_port/Block_port.py new file mode 100644 index 000000000..3d2e00fa1 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_port/Block_port.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects +import re +class Block_port(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_Service_Group = self.get_param('config.name_internal_Service_Group') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + data_list=[] + data=None + for i in response.json().get("artifacts"): + if "'port'," in str(i): + ioc = i.get("data") + data_list.append(i.get("data")) + elif "'protocol'," in str(i): + ioc = i.get("data") + data_list.append(i.get("data")) + data=" ".join(data_list) + protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(data)); port="".join(port) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.ServiceObject.refreshall(fw) + if port not in str(fw.find(port, panos.objects.ServiceObject)): + new_port_object = panos.objects.ServiceObject(port, protocol, description="Blocked port",destination_port=port) + fw.add(new_port_object) + new_port_object.create() + + + panos.objects.ServiceGroup.refreshall(fw) + block_list = fw.find(self.name_internal_Service_Group, panos.objects.ServiceGroup) + port_list = block_list.about().get('value') + if port not in port_list: + port_list.append(port) + temp1 = panos.objects.ServiceGroup(self.name_internal_Service_Group, value=port_list) + fw.add(temp1) + temp1.apply() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Block_port().run() diff --git a/responders/PaloAltoNGFW_block_internal_port/PaloAltoNGFW_block_internal_port.json b/responders/PaloAltoNGFW_block_internal_port/PaloAltoNGFW_block_internal_port.json new file mode 100644 index 000000000..e2b3c94dc --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_port/PaloAltoNGFW_block_internal_port.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_block_internal_port", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Block internal port", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_block_internal_port/Block_port.py", + "baseConfig": "PaloAltoNGFW_block_internal_port", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_internal_Service_Group", + "description": "name_internal_Service_Group", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_block_internal_port/README.md b/responders/PaloAltoNGFW_block_internal_port/README.md new file mode 100644 index 000000000..ef1df5628 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_port/README.md @@ -0,0 +1,23 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Service_Group". + +First: you need add field "port" and "protocol" to "Observable types management" in the hive. +or you can change script and call your field names + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added Service_Group. +3. if ioc not in Service_Group, will add field port and protocol +4. if ioc in Service_Group, next step +5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_url/Block_url.py b/responders/PaloAltoNGFW_block_internal_url/Block_url.py new file mode 100644 index 000000000..39793efef --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_url/Block_url.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Block_url(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_URL_category = self.get_param('config.name_internal_URL_category') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'url' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.CustomUrlCategory.refreshall(fw) + block_list = fw.find(self.name_internal_URL_category, panos.objects.CustomUrlCategory) + ioc_list = block_list.about().get('url_value') + if ioc not in ioc_list: + ioc_list.append(ioc) + temp1 = panos.objects.CustomUrlCategory(self.name_internal_URL_category, url_value=ioc_list) + fw.add(temp1) + temp1.create() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Block_url().run() diff --git a/responders/PaloAltoNGFW_block_internal_url/PaloAltoNGFW_block_internal_url.json b/responders/PaloAltoNGFW_block_internal_url/PaloAltoNGFW_block_internal_url.json new file mode 100644 index 000000000..04258ecd7 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_url/PaloAltoNGFW_block_internal_url.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_block_internal_url", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Block internal domain", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_block_internal_url/Block_url.py", + "baseConfig": "PaloAltoNGFW_block_internal_url", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_internal_URL_category", + "description": "name_internal_URL_category", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_block_internal_url/README.md b/responders/PaloAltoNGFW_block_internal_url/README.md new file mode 100644 index 000000000..bda74a5f2 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_url/README.md @@ -0,0 +1,21 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Address_Group_for_domain". +https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added AddressObject. +3. if ioc not in AddressObject, will add +4. if ioc in AddressObject, next step +5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_domain/PaloAltoNGFW_unblock_domain.json b/responders/PaloAltoNGFW_unblock_domain/PaloAltoNGFW_unblock_domain.json new file mode 100644 index 000000000..e93782451 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_domain/PaloAltoNGFW_unblock_domain.json @@ -0,0 +1,62 @@ +{ + "name": "PaloAltoNGFW_unblock_domain", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Unblock domain", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_unblock_domain/Unblock_domain.py", + "baseConfig": "PaloAltoNGFW_unblock_domain", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_internal_Address_Group", + "description": "name_internal_Address_Group_for_domain", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_external_Address_Group", + "description": "name_external_Address_Group_for_domain", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_unblock_domain/README.md b/responders/PaloAltoNGFW_unblock_domain/README.md new file mode 100644 index 000000000..cfa6e002f --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_domain/README.md @@ -0,0 +1,18 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Address_Group_for_domain" and "name_external_Address_Group_for_domain" + +principle of operation: +1. the value is selected from the alert the hive. +2. if ioc added in Address_Groups, script deleted ioc +3. if ioc in AddressObject, script deleted ioc \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_domain/Unblock_domain.py b/responders/PaloAltoNGFW_unblock_domain/Unblock_domain.py new file mode 100644 index 000000000..8b4c96e54 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_domain/Unblock_domain.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Unblock_domain(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_Address_Group_for_domain = self.get_param('config.name_internal_Address_Group') + self.name_external_Address_Group_for_domain = self.get_param('config.name_external_Address_Group') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'hostname' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressGroup.refreshall(fw) + block_list = fw.find(self.name_internal_Address_Group_for_domain, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc in ioc_list: + ioc_list.remove(ioc) + temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group_for_domain, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + + block_list = fw.find(self.name_external_Address_Group_for_domain, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc in ioc_list: + ioc_list.remove(ioc) + temp1 = panos.objects.AddressGroup(self.name_external_Address_Group_for_domain, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + + panos.objects.AddressObject.refreshall(fw) + if ioc in str(fw.find(ioc, panos.objects.AddressObject)): + deleted_ioc = fw.find(ioc, panos.objects.AddressObject) + deleted_ioc.delete() + + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Unblock_domain().run() diff --git a/responders/PaloAltoNGFW_unblock_ip/PaloAltoNGFW_unblock_ip.json b/responders/PaloAltoNGFW_unblock_ip/PaloAltoNGFW_unblock_ip.json new file mode 100644 index 000000000..b5c2bacb6 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_ip/PaloAltoNGFW_unblock_ip.json @@ -0,0 +1,62 @@ +{ + "name": "PaloAltoNGFW_unblock_ip", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Unblock ip", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_unblock_ip/Unblock_ip.py", + "baseConfig": "PaloAltoNGFW_unblock_ip", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_internal_Address_Group", + "description": "name_internal_Address_Group_for_ip", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_external_Address_Group", + "description": "name_external_Address_Group_for_ip", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_unblock_ip/README.md b/responders/PaloAltoNGFW_unblock_ip/README.md new file mode 100644 index 000000000..0ff66431e --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_ip/README.md @@ -0,0 +1,18 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Address_Group_" and "name_external_Address_Group" + +principle of operation: +1. the value is selected from the alert the hive. +2. if ioc added in Address_Groups, script deleted ioc +3. if ioc in AddressObject, script deleted ioc \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_ip/Unblock_ip.py b/responders/PaloAltoNGFW_unblock_ip/Unblock_ip.py new file mode 100644 index 000000000..2fae0f761 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_ip/Unblock_ip.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Unblock_ip(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_Address_Group = self.get_param('config.name_internal_Address_Group') + self.name_external_Address_Group = self.get_param('config.name_external_Address_Group') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'ip' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressGroup.refreshall(fw) + block_list = fw.find(self.name_internal_Address_Group, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc in ioc_list: + ioc_list.remove(ioc) + temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + + block_list = fw.find(self.name_external_Address_Group, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc in ioc_list: + ioc_list.remove(ioc) + temp1 = panos.objects.AddressGroup(self.name_external_Address_Group, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + + panos.objects.AddressObject.refreshall(fw) + if ioc in str(fw.find(ioc, panos.objects.AddressObject)): + deleted_ioc = fw.find(ioc, panos.objects.AddressObject) + deleted_ioc.delete() + + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Unblock_ip().run() diff --git a/responders/PaloAltoNGFW_unblock_port/.Unblock_port.py.swp b/responders/PaloAltoNGFW_unblock_port/.Unblock_port.py.swp new file mode 100644 index 0000000000000000000000000000000000000000..250cf29671ef19c5b0df4056331e4c2003749a86 GIT binary patch literal 12288 zcmeHNO=u)V7_HS^*T2=(1qJcYJ3)HJo%Cdl$Qm7EknC>M-GrDZVOiSBbahfmPgh%A zlVnyz1i^y`FM1LL5icG*i(Wl=5Y~%&6Ff<-i$_^})qm47naS)y#FZ*|GgZ}Jz543) zS6@v?txvtaaLGF7Oc9imgxom(k^A|3kCN%P2$4c4-94@ZqD6yE5i2LDd7@2uIAl;m zM5^(Ukc#b1&V@ASUSl$DNESyT^mKKJ24XHy;_`*_Z@8Us9dz4ngaM7!Qp1V5L&!~+ zQNSoLMu8J#`l++YR-dSxwoW~~I>z2SHVPO8i~>dhqkvJsC}0#Y3K#|cPYS5$2zeI^ zx+7cEZ1#O*;5%!YFQb4_z$jo8FbWt2i~>dhqkvJsC}0#Y3K#`$Lj|Zu$TxQq^3zc` zkN^MYfB)}4NXW0iFThv8`v3=4fR}+Yz$xIy1B84AECV-BpboqM{CPhip8`w3BJezL z68QZ-LVg6k1wH^;z>B~`z#sP#@;&eg5CM+>Ki@;htH5Kx&ASQt0@wyF0Z#%y94F*! z;A7xJU<&x_E<%0-z5~{PS>OraabW)#AzuP-0<*v~z%k$`un!Hi4%f97rWgf`0=Jz4 z7E1ZDP_^dBPFSrG?pv-K(l&EltJ$<{*VVU_T-TlW`XZWrf(co-?rNlh!eU@m!1CY@^}K3g&>LKg!IFp0eL;#&R86E$UJu(-OyYK!n~C5i26bzP1|8Pa>vsbl ztNs~^Zmgj#c37fn&!i+=VOf$S=Y)&toijawL)S$|A$~TPs@loyc8{@VS9+D>7cp9a z9`(N~HxK{Aa_itJs?H7Mn#{`#b7dy#0 zpHDvn6;qux}zMlxT@yfP_w7J3x|KYUYA0>#Wsq zGjx~9frOzQXjZIjX5AXHvk?Ks6PysjNdMh?&&Q>gNe5DJfQgNT+fT)xl)gCr4 zi;xwIEPQTWxmtAQgpekQFGQRsb!otG+9jV0UQf%cBe&L;5tX!EwKcoLy(|}c%(wIb zt2yCRFu4-EAwma#rfs=QV#DU&b=AWoLdeu9dde&COu@(Q2yarZVdnML4*85 zlgVi2q2_~}2eQ~`z5}L%TtidmXugZXGHr=-Ilp)AxClkATsIBkB!qQX_jk{bR)B2V z|KqaYKs!b72lfMD%qTZ?i literal 0 HcmV?d00001 diff --git a/responders/PaloAltoNGFW_unblock_port/PaloAltoNGFW_unblock_port.json b/responders/PaloAltoNGFW_unblock_port/PaloAltoNGFW_unblock_port.json new file mode 100644 index 000000000..dfb3e6246 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_port/PaloAltoNGFW_unblock_port.json @@ -0,0 +1,62 @@ +{ + "name": "PaloAltoNGFW_unblock_port", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Unblock domain", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_unblock_port/Unblock_port.py", + "baseConfig": "PaloAltoNGFW_unblock_port", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_internal_Service_Group", + "description": "name_internal_Service_Group", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_external_Service_Group", + "description": "name_external_Service_Group", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_unblock_port/README.md b/responders/PaloAltoNGFW_unblock_port/README.md new file mode 100644 index 000000000..3b0110cf7 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_port/README.md @@ -0,0 +1,19 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Service_Group" and "name_external_Service_Group". + + +principle of operation: +1. the value is selected from the alert the hive. +2. if ioc added in Service_Groups, script deleted ioc +3. if ioc in AddressObject, script deleted ioc \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_port/Unblock_port.py b/responders/PaloAltoNGFW_unblock_port/Unblock_port.py new file mode 100644 index 000000000..c6c8cc835 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_port/Unblock_port.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects +import re +class Unblock_port(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_Service_Group = self.get_param('config.name_internal_Service_Group') + self.name_external_Service_Group = self.get_param('config.name_external_Service_Group') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + data_list=[] + data=None + for i in response.json().get("artifacts"): + if "'port'," in str(i): + ioc = i.get("data") + data_list.append(i.get("data")) + elif "'protocol'," in str(i): + ioc = i.get("data") + data_list.append(i.get("data")) + data=" ".join(data_list) + protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(data)); port="".join(port) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.ServiceGroup.refreshall(fw) + raise IOError("to") + block_list = fw.find(self.name_internal_Service_Group, panos.objects.ServiceGroup) + port_list = block_list.about().get('value') + if port in port_list: + port_list.remove(port) + temp1 = panos.objects.ServiceGroup(self.name_internal_Service_Group, value=port_list) + fw.add(temp1) + temp1.apply() + + block_list = fw.find(self.name_external_Service_Group, panos.objects.ServiceGroup) + port_list = block_list.about().get('value') + if port in port_list: + port_list.remove(port) + temp1 = panos.objects.ServiceGroup(self.name_external_Service_Group, value=port_list) + fw.add(temp1) + temp1.apply() + + panos.objects.ServiceObject.refreshall(fw) + if port in str(fw.find(port, panos.objects.ServiceObject)): + deleted_ioc = fw.find(port, panos.objects.ServiceObject) + deleted_ioc.delete() + + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Unblock_port().run() From 0e5aa7c451ce9d03ca5203a1fbb9c284395e5cfa Mon Sep 17 00:00:00 2001 From: staf711 <40694301+staf711@users.noreply.github.com> Date: Tue, 20 Oct 2020 20:54:28 +0300 Subject: [PATCH 07/25] Add new responders for PaloAltoNGFW This reverts commit 677c830713eeaaaf45c9afd4011b852271224e5c. --- .../Block_ip.py | 51 -------------- ...aloAltoNGFW_block_external_IP_address.json | 55 --------------- .../README.md | 21 ------ .../Block_domain.py | 51 -------------- .../PaloAltoNGFW_block_external_domain.json | 55 --------------- .../README.md | 21 ------ .../Block_port.py | 54 --------------- .../PaloAltoNGFW_block_external_port.json | 55 --------------- .../README.md | 23 ------- .../Block_url.py | 46 ------------- .../PaloAltoNGFW_block_external_url.json | 55 --------------- .../PaloAltoNGFW_block_external_url/README.md | 19 ------ .../Block_ip.py | 51 -------------- ...aloAltoNGFW_block_internal_IP_address.json | 55 --------------- .../README.md | 21 ------ .../Block_domain.py | 51 -------------- .../PaloAltoNGFW_block_internal_domain.json | 55 --------------- .../README.md | 21 ------ .../Block_port.py | 54 --------------- .../PaloAltoNGFW_block_internal_port.json | 55 --------------- .../README.md | 23 ------- .../Block_url.py | 46 ------------- .../PaloAltoNGFW_block_internal_url.json | 55 --------------- .../PaloAltoNGFW_block_internal_url/README.md | 21 ------ .../PaloAltoNGFW_unblock_domain.json | 62 ----------------- .../PaloAltoNGFW_unblock_domain/README.md | 18 ----- .../Unblock_domain.py | 61 ----------------- .../PaloAltoNGFW_unblock_ip.json | 62 ----------------- responders/PaloAltoNGFW_unblock_ip/README.md | 18 ----- .../PaloAltoNGFW_unblock_ip/Unblock_ip.py | 61 ----------------- .../.Unblock_port.py.swp | Bin 12288 -> 0 bytes .../PaloAltoNGFW_unblock_port.json | 62 ----------------- .../PaloAltoNGFW_unblock_port/README.md | 19 ------ .../PaloAltoNGFW_unblock_port/Unblock_port.py | 63 ------------------ 34 files changed, 1440 deletions(-) delete mode 100644 responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py delete mode 100644 responders/PaloAltoNGFW_block_external_IP_address/PaloAltoNGFW_block_external_IP_address.json delete mode 100644 responders/PaloAltoNGFW_block_external_IP_address/README.md delete mode 100644 responders/PaloAltoNGFW_block_external_domain/Block_domain.py delete mode 100644 responders/PaloAltoNGFW_block_external_domain/PaloAltoNGFW_block_external_domain.json delete mode 100644 responders/PaloAltoNGFW_block_external_domain/README.md delete mode 100644 responders/PaloAltoNGFW_block_external_port/Block_port.py delete mode 100644 responders/PaloAltoNGFW_block_external_port/PaloAltoNGFW_block_external_port.json delete mode 100644 responders/PaloAltoNGFW_block_external_port/README.md delete mode 100644 responders/PaloAltoNGFW_block_external_url/Block_url.py delete mode 100644 responders/PaloAltoNGFW_block_external_url/PaloAltoNGFW_block_external_url.json delete mode 100644 responders/PaloAltoNGFW_block_external_url/README.md delete mode 100644 responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py delete mode 100644 responders/PaloAltoNGFW_block_internal_IP_address/PaloAltoNGFW_block_internal_IP_address.json delete mode 100644 responders/PaloAltoNGFW_block_internal_IP_address/README.md delete mode 100644 responders/PaloAltoNGFW_block_internal_domain/Block_domain.py delete mode 100644 responders/PaloAltoNGFW_block_internal_domain/PaloAltoNGFW_block_internal_domain.json delete mode 100644 responders/PaloAltoNGFW_block_internal_domain/README.md delete mode 100644 responders/PaloAltoNGFW_block_internal_port/Block_port.py delete mode 100644 responders/PaloAltoNGFW_block_internal_port/PaloAltoNGFW_block_internal_port.json delete mode 100644 responders/PaloAltoNGFW_block_internal_port/README.md delete mode 100644 responders/PaloAltoNGFW_block_internal_url/Block_url.py delete mode 100644 responders/PaloAltoNGFW_block_internal_url/PaloAltoNGFW_block_internal_url.json delete mode 100644 responders/PaloAltoNGFW_block_internal_url/README.md delete mode 100644 responders/PaloAltoNGFW_unblock_domain/PaloAltoNGFW_unblock_domain.json delete mode 100644 responders/PaloAltoNGFW_unblock_domain/README.md delete mode 100644 responders/PaloAltoNGFW_unblock_domain/Unblock_domain.py delete mode 100644 responders/PaloAltoNGFW_unblock_ip/PaloAltoNGFW_unblock_ip.json delete mode 100644 responders/PaloAltoNGFW_unblock_ip/README.md delete mode 100644 responders/PaloAltoNGFW_unblock_ip/Unblock_ip.py delete mode 100644 responders/PaloAltoNGFW_unblock_port/.Unblock_port.py.swp delete mode 100644 responders/PaloAltoNGFW_unblock_port/PaloAltoNGFW_unblock_port.json delete mode 100644 responders/PaloAltoNGFW_unblock_port/README.md delete mode 100644 responders/PaloAltoNGFW_unblock_port/Unblock_port.py diff --git a/responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py b/responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py deleted file mode 100644 index da280475c..000000000 --- a/responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects - -class Block_ip(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_external_Address_Group = self.get_param('config.name_external_Address_Group') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'ip' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.AddressObject.refreshall(fw) - if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): - new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked ip address") - fw.add(new_ioc_object) - new_ioc_object.create() - panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find(self.name_external_Address_Group, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc not in ioc_list: - ioc_list.append(ioc) - temp1 = panos.objects.AddressGroup(self.name_external_Address_Group, static_value=ioc_list) - fw.add(temp1) - temp1.apply() - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Block_ip().run() diff --git a/responders/PaloAltoNGFW_block_external_IP_address/PaloAltoNGFW_block_external_IP_address.json b/responders/PaloAltoNGFW_block_external_IP_address/PaloAltoNGFW_block_external_IP_address.json deleted file mode 100644 index 761727b33..000000000 --- a/responders/PaloAltoNGFW_block_external_IP_address/PaloAltoNGFW_block_external_IP_address.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "PaloAltoNGFW_block_external_IP_address", - "version": "1.0.0", - "author": "Maxim Konakin", - "url": "", - "license": "AGPL-V3", - "description": "Block external IP address", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_block_external_IP_address/Block_ip.py", - "baseConfig": "PaloAltoNGFW_block_external_IP_address", - "configurationItems": [ - { - "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_external_Address_Group", - "description": "name_external_Address_Group", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_api_key", - "description": "TheHive API key with read access", - "type": "string", - "multi": false, - "required": true - } - ] -} diff --git a/responders/PaloAltoNGFW_block_external_IP_address/README.md b/responders/PaloAltoNGFW_block_external_IP_address/README.md deleted file mode 100644 index e58e9dd68..000000000 --- a/responders/PaloAltoNGFW_block_external_IP_address/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_Address_Group". -https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added AddressObject. -3. if ioc not in AddressObject, will add -4. if ioc in AddressObject, next step -5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_external_domain/Block_domain.py b/responders/PaloAltoNGFW_block_external_domain/Block_domain.py deleted file mode 100644 index b1557d77f..000000000 --- a/responders/PaloAltoNGFW_block_external_domain/Block_domain.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects - -class Block_domain(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_external_Address_Group_for_domain = self.get_param('config.name_external_Address_Group') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'hostname' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.AddressObject.refreshall(fw) - if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): - new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked fqdn",type="fqdn") - fw.add(new_ioc_object) - new_ioc_object.create() - panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find(self.name_external_Address_Group_for_domain, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc not in ioc_list: - ioc_list.append(ioc) - temp1 = panos.objects.AddressGroup(self.name_external_Address_Group_for_domain, static_value=ioc_list) - fw.add(temp1) - temp1.apply() - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Block_domain().run() diff --git a/responders/PaloAltoNGFW_block_external_domain/PaloAltoNGFW_block_external_domain.json b/responders/PaloAltoNGFW_block_external_domain/PaloAltoNGFW_block_external_domain.json deleted file mode 100644 index 28de7ece6..000000000 --- a/responders/PaloAltoNGFW_block_external_domain/PaloAltoNGFW_block_external_domain.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "PaloAltoNGFW_block_external_domain", - "version": "1.0.0", - "author": "Maxim Konakin", - "url": "", - "license": "AGPL-V3", - "description": "Block external domain", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_block_external_domain/Block_domain.py", - "baseConfig": "PaloAltoNGFW_block_external_domain", - "configurationItems": [ - { - "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_external_Address_Group", - "description": "name_external_Address_Group_for_domain", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_api_key", - "description": "TheHive API key with read access", - "type": "string", - "multi": false, - "required": true - } - ] -} diff --git a/responders/PaloAltoNGFW_block_external_domain/README.md b/responders/PaloAltoNGFW_block_external_domain/README.md deleted file mode 100644 index dfa67ff6d..000000000 --- a/responders/PaloAltoNGFW_block_external_domain/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_Address_Group". -https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added AddressObject. -3. if ioc not in AddressObject, will add -4. if ioc in AddressObject, next step -5. checks if there is already a blocking list (Address_Group), if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_external_port/Block_port.py b/responders/PaloAltoNGFW_block_external_port/Block_port.py deleted file mode 100644 index 6f1a919bc..000000000 --- a/responders/PaloAltoNGFW_block_external_port/Block_port.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects -import re -class Block_port(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_external_Service_Group = self.get_param('config.name_external_Service_Group') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - data_list=[] - data=None - for i in response.json().get("artifacts"): - if "'port'," in str(i): - ioc = i.get("data") - data_list.append(i.get("data")) - elif "'protocol'," in str(i): - ioc = i.get("data") - data_list.append(i.get("data")) - data=" ".join(data_list) - protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() - port=re.findall(r'[0-9]+',str(data)); port="".join(port) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.ServiceObject.refreshall(fw) - if port not in str(fw.find(port, panos.objects.ServiceObject)): - new_port_object = panos.objects.ServiceObject(port, protocol, description="Blocked port",destination_port=port) - fw.add(new_port_object) - new_port_object.create() - - - panos.objects.ServiceGroup.refreshall(fw) - block_list = fw.find(self.name_external_Service_Group, panos.objects.ServiceGroup) - port_list = block_list.about().get('value') - if port not in port_list: - port_list.append(port) - temp1 = panos.objects.ServiceGroup(self.name_external_Service_Group, value=port_list) - fw.add(temp1) - temp1.apply() - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Block_port().run() diff --git a/responders/PaloAltoNGFW_block_external_port/PaloAltoNGFW_block_external_port.json b/responders/PaloAltoNGFW_block_external_port/PaloAltoNGFW_block_external_port.json deleted file mode 100644 index 540be6dc7..000000000 --- a/responders/PaloAltoNGFW_block_external_port/PaloAltoNGFW_block_external_port.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "PaloAltoNGFW_block_external_port", - "version": "1.0.0", - "author": "Maxim Konakin", - "url": "", - "license": "AGPL-V3", - "description": "Block external port", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_block_external_port/Block_port.py", - "baseConfig": "PaloAltoNGFW_block_external_port", - "configurationItems": [ - { - "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_external_Service_Group", - "description": "name_external_Service_Group", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_api_key", - "description": "TheHive API key with read access", - "type": "string", - "multi": false, - "required": true - } - ] -} diff --git a/responders/PaloAltoNGFW_block_external_port/README.md b/responders/PaloAltoNGFW_block_external_port/README.md deleted file mode 100644 index 9b84128e4..000000000 --- a/responders/PaloAltoNGFW_block_external_port/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_Service_Group". - -First: you need add field "port" and "protocol" to "Observable types management" in the hive. -or you can change script and call your field names - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added Service_Group. -3. if ioc not in Service_Group, will add field port and protocol -4. if ioc in Service_Group, next step -5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_external_url/Block_url.py b/responders/PaloAltoNGFW_block_external_url/Block_url.py deleted file mode 100644 index 33eb834ad..000000000 --- a/responders/PaloAltoNGFW_block_external_url/Block_url.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects - -class Block_url(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_external_URL_category = self.get_param('config.name_external_URL_category') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'url' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.CustomUrlCategory.refreshall(fw) - block_list = fw.find(self.name_external_URL_category, panos.objects.CustomUrlCategory) - ioc_list = block_list.about().get('url_value') - if ioc not in ioc_list: - ioc_list.append(ioc) - temp1 = panos.objects.CustomUrlCategory(self.name_external_URL_category, url_value=ioc_list) - fw.add(temp1) - temp1.create() - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Block_url().run() diff --git a/responders/PaloAltoNGFW_block_external_url/PaloAltoNGFW_block_external_url.json b/responders/PaloAltoNGFW_block_external_url/PaloAltoNGFW_block_external_url.json deleted file mode 100644 index fbeee7697..000000000 --- a/responders/PaloAltoNGFW_block_external_url/PaloAltoNGFW_block_external_url.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "PaloAltoNGFW_block_external_url", - "version": "1.0.0", - "author": "Maxim Konakin", - "url": "", - "license": "AGPL-V3", - "description": "Block external domain", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_block_external_url/Block_url.py", - "baseConfig": "PaloAltoNGFW_block_external_url", - "configurationItems": [ - { - "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_external_URL_category", - "description": "name_external_URL_category", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_api_key", - "description": "TheHive API key with read access", - "type": "string", - "multi": false, - "required": true - } - ] -} diff --git a/responders/PaloAltoNGFW_block_external_url/README.md b/responders/PaloAltoNGFW_block_external_url/README.md deleted file mode 100644 index a97c170ef..000000000 --- a/responders/PaloAltoNGFW_block_external_url/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_URL_category". - - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added URL_category. -3. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py b/responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py deleted file mode 100644 index 6a0db4d52..000000000 --- a/responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects - -class Block_ip(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Address_Group = self.get_param('config.name_internal_Address_Group') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'ip' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.AddressObject.refreshall(fw) - if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): - new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked ip address") - fw.add(new_ioc_object) - new_ioc_object.create() - panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find(self.name_internal_Address_Group, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc not in ioc_list: - ioc_list.append(ioc) - temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group, static_value=ioc_list) - fw.add(temp1) - temp1.apply() - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Block_ip().run() diff --git a/responders/PaloAltoNGFW_block_internal_IP_address/PaloAltoNGFW_block_internal_IP_address.json b/responders/PaloAltoNGFW_block_internal_IP_address/PaloAltoNGFW_block_internal_IP_address.json deleted file mode 100644 index 36ef81cd9..000000000 --- a/responders/PaloAltoNGFW_block_internal_IP_address/PaloAltoNGFW_block_internal_IP_address.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "PaloAltoNGFW_block_internal_IP_address", - "version": "1.0.0", - "author": "Maxim Konakin", - "url": "", - "license": "AGPL-V3", - "description": "Block internal IP address", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_block_internal_IP_address/Block_ip.py", - "baseConfig": "PaloAltoNGFW_block_internal_IP_address", - "configurationItems": [ - { - "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_internal_Address_Group", - "description": "name_internal_Address_Group", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_api_key", - "description": "TheHive API key with read access", - "type": "string", - "multi": false, - "required": true - } - ] -} diff --git a/responders/PaloAltoNGFW_block_internal_IP_address/README.md b/responders/PaloAltoNGFW_block_internal_IP_address/README.md deleted file mode 100644 index e58e9dd68..000000000 --- a/responders/PaloAltoNGFW_block_internal_IP_address/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_Address_Group". -https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added AddressObject. -3. if ioc not in AddressObject, will add -4. if ioc in AddressObject, next step -5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_domain/Block_domain.py b/responders/PaloAltoNGFW_block_internal_domain/Block_domain.py deleted file mode 100644 index cb1d1ce96..000000000 --- a/responders/PaloAltoNGFW_block_internal_domain/Block_domain.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects - -class Block_domain(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Address_Group_for_domain = self.get_param('config.name_internal_Address_Group') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'hostname' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.AddressObject.refreshall(fw) - if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): - new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked fqdn",type="fqdn") - fw.add(new_ioc_object) - new_ioc_object.create() - panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find(self.name_internal_Address_Group_for_domain, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc not in ioc_list: - ioc_list.append(ioc) - temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group_for_domain, static_value=ioc_list) - fw.add(temp1) - temp1.apply() - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Block_domain().run() diff --git a/responders/PaloAltoNGFW_block_internal_domain/PaloAltoNGFW_block_internal_domain.json b/responders/PaloAltoNGFW_block_internal_domain/PaloAltoNGFW_block_internal_domain.json deleted file mode 100644 index e52db2720..000000000 --- a/responders/PaloAltoNGFW_block_internal_domain/PaloAltoNGFW_block_internal_domain.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "PaloAltoNGFW_block_internal_domain", - "version": "1.0.0", - "author": "Maxim Konakin", - "url": "", - "license": "AGPL-V3", - "description": "Block internal domain", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_block_internal_domain/Block_domain.py", - "baseConfig": "PaloAltoNGFW_block_internal_domain", - "configurationItems": [ - { - "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_internal_Address_Group", - "description": "name_internal_Address_Group_for_domain", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_api_key", - "description": "TheHive API key with read access", - "type": "string", - "multi": false, - "required": true - } - ] -} diff --git a/responders/PaloAltoNGFW_block_internal_domain/README.md b/responders/PaloAltoNGFW_block_internal_domain/README.md deleted file mode 100644 index bda74a5f2..000000000 --- a/responders/PaloAltoNGFW_block_internal_domain/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Address_Group_for_domain". -https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added AddressObject. -3. if ioc not in AddressObject, will add -4. if ioc in AddressObject, next step -5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_port/Block_port.py b/responders/PaloAltoNGFW_block_internal_port/Block_port.py deleted file mode 100644 index 3d2e00fa1..000000000 --- a/responders/PaloAltoNGFW_block_internal_port/Block_port.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects -import re -class Block_port(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Service_Group = self.get_param('config.name_internal_Service_Group') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - data_list=[] - data=None - for i in response.json().get("artifacts"): - if "'port'," in str(i): - ioc = i.get("data") - data_list.append(i.get("data")) - elif "'protocol'," in str(i): - ioc = i.get("data") - data_list.append(i.get("data")) - data=" ".join(data_list) - protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() - port=re.findall(r'[0-9]+',str(data)); port="".join(port) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.ServiceObject.refreshall(fw) - if port not in str(fw.find(port, panos.objects.ServiceObject)): - new_port_object = panos.objects.ServiceObject(port, protocol, description="Blocked port",destination_port=port) - fw.add(new_port_object) - new_port_object.create() - - - panos.objects.ServiceGroup.refreshall(fw) - block_list = fw.find(self.name_internal_Service_Group, panos.objects.ServiceGroup) - port_list = block_list.about().get('value') - if port not in port_list: - port_list.append(port) - temp1 = panos.objects.ServiceGroup(self.name_internal_Service_Group, value=port_list) - fw.add(temp1) - temp1.apply() - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Block_port().run() diff --git a/responders/PaloAltoNGFW_block_internal_port/PaloAltoNGFW_block_internal_port.json b/responders/PaloAltoNGFW_block_internal_port/PaloAltoNGFW_block_internal_port.json deleted file mode 100644 index e2b3c94dc..000000000 --- a/responders/PaloAltoNGFW_block_internal_port/PaloAltoNGFW_block_internal_port.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "PaloAltoNGFW_block_internal_port", - "version": "1.0.0", - "author": "Maxim Konakin", - "url": "", - "license": "AGPL-V3", - "description": "Block internal port", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_block_internal_port/Block_port.py", - "baseConfig": "PaloAltoNGFW_block_internal_port", - "configurationItems": [ - { - "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_internal_Service_Group", - "description": "name_internal_Service_Group", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_api_key", - "description": "TheHive API key with read access", - "type": "string", - "multi": false, - "required": true - } - ] -} diff --git a/responders/PaloAltoNGFW_block_internal_port/README.md b/responders/PaloAltoNGFW_block_internal_port/README.md deleted file mode 100644 index ef1df5628..000000000 --- a/responders/PaloAltoNGFW_block_internal_port/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Service_Group". - -First: you need add field "port" and "protocol" to "Observable types management" in the hive. -or you can change script and call your field names - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added Service_Group. -3. if ioc not in Service_Group, will add field port and protocol -4. if ioc in Service_Group, next step -5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_url/Block_url.py b/responders/PaloAltoNGFW_block_internal_url/Block_url.py deleted file mode 100644 index 39793efef..000000000 --- a/responders/PaloAltoNGFW_block_internal_url/Block_url.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects - -class Block_url(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_URL_category = self.get_param('config.name_internal_URL_category') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'url' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.CustomUrlCategory.refreshall(fw) - block_list = fw.find(self.name_internal_URL_category, panos.objects.CustomUrlCategory) - ioc_list = block_list.about().get('url_value') - if ioc not in ioc_list: - ioc_list.append(ioc) - temp1 = panos.objects.CustomUrlCategory(self.name_internal_URL_category, url_value=ioc_list) - fw.add(temp1) - temp1.create() - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Block_url().run() diff --git a/responders/PaloAltoNGFW_block_internal_url/PaloAltoNGFW_block_internal_url.json b/responders/PaloAltoNGFW_block_internal_url/PaloAltoNGFW_block_internal_url.json deleted file mode 100644 index 04258ecd7..000000000 --- a/responders/PaloAltoNGFW_block_internal_url/PaloAltoNGFW_block_internal_url.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "PaloAltoNGFW_block_internal_url", - "version": "1.0.0", - "author": "Maxim Konakin", - "url": "", - "license": "AGPL-V3", - "description": "Block internal domain", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_block_internal_url/Block_url.py", - "baseConfig": "PaloAltoNGFW_block_internal_url", - "configurationItems": [ - { - "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_internal_URL_category", - "description": "name_internal_URL_category", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_api_key", - "description": "TheHive API key with read access", - "type": "string", - "multi": false, - "required": true - } - ] -} diff --git a/responders/PaloAltoNGFW_block_internal_url/README.md b/responders/PaloAltoNGFW_block_internal_url/README.md deleted file mode 100644 index bda74a5f2..000000000 --- a/responders/PaloAltoNGFW_block_internal_url/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Address_Group_for_domain". -https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added AddressObject. -3. if ioc not in AddressObject, will add -4. if ioc in AddressObject, next step -5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_domain/PaloAltoNGFW_unblock_domain.json b/responders/PaloAltoNGFW_unblock_domain/PaloAltoNGFW_unblock_domain.json deleted file mode 100644 index e93782451..000000000 --- a/responders/PaloAltoNGFW_unblock_domain/PaloAltoNGFW_unblock_domain.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "name": "PaloAltoNGFW_unblock_domain", - "version": "1.0.0", - "author": "Maxim Konakin", - "url": "", - "license": "AGPL-V3", - "description": "Unblock domain", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_unblock_domain/Unblock_domain.py", - "baseConfig": "PaloAltoNGFW_unblock_domain", - "configurationItems": [ - { - "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_internal_Address_Group", - "description": "name_internal_Address_Group_for_domain", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_external_Address_Group", - "description": "name_external_Address_Group_for_domain", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_api_key", - "description": "TheHive API key with read access", - "type": "string", - "multi": false, - "required": true - } - ] -} diff --git a/responders/PaloAltoNGFW_unblock_domain/README.md b/responders/PaloAltoNGFW_unblock_domain/README.md deleted file mode 100644 index cfa6e002f..000000000 --- a/responders/PaloAltoNGFW_unblock_domain/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Address_Group_for_domain" and "name_external_Address_Group_for_domain" - -principle of operation: -1. the value is selected from the alert the hive. -2. if ioc added in Address_Groups, script deleted ioc -3. if ioc in AddressObject, script deleted ioc \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_domain/Unblock_domain.py b/responders/PaloAltoNGFW_unblock_domain/Unblock_domain.py deleted file mode 100644 index 8b4c96e54..000000000 --- a/responders/PaloAltoNGFW_unblock_domain/Unblock_domain.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects - -class Unblock_domain(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Address_Group_for_domain = self.get_param('config.name_internal_Address_Group') - self.name_external_Address_Group_for_domain = self.get_param('config.name_external_Address_Group') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'hostname' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find(self.name_internal_Address_Group_for_domain, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc in ioc_list: - ioc_list.remove(ioc) - temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group_for_domain, static_value=ioc_list) - fw.add(temp1) - temp1.apply() - - block_list = fw.find(self.name_external_Address_Group_for_domain, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc in ioc_list: - ioc_list.remove(ioc) - temp1 = panos.objects.AddressGroup(self.name_external_Address_Group_for_domain, static_value=ioc_list) - fw.add(temp1) - temp1.apply() - - panos.objects.AddressObject.refreshall(fw) - if ioc in str(fw.find(ioc, panos.objects.AddressObject)): - deleted_ioc = fw.find(ioc, panos.objects.AddressObject) - deleted_ioc.delete() - - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Unblock_domain().run() diff --git a/responders/PaloAltoNGFW_unblock_ip/PaloAltoNGFW_unblock_ip.json b/responders/PaloAltoNGFW_unblock_ip/PaloAltoNGFW_unblock_ip.json deleted file mode 100644 index b5c2bacb6..000000000 --- a/responders/PaloAltoNGFW_unblock_ip/PaloAltoNGFW_unblock_ip.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "name": "PaloAltoNGFW_unblock_ip", - "version": "1.0.0", - "author": "Maxim Konakin", - "url": "", - "license": "AGPL-V3", - "description": "Unblock ip", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_unblock_ip/Unblock_ip.py", - "baseConfig": "PaloAltoNGFW_unblock_ip", - "configurationItems": [ - { - "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_internal_Address_Group", - "description": "name_internal_Address_Group_for_ip", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_external_Address_Group", - "description": "name_external_Address_Group_for_ip", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_api_key", - "description": "TheHive API key with read access", - "type": "string", - "multi": false, - "required": true - } - ] -} diff --git a/responders/PaloAltoNGFW_unblock_ip/README.md b/responders/PaloAltoNGFW_unblock_ip/README.md deleted file mode 100644 index 0ff66431e..000000000 --- a/responders/PaloAltoNGFW_unblock_ip/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Address_Group_" and "name_external_Address_Group" - -principle of operation: -1. the value is selected from the alert the hive. -2. if ioc added in Address_Groups, script deleted ioc -3. if ioc in AddressObject, script deleted ioc \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_ip/Unblock_ip.py b/responders/PaloAltoNGFW_unblock_ip/Unblock_ip.py deleted file mode 100644 index 2fae0f761..000000000 --- a/responders/PaloAltoNGFW_unblock_ip/Unblock_ip.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects - -class Unblock_ip(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Address_Group = self.get_param('config.name_internal_Address_Group') - self.name_external_Address_Group = self.get_param('config.name_external_Address_Group') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'ip' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find(self.name_internal_Address_Group, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc in ioc_list: - ioc_list.remove(ioc) - temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group, static_value=ioc_list) - fw.add(temp1) - temp1.apply() - - block_list = fw.find(self.name_external_Address_Group, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc in ioc_list: - ioc_list.remove(ioc) - temp1 = panos.objects.AddressGroup(self.name_external_Address_Group, static_value=ioc_list) - fw.add(temp1) - temp1.apply() - - panos.objects.AddressObject.refreshall(fw) - if ioc in str(fw.find(ioc, panos.objects.AddressObject)): - deleted_ioc = fw.find(ioc, panos.objects.AddressObject) - deleted_ioc.delete() - - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Unblock_ip().run() diff --git a/responders/PaloAltoNGFW_unblock_port/.Unblock_port.py.swp b/responders/PaloAltoNGFW_unblock_port/.Unblock_port.py.swp deleted file mode 100644 index 250cf29671ef19c5b0df4056331e4c2003749a86..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeHNO=u)V7_HS^*T2=(1qJcYJ3)HJo%Cdl$Qm7EknC>M-GrDZVOiSBbahfmPgh%A zlVnyz1i^y`FM1LL5icG*i(Wl=5Y~%&6Ff<-i$_^})qm47naS)y#FZ*|GgZ}Jz543) zS6@v?txvtaaLGF7Oc9imgxom(k^A|3kCN%P2$4c4-94@ZqD6yE5i2LDd7@2uIAl;m zM5^(Ukc#b1&V@ASUSl$DNESyT^mKKJ24XHy;_`*_Z@8Us9dz4ngaM7!Qp1V5L&!~+ zQNSoLMu8J#`l++YR-dSxwoW~~I>z2SHVPO8i~>dhqkvJsC}0#Y3K#|cPYS5$2zeI^ zx+7cEZ1#O*;5%!YFQb4_z$jo8FbWt2i~>dhqkvJsC}0#Y3K#`$Lj|Zu$TxQq^3zc` zkN^MYfB)}4NXW0iFThv8`v3=4fR}+Yz$xIy1B84AECV-BpboqM{CPhip8`w3BJezL z68QZ-LVg6k1wH^;z>B~`z#sP#@;&eg5CM+>Ki@;htH5Kx&ASQt0@wyF0Z#%y94F*! z;A7xJU<&x_E<%0-z5~{PS>OraabW)#AzuP-0<*v~z%k$`un!Hi4%f97rWgf`0=Jz4 z7E1ZDP_^dBPFSrG?pv-K(l&EltJ$<{*VVU_T-TlW`XZWrf(co-?rNlh!eU@m!1CY@^}K3g&>LKg!IFp0eL;#&R86E$UJu(-OyYK!n~C5i26bzP1|8Pa>vsbl ztNs~^Zmgj#c37fn&!i+=VOf$S=Y)&toijawL)S$|A$~TPs@loyc8{@VS9+D>7cp9a z9`(N~HxK{Aa_itJs?H7Mn#{`#b7dy#0 zpHDvn6;qux}zMlxT@yfP_w7J3x|KYUYA0>#Wsq zGjx~9frOzQXjZIjX5AXHvk?Ks6PysjNdMh?&&Q>gNe5DJfQgNT+fT)xl)gCr4 zi;xwIEPQTWxmtAQgpekQFGQRsb!otG+9jV0UQf%cBe&L;5tX!EwKcoLy(|}c%(wIb zt2yCRFu4-EAwma#rfs=QV#DU&b=AWoLdeu9dde&COu@(Q2yarZVdnML4*85 zlgVi2q2_~}2eQ~`z5}L%TtidmXugZXGHr=-Ilp)AxClkATsIBkB!qQX_jk{bR)B2V z|KqaYKs!b72lfMD%qTZ?i diff --git a/responders/PaloAltoNGFW_unblock_port/PaloAltoNGFW_unblock_port.json b/responders/PaloAltoNGFW_unblock_port/PaloAltoNGFW_unblock_port.json deleted file mode 100644 index dfb3e6246..000000000 --- a/responders/PaloAltoNGFW_unblock_port/PaloAltoNGFW_unblock_port.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "name": "PaloAltoNGFW_unblock_port", - "version": "1.0.0", - "author": "Maxim Konakin", - "url": "", - "license": "AGPL-V3", - "description": "Unblock domain", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_unblock_port/Unblock_port.py", - "baseConfig": "PaloAltoNGFW_unblock_port", - "configurationItems": [ - { - "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_internal_Service_Group", - "description": "name_internal_Service_Group", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_external_Service_Group", - "description": "name_external_Service_Group", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_api_key", - "description": "TheHive API key with read access", - "type": "string", - "multi": false, - "required": true - } - ] -} diff --git a/responders/PaloAltoNGFW_unblock_port/README.md b/responders/PaloAltoNGFW_unblock_port/README.md deleted file mode 100644 index 3b0110cf7..000000000 --- a/responders/PaloAltoNGFW_unblock_port/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Service_Group" and "name_external_Service_Group". - - -principle of operation: -1. the value is selected from the alert the hive. -2. if ioc added in Service_Groups, script deleted ioc -3. if ioc in AddressObject, script deleted ioc \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_port/Unblock_port.py b/responders/PaloAltoNGFW_unblock_port/Unblock_port.py deleted file mode 100644 index c6c8cc835..000000000 --- a/responders/PaloAltoNGFW_unblock_port/Unblock_port.py +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects -import re -class Unblock_port(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Service_Group = self.get_param('config.name_internal_Service_Group') - self.name_external_Service_Group = self.get_param('config.name_external_Service_Group') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - data_list=[] - data=None - for i in response.json().get("artifacts"): - if "'port'," in str(i): - ioc = i.get("data") - data_list.append(i.get("data")) - elif "'protocol'," in str(i): - ioc = i.get("data") - data_list.append(i.get("data")) - data=" ".join(data_list) - protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() - port=re.findall(r'[0-9]+',str(data)); port="".join(port) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.ServiceGroup.refreshall(fw) - raise IOError("to") - block_list = fw.find(self.name_internal_Service_Group, panos.objects.ServiceGroup) - port_list = block_list.about().get('value') - if port in port_list: - port_list.remove(port) - temp1 = panos.objects.ServiceGroup(self.name_internal_Service_Group, value=port_list) - fw.add(temp1) - temp1.apply() - - block_list = fw.find(self.name_external_Service_Group, panos.objects.ServiceGroup) - port_list = block_list.about().get('value') - if port in port_list: - port_list.remove(port) - temp1 = panos.objects.ServiceGroup(self.name_external_Service_Group, value=port_list) - fw.add(temp1) - temp1.apply() - - panos.objects.ServiceObject.refreshall(fw) - if port in str(fw.find(port, panos.objects.ServiceObject)): - deleted_ioc = fw.find(port, panos.objects.ServiceObject) - deleted_ioc.delete() - - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Unblock_port().run() From 1a8dfc338ba6440edb311be5efe04a81eda70318 Mon Sep 17 00:00:00 2001 From: staf711 <40694301+staf711@users.noreply.github.com> Date: Tue, 20 Oct 2020 21:07:09 +0300 Subject: [PATCH 08/25] Add responce for PaloAltoNGFW --- .../Block_ip.py | 51 ++++++++++++++ ...aloAltoNGFW_block_external_IP_address.json | 55 +++++++++++++++ .../README.md | 21 ++++++ .../Block_domain.py | 51 ++++++++++++++ .../PaloAltoNGFW_block_external_domain.json | 55 +++++++++++++++ .../README.md | 21 ++++++ .../Block_port.py | 54 +++++++++++++++ .../PaloAltoNGFW_block_external_port.json | 55 +++++++++++++++ .../README.md | 23 +++++++ .../Block_url.py | 46 +++++++++++++ .../PaloAltoNGFW_block_external_url.json | 55 +++++++++++++++ .../PaloAltoNGFW_block_external_url/README.md | 19 ++++++ .../Block_ip.py | 51 ++++++++++++++ ...aloAltoNGFW_block_internal_IP_address.json | 55 +++++++++++++++ .../README.md | 21 ++++++ .../Block_domain.py | 51 ++++++++++++++ .../PaloAltoNGFW_block_internal_domain.json | 55 +++++++++++++++ .../README.md | 21 ++++++ .../Block_port.py | 54 +++++++++++++++ .../PaloAltoNGFW_block_internal_port.json | 55 +++++++++++++++ .../README.md | 23 +++++++ .../Block_url.py | 46 +++++++++++++ .../PaloAltoNGFW_block_internal_url.json | 55 +++++++++++++++ .../PaloAltoNGFW_block_internal_url/README.md | 21 ++++++ .../PaloAltoNGFW_unblock_domain.json | 62 +++++++++++++++++ .../PaloAltoNGFW_unblock_domain/README.md | 18 +++++ .../Unblock_domain.py | 61 +++++++++++++++++ .../PaloAltoNGFW_unblock_ip.json | 62 +++++++++++++++++ responders/PaloAltoNGFW_unblock_ip/README.md | 18 +++++ .../PaloAltoNGFW_unblock_ip/Unblock_ip.py | 61 +++++++++++++++++ .../.Unblock_port.py.swp | Bin 0 -> 12288 bytes .../PaloAltoNGFW_unblock_port.json | 62 +++++++++++++++++ .../PaloAltoNGFW_unblock_port/README.md | 19 ++++++ .../PaloAltoNGFW_unblock_port/Unblock_port.py | 63 ++++++++++++++++++ 34 files changed, 1440 insertions(+) create mode 100644 responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py create mode 100644 responders/PaloAltoNGFW_block_external_IP_address/PaloAltoNGFW_block_external_IP_address.json create mode 100644 responders/PaloAltoNGFW_block_external_IP_address/README.md create mode 100644 responders/PaloAltoNGFW_block_external_domain/Block_domain.py create mode 100644 responders/PaloAltoNGFW_block_external_domain/PaloAltoNGFW_block_external_domain.json create mode 100644 responders/PaloAltoNGFW_block_external_domain/README.md create mode 100644 responders/PaloAltoNGFW_block_external_port/Block_port.py create mode 100644 responders/PaloAltoNGFW_block_external_port/PaloAltoNGFW_block_external_port.json create mode 100644 responders/PaloAltoNGFW_block_external_port/README.md create mode 100644 responders/PaloAltoNGFW_block_external_url/Block_url.py create mode 100644 responders/PaloAltoNGFW_block_external_url/PaloAltoNGFW_block_external_url.json create mode 100644 responders/PaloAltoNGFW_block_external_url/README.md create mode 100644 responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py create mode 100644 responders/PaloAltoNGFW_block_internal_IP_address/PaloAltoNGFW_block_internal_IP_address.json create mode 100644 responders/PaloAltoNGFW_block_internal_IP_address/README.md create mode 100644 responders/PaloAltoNGFW_block_internal_domain/Block_domain.py create mode 100644 responders/PaloAltoNGFW_block_internal_domain/PaloAltoNGFW_block_internal_domain.json create mode 100644 responders/PaloAltoNGFW_block_internal_domain/README.md create mode 100644 responders/PaloAltoNGFW_block_internal_port/Block_port.py create mode 100644 responders/PaloAltoNGFW_block_internal_port/PaloAltoNGFW_block_internal_port.json create mode 100644 responders/PaloAltoNGFW_block_internal_port/README.md create mode 100644 responders/PaloAltoNGFW_block_internal_url/Block_url.py create mode 100644 responders/PaloAltoNGFW_block_internal_url/PaloAltoNGFW_block_internal_url.json create mode 100644 responders/PaloAltoNGFW_block_internal_url/README.md create mode 100644 responders/PaloAltoNGFW_unblock_domain/PaloAltoNGFW_unblock_domain.json create mode 100644 responders/PaloAltoNGFW_unblock_domain/README.md create mode 100644 responders/PaloAltoNGFW_unblock_domain/Unblock_domain.py create mode 100644 responders/PaloAltoNGFW_unblock_ip/PaloAltoNGFW_unblock_ip.json create mode 100644 responders/PaloAltoNGFW_unblock_ip/README.md create mode 100644 responders/PaloAltoNGFW_unblock_ip/Unblock_ip.py create mode 100644 responders/PaloAltoNGFW_unblock_port/.Unblock_port.py.swp create mode 100644 responders/PaloAltoNGFW_unblock_port/PaloAltoNGFW_unblock_port.json create mode 100644 responders/PaloAltoNGFW_unblock_port/README.md create mode 100644 responders/PaloAltoNGFW_unblock_port/Unblock_port.py diff --git a/responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py b/responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py new file mode 100644 index 000000000..da280475c --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Block_ip(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_external_Address_Group = self.get_param('config.name_external_Address_Group') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'ip' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressObject.refreshall(fw) + if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): + new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked ip address") + fw.add(new_ioc_object) + new_ioc_object.create() + panos.objects.AddressGroup.refreshall(fw) + block_list = fw.find(self.name_external_Address_Group, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc not in ioc_list: + ioc_list.append(ioc) + temp1 = panos.objects.AddressGroup(self.name_external_Address_Group, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Block_ip().run() diff --git a/responders/PaloAltoNGFW_block_external_IP_address/PaloAltoNGFW_block_external_IP_address.json b/responders/PaloAltoNGFW_block_external_IP_address/PaloAltoNGFW_block_external_IP_address.json new file mode 100644 index 000000000..761727b33 --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_IP_address/PaloAltoNGFW_block_external_IP_address.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_block_external_IP_address", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Block external IP address", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_block_external_IP_address/Block_ip.py", + "baseConfig": "PaloAltoNGFW_block_external_IP_address", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_external_Address_Group", + "description": "name_external_Address_Group", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_block_external_IP_address/README.md b/responders/PaloAltoNGFW_block_external_IP_address/README.md new file mode 100644 index 000000000..e58e9dd68 --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_IP_address/README.md @@ -0,0 +1,21 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_Address_Group". +https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added AddressObject. +3. if ioc not in AddressObject, will add +4. if ioc in AddressObject, next step +5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_external_domain/Block_domain.py b/responders/PaloAltoNGFW_block_external_domain/Block_domain.py new file mode 100644 index 000000000..b1557d77f --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_domain/Block_domain.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Block_domain(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_external_Address_Group_for_domain = self.get_param('config.name_external_Address_Group') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'hostname' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressObject.refreshall(fw) + if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): + new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked fqdn",type="fqdn") + fw.add(new_ioc_object) + new_ioc_object.create() + panos.objects.AddressGroup.refreshall(fw) + block_list = fw.find(self.name_external_Address_Group_for_domain, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc not in ioc_list: + ioc_list.append(ioc) + temp1 = panos.objects.AddressGroup(self.name_external_Address_Group_for_domain, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Block_domain().run() diff --git a/responders/PaloAltoNGFW_block_external_domain/PaloAltoNGFW_block_external_domain.json b/responders/PaloAltoNGFW_block_external_domain/PaloAltoNGFW_block_external_domain.json new file mode 100644 index 000000000..28de7ece6 --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_domain/PaloAltoNGFW_block_external_domain.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_block_external_domain", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Block external domain", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_block_external_domain/Block_domain.py", + "baseConfig": "PaloAltoNGFW_block_external_domain", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_external_Address_Group", + "description": "name_external_Address_Group_for_domain", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_block_external_domain/README.md b/responders/PaloAltoNGFW_block_external_domain/README.md new file mode 100644 index 000000000..dfa67ff6d --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_domain/README.md @@ -0,0 +1,21 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_Address_Group". +https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added AddressObject. +3. if ioc not in AddressObject, will add +4. if ioc in AddressObject, next step +5. checks if there is already a blocking list (Address_Group), if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_external_port/Block_port.py b/responders/PaloAltoNGFW_block_external_port/Block_port.py new file mode 100644 index 000000000..6f1a919bc --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_port/Block_port.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects +import re +class Block_port(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_external_Service_Group = self.get_param('config.name_external_Service_Group') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + data_list=[] + data=None + for i in response.json().get("artifacts"): + if "'port'," in str(i): + ioc = i.get("data") + data_list.append(i.get("data")) + elif "'protocol'," in str(i): + ioc = i.get("data") + data_list.append(i.get("data")) + data=" ".join(data_list) + protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(data)); port="".join(port) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.ServiceObject.refreshall(fw) + if port not in str(fw.find(port, panos.objects.ServiceObject)): + new_port_object = panos.objects.ServiceObject(port, protocol, description="Blocked port",destination_port=port) + fw.add(new_port_object) + new_port_object.create() + + + panos.objects.ServiceGroup.refreshall(fw) + block_list = fw.find(self.name_external_Service_Group, panos.objects.ServiceGroup) + port_list = block_list.about().get('value') + if port not in port_list: + port_list.append(port) + temp1 = panos.objects.ServiceGroup(self.name_external_Service_Group, value=port_list) + fw.add(temp1) + temp1.apply() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Block_port().run() diff --git a/responders/PaloAltoNGFW_block_external_port/PaloAltoNGFW_block_external_port.json b/responders/PaloAltoNGFW_block_external_port/PaloAltoNGFW_block_external_port.json new file mode 100644 index 000000000..540be6dc7 --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_port/PaloAltoNGFW_block_external_port.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_block_external_port", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Block external port", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_block_external_port/Block_port.py", + "baseConfig": "PaloAltoNGFW_block_external_port", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_external_Service_Group", + "description": "name_external_Service_Group", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_block_external_port/README.md b/responders/PaloAltoNGFW_block_external_port/README.md new file mode 100644 index 000000000..9b84128e4 --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_port/README.md @@ -0,0 +1,23 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_Service_Group". + +First: you need add field "port" and "protocol" to "Observable types management" in the hive. +or you can change script and call your field names + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added Service_Group. +3. if ioc not in Service_Group, will add field port and protocol +4. if ioc in Service_Group, next step +5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_external_url/Block_url.py b/responders/PaloAltoNGFW_block_external_url/Block_url.py new file mode 100644 index 000000000..33eb834ad --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_url/Block_url.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Block_url(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_external_URL_category = self.get_param('config.name_external_URL_category') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'url' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.CustomUrlCategory.refreshall(fw) + block_list = fw.find(self.name_external_URL_category, panos.objects.CustomUrlCategory) + ioc_list = block_list.about().get('url_value') + if ioc not in ioc_list: + ioc_list.append(ioc) + temp1 = panos.objects.CustomUrlCategory(self.name_external_URL_category, url_value=ioc_list) + fw.add(temp1) + temp1.create() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Block_url().run() diff --git a/responders/PaloAltoNGFW_block_external_url/PaloAltoNGFW_block_external_url.json b/responders/PaloAltoNGFW_block_external_url/PaloAltoNGFW_block_external_url.json new file mode 100644 index 000000000..fbeee7697 --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_url/PaloAltoNGFW_block_external_url.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_block_external_url", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Block external domain", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_block_external_url/Block_url.py", + "baseConfig": "PaloAltoNGFW_block_external_url", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_external_URL_category", + "description": "name_external_URL_category", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_block_external_url/README.md b/responders/PaloAltoNGFW_block_external_url/README.md new file mode 100644 index 000000000..a97c170ef --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_url/README.md @@ -0,0 +1,19 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_URL_category". + + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added URL_category. +3. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py b/responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py new file mode 100644 index 000000000..6a0db4d52 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Block_ip(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_Address_Group = self.get_param('config.name_internal_Address_Group') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'ip' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressObject.refreshall(fw) + if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): + new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked ip address") + fw.add(new_ioc_object) + new_ioc_object.create() + panos.objects.AddressGroup.refreshall(fw) + block_list = fw.find(self.name_internal_Address_Group, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc not in ioc_list: + ioc_list.append(ioc) + temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Block_ip().run() diff --git a/responders/PaloAltoNGFW_block_internal_IP_address/PaloAltoNGFW_block_internal_IP_address.json b/responders/PaloAltoNGFW_block_internal_IP_address/PaloAltoNGFW_block_internal_IP_address.json new file mode 100644 index 000000000..36ef81cd9 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_IP_address/PaloAltoNGFW_block_internal_IP_address.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_block_internal_IP_address", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Block internal IP address", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_block_internal_IP_address/Block_ip.py", + "baseConfig": "PaloAltoNGFW_block_internal_IP_address", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_internal_Address_Group", + "description": "name_internal_Address_Group", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_block_internal_IP_address/README.md b/responders/PaloAltoNGFW_block_internal_IP_address/README.md new file mode 100644 index 000000000..e58e9dd68 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_IP_address/README.md @@ -0,0 +1,21 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_Address_Group". +https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added AddressObject. +3. if ioc not in AddressObject, will add +4. if ioc in AddressObject, next step +5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_domain/Block_domain.py b/responders/PaloAltoNGFW_block_internal_domain/Block_domain.py new file mode 100644 index 000000000..cb1d1ce96 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_domain/Block_domain.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Block_domain(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_Address_Group_for_domain = self.get_param('config.name_internal_Address_Group') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'hostname' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressObject.refreshall(fw) + if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): + new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked fqdn",type="fqdn") + fw.add(new_ioc_object) + new_ioc_object.create() + panos.objects.AddressGroup.refreshall(fw) + block_list = fw.find(self.name_internal_Address_Group_for_domain, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc not in ioc_list: + ioc_list.append(ioc) + temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group_for_domain, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Block_domain().run() diff --git a/responders/PaloAltoNGFW_block_internal_domain/PaloAltoNGFW_block_internal_domain.json b/responders/PaloAltoNGFW_block_internal_domain/PaloAltoNGFW_block_internal_domain.json new file mode 100644 index 000000000..e52db2720 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_domain/PaloAltoNGFW_block_internal_domain.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_block_internal_domain", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Block internal domain", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_block_internal_domain/Block_domain.py", + "baseConfig": "PaloAltoNGFW_block_internal_domain", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_internal_Address_Group", + "description": "name_internal_Address_Group_for_domain", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_block_internal_domain/README.md b/responders/PaloAltoNGFW_block_internal_domain/README.md new file mode 100644 index 000000000..bda74a5f2 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_domain/README.md @@ -0,0 +1,21 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Address_Group_for_domain". +https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added AddressObject. +3. if ioc not in AddressObject, will add +4. if ioc in AddressObject, next step +5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_port/Block_port.py b/responders/PaloAltoNGFW_block_internal_port/Block_port.py new file mode 100644 index 000000000..3d2e00fa1 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_port/Block_port.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects +import re +class Block_port(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_Service_Group = self.get_param('config.name_internal_Service_Group') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + data_list=[] + data=None + for i in response.json().get("artifacts"): + if "'port'," in str(i): + ioc = i.get("data") + data_list.append(i.get("data")) + elif "'protocol'," in str(i): + ioc = i.get("data") + data_list.append(i.get("data")) + data=" ".join(data_list) + protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(data)); port="".join(port) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.ServiceObject.refreshall(fw) + if port not in str(fw.find(port, panos.objects.ServiceObject)): + new_port_object = panos.objects.ServiceObject(port, protocol, description="Blocked port",destination_port=port) + fw.add(new_port_object) + new_port_object.create() + + + panos.objects.ServiceGroup.refreshall(fw) + block_list = fw.find(self.name_internal_Service_Group, panos.objects.ServiceGroup) + port_list = block_list.about().get('value') + if port not in port_list: + port_list.append(port) + temp1 = panos.objects.ServiceGroup(self.name_internal_Service_Group, value=port_list) + fw.add(temp1) + temp1.apply() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Block_port().run() diff --git a/responders/PaloAltoNGFW_block_internal_port/PaloAltoNGFW_block_internal_port.json b/responders/PaloAltoNGFW_block_internal_port/PaloAltoNGFW_block_internal_port.json new file mode 100644 index 000000000..e2b3c94dc --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_port/PaloAltoNGFW_block_internal_port.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_block_internal_port", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Block internal port", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_block_internal_port/Block_port.py", + "baseConfig": "PaloAltoNGFW_block_internal_port", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_internal_Service_Group", + "description": "name_internal_Service_Group", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_block_internal_port/README.md b/responders/PaloAltoNGFW_block_internal_port/README.md new file mode 100644 index 000000000..ef1df5628 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_port/README.md @@ -0,0 +1,23 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Service_Group". + +First: you need add field "port" and "protocol" to "Observable types management" in the hive. +or you can change script and call your field names + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added Service_Group. +3. if ioc not in Service_Group, will add field port and protocol +4. if ioc in Service_Group, next step +5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_url/Block_url.py b/responders/PaloAltoNGFW_block_internal_url/Block_url.py new file mode 100644 index 000000000..39793efef --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_url/Block_url.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Block_url(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_URL_category = self.get_param('config.name_internal_URL_category') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'url' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.CustomUrlCategory.refreshall(fw) + block_list = fw.find(self.name_internal_URL_category, panos.objects.CustomUrlCategory) + ioc_list = block_list.about().get('url_value') + if ioc not in ioc_list: + ioc_list.append(ioc) + temp1 = panos.objects.CustomUrlCategory(self.name_internal_URL_category, url_value=ioc_list) + fw.add(temp1) + temp1.create() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Block_url().run() diff --git a/responders/PaloAltoNGFW_block_internal_url/PaloAltoNGFW_block_internal_url.json b/responders/PaloAltoNGFW_block_internal_url/PaloAltoNGFW_block_internal_url.json new file mode 100644 index 000000000..04258ecd7 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_url/PaloAltoNGFW_block_internal_url.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_block_internal_url", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Block internal domain", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_block_internal_url/Block_url.py", + "baseConfig": "PaloAltoNGFW_block_internal_url", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_internal_URL_category", + "description": "name_internal_URL_category", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_block_internal_url/README.md b/responders/PaloAltoNGFW_block_internal_url/README.md new file mode 100644 index 000000000..bda74a5f2 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_url/README.md @@ -0,0 +1,21 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Address_Group_for_domain". +https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added AddressObject. +3. if ioc not in AddressObject, will add +4. if ioc in AddressObject, next step +5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_domain/PaloAltoNGFW_unblock_domain.json b/responders/PaloAltoNGFW_unblock_domain/PaloAltoNGFW_unblock_domain.json new file mode 100644 index 000000000..e93782451 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_domain/PaloAltoNGFW_unblock_domain.json @@ -0,0 +1,62 @@ +{ + "name": "PaloAltoNGFW_unblock_domain", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Unblock domain", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_unblock_domain/Unblock_domain.py", + "baseConfig": "PaloAltoNGFW_unblock_domain", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_internal_Address_Group", + "description": "name_internal_Address_Group_for_domain", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_external_Address_Group", + "description": "name_external_Address_Group_for_domain", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_unblock_domain/README.md b/responders/PaloAltoNGFW_unblock_domain/README.md new file mode 100644 index 000000000..cfa6e002f --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_domain/README.md @@ -0,0 +1,18 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Address_Group_for_domain" and "name_external_Address_Group_for_domain" + +principle of operation: +1. the value is selected from the alert the hive. +2. if ioc added in Address_Groups, script deleted ioc +3. if ioc in AddressObject, script deleted ioc \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_domain/Unblock_domain.py b/responders/PaloAltoNGFW_unblock_domain/Unblock_domain.py new file mode 100644 index 000000000..8b4c96e54 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_domain/Unblock_domain.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Unblock_domain(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_Address_Group_for_domain = self.get_param('config.name_internal_Address_Group') + self.name_external_Address_Group_for_domain = self.get_param('config.name_external_Address_Group') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'hostname' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressGroup.refreshall(fw) + block_list = fw.find(self.name_internal_Address_Group_for_domain, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc in ioc_list: + ioc_list.remove(ioc) + temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group_for_domain, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + + block_list = fw.find(self.name_external_Address_Group_for_domain, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc in ioc_list: + ioc_list.remove(ioc) + temp1 = panos.objects.AddressGroup(self.name_external_Address_Group_for_domain, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + + panos.objects.AddressObject.refreshall(fw) + if ioc in str(fw.find(ioc, panos.objects.AddressObject)): + deleted_ioc = fw.find(ioc, panos.objects.AddressObject) + deleted_ioc.delete() + + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Unblock_domain().run() diff --git a/responders/PaloAltoNGFW_unblock_ip/PaloAltoNGFW_unblock_ip.json b/responders/PaloAltoNGFW_unblock_ip/PaloAltoNGFW_unblock_ip.json new file mode 100644 index 000000000..b5c2bacb6 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_ip/PaloAltoNGFW_unblock_ip.json @@ -0,0 +1,62 @@ +{ + "name": "PaloAltoNGFW_unblock_ip", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Unblock ip", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_unblock_ip/Unblock_ip.py", + "baseConfig": "PaloAltoNGFW_unblock_ip", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_internal_Address_Group", + "description": "name_internal_Address_Group_for_ip", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_external_Address_Group", + "description": "name_external_Address_Group_for_ip", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_unblock_ip/README.md b/responders/PaloAltoNGFW_unblock_ip/README.md new file mode 100644 index 000000000..0ff66431e --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_ip/README.md @@ -0,0 +1,18 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Address_Group_" and "name_external_Address_Group" + +principle of operation: +1. the value is selected from the alert the hive. +2. if ioc added in Address_Groups, script deleted ioc +3. if ioc in AddressObject, script deleted ioc \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_ip/Unblock_ip.py b/responders/PaloAltoNGFW_unblock_ip/Unblock_ip.py new file mode 100644 index 000000000..2fae0f761 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_ip/Unblock_ip.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Unblock_ip(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_Address_Group = self.get_param('config.name_internal_Address_Group') + self.name_external_Address_Group = self.get_param('config.name_external_Address_Group') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'ip' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressGroup.refreshall(fw) + block_list = fw.find(self.name_internal_Address_Group, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc in ioc_list: + ioc_list.remove(ioc) + temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + + block_list = fw.find(self.name_external_Address_Group, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc in ioc_list: + ioc_list.remove(ioc) + temp1 = panos.objects.AddressGroup(self.name_external_Address_Group, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + + panos.objects.AddressObject.refreshall(fw) + if ioc in str(fw.find(ioc, panos.objects.AddressObject)): + deleted_ioc = fw.find(ioc, panos.objects.AddressObject) + deleted_ioc.delete() + + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Unblock_ip().run() diff --git a/responders/PaloAltoNGFW_unblock_port/.Unblock_port.py.swp b/responders/PaloAltoNGFW_unblock_port/.Unblock_port.py.swp new file mode 100644 index 0000000000000000000000000000000000000000..250cf29671ef19c5b0df4056331e4c2003749a86 GIT binary patch literal 12288 zcmeHNO=u)V7_HS^*T2=(1qJcYJ3)HJo%Cdl$Qm7EknC>M-GrDZVOiSBbahfmPgh%A zlVnyz1i^y`FM1LL5icG*i(Wl=5Y~%&6Ff<-i$_^})qm47naS)y#FZ*|GgZ}Jz543) zS6@v?txvtaaLGF7Oc9imgxom(k^A|3kCN%P2$4c4-94@ZqD6yE5i2LDd7@2uIAl;m zM5^(Ukc#b1&V@ASUSl$DNESyT^mKKJ24XHy;_`*_Z@8Us9dz4ngaM7!Qp1V5L&!~+ zQNSoLMu8J#`l++YR-dSxwoW~~I>z2SHVPO8i~>dhqkvJsC}0#Y3K#|cPYS5$2zeI^ zx+7cEZ1#O*;5%!YFQb4_z$jo8FbWt2i~>dhqkvJsC}0#Y3K#`$Lj|Zu$TxQq^3zc` zkN^MYfB)}4NXW0iFThv8`v3=4fR}+Yz$xIy1B84AECV-BpboqM{CPhip8`w3BJezL z68QZ-LVg6k1wH^;z>B~`z#sP#@;&eg5CM+>Ki@;htH5Kx&ASQt0@wyF0Z#%y94F*! z;A7xJU<&x_E<%0-z5~{PS>OraabW)#AzuP-0<*v~z%k$`un!Hi4%f97rWgf`0=Jz4 z7E1ZDP_^dBPFSrG?pv-K(l&EltJ$<{*VVU_T-TlW`XZWrf(co-?rNlh!eU@m!1CY@^}K3g&>LKg!IFp0eL;#&R86E$UJu(-OyYK!n~C5i26bzP1|8Pa>vsbl ztNs~^Zmgj#c37fn&!i+=VOf$S=Y)&toijawL)S$|A$~TPs@loyc8{@VS9+D>7cp9a z9`(N~HxK{Aa_itJs?H7Mn#{`#b7dy#0 zpHDvn6;qux}zMlxT@yfP_w7J3x|KYUYA0>#Wsq zGjx~9frOzQXjZIjX5AXHvk?Ks6PysjNdMh?&&Q>gNe5DJfQgNT+fT)xl)gCr4 zi;xwIEPQTWxmtAQgpekQFGQRsb!otG+9jV0UQf%cBe&L;5tX!EwKcoLy(|}c%(wIb zt2yCRFu4-EAwma#rfs=QV#DU&b=AWoLdeu9dde&COu@(Q2yarZVdnML4*85 zlgVi2q2_~}2eQ~`z5}L%TtidmXugZXGHr=-Ilp)AxClkATsIBkB!qQX_jk{bR)B2V z|KqaYKs!b72lfMD%qTZ?i literal 0 HcmV?d00001 diff --git a/responders/PaloAltoNGFW_unblock_port/PaloAltoNGFW_unblock_port.json b/responders/PaloAltoNGFW_unblock_port/PaloAltoNGFW_unblock_port.json new file mode 100644 index 000000000..dfb3e6246 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_port/PaloAltoNGFW_unblock_port.json @@ -0,0 +1,62 @@ +{ + "name": "PaloAltoNGFW_unblock_port", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Unblock domain", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_unblock_port/Unblock_port.py", + "baseConfig": "PaloAltoNGFW_unblock_port", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_internal_Service_Group", + "description": "name_internal_Service_Group", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_external_Service_Group", + "description": "name_external_Service_Group", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_unblock_port/README.md b/responders/PaloAltoNGFW_unblock_port/README.md new file mode 100644 index 000000000..3b0110cf7 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_port/README.md @@ -0,0 +1,19 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Service_Group" and "name_external_Service_Group". + + +principle of operation: +1. the value is selected from the alert the hive. +2. if ioc added in Service_Groups, script deleted ioc +3. if ioc in AddressObject, script deleted ioc \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_port/Unblock_port.py b/responders/PaloAltoNGFW_unblock_port/Unblock_port.py new file mode 100644 index 000000000..c6c8cc835 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_port/Unblock_port.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects +import re +class Unblock_port(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_Service_Group = self.get_param('config.name_internal_Service_Group') + self.name_external_Service_Group = self.get_param('config.name_external_Service_Group') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + data_list=[] + data=None + for i in response.json().get("artifacts"): + if "'port'," in str(i): + ioc = i.get("data") + data_list.append(i.get("data")) + elif "'protocol'," in str(i): + ioc = i.get("data") + data_list.append(i.get("data")) + data=" ".join(data_list) + protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(data)); port="".join(port) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.ServiceGroup.refreshall(fw) + raise IOError("to") + block_list = fw.find(self.name_internal_Service_Group, panos.objects.ServiceGroup) + port_list = block_list.about().get('value') + if port in port_list: + port_list.remove(port) + temp1 = panos.objects.ServiceGroup(self.name_internal_Service_Group, value=port_list) + fw.add(temp1) + temp1.apply() + + block_list = fw.find(self.name_external_Service_Group, panos.objects.ServiceGroup) + port_list = block_list.about().get('value') + if port in port_list: + port_list.remove(port) + temp1 = panos.objects.ServiceGroup(self.name_external_Service_Group, value=port_list) + fw.add(temp1) + temp1.apply() + + panos.objects.ServiceObject.refreshall(fw) + if port in str(fw.find(port, panos.objects.ServiceObject)): + deleted_ioc = fw.find(port, panos.objects.ServiceObject) + deleted_ioc.delete() + + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Unblock_port().run() From 456bf91c266876ec2f46829a82f65801cbf36ad6 Mon Sep 17 00:00:00 2001 From: staf711 <40694301+staf711@users.noreply.github.com> Date: Mon, 26 Oct 2020 11:53:27 +0300 Subject: [PATCH 09/25] Add response with security rules Response with rules for: 1. IP address 2. domains 3. users This response contain security rules with default name, for use need add setting PaloAltoNGFW and the hive. --- .../Block_ip.py | 32 ++++++++--- ...aloAltoNGFW_block_external_IP_address.json | 8 +-- .../README.md | 6 +- .../Block_domain.py | 35 +++++++++--- .../PaloAltoNGFW_block_external_domain.json | 8 +-- .../README.md | 5 +- .../Block_user.py | 57 +++++++++++++++++++ .../PaloAltoNGFW_block_external_user.json | 55 ++++++++++++++++++ .../README.md | 18 ++++++ .../Block_ip.py | 34 ++++++++--- ...aloAltoNGFW_block_internal_IP_address.json | 8 +-- .../README.md | 5 +- .../Block_domain.py | 35 +++++++++--- .../PaloAltoNGFW_block_internal_domain.json | 8 +-- .../README.md | 5 +- .../Block_user.py | 57 +++++++++++++++++++ .../PaloAltoNGFW_block_internal_user.json | 55 ++++++++++++++++++ .../README.md | 18 ++++++ ...oAltoNGFW_unblock_external_IP_address.json | 55 ++++++++++++++++++ .../README.md | 20 +++++++ .../Unblock_ip.py | 55 ++++++++++++++++++ .../PaloAltoNGFW_unblock_external_domain.json | 55 ++++++++++++++++++ .../README.md | 20 +++++++ .../Unblock_domain.py | 57 +++++++++++++++++++ .../PaloAltoNGFW_unblock_external_user.json | 55 ++++++++++++++++++ .../README.md | 18 ++++++ .../Unblock_user.py | 57 +++++++++++++++++++ ...oAltoNGFW_unblock_internal_IP_address.json | 55 ++++++++++++++++++ .../README.md | 20 +++++++ .../Unblock_ip.py | 55 ++++++++++++++++++ .../PaloAltoNGFW_unblock_internal_domain.json | 55 ++++++++++++++++++ .../README.md | 20 +++++++ .../Unblock_domain.py | 57 +++++++++++++++++++ .../PaloAltoNGFW_unblock_internal_user.json | 55 ++++++++++++++++++ .../README.md | 18 ++++++ .../Unblock_user.py | 57 +++++++++++++++++++ 36 files changed, 1177 insertions(+), 56 deletions(-) create mode 100644 responders/PaloAltoNGFW_block_external_user/Block_user.py create mode 100644 responders/PaloAltoNGFW_block_external_user/PaloAltoNGFW_block_external_user.json create mode 100644 responders/PaloAltoNGFW_block_external_user/README.md create mode 100644 responders/PaloAltoNGFW_block_internal_user/Block_user.py create mode 100644 responders/PaloAltoNGFW_block_internal_user/PaloAltoNGFW_block_internal_user.json create mode 100644 responders/PaloAltoNGFW_block_internal_user/README.md create mode 100644 responders/PaloAltoNGFW_unblock_external_IP_address/PaloAltoNGFW_unblock_external_IP_address.json create mode 100644 responders/PaloAltoNGFW_unblock_external_IP_address/README.md create mode 100644 responders/PaloAltoNGFW_unblock_external_IP_address/Unblock_ip.py create mode 100644 responders/PaloAltoNGFW_unblock_external_domain/PaloAltoNGFW_unblock_external_domain.json create mode 100644 responders/PaloAltoNGFW_unblock_external_domain/README.md create mode 100644 responders/PaloAltoNGFW_unblock_external_domain/Unblock_domain.py create mode 100644 responders/PaloAltoNGFW_unblock_external_user/PaloAltoNGFW_unblock_external_user.json create mode 100644 responders/PaloAltoNGFW_unblock_external_user/README.md create mode 100644 responders/PaloAltoNGFW_unblock_external_user/Unblock_user.py create mode 100644 responders/PaloAltoNGFW_unblock_internal_IP_address/PaloAltoNGFW_unblock_internal_IP_address.json create mode 100644 responders/PaloAltoNGFW_unblock_internal_IP_address/README.md create mode 100644 responders/PaloAltoNGFW_unblock_internal_IP_address/Unblock_ip.py create mode 100644 responders/PaloAltoNGFW_unblock_internal_domain/PaloAltoNGFW_unblock_internal_domain.json create mode 100644 responders/PaloAltoNGFW_unblock_internal_domain/README.md create mode 100644 responders/PaloAltoNGFW_unblock_internal_domain/Unblock_domain.py create mode 100644 responders/PaloAltoNGFW_unblock_internal_user/PaloAltoNGFW_unblock_internal_user.json create mode 100644 responders/PaloAltoNGFW_unblock_internal_user/README.md create mode 100644 responders/PaloAltoNGFW_unblock_internal_user/Unblock_user.py diff --git a/responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py b/responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py index da280475c..dde73785c 100644 --- a/responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py +++ b/responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py @@ -5,6 +5,7 @@ from thehive4py.api import TheHiveApi from panos import firewall import panos.objects +import panos.policies class Block_ip(Responder): def __init__(self): @@ -12,7 +13,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_external_Address_Group = self.get_param('config.name_external_Address_Group') + self.name_security_rule = self.get_param('config.name_security_rule','Block external IP address') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -33,19 +34,36 @@ def run(self): ioc="".join(ioc_clear) fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) panos.objects.AddressObject.refreshall(fw) + rulebase = panos.policies.Rulebase() + fw.add(rulebase) + current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked ip address") fw.add(new_ioc_object) new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find(self.name_external_Address_Group, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc not in ioc_list: - ioc_list.append(ioc) - temp1 = panos.objects.AddressGroup(self.name_external_Address_Group, static_value=ioc_list) + block_list = fw.find("Black list external IP", panos.objects.AddressGroup) + if block_list != None: + ioc_list = block_list.about().get('static_value') + if ioc not in ioc_list: + ioc_list.append(ioc) + temp1 = panos.objects.AddressGroup("Black list external IP", static_value=ioc_list) + fw.add(temp1) + temp1.apply() + elif block_list == None: + temp1 = panos.objects.AddressGroup("Black list external IP", static_value=ioc) fw.add(temp1) temp1.apply() + desired_rule_params = { + "name": self.name_security_rule, + "description": "Block external IP address", + "type": "interzone", + "action": "deny", + 'destination': "Black list external IP" + } + new_rule = panos.policies.SecurityRule(**desired_rule_params) + rulebase.add(new_rule) + new_rule.apply() self.report({'message': 'message sent'}) - if __name__ == '__main__': Block_ip().run() diff --git a/responders/PaloAltoNGFW_block_external_IP_address/PaloAltoNGFW_block_external_IP_address.json b/responders/PaloAltoNGFW_block_external_IP_address/PaloAltoNGFW_block_external_IP_address.json index 761727b33..23dba633d 100644 --- a/responders/PaloAltoNGFW_block_external_IP_address/PaloAltoNGFW_block_external_IP_address.json +++ b/responders/PaloAltoNGFW_block_external_IP_address/PaloAltoNGFW_block_external_IP_address.json @@ -1,6 +1,6 @@ { "name": "PaloAltoNGFW_block_external_IP_address", - "version": "1.0.0", + "version": "2.0.0", "author": "Maxim Konakin", "url": "", "license": "AGPL-V3", @@ -31,11 +31,11 @@ "required": true }, { - "name": "name_external_Address_Group", - "description": "name_external_Address_Group", + "name": "name_security_rule", + "description": "name_external_name_security_rule_for_ip", "type": "string", "multi": false, - "required": true + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW_block_external_IP_address/README.md b/responders/PaloAltoNGFW_block_external_IP_address/README.md index e58e9dd68..e55a8d2be 100644 --- a/responders/PaloAltoNGFW_block_external_IP_address/README.md +++ b/responders/PaloAltoNGFW_block_external_IP_address/README.md @@ -10,12 +10,12 @@ need install: # ToDo -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_Address_Group". -https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list +to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" principle of operation: 1. the value is selected from the alert the hive. 2. ioc compare against already added AddressObject. 3. if ioc not in AddressObject, will add 4. if ioc in AddressObject, next step -5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file +5. checks if there is already a blocking list, if not, ioc will add +6. create security rule and add AddressObject \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_external_domain/Block_domain.py b/responders/PaloAltoNGFW_block_external_domain/Block_domain.py index b1557d77f..4e2c1b5ed 100644 --- a/responders/PaloAltoNGFW_block_external_domain/Block_domain.py +++ b/responders/PaloAltoNGFW_block_external_domain/Block_domain.py @@ -5,6 +5,7 @@ from thehive4py.api import TheHiveApi from panos import firewall import panos.objects +import panos.policies class Block_domain(Responder): def __init__(self): @@ -12,7 +13,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_external_Address_Group_for_domain = self.get_param('config.name_external_Address_Group') + self.name_security_rule = self.get_param('config.name_security_rule','Block external Domain') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -33,18 +34,36 @@ def run(self): ioc="".join(ioc_clear) fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) panos.objects.AddressObject.refreshall(fw) + rulebase = panos.policies.Rulebase() + fw.add(rulebase) + current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): - new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked fqdn",type="fqdn") + new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked domain",type="fqdn") fw.add(new_ioc_object) - new_ioc_object.create() + new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find(self.name_external_Address_Group_for_domain, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc not in ioc_list: - ioc_list.append(ioc) - temp1 = panos.objects.AddressGroup(self.name_external_Address_Group_for_domain, static_value=ioc_list) + block_list = fw.find("Black list external domain", panos.objects.AddressGroup) + if block_list != None: + ioc_list = block_list.about().get('static_value') + if ioc not in ioc_list: + ioc_list.append(ioc) + temp1 = panos.objects.AddressGroup("Black list external domain", static_value=ioc_list) + fw.add(temp1) + temp1.apply() + elif block_list == None: + temp1 = panos.objects.AddressGroup("Black list external domain", static_value=ioc) fw.add(temp1) temp1.apply() + desired_rule_params = { + "name": self.name_security_rule, + "description": "Block external Domain", + "type": "interzone", + "action": "deny", + 'destination': "Black list external domain" + } + new_rule = panos.policies.SecurityRule(**desired_rule_params) + rulebase.add(new_rule) + new_rule.apply() self.report({'message': 'message sent'}) if __name__ == '__main__': diff --git a/responders/PaloAltoNGFW_block_external_domain/PaloAltoNGFW_block_external_domain.json b/responders/PaloAltoNGFW_block_external_domain/PaloAltoNGFW_block_external_domain.json index 28de7ece6..2d1d53369 100644 --- a/responders/PaloAltoNGFW_block_external_domain/PaloAltoNGFW_block_external_domain.json +++ b/responders/PaloAltoNGFW_block_external_domain/PaloAltoNGFW_block_external_domain.json @@ -1,6 +1,6 @@ { "name": "PaloAltoNGFW_block_external_domain", - "version": "1.0.0", + "version": "2.0.0", "author": "Maxim Konakin", "url": "", "license": "AGPL-V3", @@ -31,11 +31,11 @@ "required": true }, { - "name": "name_external_Address_Group", - "description": "name_external_Address_Group_for_domain", + "name": "name_security_rule", + "description": "name_internal_security_rule_for_domain", "type": "string", "multi": false, - "required": true + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW_block_external_domain/README.md b/responders/PaloAltoNGFW_block_external_domain/README.md index dfa67ff6d..740b81d06 100644 --- a/responders/PaloAltoNGFW_block_external_domain/README.md +++ b/responders/PaloAltoNGFW_block_external_domain/README.md @@ -10,7 +10,7 @@ need install: # ToDo -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_Address_Group". +to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list principle of operation: @@ -18,4 +18,5 @@ principle of operation: 2. ioc compare against already added AddressObject. 3. if ioc not in AddressObject, will add 4. if ioc in AddressObject, next step -5. checks if there is already a blocking list (Address_Group), if not, ioc will add \ No newline at end of file +5. checks if there is already a blocking list, if not, ioc will add +6. create security rule and add AddressObject \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_external_user/Block_user.py b/responders/PaloAltoNGFW_block_external_user/Block_user.py new file mode 100644 index 000000000..6392bab9a --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_user/Block_user.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.policies + +class Block_user(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_security_rule = self.get_param('config.name_security_rule','Block user external communication') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + user=None + user_list_alert=[] + for i in list(response.json().get("artifacts")): + if 'user-agent' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + user_list_alert.append(i) + user="".join(user_list_alert) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + rulebase = panos.policies.Rulebase() + fw.add(rulebase) + current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) + user_list=[] + for i in current_security_rules: + if i.about().get('name') == self.name_security_rule: + user_list=i.about().get("source_user") + if user not in user_list: + user_list.append(user) + desired_rule_params = { + "name": self.name_security_rule, + "description": "Block user external communication", + "type": "interzone", + "action": "deny", + 'source_user': user_list + } + new_rule = panos.policies.SecurityRule(**desired_rule_params) + rulebase.add(new_rule) + new_rule.apply() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Block_user().run() diff --git a/responders/PaloAltoNGFW_block_external_user/PaloAltoNGFW_block_external_user.json b/responders/PaloAltoNGFW_block_external_user/PaloAltoNGFW_block_external_user.json new file mode 100644 index 000000000..980727784 --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_user/PaloAltoNGFW_block_external_user.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_block_external_user", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Block external user", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_block_external_user/Block_user.py", + "baseConfig": "PaloAltoNGFW_block_external_user", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_security_rule", + "description": "name_external_name_security_rule_for_users", + "type": "string", + "multi": false, + "required": false + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_block_external_user/README.md b/responders/PaloAltoNGFW_block_external_user/README.md new file mode 100644 index 000000000..33b80bacb --- /dev/null +++ b/responders/PaloAltoNGFW_block_external_user/README.md @@ -0,0 +1,18 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" + +principle of operation: +1. the value is selected from the alert the hive. +2. user compare against already added security rule. +3. if user not in security rule, will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py b/responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py index 6a0db4d52..9fb32ac5a 100644 --- a/responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py +++ b/responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py @@ -5,6 +5,7 @@ from thehive4py.api import TheHiveApi from panos import firewall import panos.objects +import panos.policies class Block_ip(Responder): def __init__(self): @@ -12,7 +13,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Address_Group = self.get_param('config.name_internal_Address_Group') + self.name_security_rule = self.get_param('config.name_security_rule','Block internal IP address') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -33,19 +34,36 @@ def run(self): ioc="".join(ioc_clear) fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) panos.objects.AddressObject.refreshall(fw) + rulebase = panos.policies.Rulebase() + fw.add(rulebase) + current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked ip address") fw.add(new_ioc_object) - new_ioc_object.create() + new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find(self.name_internal_Address_Group, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc not in ioc_list: - ioc_list.append(ioc) - temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group, static_value=ioc_list) + block_list = fw.find("Black list internal IP", panos.objects.AddressGroup) + if block_list != None: + ioc_list = block_list.about().get('static_value') + if ioc not in ioc_list: + ioc_list.append(ioc) + temp1 = panos.objects.AddressGroup("Black list internal IP", static_value=ioc_list) + fw.add(temp1) + temp1.apply() + elif block_list == None: + temp1 = panos.objects.AddressGroup("Black list internal IP", static_value=ioc) fw.add(temp1) temp1.apply() + desired_rule_params = { + "name": self.name_security_rule, + "description": "Block internal IP address", + "type": "intrazone", + "action": "deny", + 'destination': "Black list internal IP" + } + new_rule = panos.policies.SecurityRule(**desired_rule_params) + rulebase.add(new_rule) + new_rule.apply() self.report({'message': 'message sent'}) - if __name__ == '__main__': Block_ip().run() diff --git a/responders/PaloAltoNGFW_block_internal_IP_address/PaloAltoNGFW_block_internal_IP_address.json b/responders/PaloAltoNGFW_block_internal_IP_address/PaloAltoNGFW_block_internal_IP_address.json index 36ef81cd9..f59630e2c 100644 --- a/responders/PaloAltoNGFW_block_internal_IP_address/PaloAltoNGFW_block_internal_IP_address.json +++ b/responders/PaloAltoNGFW_block_internal_IP_address/PaloAltoNGFW_block_internal_IP_address.json @@ -1,6 +1,6 @@ { "name": "PaloAltoNGFW_block_internal_IP_address", - "version": "1.0.0", + "version": "2.0.0", "author": "Maxim Konakin", "url": "", "license": "AGPL-V3", @@ -31,11 +31,11 @@ "required": true }, { - "name": "name_internal_Address_Group", - "description": "name_internal_Address_Group", + "name": "name_security_rule", + "description": "name_internal_name_security_rule_for_ip", "type": "string", "multi": false, - "required": true + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW_block_internal_IP_address/README.md b/responders/PaloAltoNGFW_block_internal_IP_address/README.md index e58e9dd68..740b81d06 100644 --- a/responders/PaloAltoNGFW_block_internal_IP_address/README.md +++ b/responders/PaloAltoNGFW_block_internal_IP_address/README.md @@ -10,7 +10,7 @@ need install: # ToDo -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_Address_Group". +to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list principle of operation: @@ -18,4 +18,5 @@ principle of operation: 2. ioc compare against already added AddressObject. 3. if ioc not in AddressObject, will add 4. if ioc in AddressObject, next step -5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file +5. checks if there is already a blocking list, if not, ioc will add +6. create security rule and add AddressObject \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_domain/Block_domain.py b/responders/PaloAltoNGFW_block_internal_domain/Block_domain.py index cb1d1ce96..f38e768c1 100644 --- a/responders/PaloAltoNGFW_block_internal_domain/Block_domain.py +++ b/responders/PaloAltoNGFW_block_internal_domain/Block_domain.py @@ -5,6 +5,7 @@ from thehive4py.api import TheHiveApi from panos import firewall import panos.objects +import panos.policies class Block_domain(Responder): def __init__(self): @@ -12,7 +13,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Address_Group_for_domain = self.get_param('config.name_internal_Address_Group') + self.name_security_rule = self.get_param('config.name_security_rule','Block internal Domain') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -33,18 +34,36 @@ def run(self): ioc="".join(ioc_clear) fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) panos.objects.AddressObject.refreshall(fw) + rulebase = panos.policies.Rulebase() + fw.add(rulebase) + current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): - new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked fqdn",type="fqdn") + new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked domain",type="fqdn") fw.add(new_ioc_object) - new_ioc_object.create() + new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find(self.name_internal_Address_Group_for_domain, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc not in ioc_list: - ioc_list.append(ioc) - temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group_for_domain, static_value=ioc_list) + block_list = fw.find("Black list internal domain", panos.objects.AddressGroup) + if block_list != None: + ioc_list = block_list.about().get('static_value') + if ioc not in ioc_list: + ioc_list.append(ioc) + temp1 = panos.objects.AddressGroup("Black list internal domain", static_value=ioc_list) + fw.add(temp1) + temp1.apply() + elif block_list == None: + temp1 = panos.objects.AddressGroup("Black list internal domain", static_value=ioc) fw.add(temp1) temp1.apply() + desired_rule_params = { + "name": self.name_security_rule, + "description": "Block internal Domain", + "type": "intrazone", + "action": "deny", + 'destination': "Black list internal domain" + } + new_rule = panos.policies.SecurityRule(**desired_rule_params) + rulebase.add(new_rule) + new_rule.apply() self.report({'message': 'message sent'}) if __name__ == '__main__': diff --git a/responders/PaloAltoNGFW_block_internal_domain/PaloAltoNGFW_block_internal_domain.json b/responders/PaloAltoNGFW_block_internal_domain/PaloAltoNGFW_block_internal_domain.json index e52db2720..844244a70 100644 --- a/responders/PaloAltoNGFW_block_internal_domain/PaloAltoNGFW_block_internal_domain.json +++ b/responders/PaloAltoNGFW_block_internal_domain/PaloAltoNGFW_block_internal_domain.json @@ -1,6 +1,6 @@ { "name": "PaloAltoNGFW_block_internal_domain", - "version": "1.0.0", + "version": "2.0.0", "author": "Maxim Konakin", "url": "", "license": "AGPL-V3", @@ -31,11 +31,11 @@ "required": true }, { - "name": "name_internal_Address_Group", - "description": "name_internal_Address_Group_for_domain", + "name": "name_security_rule", + "description": "name_internal_security_rule_for_domain", "type": "string", "multi": false, - "required": true + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW_block_internal_domain/README.md b/responders/PaloAltoNGFW_block_internal_domain/README.md index bda74a5f2..740b81d06 100644 --- a/responders/PaloAltoNGFW_block_internal_domain/README.md +++ b/responders/PaloAltoNGFW_block_internal_domain/README.md @@ -10,7 +10,7 @@ need install: # ToDo -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Address_Group_for_domain". +to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list principle of operation: @@ -18,4 +18,5 @@ principle of operation: 2. ioc compare against already added AddressObject. 3. if ioc not in AddressObject, will add 4. if ioc in AddressObject, next step -5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file +5. checks if there is already a blocking list, if not, ioc will add +6. create security rule and add AddressObject \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_user/Block_user.py b/responders/PaloAltoNGFW_block_internal_user/Block_user.py new file mode 100644 index 000000000..7f63cf059 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_user/Block_user.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.policies + +class Block_user(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_security_rule = self.get_param('config.name_security_rule','Block user internal communication') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + user=None + user_list_alert=[] + for i in list(response.json().get("artifacts")): + if 'user' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + user_list_alert.append(i) + user="".join(user_list_alert) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + rulebase = panos.policies.Rulebase() + fw.add(rulebase) + current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) + user_list=[] + for i in current_security_rules: + if i.about().get('name') == self.name_security_rule: + user_list=i.about().get("source_user") + if user not in user_list: + user_list.append(user) + desired_rule_params = { + "name": self.name_security_rule, + "description": "Block user internal communication", + "type": "intrazone", + "action": "deny", + 'source_user': user_list + } + new_rule = panos.policies.SecurityRule(**desired_rule_params) + rulebase.add(new_rule) + new_rule.apply() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Block_user().run() diff --git a/responders/PaloAltoNGFW_block_internal_user/PaloAltoNGFW_block_internal_user.json b/responders/PaloAltoNGFW_block_internal_user/PaloAltoNGFW_block_internal_user.json new file mode 100644 index 000000000..24ae71691 --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_user/PaloAltoNGFW_block_internal_user.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_block_internal_user", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Block internal user", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_block_internal_user/Block_user.py", + "baseConfig": "PaloAltoNGFW_block_internal_user", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_security_rule", + "description": "name_internal_name_security_rule_for_users", + "type": "string", + "multi": false, + "required": false + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_block_internal_user/README.md b/responders/PaloAltoNGFW_block_internal_user/README.md new file mode 100644 index 000000000..33b80bacb --- /dev/null +++ b/responders/PaloAltoNGFW_block_internal_user/README.md @@ -0,0 +1,18 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" + +principle of operation: +1. the value is selected from the alert the hive. +2. user compare against already added security rule. +3. if user not in security rule, will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_external_IP_address/PaloAltoNGFW_unblock_external_IP_address.json b/responders/PaloAltoNGFW_unblock_external_IP_address/PaloAltoNGFW_unblock_external_IP_address.json new file mode 100644 index 000000000..549aeedd0 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_external_IP_address/PaloAltoNGFW_unblock_external_IP_address.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_unblock_external_IP_address", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Unblock ip", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_unblock_external_IP_address/Unblock_ip.py", + "baseConfig": "PaloAltoNGFW_unblock_ip", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_external_Address_Group", + "description": "name_external_Address_Group", + "type": "string", + "multi": false, + "required": false + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_unblock_external_IP_address/README.md b/responders/PaloAltoNGFW_unblock_external_IP_address/README.md new file mode 100644 index 000000000..65a3ee6d5 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_external_IP_address/README.md @@ -0,0 +1,20 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need set setting PaloAltoNGFW and The Hive. If you want delete in custom Address Group you need set "Address_Group" +https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added AddressObject. +3. if ioc in AddressGroup, will delete +4. if ioc in AddressObject, will delete \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_external_IP_address/Unblock_ip.py b/responders/PaloAltoNGFW_unblock_external_IP_address/Unblock_ip.py new file mode 100644 index 000000000..bba99cfcd --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_external_IP_address/Unblock_ip.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Unblock_ip(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_external_Address_Group = self.get_param('config.name_external_Address_Group',"Black list external IP") + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'ip' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressGroup.refreshall(fw) + block_list = fw.find(self.name_external_Address_Group, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc in ioc_list: + ioc_list.remove(ioc) + temp1 = panos.objects.AddressGroup(self.name_external_Address_Group, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + + panos.objects.AddressObject.refreshall(fw) + if ioc in str(fw.find(ioc, panos.objects.AddressObject)): + try: + deleted_ioc = fw.find(ioc, panos.objects.AddressObject) + deleted_ioc.delete() + except: + self.report({'message': 'message sent'}) + + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Unblock_ip().run() diff --git a/responders/PaloAltoNGFW_unblock_external_domain/PaloAltoNGFW_unblock_external_domain.json b/responders/PaloAltoNGFW_unblock_external_domain/PaloAltoNGFW_unblock_external_domain.json new file mode 100644 index 000000000..b3d8f0eff --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_external_domain/PaloAltoNGFW_unblock_external_domain.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_unblock_external_domain", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Unblock domain", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_unblock_external_domain/Unblock_domain.py", + "baseConfig": "PaloAltoNGFW_unblock_external_domain", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_external_Address_Group", + "description": "name_external_Address_Group_for_domain", + "type": "string", + "multi": false, + "required": false + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_unblock_external_domain/README.md b/responders/PaloAltoNGFW_unblock_external_domain/README.md new file mode 100644 index 000000000..65a3ee6d5 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_external_domain/README.md @@ -0,0 +1,20 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need set setting PaloAltoNGFW and The Hive. If you want delete in custom Address Group you need set "Address_Group" +https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added AddressObject. +3. if ioc in AddressGroup, will delete +4. if ioc in AddressObject, will delete \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_external_domain/Unblock_domain.py b/responders/PaloAltoNGFW_unblock_external_domain/Unblock_domain.py new file mode 100644 index 000000000..9eff67092 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_external_domain/Unblock_domain.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects +import panos.policies + +class Unblock_domain(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_external_Address_Group_for_domain = self.get_param('config.name_external_Address_Group',"Black list external domain") + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'hostname' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressGroup.refreshall(fw) + + block_list = fw.find(self.name_external_Address_Group_for_domain, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc in ioc_list: + ioc_list.remove(ioc) + temp1 = panos.objects.AddressGroup(self.name_external_Address_Group_for_domain, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + + panos.objects.AddressObject.refreshall(fw) + if ioc in str(fw.find(ioc, panos.objects.AddressObject)): + try: + deleted_ioc = fw.find(ioc, panos.objects.AddressObject) + deleted_ioc.delete() + except: + self.report({'message': 'message sent'}) + + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Unblock_domain().run() diff --git a/responders/PaloAltoNGFW_unblock_external_user/PaloAltoNGFW_unblock_external_user.json b/responders/PaloAltoNGFW_unblock_external_user/PaloAltoNGFW_unblock_external_user.json new file mode 100644 index 000000000..62f5699f1 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_external_user/PaloAltoNGFW_unblock_external_user.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_unblock_external_user", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Unblock external user", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_unblock_external_user/Unblock_user.py", + "baseConfig": "PaloAltoNGFW_unblock_external_user", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_security_rule", + "description": "name_external_name_security_rule_for_users", + "type": "string", + "multi": false, + "required": false + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_unblock_external_user/README.md b/responders/PaloAltoNGFW_unblock_external_user/README.md new file mode 100644 index 000000000..18aa819d1 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_external_user/README.md @@ -0,0 +1,18 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" + +principle of operation: +1. the value is selected from the alert the hive. +2. user compare against already added in security rules. +3. if user in security rules, will delete \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_external_user/Unblock_user.py b/responders/PaloAltoNGFW_unblock_external_user/Unblock_user.py new file mode 100644 index 000000000..5a30e474f --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_external_user/Unblock_user.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.policies + +class Unblock_user(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_security_rule = self.get_param('config.name_security_rule','Block user external communication') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + user=None + user_list_alert=[] + for i in list(response.json().get("artifacts")): + if 'user' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + user_list_alert.append(i) + user="".join(user_list_alert) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + rulebase = panos.policies.Rulebase() + fw.add(rulebase) + current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) + user_list=[] + for i in current_security_rules: + if i.about().get('name') == self.name_security_rule: + user_list=i.about().get("source_user") + if user in user_list: + user_list.remove(user) + desired_rule_params = { + "name": self.name_security_rule, + "description": "Block user external communication", + "type": "interzone", + "action": "deny", + 'source_user': user_list + } + new_rule = panos.policies.SecurityRule(**desired_rule_params) + rulebase.add(new_rule) + new_rule.apply() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Unblock_user().run() diff --git a/responders/PaloAltoNGFW_unblock_internal_IP_address/PaloAltoNGFW_unblock_internal_IP_address.json b/responders/PaloAltoNGFW_unblock_internal_IP_address/PaloAltoNGFW_unblock_internal_IP_address.json new file mode 100644 index 000000000..7b4f2f71b --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_internal_IP_address/PaloAltoNGFW_unblock_internal_IP_address.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_unblock_internal_IP_address", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Unblock ip", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_unblock_internal_IP_address/Unblock_ip.py", + "baseConfig": "PaloAltoNGFW_unblock_ip", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_internal_Address_Group", + "description": "name_internal_Address_Group", + "type": "string", + "multi": false, + "required": false + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_unblock_internal_IP_address/README.md b/responders/PaloAltoNGFW_unblock_internal_IP_address/README.md new file mode 100644 index 000000000..65a3ee6d5 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_internal_IP_address/README.md @@ -0,0 +1,20 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need set setting PaloAltoNGFW and The Hive. If you want delete in custom Address Group you need set "Address_Group" +https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added AddressObject. +3. if ioc in AddressGroup, will delete +4. if ioc in AddressObject, will delete \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_internal_IP_address/Unblock_ip.py b/responders/PaloAltoNGFW_unblock_internal_IP_address/Unblock_ip.py new file mode 100644 index 000000000..3ac261056 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_internal_IP_address/Unblock_ip.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Unblock_ip(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_Address_Group = self.get_param('config.name_internal_Address_Group',"Black list internal IP") + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'ip' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressGroup.refreshall(fw) + block_list = fw.find(self.name_internal_Address_Group, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc in ioc_list: + ioc_list.remove(ioc) + temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + + panos.objects.AddressObject.refreshall(fw) + if ioc in str(fw.find(ioc, panos.objects.AddressObject)): + try: + deleted_ioc = fw.find(ioc, panos.objects.AddressObject) + deleted_ioc.delete() + except: + self.report({'message': 'message sent'}) + + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Unblock_ip().run() diff --git a/responders/PaloAltoNGFW_unblock_internal_domain/PaloAltoNGFW_unblock_internal_domain.json b/responders/PaloAltoNGFW_unblock_internal_domain/PaloAltoNGFW_unblock_internal_domain.json new file mode 100644 index 000000000..a2f0c1dd2 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_internal_domain/PaloAltoNGFW_unblock_internal_domain.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_unblock_internal_domain", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Unblock domain", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_unblock_internal_domain/Unblock_domain.py", + "baseConfig": "PaloAltoNGFW_unblock_internal_domain", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_internal_Address_Group", + "description": "name_internal_Address_Group_for_domain", + "type": "string", + "multi": false, + "required": false + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_unblock_internal_domain/README.md b/responders/PaloAltoNGFW_unblock_internal_domain/README.md new file mode 100644 index 000000000..65a3ee6d5 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_internal_domain/README.md @@ -0,0 +1,20 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need set setting PaloAltoNGFW and The Hive. If you want delete in custom Address Group you need set "Address_Group" +https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added AddressObject. +3. if ioc in AddressGroup, will delete +4. if ioc in AddressObject, will delete \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_internal_domain/Unblock_domain.py b/responders/PaloAltoNGFW_unblock_internal_domain/Unblock_domain.py new file mode 100644 index 000000000..949daa7ba --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_internal_domain/Unblock_domain.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects +import panos.policies + +class Unblock_domain(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_Address_Group_for_domain = self.get_param('config.name_external_Address_Group',"Black list internal domain") + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'hostname' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressGroup.refreshall(fw) + + block_list = fw.find(self.name_internal_Address_Group_for_domain, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc in ioc_list: + ioc_list.remove(ioc) + temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group_for_domain, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + + panos.objects.AddressObject.refreshall(fw) + if ioc in str(fw.find(ioc, panos.objects.AddressObject)): + try: + deleted_ioc = fw.find(ioc, panos.objects.AddressObject) + deleted_ioc.delete() + except: + self.report({'message': 'message sent'}) + + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Unblock_domain().run() diff --git a/responders/PaloAltoNGFW_unblock_internal_user/PaloAltoNGFW_unblock_internal_user.json b/responders/PaloAltoNGFW_unblock_internal_user/PaloAltoNGFW_unblock_internal_user.json new file mode 100644 index 000000000..04c0117d0 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_internal_user/PaloAltoNGFW_unblock_internal_user.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_unblock_internal_user", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Unblock internal user", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_unblock_internal_user/Unblock_user.py", + "baseConfig": "PaloAltoNGFW_unblock_internal_user", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_security_rule", + "description": "name_internal_name_security_rule_for_users", + "type": "string", + "multi": false, + "required": false + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_unblock_internal_user/README.md b/responders/PaloAltoNGFW_unblock_internal_user/README.md new file mode 100644 index 000000000..18aa819d1 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_internal_user/README.md @@ -0,0 +1,18 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" + +principle of operation: +1. the value is selected from the alert the hive. +2. user compare against already added in security rules. +3. if user in security rules, will delete \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_internal_user/Unblock_user.py b/responders/PaloAltoNGFW_unblock_internal_user/Unblock_user.py new file mode 100644 index 000000000..152b1f91e --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_internal_user/Unblock_user.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.policies + +class Unblock_user(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_security_rule = self.get_param('config.name_security_rule','Block user internal communication') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + user=None + user_list_alert=[] + for i in list(response.json().get("artifacts")): + if 'user' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + user_list_alert.append(i) + user="".join(user_list_alert) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + rulebase = panos.policies.Rulebase() + fw.add(rulebase) + current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) + user_list=[] + for i in current_security_rules: + if i.about().get('name') == self.name_security_rule: + user_list=i.about().get("source_user") + if user in user_list: + user_list.remove(user) + desired_rule_params = { + "name": self.name_security_rule, + "description": "Block user internal communication", + "type": "intrazone", + "action": "deny", + 'source_user': user_list + } + new_rule = panos.policies.SecurityRule(**desired_rule_params) + rulebase.add(new_rule) + new_rule.apply() + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Unblock_user().run() From c45961fa0acef5155894da9b4c3fbd7b895ec301 Mon Sep 17 00:00:00 2001 From: staf711 <40694301+staf711@users.noreply.github.com> Date: Thu, 29 Oct 2020 18:37:56 +0300 Subject: [PATCH 10/25] Add Responder for port with rules Add Responder for: 1. Block internal port 2. Block external port 3. Unblock internal port 4. Unblock external port --- .../Block_port.py | 32 ++++++++-- .../PaloAltoNGFW_block_external_port.json | 8 +-- .../README.md | 14 ++--- .../Block_port.py | 31 ++++++++-- .../PaloAltoNGFW_block_internal_port.json | 8 +-- .../README.md | 14 ++--- .../PaloAltoNGFW_unblock_external_port.json} | 21 +++---- .../README.md | 19 ++++++ .../Unblock_port.py | 53 ++++++++++++++++ .../PaloAltoNGFW_unblock_internal_port.json | 55 +++++++++++++++++ .../README.md | 19 ++++++ .../Unblock_port.py | 53 ++++++++++++++++ responders/PaloAltoNGFW_unblock_ip/README.md | 18 ------ .../PaloAltoNGFW_unblock_ip/Unblock_ip.py | 61 ------------------- 14 files changed, 277 insertions(+), 129 deletions(-) rename responders/{PaloAltoNGFW_unblock_ip/PaloAltoNGFW_unblock_ip.json => PaloAltoNGFW_unblock_external_port/PaloAltoNGFW_unblock_external_port.json} (68%) create mode 100644 responders/PaloAltoNGFW_unblock_external_port/README.md create mode 100644 responders/PaloAltoNGFW_unblock_external_port/Unblock_port.py create mode 100644 responders/PaloAltoNGFW_unblock_internal_port/PaloAltoNGFW_unblock_internal_port.json create mode 100644 responders/PaloAltoNGFW_unblock_internal_port/README.md create mode 100644 responders/PaloAltoNGFW_unblock_internal_port/Unblock_port.py delete mode 100644 responders/PaloAltoNGFW_unblock_ip/README.md delete mode 100644 responders/PaloAltoNGFW_unblock_ip/Unblock_ip.py diff --git a/responders/PaloAltoNGFW_block_external_port/Block_port.py b/responders/PaloAltoNGFW_block_external_port/Block_port.py index 6f1a919bc..b06bcf8e3 100644 --- a/responders/PaloAltoNGFW_block_external_port/Block_port.py +++ b/responders/PaloAltoNGFW_block_external_port/Block_port.py @@ -6,13 +6,15 @@ from panos import firewall import panos.objects import re +import panos.policies + class Block_port(Responder): def __init__(self): Responder.__init__(self) self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_external_Service_Group = self.get_param('config.name_external_Service_Group') + self.name_security_rule = self.get_param('config.name_security_rule','Block external port') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -34,6 +36,9 @@ def run(self): port=re.findall(r'[0-9]+',str(data)); port="".join(port) fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) panos.objects.ServiceObject.refreshall(fw) + rulebase = panos.policies.Rulebase() + fw.add(rulebase) + current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) if port not in str(fw.find(port, panos.objects.ServiceObject)): new_port_object = panos.objects.ServiceObject(port, protocol, description="Blocked port",destination_port=port) fw.add(new_port_object) @@ -41,13 +46,28 @@ def run(self): panos.objects.ServiceGroup.refreshall(fw) - block_list = fw.find(self.name_external_Service_Group, panos.objects.ServiceGroup) - port_list = block_list.about().get('value') - if port not in port_list: - port_list.append(port) - temp1 = panos.objects.ServiceGroup(self.name_external_Service_Group, value=port_list) + block_list = fw.find("Black list external port", panos.objects.ServiceGroup) + if block_list != None: + port_list = block_list.about().get('value') + if port not in port_list: + port_list.append(port) + temp1 = panos.objects.ServiceGroup("Black list external port", value=port_list) + fw.add(temp1) + temp1.apply() + elif block_list == None: + temp1 = panos.objects.ServiceGroup("Black list external port", value=port) fw.add(temp1) temp1.apply() + desired_rule_params = { + "name": self.name_security_rule, + "description": "Block external port", + "type": "interzone", + "action": "deny", + 'service': "Black list external port" + } + new_rule = panos.policies.SecurityRule(**desired_rule_params) + rulebase.add(new_rule) + new_rule.apply() self.report({'message': 'message sent'}) if __name__ == '__main__': diff --git a/responders/PaloAltoNGFW_block_external_port/PaloAltoNGFW_block_external_port.json b/responders/PaloAltoNGFW_block_external_port/PaloAltoNGFW_block_external_port.json index 540be6dc7..9de58eddb 100644 --- a/responders/PaloAltoNGFW_block_external_port/PaloAltoNGFW_block_external_port.json +++ b/responders/PaloAltoNGFW_block_external_port/PaloAltoNGFW_block_external_port.json @@ -1,6 +1,6 @@ { "name": "PaloAltoNGFW_block_external_port", - "version": "1.0.0", + "version": "2.0.0", "author": "Maxim Konakin", "url": "", "license": "AGPL-V3", @@ -31,11 +31,11 @@ "required": true }, { - "name": "name_external_Service_Group", - "description": "name_external_Service_Group", + "name": "name_security_rule", + "description": "name_external_name_security_rule_for_port", "type": "string", "multi": false, - "required": true + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW_block_external_port/README.md b/responders/PaloAltoNGFW_block_external_port/README.md index 9b84128e4..02695978b 100644 --- a/responders/PaloAltoNGFW_block_external_port/README.md +++ b/responders/PaloAltoNGFW_block_external_port/README.md @@ -10,14 +10,12 @@ need install: # ToDo -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_Service_Group". - -First: you need add field "port" and "protocol" to "Observable types management" in the hive. -or you can change script and call your field names +to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" principle of operation: 1. the value is selected from the alert the hive. -2. ioc compare against already added Service_Group. -3. if ioc not in Service_Group, will add field port and protocol -4. if ioc in Service_Group, next step -5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file +2. ioc compare against already added ServiceObject. +3. if ioc not in ServiceObject, will add +4. if ioc in ServiceObject, next step +5. checks if there is already a blocking list, if not, ioc will add +6. create security rule and add ServiceGroup \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_port/Block_port.py b/responders/PaloAltoNGFW_block_internal_port/Block_port.py index 3d2e00fa1..a23d76409 100644 --- a/responders/PaloAltoNGFW_block_internal_port/Block_port.py +++ b/responders/PaloAltoNGFW_block_internal_port/Block_port.py @@ -5,6 +5,7 @@ from thehive4py.api import TheHiveApi from panos import firewall import panos.objects +import panos.policies import re class Block_port(Responder): def __init__(self): @@ -12,7 +13,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Service_Group = self.get_param('config.name_internal_Service_Group') + self.name_security_rule = self.get_param('config.name_security_rule','Block internal port') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -34,6 +35,9 @@ def run(self): port=re.findall(r'[0-9]+',str(data)); port="".join(port) fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) panos.objects.ServiceObject.refreshall(fw) + rulebase = panos.policies.Rulebase() + fw.add(rulebase) + current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) if port not in str(fw.find(port, panos.objects.ServiceObject)): new_port_object = panos.objects.ServiceObject(port, protocol, description="Blocked port",destination_port=port) fw.add(new_port_object) @@ -41,13 +45,28 @@ def run(self): panos.objects.ServiceGroup.refreshall(fw) - block_list = fw.find(self.name_internal_Service_Group, panos.objects.ServiceGroup) - port_list = block_list.about().get('value') - if port not in port_list: - port_list.append(port) - temp1 = panos.objects.ServiceGroup(self.name_internal_Service_Group, value=port_list) + block_list = fw.find("Black list internal port", panos.objects.ServiceGroup) + if block_list != None: + port_list = block_list.about().get('value') + if port not in port_list: + port_list.append(port) + temp1 = panos.objects.ServiceGroup("Black list internal port", value=port_list) + fw.add(temp1) + temp1.apply() + elif block_list == None: + temp1 = panos.objects.ServiceGroup("Black list internal port", value=port) fw.add(temp1) temp1.apply() + desired_rule_params = { + "name": self.name_security_rule, + "description": "Block internal port", + "type": "interzone", + "action": "deny", + 'service': "Black list internal port" + } + new_rule = panos.policies.SecurityRule(**desired_rule_params) + rulebase.add(new_rule) + new_rule.apply() self.report({'message': 'message sent'}) if __name__ == '__main__': diff --git a/responders/PaloAltoNGFW_block_internal_port/PaloAltoNGFW_block_internal_port.json b/responders/PaloAltoNGFW_block_internal_port/PaloAltoNGFW_block_internal_port.json index e2b3c94dc..dd3e6695c 100644 --- a/responders/PaloAltoNGFW_block_internal_port/PaloAltoNGFW_block_internal_port.json +++ b/responders/PaloAltoNGFW_block_internal_port/PaloAltoNGFW_block_internal_port.json @@ -1,6 +1,6 @@ { "name": "PaloAltoNGFW_block_internal_port", - "version": "1.0.0", + "version": "2.0.0", "author": "Maxim Konakin", "url": "", "license": "AGPL-V3", @@ -31,11 +31,11 @@ "required": true }, { - "name": "name_internal_Service_Group", - "description": "name_internal_Service_Group", + "name": "name_security_rule", + "description": "name_internal_name_security_rule_for_port", "type": "string", "multi": false, - "required": true + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW_block_internal_port/README.md b/responders/PaloAltoNGFW_block_internal_port/README.md index ef1df5628..02695978b 100644 --- a/responders/PaloAltoNGFW_block_internal_port/README.md +++ b/responders/PaloAltoNGFW_block_internal_port/README.md @@ -10,14 +10,12 @@ need install: # ToDo -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Service_Group". - -First: you need add field "port" and "protocol" to "Observable types management" in the hive. -or you can change script and call your field names +to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" principle of operation: 1. the value is selected from the alert the hive. -2. ioc compare against already added Service_Group. -3. if ioc not in Service_Group, will add field port and protocol -4. if ioc in Service_Group, next step -5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file +2. ioc compare against already added ServiceObject. +3. if ioc not in ServiceObject, will add +4. if ioc in ServiceObject, next step +5. checks if there is already a blocking list, if not, ioc will add +6. create security rule and add ServiceGroup \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_ip/PaloAltoNGFW_unblock_ip.json b/responders/PaloAltoNGFW_unblock_external_port/PaloAltoNGFW_unblock_external_port.json similarity index 68% rename from responders/PaloAltoNGFW_unblock_ip/PaloAltoNGFW_unblock_ip.json rename to responders/PaloAltoNGFW_unblock_external_port/PaloAltoNGFW_unblock_external_port.json index b5c2bacb6..45481ffb5 100644 --- a/responders/PaloAltoNGFW_unblock_ip/PaloAltoNGFW_unblock_ip.json +++ b/responders/PaloAltoNGFW_unblock_external_port/PaloAltoNGFW_unblock_external_port.json @@ -1,13 +1,13 @@ { - "name": "PaloAltoNGFW_unblock_ip", + "name": "PaloAltoNGFW_unblock_external_port", "version": "1.0.0", "author": "Maxim Konakin", "url": "", "license": "AGPL-V3", - "description": "Unblock ip", + "description": "Unblock domain", "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_unblock_ip/Unblock_ip.py", - "baseConfig": "PaloAltoNGFW_unblock_ip", + "command": "PaloAltoNGFW_unblock_external_port/Unblock_port.py", + "baseConfig": "PaloAltoNGFW_unblock_port", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -31,18 +31,11 @@ "required": true }, { - "name": "name_internal_Address_Group", - "description": "name_internal_Address_Group_for_ip", + "name": "name_external_Service_Group", + "description": "name_external_Service_Group", "type": "string", "multi": false, - "required": true - }, - { - "name": "name_external_Address_Group", - "description": "name_external_Address_Group_for_ip", - "type": "string", - "multi": false, - "required": true + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW_unblock_external_port/README.md b/responders/PaloAltoNGFW_unblock_external_port/README.md new file mode 100644 index 000000000..e6a38990a --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_external_port/README.md @@ -0,0 +1,19 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need set setting PaloAltoNGFW and The Hive. If you want delete in custom Address Group you need set "ServiceGroup" + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added AddressObject. +3. if ioc in ServiceGroup, will delete +4. if ioc in ServiceObject, will delete \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_external_port/Unblock_port.py b/responders/PaloAltoNGFW_unblock_external_port/Unblock_port.py new file mode 100644 index 000000000..7c1920e1e --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_external_port/Unblock_port.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects +import re +class Unblock_port(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_external_Service_Group = self.get_param('config.name_external_Service_Group','Black list external port') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + data_list=[] + data=None + for i in response.json().get("artifacts"): + if "'port'," in str(i): + ioc = i.get("data") + data_list.append(i.get("data")) + elif "'protocol'," in str(i): + ioc = i.get("data") + data_list.append(i.get("data")) + data=" ".join(data_list) + protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(data)); port="".join(port) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.ServiceGroup.refreshall(fw) + block_list = fw.find(self.name_external_Service_Group, panos.objects.ServiceGroup) + port_list = block_list.about().get('value') + if port in port_list: + port_list.remove(port) + temp1 = panos.objects.ServiceGroup(self.name_external_Service_Group, value=port_list) + fw.add(temp1) + temp1.apply() + + panos.objects.ServiceObject.refreshall(fw) + if port in str(fw.find(port, panos.objects.ServiceObject)): + deleted_ioc = fw.find(port, panos.objects.ServiceObject) + deleted_ioc.delete() + + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Unblock_port().run() diff --git a/responders/PaloAltoNGFW_unblock_internal_port/PaloAltoNGFW_unblock_internal_port.json b/responders/PaloAltoNGFW_unblock_internal_port/PaloAltoNGFW_unblock_internal_port.json new file mode 100644 index 000000000..4a6044fd8 --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_internal_port/PaloAltoNGFW_unblock_internal_port.json @@ -0,0 +1,55 @@ +{ + "name": "PaloAltoNGFW_unblock_internal_port", + "version": "1.0.0", + "author": "Maxim Konakin", + "url": "", + "license": "AGPL-V3", + "description": "Unblock domain", + "dataTypeList": ["thehive:alert"], + "command": "PaloAltoNGFW_unblock_internal_port/Unblock_port.py", + "baseConfig": "PaloAltoNGFW_unblock_port", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User_PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "name_internal_Service_Group", + "description": "name_internal_Service_Group", + "type": "string", + "multi": false, + "required": false + }, + { + "name": "thehive_instance", + "description": "URL of the Thehive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "thehive_api_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW_unblock_internal_port/README.md b/responders/PaloAltoNGFW_unblock_internal_port/README.md new file mode 100644 index 000000000..e6a38990a --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_internal_port/README.md @@ -0,0 +1,19 @@ +# Block external IP address for Palo Alto NGFW + +Response module for block external IP address for Palo Alto NGFW + +# Installation + +need install: +1. pan-os-python +2. thehive4py + +# ToDo + +to work, you need set setting PaloAltoNGFW and The Hive. If you want delete in custom Address Group you need set "ServiceGroup" + +principle of operation: +1. the value is selected from the alert the hive. +2. ioc compare against already added AddressObject. +3. if ioc in ServiceGroup, will delete +4. if ioc in ServiceObject, will delete \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_internal_port/Unblock_port.py b/responders/PaloAltoNGFW_unblock_internal_port/Unblock_port.py new file mode 100644 index 000000000..866602c1e --- /dev/null +++ b/responders/PaloAltoNGFW_unblock_internal_port/Unblock_port.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects +import re +class Unblock_port(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_Service_Group = self.get_param('config.name_internal_Service_Group','Black list internal port') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + data_list=[] + data=None + for i in response.json().get("artifacts"): + if "'port'," in str(i): + ioc = i.get("data") + data_list.append(i.get("data")) + elif "'protocol'," in str(i): + ioc = i.get("data") + data_list.append(i.get("data")) + data=" ".join(data_list) + protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(data)); port="".join(port) + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.ServiceGroup.refreshall(fw) + block_list = fw.find(self.name_internal_Service_Group, panos.objects.ServiceGroup) + port_list = block_list.about().get('value') + if port in port_list: + port_list.remove(port) + temp1 = panos.objects.ServiceGroup(self.name_internal_Service_Group, value=port_list) + fw.add(temp1) + temp1.apply() + + panos.objects.ServiceObject.refreshall(fw) + if port in str(fw.find(port, panos.objects.ServiceObject)): + deleted_ioc = fw.find(port, panos.objects.ServiceObject) + deleted_ioc.delete() + + self.report({'message': 'message sent'}) + +if __name__ == '__main__': + Unblock_port().run() diff --git a/responders/PaloAltoNGFW_unblock_ip/README.md b/responders/PaloAltoNGFW_unblock_ip/README.md deleted file mode 100644 index 0ff66431e..000000000 --- a/responders/PaloAltoNGFW_unblock_ip/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Address_Group_" and "name_external_Address_Group" - -principle of operation: -1. the value is selected from the alert the hive. -2. if ioc added in Address_Groups, script deleted ioc -3. if ioc in AddressObject, script deleted ioc \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_ip/Unblock_ip.py b/responders/PaloAltoNGFW_unblock_ip/Unblock_ip.py deleted file mode 100644 index 2fae0f761..000000000 --- a/responders/PaloAltoNGFW_unblock_ip/Unblock_ip.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects - -class Unblock_ip(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Address_Group = self.get_param('config.name_internal_Address_Group') - self.name_external_Address_Group = self.get_param('config.name_external_Address_Group') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'ip' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find(self.name_internal_Address_Group, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc in ioc_list: - ioc_list.remove(ioc) - temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group, static_value=ioc_list) - fw.add(temp1) - temp1.apply() - - block_list = fw.find(self.name_external_Address_Group, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc in ioc_list: - ioc_list.remove(ioc) - temp1 = panos.objects.AddressGroup(self.name_external_Address_Group, static_value=ioc_list) - fw.add(temp1) - temp1.apply() - - panos.objects.AddressObject.refreshall(fw) - if ioc in str(fw.find(ioc, panos.objects.AddressObject)): - deleted_ioc = fw.find(ioc, panos.objects.AddressObject) - deleted_ioc.delete() - - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Unblock_ip().run() From 2cb53cff9070f1c426b87235f1e7f74faddf4575 Mon Sep 17 00:00:00 2001 From: staf711 <40694301+staf711@users.noreply.github.com> Date: Sun, 8 Nov 2020 21:20:24 +0300 Subject: [PATCH 11/25] Add custom rules and save attributes New version response scripts for save attributes in rules --- .../Block_ip.py | 26 ++++++++++++++----- .../Block_domain.py | 26 ++++++++++++++----- .../Block_port.py | 26 ++++++++++++++----- .../Block_user.py | 23 +++++++++++----- .../Block_ip.py | 26 ++++++++++++++----- .../Block_domain.py | 26 ++++++++++++++----- .../Block_port.py | 26 ++++++++++++++----- .../Block_user.py | 23 +++++++++++----- 8 files changed, 146 insertions(+), 56 deletions(-) diff --git a/responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py b/responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py index dde73785c..fafd5fdd1 100644 --- a/responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py +++ b/responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py @@ -54,13 +54,25 @@ def run(self): temp1 = panos.objects.AddressGroup("Black list external IP", static_value=ioc) fw.add(temp1) temp1.apply() - desired_rule_params = { - "name": self.name_security_rule, - "description": "Block external IP address", - "type": "interzone", - "action": "deny", - 'destination': "Black list external IP" - } + desired_rule_params = None + for i in current_security_rules: + if self.name_security_rule == i.about().get("name"): + rule_atrib = i.about() + temp_rule_atrib = rule_atrib.get("destination") + if "Black list external IP" not in temp_rule_atrib: + temp_rule_atrib.append("Black list external IP") + if "any" in temp_rule_atrib: + temp_rule_atrib.remove("any") + rule_atrib.update({"destination": temp_rule_atrib}) + desired_rule_params = rule_atrib + elif self.name_security_rule != i.about().get("name"): + desired_rule_params = { + "name": self.name_security_rule, + "description": "Block external IP address", + "type": "interzone", + "action": "deny", + 'destination': "Black list external IP" + } new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() diff --git a/responders/PaloAltoNGFW_block_external_domain/Block_domain.py b/responders/PaloAltoNGFW_block_external_domain/Block_domain.py index 4e2c1b5ed..bea786061 100644 --- a/responders/PaloAltoNGFW_block_external_domain/Block_domain.py +++ b/responders/PaloAltoNGFW_block_external_domain/Block_domain.py @@ -54,13 +54,25 @@ def run(self): temp1 = panos.objects.AddressGroup("Black list external domain", static_value=ioc) fw.add(temp1) temp1.apply() - desired_rule_params = { - "name": self.name_security_rule, - "description": "Block external Domain", - "type": "interzone", - "action": "deny", - 'destination': "Black list external domain" - } + desired_rule_params = None + for i in current_security_rules: + if self.name_security_rule == i.about().get("name"): + rule_atrib = i.about() + temp_rule_atrib = rule_atrib.get("destination") + if "Black list external domain" not in temp_rule_atrib: + temp_rule_atrib.append("Black list external domain") + if "any" in temp_rule_atrib: + temp_rule_atrib.remove("any") + rule_atrib.update({"destination": temp_rule_atrib}) + desired_rule_params = rule_atrib + elif self.name_security_rule != i.about().get("name"): + desired_rule_params = { + "name": self.name_security_rule, + "description": "Block external Domain", + "type": "interzone", + "action": "deny", + 'destination': "Black list external domain" + } new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() diff --git a/responders/PaloAltoNGFW_block_external_port/Block_port.py b/responders/PaloAltoNGFW_block_external_port/Block_port.py index b06bcf8e3..6d9261261 100644 --- a/responders/PaloAltoNGFW_block_external_port/Block_port.py +++ b/responders/PaloAltoNGFW_block_external_port/Block_port.py @@ -58,13 +58,25 @@ def run(self): temp1 = panos.objects.ServiceGroup("Black list external port", value=port) fw.add(temp1) temp1.apply() - desired_rule_params = { - "name": self.name_security_rule, - "description": "Block external port", - "type": "interzone", - "action": "deny", - 'service': "Black list external port" - } + desired_rule_params = None + for i in current_security_rules: + if self.name_security_rule == str(i.about().get("name")): + rule_atrib = i.about() + temp_rule_atrib = rule_atrib.get("service") + if "Black list external port" not in temp_rule_atrib: + temp_rule_atrib.append("Black list external port") + if "application-default" in temp_rule_atrib: + temp_rule_atrib.remove("application-default") + rule_atrib.update({"service": temp_rule_atrib}) + desired_rule_params = rule_atrib + elif self.name_security_rule != i.about().get("name"): + desired_rule_params = { + "name": self.name_security_rule, + "description": "Block external port", + "type": "interzone", + "action": "deny", + 'service': "Black list external port" + } new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() diff --git a/responders/PaloAltoNGFW_block_external_user/Block_user.py b/responders/PaloAltoNGFW_block_external_user/Block_user.py index 6392bab9a..81b8e1ff2 100644 --- a/responders/PaloAltoNGFW_block_external_user/Block_user.py +++ b/responders/PaloAltoNGFW_block_external_user/Block_user.py @@ -41,13 +41,22 @@ def run(self): user_list=i.about().get("source_user") if user not in user_list: user_list.append(user) - desired_rule_params = { - "name": self.name_security_rule, - "description": "Block user external communication", - "type": "interzone", - "action": "deny", - 'source_user': user_list - } + if "any" in user_list: + user_list.remove("any") + desired_rule_params = None + for i in current_security_rules: + if self.name_security_rule == i.about().get("name"): + rule_atrib = i.about() + rule_atrib.update({"source_user": user_list}) + desired_rule_params = rule_atrib + elif self.name_security_rule != i.about().get("name"): + desired_rule_params = { + "name": self.name_security_rule, + "description": "Block user external communication", + "type": "interzone", + "action": "deny", + 'source_user': user_list + } new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() diff --git a/responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py b/responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py index 9fb32ac5a..2c73b4098 100644 --- a/responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py +++ b/responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py @@ -54,13 +54,25 @@ def run(self): temp1 = panos.objects.AddressGroup("Black list internal IP", static_value=ioc) fw.add(temp1) temp1.apply() - desired_rule_params = { - "name": self.name_security_rule, - "description": "Block internal IP address", - "type": "intrazone", - "action": "deny", - 'destination': "Black list internal IP" - } + desired_rule_params = None + for i in current_security_rules: + if self.name_security_rule == i.about().get("name"): + rule_atrib = i.about() + temp_rule_atrib = rule_atrib.get("destination") + if "Black list internal IP" not in temp_rule_atrib: + temp_rule_atrib.append("Black list internal IP") + if "any" in temp_rule_atrib: + temp_rule_atrib.remove("any") + rule_atrib.update({"destination": temp_rule_atrib}) + desired_rule_params = rule_atrib + elif self.name_security_rule != i.about().get("name"): + desired_rule_params = { + "name": self.name_security_rule, + "description": "Block internal IP address", + "type": "intrazone", + "action": "deny", + 'destination': "Black list internal IP" + } new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() diff --git a/responders/PaloAltoNGFW_block_internal_domain/Block_domain.py b/responders/PaloAltoNGFW_block_internal_domain/Block_domain.py index f38e768c1..4d935e06b 100644 --- a/responders/PaloAltoNGFW_block_internal_domain/Block_domain.py +++ b/responders/PaloAltoNGFW_block_internal_domain/Block_domain.py @@ -54,13 +54,25 @@ def run(self): temp1 = panos.objects.AddressGroup("Black list internal domain", static_value=ioc) fw.add(temp1) temp1.apply() - desired_rule_params = { - "name": self.name_security_rule, - "description": "Block internal Domain", - "type": "intrazone", - "action": "deny", - 'destination': "Black list internal domain" - } + desired_rule_params = None + for i in current_security_rules: + if self.name_security_rule == i.about().get("name"): + rule_atrib = i.about() + temp_rule_atrib = rule_atrib.get("destination") + if "Black list internal domain" not in temp_rule_atrib: + temp_rule_atrib.append("Black list internal domain") + if "any" in temp_rule_atrib: + temp_rule_atrib.remove("any") + rule_atrib.update({"destination": temp_rule_atrib}) + desired_rule_params = rule_atrib + elif self.name_security_rule != i.about().get("name"): + desired_rule_params = { + "name": self.name_security_rule, + "description": "Block internal Domain", + "type": "intrazone", + "action": "deny", + 'destination': "Black list internal domain" + } new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() diff --git a/responders/PaloAltoNGFW_block_internal_port/Block_port.py b/responders/PaloAltoNGFW_block_internal_port/Block_port.py index a23d76409..dbce2b47a 100644 --- a/responders/PaloAltoNGFW_block_internal_port/Block_port.py +++ b/responders/PaloAltoNGFW_block_internal_port/Block_port.py @@ -57,13 +57,25 @@ def run(self): temp1 = panos.objects.ServiceGroup("Black list internal port", value=port) fw.add(temp1) temp1.apply() - desired_rule_params = { - "name": self.name_security_rule, - "description": "Block internal port", - "type": "interzone", - "action": "deny", - 'service': "Black list internal port" - } + desired_rule_params = None + for i in current_security_rules: + if self.name_security_rule == i.about().get("name"): + rule_atrib = i.about() + temp_rule_atrib = rule_atrib.get("service") + if "Black list internal port" not in temp_rule_atrib: + temp_rule_atrib.append("Black list internal port") + if "application-default" in temp_rule_atrib: + temp_rule_atrib.remove("application-default") + rule_atrib.update({"service": temp_rule_atrib}) + desired_rule_params = rule_atrib + elif self.name_security_rule != i.about().get("name"): + desired_rule_params = { + "name": self.name_security_rule, + "description": "Block internal port", + "type": "interzone", + "action": "deny", + 'service': "Black list internal port" + } new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() diff --git a/responders/PaloAltoNGFW_block_internal_user/Block_user.py b/responders/PaloAltoNGFW_block_internal_user/Block_user.py index 7f63cf059..34d5a2c04 100644 --- a/responders/PaloAltoNGFW_block_internal_user/Block_user.py +++ b/responders/PaloAltoNGFW_block_internal_user/Block_user.py @@ -41,13 +41,22 @@ def run(self): user_list=i.about().get("source_user") if user not in user_list: user_list.append(user) - desired_rule_params = { - "name": self.name_security_rule, - "description": "Block user internal communication", - "type": "intrazone", - "action": "deny", - 'source_user': user_list - } + if "any" in user_list: + user_list.remove("any") + desired_rule_params = None + for i in current_security_rules: + if self.name_security_rule == i.about().get("name"): + rule_atrib = i.about() + rule_atrib.update({"source_user": user_list}) + desired_rule_params = rule_atrib + elif self.name_security_rule != i.about().get("name"): + desired_rule_params = { + "name": self.name_security_rule, + "description": "Block user internal communication", + "type": "intrazone", + "action": "deny", + 'source_user': user_list + } new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() From da777ab572799507d68d97ba8f1c9edec66b6b41 Mon Sep 17 00:00:00 2001 From: staf711 <40694301+staf711@users.noreply.github.com> Date: Wed, 16 Dec 2020 19:29:03 +0300 Subject: [PATCH 12/25] Add new version responders In new vesion: 1. responders in one folder. 2. responders run with case_artifact and case. 3. added prefixes to the names of the rules and the list 4. README.md please write if you find a bug or have a suggestion for a future request. --- .../Block_external_domain.py} | 71 +++++++++------- .../Block_external_ip.py} | 71 +++++++++------- .../Block_external_port.py} | 69 +++++++++------- .../Block_external_user.py} | 59 +++++++------ .../Block_internal_domain.py} | 71 +++++++++------- .../Block_internal_ip.py} | 71 +++++++++------- .../Block_internal_port.py} | 71 +++++++++------- .../Block_internal_user.py} | 59 +++++++------ ...aloAltoNGFW_block_external_IP_address.json | 6 +- .../PaloAltoNGFW_block_external_domain.json | 6 +- .../PaloAltoNGFW_block_external_port.json | 6 +- .../PaloAltoNGFW_block_external_user.json | 6 +- ...aloAltoNGFW_block_internal_IP_address.json | 6 +- .../PaloAltoNGFW_block_internal_domain.json | 6 +- .../PaloAltoNGFW_block_internal_port.json | 6 +- .../PaloAltoNGFW_block_internal_user.json | 6 +- ...oAltoNGFW_unblock_external_IP_address.json | 6 +- .../PaloAltoNGFW_unblock_external_domain.json | 6 +- .../PaloAltoNGFW_unblock_external_port.json | 6 +- .../PaloAltoNGFW_unblock_external_user.json | 6 +- ...oAltoNGFW_unblock_internal_IP_address.json | 6 +- .../PaloAltoNGFW_unblock_internal_domain.json | 6 +- .../PaloAltoNGFW_unblock_internal_port.json | 6 +- .../PaloAltoNGFW_unblock_internal_user.json | 6 +- responders/PaloAltoNGFW/README.md | 47 +++++++++++ .../PaloAltoNGFW/Unblock_external_domain.py | 78 ++++++++++++++++++ .../PaloAltoNGFW/Unblock_external_ip.py | 76 +++++++++++++++++ .../PaloAltoNGFW/Unblock_external_port.py | 69 ++++++++++++++++ .../PaloAltoNGFW/Unblock_external_user.py | 75 +++++++++++++++++ .../PaloAltoNGFW/Unblock_internal_domain.py | 78 ++++++++++++++++++ .../PaloAltoNGFW/Unblock_internal_ip.py | 76 +++++++++++++++++ .../PaloAltoNGFW/Unblock_internal_port.py | 69 ++++++++++++++++ .../PaloAltoNGFW/Unblock_internal_user.py | 75 +++++++++++++++++ responders/PaloAltoNGFW/requirements.txt | 3 + .../README.md | 21 ----- .../README.md | 22 ----- .../README.md | 21 ----- .../Block_url.py | 46 ----------- .../PaloAltoNGFW_block_external_url.json | 55 ------------ .../PaloAltoNGFW_block_external_url/README.md | 19 ----- .../README.md | 18 ---- .../README.md | 22 ----- .../README.md | 22 ----- .../README.md | 21 ----- .../Block_url.py | 46 ----------- .../PaloAltoNGFW_block_internal_url.json | 55 ------------ .../PaloAltoNGFW_block_internal_url/README.md | 21 ----- .../README.md | 18 ---- .../PaloAltoNGFW_unblock_domain.json | 62 -------------- .../PaloAltoNGFW_unblock_domain/README.md | 18 ---- .../Unblock_domain.py | 61 -------------- .../README.md | 20 ----- .../Unblock_ip.py | 55 ------------ .../README.md | 20 ----- .../Unblock_domain.py | 57 ------------- .../README.md | 19 ----- .../Unblock_port.py | 53 ------------ .../README.md | 18 ---- .../Unblock_user.py | 57 ------------- .../README.md | 20 ----- .../Unblock_ip.py | 55 ------------ .../README.md | 20 ----- .../Unblock_domain.py | 57 ------------- .../README.md | 19 ----- .../Unblock_port.py | 53 ------------ .../README.md | 18 ---- .../Unblock_user.py | 57 ------------- .../.Unblock_port.py.swp | Bin 12288 -> 0 bytes .../PaloAltoNGFW_unblock_port.json | 62 -------------- .../PaloAltoNGFW_unblock_port/README.md | 19 ----- .../PaloAltoNGFW_unblock_port/Unblock_port.py | 63 -------------- 71 files changed, 1016 insertions(+), 1558 deletions(-) rename responders/{PaloAltoNGFW_block_internal_domain/Block_domain.py => PaloAltoNGFW/Block_external_domain.py} (51%) rename responders/{PaloAltoNGFW_block_external_IP_address/Block_ip.py => PaloAltoNGFW/Block_external_ip.py} (51%) rename responders/{PaloAltoNGFW_block_external_port/Block_port.py => PaloAltoNGFW/Block_external_port.py} (52%) rename responders/{PaloAltoNGFW_block_external_user/Block_user.py => PaloAltoNGFW/Block_external_user.py} (51%) rename responders/{PaloAltoNGFW_block_external_domain/Block_domain.py => PaloAltoNGFW/Block_internal_domain.py} (51%) rename responders/{PaloAltoNGFW_block_internal_IP_address/Block_ip.py => PaloAltoNGFW/Block_internal_ip.py} (51%) rename responders/{PaloAltoNGFW_block_internal_port/Block_port.py => PaloAltoNGFW/Block_internal_port.py} (51%) rename responders/{PaloAltoNGFW_block_internal_user/Block_user.py => PaloAltoNGFW/Block_internal_user.py} (51%) rename responders/{PaloAltoNGFW_block_external_IP_address => PaloAltoNGFW}/PaloAltoNGFW_block_external_IP_address.json (88%) rename responders/{PaloAltoNGFW_block_external_domain => PaloAltoNGFW}/PaloAltoNGFW_block_external_domain.json (87%) rename responders/{PaloAltoNGFW_block_external_port => PaloAltoNGFW}/PaloAltoNGFW_block_external_port.json (88%) rename responders/{PaloAltoNGFW_block_external_user => PaloAltoNGFW}/PaloAltoNGFW_block_external_user.json (88%) rename responders/{PaloAltoNGFW_block_internal_IP_address => PaloAltoNGFW}/PaloAltoNGFW_block_internal_IP_address.json (88%) rename responders/{PaloAltoNGFW_block_internal_domain => PaloAltoNGFW}/PaloAltoNGFW_block_internal_domain.json (87%) rename responders/{PaloAltoNGFW_block_internal_port => PaloAltoNGFW}/PaloAltoNGFW_block_internal_port.json (88%) rename responders/{PaloAltoNGFW_block_internal_user => PaloAltoNGFW}/PaloAltoNGFW_block_internal_user.json (88%) rename responders/{PaloAltoNGFW_unblock_external_IP_address => PaloAltoNGFW}/PaloAltoNGFW_unblock_external_IP_address.json (87%) rename responders/{PaloAltoNGFW_unblock_external_domain => PaloAltoNGFW}/PaloAltoNGFW_unblock_external_domain.json (87%) rename responders/{PaloAltoNGFW_unblock_external_port => PaloAltoNGFW}/PaloAltoNGFW_unblock_external_port.json (87%) rename responders/{PaloAltoNGFW_unblock_external_user => PaloAltoNGFW}/PaloAltoNGFW_unblock_external_user.json (87%) rename responders/{PaloAltoNGFW_unblock_internal_IP_address => PaloAltoNGFW}/PaloAltoNGFW_unblock_internal_IP_address.json (87%) rename responders/{PaloAltoNGFW_unblock_internal_domain => PaloAltoNGFW}/PaloAltoNGFW_unblock_internal_domain.json (87%) rename responders/{PaloAltoNGFW_unblock_internal_port => PaloAltoNGFW}/PaloAltoNGFW_unblock_internal_port.json (87%) rename responders/{PaloAltoNGFW_unblock_internal_user => PaloAltoNGFW}/PaloAltoNGFW_unblock_internal_user.json (87%) create mode 100644 responders/PaloAltoNGFW/README.md create mode 100644 responders/PaloAltoNGFW/Unblock_external_domain.py create mode 100644 responders/PaloAltoNGFW/Unblock_external_ip.py create mode 100644 responders/PaloAltoNGFW/Unblock_external_port.py create mode 100644 responders/PaloAltoNGFW/Unblock_external_user.py create mode 100644 responders/PaloAltoNGFW/Unblock_internal_domain.py create mode 100644 responders/PaloAltoNGFW/Unblock_internal_ip.py create mode 100644 responders/PaloAltoNGFW/Unblock_internal_port.py create mode 100644 responders/PaloAltoNGFW/Unblock_internal_user.py create mode 100644 responders/PaloAltoNGFW/requirements.txt delete mode 100644 responders/PaloAltoNGFW_block_external_IP_address/README.md delete mode 100644 responders/PaloAltoNGFW_block_external_domain/README.md delete mode 100644 responders/PaloAltoNGFW_block_external_port/README.md delete mode 100644 responders/PaloAltoNGFW_block_external_url/Block_url.py delete mode 100644 responders/PaloAltoNGFW_block_external_url/PaloAltoNGFW_block_external_url.json delete mode 100644 responders/PaloAltoNGFW_block_external_url/README.md delete mode 100644 responders/PaloAltoNGFW_block_external_user/README.md delete mode 100644 responders/PaloAltoNGFW_block_internal_IP_address/README.md delete mode 100644 responders/PaloAltoNGFW_block_internal_domain/README.md delete mode 100644 responders/PaloAltoNGFW_block_internal_port/README.md delete mode 100644 responders/PaloAltoNGFW_block_internal_url/Block_url.py delete mode 100644 responders/PaloAltoNGFW_block_internal_url/PaloAltoNGFW_block_internal_url.json delete mode 100644 responders/PaloAltoNGFW_block_internal_url/README.md delete mode 100644 responders/PaloAltoNGFW_block_internal_user/README.md delete mode 100644 responders/PaloAltoNGFW_unblock_domain/PaloAltoNGFW_unblock_domain.json delete mode 100644 responders/PaloAltoNGFW_unblock_domain/README.md delete mode 100644 responders/PaloAltoNGFW_unblock_domain/Unblock_domain.py delete mode 100644 responders/PaloAltoNGFW_unblock_external_IP_address/README.md delete mode 100644 responders/PaloAltoNGFW_unblock_external_IP_address/Unblock_ip.py delete mode 100644 responders/PaloAltoNGFW_unblock_external_domain/README.md delete mode 100644 responders/PaloAltoNGFW_unblock_external_domain/Unblock_domain.py delete mode 100644 responders/PaloAltoNGFW_unblock_external_port/README.md delete mode 100644 responders/PaloAltoNGFW_unblock_external_port/Unblock_port.py delete mode 100644 responders/PaloAltoNGFW_unblock_external_user/README.md delete mode 100644 responders/PaloAltoNGFW_unblock_external_user/Unblock_user.py delete mode 100644 responders/PaloAltoNGFW_unblock_internal_IP_address/README.md delete mode 100644 responders/PaloAltoNGFW_unblock_internal_IP_address/Unblock_ip.py delete mode 100644 responders/PaloAltoNGFW_unblock_internal_domain/README.md delete mode 100644 responders/PaloAltoNGFW_unblock_internal_domain/Unblock_domain.py delete mode 100644 responders/PaloAltoNGFW_unblock_internal_port/README.md delete mode 100644 responders/PaloAltoNGFW_unblock_internal_port/Unblock_port.py delete mode 100644 responders/PaloAltoNGFW_unblock_internal_user/README.md delete mode 100644 responders/PaloAltoNGFW_unblock_internal_user/Unblock_user.py delete mode 100644 responders/PaloAltoNGFW_unblock_port/.Unblock_port.py.swp delete mode 100644 responders/PaloAltoNGFW_unblock_port/PaloAltoNGFW_unblock_port.json delete mode 100644 responders/PaloAltoNGFW_unblock_port/README.md delete mode 100644 responders/PaloAltoNGFW_unblock_port/Unblock_port.py diff --git a/responders/PaloAltoNGFW_block_internal_domain/Block_domain.py b/responders/PaloAltoNGFW/Block_external_domain.py similarity index 51% rename from responders/PaloAltoNGFW_block_internal_domain/Block_domain.py rename to responders/PaloAltoNGFW/Block_external_domain.py index 4d935e06b..5d0fc816b 100644 --- a/responders/PaloAltoNGFW_block_internal_domain/Block_domain.py +++ b/responders/PaloAltoNGFW/Block_external_domain.py @@ -13,45 +13,66 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','Block internal Domain') + self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block external Domain') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'hostname' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) + self.instance_type = self.get_param('data._type') + if self.instance_type == 'case_artifact': + ioc = self.get_param('data.data') + if self.instance_type == 'alert': + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'hostname' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + if self.instance_type == 'case': + import requests + case_id = self.get_param('data._id') + payload = { + "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, + "range": "all" + } + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) + if r.status_code != requests.codes.ok: + self.error(json.dumps(r.text)) + a=None + data = r.json() + for n in data: + if n.get('dataType') == 'hostname': + ioc=n.get('data') fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) panos.objects.AddressObject.refreshall(fw) rulebase = panos.policies.Rulebase() fw.add(rulebase) current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): - new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked domain",type="fqdn") + new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="TheHive Blocked domain",type="fqdn") fw.add(new_ioc_object) new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find("Black list internal domain", panos.objects.AddressGroup) + block_list = fw.find("TheHive Black list external domain", panos.objects.AddressGroup) if block_list != None: ioc_list = block_list.about().get('static_value') if ioc not in ioc_list: ioc_list.append(ioc) - temp1 = panos.objects.AddressGroup("Black list internal domain", static_value=ioc_list) + temp1 = panos.objects.AddressGroup("TheHive Black list external domain", static_value=ioc_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.AddressGroup("Black list internal domain", static_value=ioc) + temp1 = panos.objects.AddressGroup("TheHive Black list external domain", static_value=ioc) fw.add(temp1) temp1.apply() desired_rule_params = None @@ -59,24 +80,16 @@ def run(self): if self.name_security_rule == i.about().get("name"): rule_atrib = i.about() temp_rule_atrib = rule_atrib.get("destination") - if "Black list internal domain" not in temp_rule_atrib: - temp_rule_atrib.append("Black list internal domain") + if "TheHive Black list external domain" not in temp_rule_atrib: + temp_rule_atrib.append("TheHive Black list external domain") if "any" in temp_rule_atrib: temp_rule_atrib.remove("any") rule_atrib.update({"destination": temp_rule_atrib}) desired_rule_params = rule_atrib - elif self.name_security_rule != i.about().get("name"): - desired_rule_params = { - "name": self.name_security_rule, - "description": "Block internal Domain", - "type": "intrazone", - "action": "deny", - 'destination': "Black list internal domain" - } new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() - self.report({'message': 'message sent'}) + self.report({'message': 'Responder comlited, aded %s into TheHive Black list external domain from %s' % (ioc,self.name_security_rule)}) if __name__ == '__main__': Block_domain().run() diff --git a/responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py b/responders/PaloAltoNGFW/Block_external_ip.py similarity index 51% rename from responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py rename to responders/PaloAltoNGFW/Block_external_ip.py index fafd5fdd1..99db518bc 100644 --- a/responders/PaloAltoNGFW_block_external_IP_address/Block_ip.py +++ b/responders/PaloAltoNGFW/Block_external_ip.py @@ -13,45 +13,66 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','Block external IP address') + self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block external IP address') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'ip' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) + self.instance_type = self.get_param('data._type') + if self.instance_type == 'case_artifact': + ioc = self.get_param('data.data') + if self.instance_type == 'alert': + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'ip' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + if self.instance_type == 'case': + import requests + case_id = self.get_param('data._id') + payload = { + "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, + "range": "all" + } + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) + if r.status_code != requests.codes.ok: + self.error(json.dumps(r.text)) + a=None + data = r.json() + for n in data: + if n.get('dataType') == 'ip': + ioc=n.get('data') fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) panos.objects.AddressObject.refreshall(fw) rulebase = panos.policies.Rulebase() fw.add(rulebase) current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): - new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked ip address") + new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="TheHive Blocked ip address") fw.add(new_ioc_object) new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find("Black list external IP", panos.objects.AddressGroup) + block_list = fw.find("TheHive Black list external IP", panos.objects.AddressGroup) if block_list != None: ioc_list = block_list.about().get('static_value') if ioc not in ioc_list: ioc_list.append(ioc) - temp1 = panos.objects.AddressGroup("Black list external IP", static_value=ioc_list) + temp1 = panos.objects.AddressGroup("TheHive Black list external IP", static_value=ioc_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.AddressGroup("Black list external IP", static_value=ioc) + temp1 = panos.objects.AddressGroup("TheHive Black list external IP", static_value=ioc) fw.add(temp1) temp1.apply() desired_rule_params = None @@ -59,23 +80,15 @@ def run(self): if self.name_security_rule == i.about().get("name"): rule_atrib = i.about() temp_rule_atrib = rule_atrib.get("destination") - if "Black list external IP" not in temp_rule_atrib: - temp_rule_atrib.append("Black list external IP") + if "TheHive Black list external IP" not in temp_rule_atrib: + temp_rule_atrib.append("TheHive Black list external IP") if "any" in temp_rule_atrib: temp_rule_atrib.remove("any") rule_atrib.update({"destination": temp_rule_atrib}) desired_rule_params = rule_atrib - elif self.name_security_rule != i.about().get("name"): - desired_rule_params = { - "name": self.name_security_rule, - "description": "Block external IP address", - "type": "interzone", - "action": "deny", - 'destination': "Black list external IP" - } new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() - self.report({'message': 'message sent'}) + self.report({'message': 'Responder comlited, added %s into TheHive Black list external IP from %s' % (ioc,self.name_security_rule)}) if __name__ == '__main__': Block_ip().run() diff --git a/responders/PaloAltoNGFW_block_external_port/Block_port.py b/responders/PaloAltoNGFW/Block_external_port.py similarity index 52% rename from responders/PaloAltoNGFW_block_external_port/Block_port.py rename to responders/PaloAltoNGFW/Block_external_port.py index 6d9261261..5d14af2b3 100644 --- a/responders/PaloAltoNGFW_block_external_port/Block_port.py +++ b/responders/PaloAltoNGFW/Block_external_port.py @@ -14,48 +14,67 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','Block external port') + self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block external port') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - data_list=[] - data=None - for i in response.json().get("artifacts"): - if "'port'," in str(i): - ioc = i.get("data") - data_list.append(i.get("data")) - elif "'protocol'," in str(i): - ioc = i.get("data") - data_list.append(i.get("data")) - data=" ".join(data_list) - protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() - port=re.findall(r'[0-9]+',str(data)); port="".join(port) + self.instance_type = self.get_param('data._type') + if self.instance_type == 'case_artifact': + port = self.get_param('data.data') + if self.instance_type == 'alert': + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + data_list=[] + data=None + for i in response.json().get("artifacts"): + if "'port'," in str(i): + data_list.append(i.get("data")) + elif "'protocol'," in str(i): + data_list.append(i.get("data")) + data=" ".join(data_list) + protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(data)); port="".join(port) + if self.instance_type == 'case': + import requests + case_id = self.get_param('data._id') + payload = { + "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, + "range": "all" + } + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) + if r.status_code != requests.codes.ok: + self.error(json.dumps(r.text)) + a=None + data = r.json() + for n in data: + if n.get('dataType') == 'port': + port=n.get('data') fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) panos.objects.ServiceObject.refreshall(fw) rulebase = panos.policies.Rulebase() fw.add(rulebase) current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) if port not in str(fw.find(port, panos.objects.ServiceObject)): - new_port_object = panos.objects.ServiceObject(port, protocol, description="Blocked port",destination_port=port) + new_port_object = panos.objects.ServiceObject(port, protocol, description="TheHive Blocked port",destination_port=port) fw.add(new_port_object) new_port_object.create() panos.objects.ServiceGroup.refreshall(fw) - block_list = fw.find("Black list external port", panos.objects.ServiceGroup) + block_list = fw.find("TheHive Black list external port", panos.objects.ServiceGroup) if block_list != None: port_list = block_list.about().get('value') if port not in port_list: port_list.append(port) - temp1 = panos.objects.ServiceGroup("Black list external port", value=port_list) + temp1 = panos.objects.ServiceGroup("TheHive Black list external port", value=port_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.ServiceGroup("Black list external port", value=port) + temp1 = panos.objects.ServiceGroup("TheHive Black list external port", value=port) fw.add(temp1) temp1.apply() desired_rule_params = None @@ -63,24 +82,16 @@ def run(self): if self.name_security_rule == str(i.about().get("name")): rule_atrib = i.about() temp_rule_atrib = rule_atrib.get("service") - if "Black list external port" not in temp_rule_atrib: + if "TheHive Black list external port" not in temp_rule_atrib: temp_rule_atrib.append("Black list external port") if "application-default" in temp_rule_atrib: temp_rule_atrib.remove("application-default") rule_atrib.update({"service": temp_rule_atrib}) desired_rule_params = rule_atrib - elif self.name_security_rule != i.about().get("name"): - desired_rule_params = { - "name": self.name_security_rule, - "description": "Block external port", - "type": "interzone", - "action": "deny", - 'service': "Black list external port" - } new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() - self.report({'message': 'message sent'}) + self.report({'message': 'Responder comlited, added %s into TheHive Black list external port to %s' % (port,self.name_security_rule)}) if __name__ == '__main__': Block_port().run() diff --git a/responders/PaloAltoNGFW_block_external_user/Block_user.py b/responders/PaloAltoNGFW/Block_external_user.py similarity index 51% rename from responders/PaloAltoNGFW_block_external_user/Block_user.py rename to responders/PaloAltoNGFW/Block_external_user.py index 81b8e1ff2..d7f741b1f 100644 --- a/responders/PaloAltoNGFW_block_external_user/Block_user.py +++ b/responders/PaloAltoNGFW/Block_external_user.py @@ -12,25 +12,46 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','Block user external communication') + self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block user external communication') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - user=None - user_list_alert=[] - for i in list(response.json().get("artifacts")): - if 'user-agent' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - user_list_alert.append(i) - user="".join(user_list_alert) + self.instance_type = self.get_param('data._type') + if self.instance_type == 'case_artifact': + user = self.get_param('data.data') + if self.instance_type == 'alert': + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + user=None + user_list_alert=[] + for i in list(response.json().get("artifacts")): + if 'user-agent' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + user_list_alert.append(i) + user="".join(user_list_alert) + if self.instance_type == 'case': + import requests + case_id = self.get_param('data._id') + payload = { + "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, + "range": "all" + } + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) + if r.status_code != requests.codes.ok: + self.error(json.dumps(r.text)) + a=None + data = r.json() + for n in data: + if n.get('dataType') == 'user-agent': + user=n.get('data') fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) rulebase = panos.policies.Rulebase() fw.add(rulebase) @@ -49,18 +70,10 @@ def run(self): rule_atrib = i.about() rule_atrib.update({"source_user": user_list}) desired_rule_params = rule_atrib - elif self.name_security_rule != i.about().get("name"): - desired_rule_params = { - "name": self.name_security_rule, - "description": "Block user external communication", - "type": "interzone", - "action": "deny", - 'source_user': user_list - } new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() - self.report({'message': 'message sent'}) + self.report({'message': 'Responder comlited, added %s to %s' % (user,self.name_security_rule)}) if __name__ == '__main__': Block_user().run() diff --git a/responders/PaloAltoNGFW_block_external_domain/Block_domain.py b/responders/PaloAltoNGFW/Block_internal_domain.py similarity index 51% rename from responders/PaloAltoNGFW_block_external_domain/Block_domain.py rename to responders/PaloAltoNGFW/Block_internal_domain.py index bea786061..373353742 100644 --- a/responders/PaloAltoNGFW_block_external_domain/Block_domain.py +++ b/responders/PaloAltoNGFW/Block_internal_domain.py @@ -13,45 +13,66 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','Block external Domain') + self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block internal Domain') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'hostname' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) + self.instance_type = self.get_param('data._type') + if self.instance_type == 'case_artifact': + ioc = self.get_param('data.data') + if self.instance_type == 'alert': + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'hostname' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + if self.instance_type == 'case': + import requests + case_id = self.get_param('data._id') + payload = { + "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, + "range": "all" + } + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) + if r.status_code != requests.codes.ok: + self.error(json.dumps(r.text)) + a=None + data = r.json() + for n in data: + if n.get('dataType') == 'hostname': + ioc=n.get('data') fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) panos.objects.AddressObject.refreshall(fw) rulebase = panos.policies.Rulebase() fw.add(rulebase) current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): - new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked domain",type="fqdn") + new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="TheHive Blocked domain",type="fqdn") fw.add(new_ioc_object) new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find("Black list external domain", panos.objects.AddressGroup) + block_list = fw.find("TheHive Black list internal domain", panos.objects.AddressGroup) if block_list != None: ioc_list = block_list.about().get('static_value') if ioc not in ioc_list: ioc_list.append(ioc) - temp1 = panos.objects.AddressGroup("Black list external domain", static_value=ioc_list) + temp1 = panos.objects.AddressGroup("TheHive Black list internal domain", static_value=ioc_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.AddressGroup("Black list external domain", static_value=ioc) + temp1 = panos.objects.AddressGroup("TheHive Black list internal domain", static_value=ioc) fw.add(temp1) temp1.apply() desired_rule_params = None @@ -59,24 +80,16 @@ def run(self): if self.name_security_rule == i.about().get("name"): rule_atrib = i.about() temp_rule_atrib = rule_atrib.get("destination") - if "Black list external domain" not in temp_rule_atrib: - temp_rule_atrib.append("Black list external domain") + if "TheHive Black list internal domain" not in temp_rule_atrib: + temp_rule_atrib.append("TheHive Black list internal domain") if "any" in temp_rule_atrib: temp_rule_atrib.remove("any") rule_atrib.update({"destination": temp_rule_atrib}) desired_rule_params = rule_atrib - elif self.name_security_rule != i.about().get("name"): - desired_rule_params = { - "name": self.name_security_rule, - "description": "Block external Domain", - "type": "interzone", - "action": "deny", - 'destination': "Black list external domain" - } new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() - self.report({'message': 'message sent'}) + self.report({'message': 'Responder comlited, added %s into TheHive Black list internal domain from %s' % (ioc,self.name_security_rule)}) if __name__ == '__main__': Block_domain().run() diff --git a/responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py b/responders/PaloAltoNGFW/Block_internal_ip.py similarity index 51% rename from responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py rename to responders/PaloAltoNGFW/Block_internal_ip.py index 2c73b4098..0cf928840 100644 --- a/responders/PaloAltoNGFW_block_internal_IP_address/Block_ip.py +++ b/responders/PaloAltoNGFW/Block_internal_ip.py @@ -13,45 +13,66 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','Block internal IP address') + self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block internal IP address') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'ip' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) + self.instance_type = self.get_param('data._type') + if self.instance_type == 'case_artifact': + ioc = self.get_param('data.data') + if self.instance_type == 'alert': + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'ip' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + if self.instance_type == 'case': + import requests + case_id = self.get_param('data._id') + payload = { + "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, + "range": "all" + } + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) + if r.status_code != requests.codes.ok: + self.error(json.dumps(r.text)) + a=None + data = r.json() + for n in data: + if n.get('dataType') == 'ip': + ioc=n.get('data') fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) panos.objects.AddressObject.refreshall(fw) rulebase = panos.policies.Rulebase() fw.add(rulebase) current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): - new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="Blocked ip address") + new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="TheHive Blocked ip address") fw.add(new_ioc_object) new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find("Black list internal IP", panos.objects.AddressGroup) + block_list = fw.find("TheHive Black list internal IP", panos.objects.AddressGroup) if block_list != None: ioc_list = block_list.about().get('static_value') if ioc not in ioc_list: ioc_list.append(ioc) - temp1 = panos.objects.AddressGroup("Black list internal IP", static_value=ioc_list) + temp1 = panos.objects.AddressGroup("TheHive Black list internal IP", static_value=ioc_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.AddressGroup("Black list internal IP", static_value=ioc) + temp1 = panos.objects.AddressGroup("TheHive Black list internal IP", static_value=ioc) fw.add(temp1) temp1.apply() desired_rule_params = None @@ -59,23 +80,15 @@ def run(self): if self.name_security_rule == i.about().get("name"): rule_atrib = i.about() temp_rule_atrib = rule_atrib.get("destination") - if "Black list internal IP" not in temp_rule_atrib: - temp_rule_atrib.append("Black list internal IP") + if "TheHive Black list internal IP" not in temp_rule_atrib: + temp_rule_atrib.append("TheHive Black list internal IP") if "any" in temp_rule_atrib: temp_rule_atrib.remove("any") rule_atrib.update({"destination": temp_rule_atrib}) desired_rule_params = rule_atrib - elif self.name_security_rule != i.about().get("name"): - desired_rule_params = { - "name": self.name_security_rule, - "description": "Block internal IP address", - "type": "intrazone", - "action": "deny", - 'destination': "Black list internal IP" - } new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() - self.report({'message': 'message sent'}) + self.report({'message': 'Responder comlited, added %s into TheHive Black list internal IP from %s' % (ioc,self.name_security_rule)}) if __name__ == '__main__': Block_ip().run() diff --git a/responders/PaloAltoNGFW_block_internal_port/Block_port.py b/responders/PaloAltoNGFW/Block_internal_port.py similarity index 51% rename from responders/PaloAltoNGFW_block_internal_port/Block_port.py rename to responders/PaloAltoNGFW/Block_internal_port.py index dbce2b47a..52ec014d2 100644 --- a/responders/PaloAltoNGFW_block_internal_port/Block_port.py +++ b/responders/PaloAltoNGFW/Block_internal_port.py @@ -13,48 +13,69 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','Block internal port') + self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block internal port') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - data_list=[] - data=None - for i in response.json().get("artifacts"): - if "'port'," in str(i): - ioc = i.get("data") - data_list.append(i.get("data")) - elif "'protocol'," in str(i): - ioc = i.get("data") - data_list.append(i.get("data")) - data=" ".join(data_list) - protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() - port=re.findall(r'[0-9]+',str(data)); port="".join(port) + self.instance_type = self.get_param('data._type') + if self.instance_type == 'case_artifact': + port = self.get_param('data.data') + if self.instance_type == 'alert': + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + data_list=[] + data=None + for i in response.json().get("artifacts"): + if "'port'," in str(i): + ioc = i.get("data") + data_list.append(i.get("data")) + elif "'protocol'," in str(i): + ioc = i.get("data") + data_list.append(i.get("data")) + data=" ".join(data_list) + protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(data)); port="".join(port) + if self.instance_type == 'case': + import requests + case_id = self.get_param('data._id') + payload = { + "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, + "range": "all" + } + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) + if r.status_code != requests.codes.ok: + self.error(json.dumps(r.text)) + a=None + data = r.json() + for n in data: + if n.get('dataType') == 'port': + port=n.get('data') fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) panos.objects.ServiceObject.refreshall(fw) rulebase = panos.policies.Rulebase() fw.add(rulebase) current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) if port not in str(fw.find(port, panos.objects.ServiceObject)): - new_port_object = panos.objects.ServiceObject(port, protocol, description="Blocked port",destination_port=port) + new_port_object = panos.objects.ServiceObject(port, protocol, description="TheHive Blocked port",destination_port=port) fw.add(new_port_object) new_port_object.create() panos.objects.ServiceGroup.refreshall(fw) - block_list = fw.find("Black list internal port", panos.objects.ServiceGroup) + block_list = fw.find("TheHive Black list internal port", panos.objects.ServiceGroup) if block_list != None: port_list = block_list.about().get('value') if port not in port_list: port_list.append(port) - temp1 = panos.objects.ServiceGroup("Black list internal port", value=port_list) + temp1 = panos.objects.ServiceGroup("TheHive Black list internal port", value=port_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.ServiceGroup("Black list internal port", value=port) + temp1 = panos.objects.ServiceGroup("TheHive Black list internal port", value=port) fw.add(temp1) temp1.apply() desired_rule_params = None @@ -62,24 +83,16 @@ def run(self): if self.name_security_rule == i.about().get("name"): rule_atrib = i.about() temp_rule_atrib = rule_atrib.get("service") - if "Black list internal port" not in temp_rule_atrib: + if "TheHive Black list internal port" not in temp_rule_atrib: temp_rule_atrib.append("Black list internal port") if "application-default" in temp_rule_atrib: temp_rule_atrib.remove("application-default") rule_atrib.update({"service": temp_rule_atrib}) desired_rule_params = rule_atrib - elif self.name_security_rule != i.about().get("name"): - desired_rule_params = { - "name": self.name_security_rule, - "description": "Block internal port", - "type": "interzone", - "action": "deny", - 'service': "Black list internal port" - } new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() - self.report({'message': 'message sent'}) + self.report({'message': 'Responder comlited, added %s into TheHive Black list internal port from %s' % (port,self.name_security_rule)}) if __name__ == '__main__': Block_port().run() diff --git a/responders/PaloAltoNGFW_block_internal_user/Block_user.py b/responders/PaloAltoNGFW/Block_internal_user.py similarity index 51% rename from responders/PaloAltoNGFW_block_internal_user/Block_user.py rename to responders/PaloAltoNGFW/Block_internal_user.py index 34d5a2c04..0b2482e57 100644 --- a/responders/PaloAltoNGFW_block_internal_user/Block_user.py +++ b/responders/PaloAltoNGFW/Block_internal_user.py @@ -12,25 +12,46 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','Block user internal communication') + self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block user internal communication') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - user=None - user_list_alert=[] - for i in list(response.json().get("artifacts")): - if 'user' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - user_list_alert.append(i) - user="".join(user_list_alert) + self.instance_type = self.get_param('data._type') + if self.instance_type == 'case_artifact': + user = self.get_param('data.data') + if self.instance_type == 'alert': + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + user=None + user_list_alert=[] + for i in list(response.json().get("artifacts")): + if 'user' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + user_list_alert.append(i) + user="".join(user_list_alert) + if self.instance_type == 'case': + import requests + case_id = self.get_param('data._id') + payload = { + "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, + "range": "all" + } + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) + if r.status_code != requests.codes.ok: + self.error(json.dumps(r.text)) + a=None + data = r.json() + for n in data: + if n.get('dataType') == 'user-agent': + user=n.get('data') fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) rulebase = panos.policies.Rulebase() fw.add(rulebase) @@ -49,18 +70,10 @@ def run(self): rule_atrib = i.about() rule_atrib.update({"source_user": user_list}) desired_rule_params = rule_atrib - elif self.name_security_rule != i.about().get("name"): - desired_rule_params = { - "name": self.name_security_rule, - "description": "Block user internal communication", - "type": "intrazone", - "action": "deny", - 'source_user': user_list - } new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() - self.report({'message': 'message sent'}) + self.report({'message': 'Responder comlited, added %s to %s' % (user,self.name_security_rule)}) if __name__ == '__main__': Block_user().run() diff --git a/responders/PaloAltoNGFW_block_external_IP_address/PaloAltoNGFW_block_external_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json similarity index 88% rename from responders/PaloAltoNGFW_block_external_IP_address/PaloAltoNGFW_block_external_IP_address.json rename to responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json index 23dba633d..bb4b653f7 100644 --- a/responders/PaloAltoNGFW_block_external_IP_address/PaloAltoNGFW_block_external_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_block_external_IP_address", "version": "2.0.0", - "author": "Maxim Konakin", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Block external IP address", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_block_external_IP_address/Block_ip.py", + "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], + "command": "PaloAltoNGFW/Block_external_ip.py", "baseConfig": "PaloAltoNGFW_block_external_IP_address", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW_block_external_domain/PaloAltoNGFW_block_external_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json similarity index 87% rename from responders/PaloAltoNGFW_block_external_domain/PaloAltoNGFW_block_external_domain.json rename to responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json index 2d1d53369..c97843939 100644 --- a/responders/PaloAltoNGFW_block_external_domain/PaloAltoNGFW_block_external_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_block_external_domain", "version": "2.0.0", - "author": "Maxim Konakin", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Block external domain", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_block_external_domain/Block_domain.py", + "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], + "command": "PaloAltoNGFW/Block_external_domain.py", "baseConfig": "PaloAltoNGFW_block_external_domain", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW_block_external_port/PaloAltoNGFW_block_external_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_port.json similarity index 88% rename from responders/PaloAltoNGFW_block_external_port/PaloAltoNGFW_block_external_port.json rename to responders/PaloAltoNGFW/PaloAltoNGFW_block_external_port.json index 9de58eddb..e989e7470 100644 --- a/responders/PaloAltoNGFW_block_external_port/PaloAltoNGFW_block_external_port.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_port.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_block_external_port", "version": "2.0.0", - "author": "Maxim Konakin", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Block external port", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_block_external_port/Block_port.py", + "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], + "command": "PaloAltoNGFW/Block_external_port.py", "baseConfig": "PaloAltoNGFW_block_external_port", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW_block_external_user/PaloAltoNGFW_block_external_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json similarity index 88% rename from responders/PaloAltoNGFW_block_external_user/PaloAltoNGFW_block_external_user.json rename to responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json index 980727784..d0200765f 100644 --- a/responders/PaloAltoNGFW_block_external_user/PaloAltoNGFW_block_external_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_block_external_user", "version": "1.0.0", - "author": "Maxim Konakin", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Block external user", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_block_external_user/Block_user.py", + "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], + "command": "PaloAltoNGFW/Block_external_user.py", "baseConfig": "PaloAltoNGFW_block_external_user", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW_block_internal_IP_address/PaloAltoNGFW_block_internal_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json similarity index 88% rename from responders/PaloAltoNGFW_block_internal_IP_address/PaloAltoNGFW_block_internal_IP_address.json rename to responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json index f59630e2c..af97484c7 100644 --- a/responders/PaloAltoNGFW_block_internal_IP_address/PaloAltoNGFW_block_internal_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_block_internal_IP_address", "version": "2.0.0", - "author": "Maxim Konakin", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Block internal IP address", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_block_internal_IP_address/Block_ip.py", + "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], + "command": "PaloAltoNGFW/Block_internal_ip.py", "baseConfig": "PaloAltoNGFW_block_internal_IP_address", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW_block_internal_domain/PaloAltoNGFW_block_internal_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json similarity index 87% rename from responders/PaloAltoNGFW_block_internal_domain/PaloAltoNGFW_block_internal_domain.json rename to responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json index 844244a70..d806ca8af 100644 --- a/responders/PaloAltoNGFW_block_internal_domain/PaloAltoNGFW_block_internal_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_block_internal_domain", "version": "2.0.0", - "author": "Maxim Konakin", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Block internal domain", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_block_internal_domain/Block_domain.py", + "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], + "command": "PaloAltoNGFW/Block_internal_domain.py", "baseConfig": "PaloAltoNGFW_block_internal_domain", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW_block_internal_port/PaloAltoNGFW_block_internal_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_port.json similarity index 88% rename from responders/PaloAltoNGFW_block_internal_port/PaloAltoNGFW_block_internal_port.json rename to responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_port.json index dd3e6695c..fb4e16a6f 100644 --- a/responders/PaloAltoNGFW_block_internal_port/PaloAltoNGFW_block_internal_port.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_port.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_block_internal_port", "version": "2.0.0", - "author": "Maxim Konakin", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Block internal port", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_block_internal_port/Block_port.py", + "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], + "command": "PaloAltoNGFW/Block_internal_port.py", "baseConfig": "PaloAltoNGFW_block_internal_port", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW_block_internal_user/PaloAltoNGFW_block_internal_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json similarity index 88% rename from responders/PaloAltoNGFW_block_internal_user/PaloAltoNGFW_block_internal_user.json rename to responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json index 24ae71691..dd8d712ea 100644 --- a/responders/PaloAltoNGFW_block_internal_user/PaloAltoNGFW_block_internal_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_block_internal_user", "version": "1.0.0", - "author": "Maxim Konakin", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Block internal user", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_block_internal_user/Block_user.py", + "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], + "command": "PaloAltoNGFW/Block_internal_user.py", "baseConfig": "PaloAltoNGFW_block_internal_user", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW_unblock_external_IP_address/PaloAltoNGFW_unblock_external_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json similarity index 87% rename from responders/PaloAltoNGFW_unblock_external_IP_address/PaloAltoNGFW_unblock_external_IP_address.json rename to responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json index 549aeedd0..c88b5aea1 100644 --- a/responders/PaloAltoNGFW_unblock_external_IP_address/PaloAltoNGFW_unblock_external_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_unblock_external_IP_address", "version": "1.0.0", - "author": "Maxim Konakin", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Unblock ip", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_unblock_external_IP_address/Unblock_ip.py", + "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], + "command": "PaloAltoNGFW/Unblock_external_ip.py", "baseConfig": "PaloAltoNGFW_unblock_ip", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW_unblock_external_domain/PaloAltoNGFW_unblock_external_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json similarity index 87% rename from responders/PaloAltoNGFW_unblock_external_domain/PaloAltoNGFW_unblock_external_domain.json rename to responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json index b3d8f0eff..cdb23cde6 100644 --- a/responders/PaloAltoNGFW_unblock_external_domain/PaloAltoNGFW_unblock_external_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_unblock_external_domain", "version": "1.0.0", - "author": "Maxim Konakin", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Unblock domain", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_unblock_external_domain/Unblock_domain.py", + "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], + "command": "PaloAltoNGFW/Unblock_external_domain.py", "baseConfig": "PaloAltoNGFW_unblock_external_domain", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW_unblock_external_port/PaloAltoNGFW_unblock_external_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json similarity index 87% rename from responders/PaloAltoNGFW_unblock_external_port/PaloAltoNGFW_unblock_external_port.json rename to responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json index 45481ffb5..493e9571a 100644 --- a/responders/PaloAltoNGFW_unblock_external_port/PaloAltoNGFW_unblock_external_port.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_unblock_external_port", "version": "1.0.0", - "author": "Maxim Konakin", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Unblock domain", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_unblock_external_port/Unblock_port.py", + "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], + "command": "PaloAltoNGFW/Unblock_external_port.py", "baseConfig": "PaloAltoNGFW_unblock_port", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW_unblock_external_user/PaloAltoNGFW_unblock_external_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json similarity index 87% rename from responders/PaloAltoNGFW_unblock_external_user/PaloAltoNGFW_unblock_external_user.json rename to responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json index 62f5699f1..5a795abeb 100644 --- a/responders/PaloAltoNGFW_unblock_external_user/PaloAltoNGFW_unblock_external_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_unblock_external_user", "version": "1.0.0", - "author": "Maxim Konakin", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Unblock external user", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_unblock_external_user/Unblock_user.py", + "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], + "command": "PaloAltoNGFW/Unblock_external_user.py", "baseConfig": "PaloAltoNGFW_unblock_external_user", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW_unblock_internal_IP_address/PaloAltoNGFW_unblock_internal_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json similarity index 87% rename from responders/PaloAltoNGFW_unblock_internal_IP_address/PaloAltoNGFW_unblock_internal_IP_address.json rename to responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json index 7b4f2f71b..47b915f67 100644 --- a/responders/PaloAltoNGFW_unblock_internal_IP_address/PaloAltoNGFW_unblock_internal_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_unblock_internal_IP_address", "version": "1.0.0", - "author": "Maxim Konakin", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Unblock ip", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_unblock_internal_IP_address/Unblock_ip.py", + "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], + "command": "PaloAltoNGFW/Unblock_internal_ip.py", "baseConfig": "PaloAltoNGFW_unblock_ip", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW_unblock_internal_domain/PaloAltoNGFW_unblock_internal_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json similarity index 87% rename from responders/PaloAltoNGFW_unblock_internal_domain/PaloAltoNGFW_unblock_internal_domain.json rename to responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json index a2f0c1dd2..06e218a45 100644 --- a/responders/PaloAltoNGFW_unblock_internal_domain/PaloAltoNGFW_unblock_internal_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_unblock_internal_domain", "version": "1.0.0", - "author": "Maxim Konakin", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Unblock domain", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_unblock_internal_domain/Unblock_domain.py", + "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], + "command": "PaloAltoNGFW/Unblock_internal_domain.py", "baseConfig": "PaloAltoNGFW_unblock_internal_domain", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW_unblock_internal_port/PaloAltoNGFW_unblock_internal_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json similarity index 87% rename from responders/PaloAltoNGFW_unblock_internal_port/PaloAltoNGFW_unblock_internal_port.json rename to responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json index 4a6044fd8..904dd9ec5 100644 --- a/responders/PaloAltoNGFW_unblock_internal_port/PaloAltoNGFW_unblock_internal_port.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_unblock_internal_port", "version": "1.0.0", - "author": "Maxim Konakin", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Unblock domain", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_unblock_internal_port/Unblock_port.py", + "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], + "command": "PaloAltoNGFW/Unblock_internal_port.py", "baseConfig": "PaloAltoNGFW_unblock_port", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW_unblock_internal_user/PaloAltoNGFW_unblock_internal_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json similarity index 87% rename from responders/PaloAltoNGFW_unblock_internal_user/PaloAltoNGFW_unblock_internal_user.json rename to responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json index 04c0117d0..4319fa601 100644 --- a/responders/PaloAltoNGFW_unblock_internal_user/PaloAltoNGFW_unblock_internal_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_unblock_internal_user", "version": "1.0.0", - "author": "Maxim Konakin", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Unblock internal user", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_unblock_internal_user/Unblock_user.py", + "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], + "command": "PaloAltoNGFW/Unblock_internal_user.py", "baseConfig": "PaloAltoNGFW_unblock_internal_user", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW/README.md b/responders/PaloAltoNGFW/README.md new file mode 100644 index 000000000..3af37eff5 --- /dev/null +++ b/responders/PaloAltoNGFW/README.md @@ -0,0 +1,47 @@ +# Описание работы responder модуля для системы Palo Alto NGFW + +Данное описание содержит требуемые действия от инженера для интеграции работы responder с Palo Alto NGFW. + +# Installation + +need install: +1. pan-os-python +2. thehive4py +3. thehive4py +# ToDo + +Для работы responders, необходимо загрузить папку PaloAltoNGFW в директорию, где храняться другие responder. Далее перейти в загруженную папку и сделать запускаемыми скрипты на языке python командой chmod +x *.py + +Далее в веб консоли системы cortex, выбрать пункт "Organization" -> "Responders", выбрать интерисующий вас responder и настроить его так, что поля: +1. Hostname_PaloAltoNGFW - сетевой адрес системы PaloAltoNGFW +2. User_PaloAltoNGFW - пользователь в системе PaloAltoNGFW +3. Password_PaloAltoNGFW - пароль для пользователя в системе PaloAltoNGFW +4. name_security_rule (не обязательное поле) - имя правила безопасности в системе PaloAltoNGFW. Установлены следующие стандартные наименования правил: +4.1 Для блокировки\разблокировки имени пользователей: +4.1.1 TheHive Block user internal communication +4.1.2 TheHive Block user external communication + +4.2 Для блокировки\разблокировки сетевых адресов: +4.2.1 TheHive Block internal IP address +4.2.2 TheHive Block external IP address + +4.3 Для блокировки\разблокировки FQDN: +4.3.1 TheHive Block external Domain +4.3.2 TheHive Block internal Domain + +4.4 Для блокировки\разблокировки портов: +4.4.1 TheHive Black list internal port +4.4.2 TheHive Block external port + +4.5 thehive_instance - url адрес системы TheHive (используется только для типов case и alert) + +4.6 thehive_api_key - API ключ для подключения к системе TheHive + +Примечание: указанные правила безопасноти должны быть созданы в PaloAltoNGFW, а так же расставлены в порядке их применения. + +Типы используемых данных для работы в системе TheHive: +1. Сетевой адрес - 'ip' +2. FQDN - 'hostname' +3. порт - 'port' +4. имя пользователя - 'user-agent' +Примечание: данный тип необходимо создать в системе TheHive \ No newline at end of file diff --git a/responders/PaloAltoNGFW/Unblock_external_domain.py b/responders/PaloAltoNGFW/Unblock_external_domain.py new file mode 100644 index 000000000..1fbc18af7 --- /dev/null +++ b/responders/PaloAltoNGFW/Unblock_external_domain.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects +import panos.policies + +class Unblock_domain(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_external_Address_Group_for_domain = self.get_param('config.name_external_Address_Group',"TheHive Black list external domain") + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + self.instance_type = self.get_param('data._type') + if self.instance_type == 'case_artifact': + ioc = self.get_param('data.data') + if self.instance_type == 'alert': + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'hostname' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + if self.instance_type == 'case': + import requests + case_id = self.get_param('data._id') + payload = { + "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, + "range": "all" + } + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) + if r.status_code != requests.codes.ok: + self.error(json.dumps(r.text)) + a=None + data = r.json() + for n in data: + if n.get('dataType') == 'hostname': + ioc=n.get('data') + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressGroup.refreshall(fw) + + block_list = fw.find(self.name_external_Address_Group_for_domain, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc in ioc_list: + ioc_list.remove(ioc) + temp1 = panos.objects.AddressGroup(self.name_external_Address_Group_for_domain, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + + panos.objects.AddressObject.refreshall(fw) + if ioc in str(fw.find(ioc, panos.objects.AddressObject)): + try: + deleted_ioc = fw.find(ioc, panos.objects.AddressObject) + deleted_ioc.delete() + except: + self.report({'message': 'Responder did not comlite. Warning in AddressObject'}) + + self.report({'message': 'Responder comlited, deleted %s from %s' % (ioc,self.name_external_Address_Group_for_domain)}) + +if __name__ == '__main__': + Unblock_domain().run() diff --git a/responders/PaloAltoNGFW/Unblock_external_ip.py b/responders/PaloAltoNGFW/Unblock_external_ip.py new file mode 100644 index 000000000..baef0c676 --- /dev/null +++ b/responders/PaloAltoNGFW/Unblock_external_ip.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Unblock_ip(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_external_Address_Group = self.get_param('config.name_external_Address_Group',"TheHive Black list external IP") + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + self.instance_type = self.get_param('data._type') + if self.instance_type == 'case_artifact': + ioc = self.get_param('data.data') + if self.instance_type == 'alert': + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'ip' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + if self.instance_type == 'case': + import requests + case_id = self.get_param('data._id') + payload = { + "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, + "range": "all" + } + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) + if r.status_code != requests.codes.ok: + self.error(json.dumps(r.text)) + a=None + data = r.json() + for n in data: + if n.get('dataType') == 'ip': + ioc=n.get('data') + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressGroup.refreshall(fw) + block_list = fw.find(self.name_external_Address_Group, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc in ioc_list: + ioc_list.remove(ioc) + temp1 = panos.objects.AddressGroup(self.name_external_Address_Group, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + + panos.objects.AddressObject.refreshall(fw) + if ioc in str(fw.find(ioc, panos.objects.AddressObject)): + try: + deleted_ioc = fw.find(ioc, panos.objects.AddressObject) + deleted_ioc.delete() + except: + self.report({'message': 'Responder did not comlite. Warning in AddressObject'}) + + self.report({'message': 'Responder comlited, deleted %s from %s' % (ioc,self.name_external_Address_Group)}) + +if __name__ == '__main__': + Unblock_ip().run() diff --git a/responders/PaloAltoNGFW/Unblock_external_port.py b/responders/PaloAltoNGFW/Unblock_external_port.py new file mode 100644 index 000000000..23bf1a6b7 --- /dev/null +++ b/responders/PaloAltoNGFW/Unblock_external_port.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects +import re +class Unblock_port(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_external_Service_Group = self.get_param('config.name_external_Service_Group','TheHive Black list external port') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + self.instance_type = self.get_param('data._type') + if self.instance_type == 'case_artifact': + port = self.get_param('data.data') + if self.instance_type == 'alert': + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + data_list=[] + data=None + for i in response.json().get("artifacts"): + if "'port'," in str(i): + data_list.append(i.get("data")) + elif "'protocol'," in str(i): + data_list.append(i.get("data")) + data=" ".join(data_list) + protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(data)); port="".join(port) + if self.instance_type == 'case': + import requests + case_id = self.get_param('data._id') + payload = { + "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, + "range": "all" + } + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) + if r.status_code != requests.codes.ok: + self.error(json.dumps(r.text)) + a=None + data = r.json() + for n in data: + if n.get('dataType') == 'port': + port=n.get('data') + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.ServiceGroup.refreshall(fw) + block_list = fw.find(self.name_external_Service_Group, panos.objects.ServiceGroup) + port_list = block_list.about().get('value') + if port in port_list: + port_list.remove(port) + temp1 = panos.objects.ServiceGroup(self.name_external_Service_Group, value=port_list) + fw.add(temp1) + temp1.apply() + + panos.objects.ServiceObject.refreshall(fw) + + self.report({'message': 'Responder comlited, deleted %s from %s' % (port,self.name_external_Service_Group)}) + +if __name__ == '__main__': + Unblock_port().run() diff --git a/responders/PaloAltoNGFW/Unblock_external_user.py b/responders/PaloAltoNGFW/Unblock_external_user.py new file mode 100644 index 000000000..f155539c2 --- /dev/null +++ b/responders/PaloAltoNGFW/Unblock_external_user.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.policies + +class Unblock_user(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block user external communication') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + self.instance_type = self.get_param('data._type') + if self.instance_type == 'case_artifact': + user = self.get_param('data.data') + if self.instance_type == 'alert': + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + user=None + user_list_alert=[] + for i in list(response.json().get("artifacts")): + if 'user' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + user_list_alert.append(i) + user="".join(user_list_alert) + if self.instance_type == 'case': + import requests + case_id = self.get_param('data._id') + payload = { + "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, + "range": "all" + } + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) + if r.status_code != requests.codes.ok: + self.error(json.dumps(r.text)) + a=None + data = r.json() + for n in data: + if n.get('dataType') == 'user-agent': + user=n.get('data') + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + rulebase = panos.policies.Rulebase() + fw.add(rulebase) + current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) + user_list=[] + rule_atrib=[] + for i in current_security_rules: + if i.about().get('name') == self.name_security_rule: + rule_atrib = i.about() + user_list=i.about().get("source_user") + if user in user_list: + user_list.remove(user) + rule_atrib.update({"source_user": user_list}) + desired_rule_params = rule_atrib + new_rule = panos.policies.SecurityRule(**desired_rule_params) + rulebase.add(new_rule) + new_rule.apply() + self.report({'message': 'Responder comlited, deleted %s from %s' % (user,self.name_security_rule)}) + +if __name__ == '__main__': + Unblock_user().run() diff --git a/responders/PaloAltoNGFW/Unblock_internal_domain.py b/responders/PaloAltoNGFW/Unblock_internal_domain.py new file mode 100644 index 000000000..b7ade6483 --- /dev/null +++ b/responders/PaloAltoNGFW/Unblock_internal_domain.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects +import panos.policies + +class Unblock_domain(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_Address_Group_for_domain = self.get_param('config.name_external_Address_Group',"TheHive Black list internal domain") + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + self.instance_type = self.get_param('data._type') + if self.instance_type == 'case_artifact': + ioc = self.get_param('data.data') + if self.instance_type == 'alert': + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'hostname' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + if self.instance_type == 'case': + import requests + case_id = self.get_param('data._id') + payload = { + "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, + "range": "all" + } + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) + if r.status_code != requests.codes.ok: + self.error(json.dumps(r.text)) + a=None + data = r.json() + for n in data: + if n.get('dataType') == 'hostname': + ioc=n.get('data') + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressGroup.refreshall(fw) + + block_list = fw.find(self.name_internal_Address_Group_for_domain, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc in ioc_list: + ioc_list.remove(ioc) + temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group_for_domain, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + + panos.objects.AddressObject.refreshall(fw) + if ioc in str(fw.find(ioc, panos.objects.AddressObject)): + try: + deleted_ioc = fw.find(ioc, panos.objects.AddressObject) + deleted_ioc.delete() + except: + self.report({'message': 'Responder did not comlite. Warning in AddressObject'}) + + self.report({'message': 'Responder comlited, deleted %s from %s' % (ioc,self.name_internal_Address_Group_for_domain)}) + +if __name__ == '__main__': + Unblock_domain().run() diff --git a/responders/PaloAltoNGFW/Unblock_internal_ip.py b/responders/PaloAltoNGFW/Unblock_internal_ip.py new file mode 100644 index 000000000..459b3f916 --- /dev/null +++ b/responders/PaloAltoNGFW/Unblock_internal_ip.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects + +class Unblock_ip(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_Address_Group = self.get_param('config.name_internal_Address_Group',"TheHive Black list internal IP") + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + self.instance_type = self.get_param('data._type') + if self.instance_type == 'case_artifact': + ioc = self.get_param('data.data') + if self.instance_type == 'alert': + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + ioc=None + ioc_clear=[] + for i in list(response.json().get("artifacts")): + if 'ip' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + ioc_clear.append(i) + ioc="".join(ioc_clear) + if self.instance_type == 'case': + import requests + case_id = self.get_param('data._id') + payload = { + "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, + "range": "all" + } + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) + if r.status_code != requests.codes.ok: + self.error(json.dumps(r.text)) + a=None + data = r.json() + for n in data: + if n.get('dataType') == 'ip': + ioc=n.get('data') + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.AddressGroup.refreshall(fw) + block_list = fw.find(self.name_internal_Address_Group, panos.objects.AddressGroup) + ioc_list = block_list.about().get('static_value') + if ioc in ioc_list: + ioc_list.remove(ioc) + temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group, static_value=ioc_list) + fw.add(temp1) + temp1.apply() + + panos.objects.AddressObject.refreshall(fw) + if ioc in str(fw.find(ioc, panos.objects.AddressObject)): + try: + deleted_ioc = fw.find(ioc, panos.objects.AddressObject) + deleted_ioc.delete() + except: + self.report({'message': 'Responder did not comlite. Warning in AddressObject'}) + + self.report({'message': 'Responder comlited, deleted %s from %s' % (ioc,self.name_internal_Address_Group)}) + +if __name__ == '__main__': + Unblock_ip().run() diff --git a/responders/PaloAltoNGFW/Unblock_internal_port.py b/responders/PaloAltoNGFW/Unblock_internal_port.py new file mode 100644 index 000000000..ece0c4311 --- /dev/null +++ b/responders/PaloAltoNGFW/Unblock_internal_port.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.objects +import re +class Unblock_port(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_internal_Service_Group = self.get_param('config.name_internal_Service_Group','TheHive Black list internal port') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + self.instance_type = self.get_param('data._type') + if self.instance_type == 'case_artifact': + port = self.get_param('data.data') + if self.instance_type == 'alert': + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + data_list=[] + data=None + for i in response.json().get("artifacts"): + if "'port'," in str(i): + data_list.append(i.get("data")) + elif "'protocol'," in str(i): + data_list.append(i.get("data")) + data=" ".join(data_list) + protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(data)); port="".join(port) + if self.instance_type == 'case': + import requests + case_id = self.get_param('data._id') + payload = { + "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, + "range": "all" + } + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) + if r.status_code != requests.codes.ok: + self.error(json.dumps(r.text)) + a=None + data = r.json() + for n in data: + if n.get('dataType') == 'port': + port=n.get('data') + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + panos.objects.ServiceGroup.refreshall(fw) + block_list = fw.find(self.name_internal_Service_Group, panos.objects.ServiceGroup) + port_list = block_list.about().get('value') + if port in port_list: + port_list.remove(port) + temp1 = panos.objects.ServiceGroup(self.name_internal_Service_Group, value=port_list) + fw.add(temp1) + temp1.apply() + + panos.objects.ServiceObject.refreshall(fw) + + self.report({'message': 'Responder comlited, deleted %s from %s' % (port,self.name_internal_Service_Group)}) + +if __name__ == '__main__': + Unblock_port().run() diff --git a/responders/PaloAltoNGFW/Unblock_internal_user.py b/responders/PaloAltoNGFW/Unblock_internal_user.py new file mode 100644 index 000000000..7ba623d5d --- /dev/null +++ b/responders/PaloAltoNGFW/Unblock_internal_user.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +from cortexutils.responder import Responder +from thehive4py.api import TheHiveApi +from panos import firewall +import panos.policies + +class Unblock_user(Responder): + def __init__(self): + Responder.__init__(self) + self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') + self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') + self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') + self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block user internal communication') + self.thehive_instance = self.get_param('config.thehive_instance') + self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + + def run(self): + self.instance_type = self.get_param('data._type') + if self.instance_type == 'case_artifact': + user = self.get_param('data.data') + if self.instance_type == 'alert': + alertId = self.get_param('data.id') + response = self.api.get_alert(alertId) + user=None + user_list_alert=[] + for i in list(response.json().get("artifacts")): + if 'user' in str(i): + ioc = i.get("data") + for i in ioc: + if i == "[" or i == "]": + continue + else: + user_list_alert.append(i) + user="".join(user_list_alert) + if self.instance_type == 'case': + import requests + case_id = self.get_param('data._id') + payload = { + "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, + "range": "all" + } + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) + if r.status_code != requests.codes.ok: + self.error(json.dumps(r.text)) + a=None + data = r.json() + for n in data: + if n.get('dataType') == 'user-agent': + user=n.get('data') + fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) + rulebase = panos.policies.Rulebase() + fw.add(rulebase) + current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) + user_list=[] + rule_atrib=[] + for i in current_security_rules: + if i.about().get('name') == self.name_security_rule: + rule_atrib = i.about() + user_list=i.about().get("source_user") + if user in user_list: + user_list.remove(user) + rule_atrib.update({"source_user": user_list}) + desired_rule_params = rule_atrib + new_rule = panos.policies.SecurityRule(**desired_rule_params) + rulebase.add(new_rule) + new_rule.apply() + self.report({'message': 'Responder comlited, deleted %s from %s' % (user,self.name_security_rule)}) + +if __name__ == '__main__': + Unblock_user().run() diff --git a/responders/PaloAltoNGFW/requirements.txt b/responders/PaloAltoNGFW/requirements.txt new file mode 100644 index 000000000..1af2ae28a --- /dev/null +++ b/responders/PaloAltoNGFW/requirements.txt @@ -0,0 +1,3 @@ +cortexutils +requests +panos \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_external_IP_address/README.md b/responders/PaloAltoNGFW_block_external_IP_address/README.md deleted file mode 100644 index e55a8d2be..000000000 --- a/responders/PaloAltoNGFW_block_external_IP_address/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added AddressObject. -3. if ioc not in AddressObject, will add -4. if ioc in AddressObject, next step -5. checks if there is already a blocking list, if not, ioc will add -6. create security rule and add AddressObject \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_external_domain/README.md b/responders/PaloAltoNGFW_block_external_domain/README.md deleted file mode 100644 index 740b81d06..000000000 --- a/responders/PaloAltoNGFW_block_external_domain/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" -https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added AddressObject. -3. if ioc not in AddressObject, will add -4. if ioc in AddressObject, next step -5. checks if there is already a blocking list, if not, ioc will add -6. create security rule and add AddressObject \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_external_port/README.md b/responders/PaloAltoNGFW_block_external_port/README.md deleted file mode 100644 index 02695978b..000000000 --- a/responders/PaloAltoNGFW_block_external_port/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added ServiceObject. -3. if ioc not in ServiceObject, will add -4. if ioc in ServiceObject, next step -5. checks if there is already a blocking list, if not, ioc will add -6. create security rule and add ServiceGroup \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_external_url/Block_url.py b/responders/PaloAltoNGFW_block_external_url/Block_url.py deleted file mode 100644 index 33eb834ad..000000000 --- a/responders/PaloAltoNGFW_block_external_url/Block_url.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects - -class Block_url(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_external_URL_category = self.get_param('config.name_external_URL_category') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'url' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.CustomUrlCategory.refreshall(fw) - block_list = fw.find(self.name_external_URL_category, panos.objects.CustomUrlCategory) - ioc_list = block_list.about().get('url_value') - if ioc not in ioc_list: - ioc_list.append(ioc) - temp1 = panos.objects.CustomUrlCategory(self.name_external_URL_category, url_value=ioc_list) - fw.add(temp1) - temp1.create() - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Block_url().run() diff --git a/responders/PaloAltoNGFW_block_external_url/PaloAltoNGFW_block_external_url.json b/responders/PaloAltoNGFW_block_external_url/PaloAltoNGFW_block_external_url.json deleted file mode 100644 index fbeee7697..000000000 --- a/responders/PaloAltoNGFW_block_external_url/PaloAltoNGFW_block_external_url.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "PaloAltoNGFW_block_external_url", - "version": "1.0.0", - "author": "Maxim Konakin", - "url": "", - "license": "AGPL-V3", - "description": "Block external domain", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_block_external_url/Block_url.py", - "baseConfig": "PaloAltoNGFW_block_external_url", - "configurationItems": [ - { - "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_external_URL_category", - "description": "name_external_URL_category", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_api_key", - "description": "TheHive API key with read access", - "type": "string", - "multi": false, - "required": true - } - ] -} diff --git a/responders/PaloAltoNGFW_block_external_url/README.md b/responders/PaloAltoNGFW_block_external_url/README.md deleted file mode 100644 index a97c170ef..000000000 --- a/responders/PaloAltoNGFW_block_external_url/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_external_URL_category". - - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added URL_category. -3. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_external_user/README.md b/responders/PaloAltoNGFW_block_external_user/README.md deleted file mode 100644 index 33b80bacb..000000000 --- a/responders/PaloAltoNGFW_block_external_user/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" - -principle of operation: -1. the value is selected from the alert the hive. -2. user compare against already added security rule. -3. if user not in security rule, will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_IP_address/README.md b/responders/PaloAltoNGFW_block_internal_IP_address/README.md deleted file mode 100644 index 740b81d06..000000000 --- a/responders/PaloAltoNGFW_block_internal_IP_address/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" -https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added AddressObject. -3. if ioc not in AddressObject, will add -4. if ioc in AddressObject, next step -5. checks if there is already a blocking list, if not, ioc will add -6. create security rule and add AddressObject \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_domain/README.md b/responders/PaloAltoNGFW_block_internal_domain/README.md deleted file mode 100644 index 740b81d06..000000000 --- a/responders/PaloAltoNGFW_block_internal_domain/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" -https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added AddressObject. -3. if ioc not in AddressObject, will add -4. if ioc in AddressObject, next step -5. checks if there is already a blocking list, if not, ioc will add -6. create security rule and add AddressObject \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_port/README.md b/responders/PaloAltoNGFW_block_internal_port/README.md deleted file mode 100644 index 02695978b..000000000 --- a/responders/PaloAltoNGFW_block_internal_port/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added ServiceObject. -3. if ioc not in ServiceObject, will add -4. if ioc in ServiceObject, next step -5. checks if there is already a blocking list, if not, ioc will add -6. create security rule and add ServiceGroup \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_url/Block_url.py b/responders/PaloAltoNGFW_block_internal_url/Block_url.py deleted file mode 100644 index 39793efef..000000000 --- a/responders/PaloAltoNGFW_block_internal_url/Block_url.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects - -class Block_url(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_URL_category = self.get_param('config.name_internal_URL_category') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'url' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.CustomUrlCategory.refreshall(fw) - block_list = fw.find(self.name_internal_URL_category, panos.objects.CustomUrlCategory) - ioc_list = block_list.about().get('url_value') - if ioc not in ioc_list: - ioc_list.append(ioc) - temp1 = panos.objects.CustomUrlCategory(self.name_internal_URL_category, url_value=ioc_list) - fw.add(temp1) - temp1.create() - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Block_url().run() diff --git a/responders/PaloAltoNGFW_block_internal_url/PaloAltoNGFW_block_internal_url.json b/responders/PaloAltoNGFW_block_internal_url/PaloAltoNGFW_block_internal_url.json deleted file mode 100644 index 04258ecd7..000000000 --- a/responders/PaloAltoNGFW_block_internal_url/PaloAltoNGFW_block_internal_url.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "PaloAltoNGFW_block_internal_url", - "version": "1.0.0", - "author": "Maxim Konakin", - "url": "", - "license": "AGPL-V3", - "description": "Block internal domain", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_block_internal_url/Block_url.py", - "baseConfig": "PaloAltoNGFW_block_internal_url", - "configurationItems": [ - { - "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_internal_URL_category", - "description": "name_internal_URL_category", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_api_key", - "description": "TheHive API key with read access", - "type": "string", - "multi": false, - "required": true - } - ] -} diff --git a/responders/PaloAltoNGFW_block_internal_url/README.md b/responders/PaloAltoNGFW_block_internal_url/README.md deleted file mode 100644 index bda74a5f2..000000000 --- a/responders/PaloAltoNGFW_block_internal_url/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Address_Group_for_domain". -https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added AddressObject. -3. if ioc not in AddressObject, will add -4. if ioc in AddressObject, next step -5. checks if there is already a blocking list, if not, ioc will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_block_internal_user/README.md b/responders/PaloAltoNGFW_block_internal_user/README.md deleted file mode 100644 index 33b80bacb..000000000 --- a/responders/PaloAltoNGFW_block_internal_user/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" - -principle of operation: -1. the value is selected from the alert the hive. -2. user compare against already added security rule. -3. if user not in security rule, will add \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_domain/PaloAltoNGFW_unblock_domain.json b/responders/PaloAltoNGFW_unblock_domain/PaloAltoNGFW_unblock_domain.json deleted file mode 100644 index e93782451..000000000 --- a/responders/PaloAltoNGFW_unblock_domain/PaloAltoNGFW_unblock_domain.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "name": "PaloAltoNGFW_unblock_domain", - "version": "1.0.0", - "author": "Maxim Konakin", - "url": "", - "license": "AGPL-V3", - "description": "Unblock domain", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_unblock_domain/Unblock_domain.py", - "baseConfig": "PaloAltoNGFW_unblock_domain", - "configurationItems": [ - { - "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_internal_Address_Group", - "description": "name_internal_Address_Group_for_domain", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_external_Address_Group", - "description": "name_external_Address_Group_for_domain", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_api_key", - "description": "TheHive API key with read access", - "type": "string", - "multi": false, - "required": true - } - ] -} diff --git a/responders/PaloAltoNGFW_unblock_domain/README.md b/responders/PaloAltoNGFW_unblock_domain/README.md deleted file mode 100644 index cfa6e002f..000000000 --- a/responders/PaloAltoNGFW_unblock_domain/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Address_Group_for_domain" and "name_external_Address_Group_for_domain" - -principle of operation: -1. the value is selected from the alert the hive. -2. if ioc added in Address_Groups, script deleted ioc -3. if ioc in AddressObject, script deleted ioc \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_domain/Unblock_domain.py b/responders/PaloAltoNGFW_unblock_domain/Unblock_domain.py deleted file mode 100644 index 8b4c96e54..000000000 --- a/responders/PaloAltoNGFW_unblock_domain/Unblock_domain.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects - -class Unblock_domain(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Address_Group_for_domain = self.get_param('config.name_internal_Address_Group') - self.name_external_Address_Group_for_domain = self.get_param('config.name_external_Address_Group') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'hostname' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find(self.name_internal_Address_Group_for_domain, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc in ioc_list: - ioc_list.remove(ioc) - temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group_for_domain, static_value=ioc_list) - fw.add(temp1) - temp1.apply() - - block_list = fw.find(self.name_external_Address_Group_for_domain, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc in ioc_list: - ioc_list.remove(ioc) - temp1 = panos.objects.AddressGroup(self.name_external_Address_Group_for_domain, static_value=ioc_list) - fw.add(temp1) - temp1.apply() - - panos.objects.AddressObject.refreshall(fw) - if ioc in str(fw.find(ioc, panos.objects.AddressObject)): - deleted_ioc = fw.find(ioc, panos.objects.AddressObject) - deleted_ioc.delete() - - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Unblock_domain().run() diff --git a/responders/PaloAltoNGFW_unblock_external_IP_address/README.md b/responders/PaloAltoNGFW_unblock_external_IP_address/README.md deleted file mode 100644 index 65a3ee6d5..000000000 --- a/responders/PaloAltoNGFW_unblock_external_IP_address/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need set setting PaloAltoNGFW and The Hive. If you want delete in custom Address Group you need set "Address_Group" -https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added AddressObject. -3. if ioc in AddressGroup, will delete -4. if ioc in AddressObject, will delete \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_external_IP_address/Unblock_ip.py b/responders/PaloAltoNGFW_unblock_external_IP_address/Unblock_ip.py deleted file mode 100644 index bba99cfcd..000000000 --- a/responders/PaloAltoNGFW_unblock_external_IP_address/Unblock_ip.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects - -class Unblock_ip(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_external_Address_Group = self.get_param('config.name_external_Address_Group',"Black list external IP") - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'ip' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find(self.name_external_Address_Group, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc in ioc_list: - ioc_list.remove(ioc) - temp1 = panos.objects.AddressGroup(self.name_external_Address_Group, static_value=ioc_list) - fw.add(temp1) - temp1.apply() - - panos.objects.AddressObject.refreshall(fw) - if ioc in str(fw.find(ioc, panos.objects.AddressObject)): - try: - deleted_ioc = fw.find(ioc, panos.objects.AddressObject) - deleted_ioc.delete() - except: - self.report({'message': 'message sent'}) - - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Unblock_ip().run() diff --git a/responders/PaloAltoNGFW_unblock_external_domain/README.md b/responders/PaloAltoNGFW_unblock_external_domain/README.md deleted file mode 100644 index 65a3ee6d5..000000000 --- a/responders/PaloAltoNGFW_unblock_external_domain/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need set setting PaloAltoNGFW and The Hive. If you want delete in custom Address Group you need set "Address_Group" -https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added AddressObject. -3. if ioc in AddressGroup, will delete -4. if ioc in AddressObject, will delete \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_external_domain/Unblock_domain.py b/responders/PaloAltoNGFW_unblock_external_domain/Unblock_domain.py deleted file mode 100644 index 9eff67092..000000000 --- a/responders/PaloAltoNGFW_unblock_external_domain/Unblock_domain.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects -import panos.policies - -class Unblock_domain(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_external_Address_Group_for_domain = self.get_param('config.name_external_Address_Group',"Black list external domain") - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'hostname' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.AddressGroup.refreshall(fw) - - block_list = fw.find(self.name_external_Address_Group_for_domain, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc in ioc_list: - ioc_list.remove(ioc) - temp1 = panos.objects.AddressGroup(self.name_external_Address_Group_for_domain, static_value=ioc_list) - fw.add(temp1) - temp1.apply() - - panos.objects.AddressObject.refreshall(fw) - if ioc in str(fw.find(ioc, panos.objects.AddressObject)): - try: - deleted_ioc = fw.find(ioc, panos.objects.AddressObject) - deleted_ioc.delete() - except: - self.report({'message': 'message sent'}) - - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Unblock_domain().run() diff --git a/responders/PaloAltoNGFW_unblock_external_port/README.md b/responders/PaloAltoNGFW_unblock_external_port/README.md deleted file mode 100644 index e6a38990a..000000000 --- a/responders/PaloAltoNGFW_unblock_external_port/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need set setting PaloAltoNGFW and The Hive. If you want delete in custom Address Group you need set "ServiceGroup" - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added AddressObject. -3. if ioc in ServiceGroup, will delete -4. if ioc in ServiceObject, will delete \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_external_port/Unblock_port.py b/responders/PaloAltoNGFW_unblock_external_port/Unblock_port.py deleted file mode 100644 index 7c1920e1e..000000000 --- a/responders/PaloAltoNGFW_unblock_external_port/Unblock_port.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects -import re -class Unblock_port(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_external_Service_Group = self.get_param('config.name_external_Service_Group','Black list external port') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - data_list=[] - data=None - for i in response.json().get("artifacts"): - if "'port'," in str(i): - ioc = i.get("data") - data_list.append(i.get("data")) - elif "'protocol'," in str(i): - ioc = i.get("data") - data_list.append(i.get("data")) - data=" ".join(data_list) - protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() - port=re.findall(r'[0-9]+',str(data)); port="".join(port) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.ServiceGroup.refreshall(fw) - block_list = fw.find(self.name_external_Service_Group, panos.objects.ServiceGroup) - port_list = block_list.about().get('value') - if port in port_list: - port_list.remove(port) - temp1 = panos.objects.ServiceGroup(self.name_external_Service_Group, value=port_list) - fw.add(temp1) - temp1.apply() - - panos.objects.ServiceObject.refreshall(fw) - if port in str(fw.find(port, panos.objects.ServiceObject)): - deleted_ioc = fw.find(port, panos.objects.ServiceObject) - deleted_ioc.delete() - - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Unblock_port().run() diff --git a/responders/PaloAltoNGFW_unblock_external_user/README.md b/responders/PaloAltoNGFW_unblock_external_user/README.md deleted file mode 100644 index 18aa819d1..000000000 --- a/responders/PaloAltoNGFW_unblock_external_user/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" - -principle of operation: -1. the value is selected from the alert the hive. -2. user compare against already added in security rules. -3. if user in security rules, will delete \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_external_user/Unblock_user.py b/responders/PaloAltoNGFW_unblock_external_user/Unblock_user.py deleted file mode 100644 index 5a30e474f..000000000 --- a/responders/PaloAltoNGFW_unblock_external_user/Unblock_user.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.policies - -class Unblock_user(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','Block user external communication') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - user=None - user_list_alert=[] - for i in list(response.json().get("artifacts")): - if 'user' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - user_list_alert.append(i) - user="".join(user_list_alert) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - rulebase = panos.policies.Rulebase() - fw.add(rulebase) - current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) - user_list=[] - for i in current_security_rules: - if i.about().get('name') == self.name_security_rule: - user_list=i.about().get("source_user") - if user in user_list: - user_list.remove(user) - desired_rule_params = { - "name": self.name_security_rule, - "description": "Block user external communication", - "type": "interzone", - "action": "deny", - 'source_user': user_list - } - new_rule = panos.policies.SecurityRule(**desired_rule_params) - rulebase.add(new_rule) - new_rule.apply() - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Unblock_user().run() diff --git a/responders/PaloAltoNGFW_unblock_internal_IP_address/README.md b/responders/PaloAltoNGFW_unblock_internal_IP_address/README.md deleted file mode 100644 index 65a3ee6d5..000000000 --- a/responders/PaloAltoNGFW_unblock_internal_IP_address/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need set setting PaloAltoNGFW and The Hive. If you want delete in custom Address Group you need set "Address_Group" -https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added AddressObject. -3. if ioc in AddressGroup, will delete -4. if ioc in AddressObject, will delete \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_internal_IP_address/Unblock_ip.py b/responders/PaloAltoNGFW_unblock_internal_IP_address/Unblock_ip.py deleted file mode 100644 index 3ac261056..000000000 --- a/responders/PaloAltoNGFW_unblock_internal_IP_address/Unblock_ip.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects - -class Unblock_ip(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Address_Group = self.get_param('config.name_internal_Address_Group',"Black list internal IP") - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'ip' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find(self.name_internal_Address_Group, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc in ioc_list: - ioc_list.remove(ioc) - temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group, static_value=ioc_list) - fw.add(temp1) - temp1.apply() - - panos.objects.AddressObject.refreshall(fw) - if ioc in str(fw.find(ioc, panos.objects.AddressObject)): - try: - deleted_ioc = fw.find(ioc, panos.objects.AddressObject) - deleted_ioc.delete() - except: - self.report({'message': 'message sent'}) - - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Unblock_ip().run() diff --git a/responders/PaloAltoNGFW_unblock_internal_domain/README.md b/responders/PaloAltoNGFW_unblock_internal_domain/README.md deleted file mode 100644 index 65a3ee6d5..000000000 --- a/responders/PaloAltoNGFW_unblock_internal_domain/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need set setting PaloAltoNGFW and The Hive. If you want delete in custom Address Group you need set "Address_Group" -https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-web-interface-help/monitor/monitor-block-ip-list - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added AddressObject. -3. if ioc in AddressGroup, will delete -4. if ioc in AddressObject, will delete \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_internal_domain/Unblock_domain.py b/responders/PaloAltoNGFW_unblock_internal_domain/Unblock_domain.py deleted file mode 100644 index 949daa7ba..000000000 --- a/responders/PaloAltoNGFW_unblock_internal_domain/Unblock_domain.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects -import panos.policies - -class Unblock_domain(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Address_Group_for_domain = self.get_param('config.name_external_Address_Group',"Black list internal domain") - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - ioc=None - ioc_clear=[] - for i in list(response.json().get("artifacts")): - if 'hostname' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - ioc_clear.append(i) - ioc="".join(ioc_clear) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.AddressGroup.refreshall(fw) - - block_list = fw.find(self.name_internal_Address_Group_for_domain, panos.objects.AddressGroup) - ioc_list = block_list.about().get('static_value') - if ioc in ioc_list: - ioc_list.remove(ioc) - temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group_for_domain, static_value=ioc_list) - fw.add(temp1) - temp1.apply() - - panos.objects.AddressObject.refreshall(fw) - if ioc in str(fw.find(ioc, panos.objects.AddressObject)): - try: - deleted_ioc = fw.find(ioc, panos.objects.AddressObject) - deleted_ioc.delete() - except: - self.report({'message': 'message sent'}) - - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Unblock_domain().run() diff --git a/responders/PaloAltoNGFW_unblock_internal_port/README.md b/responders/PaloAltoNGFW_unblock_internal_port/README.md deleted file mode 100644 index e6a38990a..000000000 --- a/responders/PaloAltoNGFW_unblock_internal_port/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need set setting PaloAltoNGFW and The Hive. If you want delete in custom Address Group you need set "ServiceGroup" - -principle of operation: -1. the value is selected from the alert the hive. -2. ioc compare against already added AddressObject. -3. if ioc in ServiceGroup, will delete -4. if ioc in ServiceObject, will delete \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_internal_port/Unblock_port.py b/responders/PaloAltoNGFW_unblock_internal_port/Unblock_port.py deleted file mode 100644 index 866602c1e..000000000 --- a/responders/PaloAltoNGFW_unblock_internal_port/Unblock_port.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects -import re -class Unblock_port(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Service_Group = self.get_param('config.name_internal_Service_Group','Black list internal port') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - data_list=[] - data=None - for i in response.json().get("artifacts"): - if "'port'," in str(i): - ioc = i.get("data") - data_list.append(i.get("data")) - elif "'protocol'," in str(i): - ioc = i.get("data") - data_list.append(i.get("data")) - data=" ".join(data_list) - protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() - port=re.findall(r'[0-9]+',str(data)); port="".join(port) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.ServiceGroup.refreshall(fw) - block_list = fw.find(self.name_internal_Service_Group, panos.objects.ServiceGroup) - port_list = block_list.about().get('value') - if port in port_list: - port_list.remove(port) - temp1 = panos.objects.ServiceGroup(self.name_internal_Service_Group, value=port_list) - fw.add(temp1) - temp1.apply() - - panos.objects.ServiceObject.refreshall(fw) - if port in str(fw.find(port, panos.objects.ServiceObject)): - deleted_ioc = fw.find(port, panos.objects.ServiceObject) - deleted_ioc.delete() - - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Unblock_port().run() diff --git a/responders/PaloAltoNGFW_unblock_internal_user/README.md b/responders/PaloAltoNGFW_unblock_internal_user/README.md deleted file mode 100644 index 18aa819d1..000000000 --- a/responders/PaloAltoNGFW_unblock_internal_user/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need set setting PaloAltoNGFW and The Hive. If you want create or add setting for custom rule you need set "name_security_rule" - -principle of operation: -1. the value is selected from the alert the hive. -2. user compare against already added in security rules. -3. if user in security rules, will delete \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_internal_user/Unblock_user.py b/responders/PaloAltoNGFW_unblock_internal_user/Unblock_user.py deleted file mode 100644 index 152b1f91e..000000000 --- a/responders/PaloAltoNGFW_unblock_internal_user/Unblock_user.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.policies - -class Unblock_user(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','Block user internal communication') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - user=None - user_list_alert=[] - for i in list(response.json().get("artifacts")): - if 'user' in str(i): - ioc = i.get("data") - for i in ioc: - if i == "[" or i == "]": - continue - else: - user_list_alert.append(i) - user="".join(user_list_alert) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - rulebase = panos.policies.Rulebase() - fw.add(rulebase) - current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) - user_list=[] - for i in current_security_rules: - if i.about().get('name') == self.name_security_rule: - user_list=i.about().get("source_user") - if user in user_list: - user_list.remove(user) - desired_rule_params = { - "name": self.name_security_rule, - "description": "Block user internal communication", - "type": "intrazone", - "action": "deny", - 'source_user': user_list - } - new_rule = panos.policies.SecurityRule(**desired_rule_params) - rulebase.add(new_rule) - new_rule.apply() - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Unblock_user().run() diff --git a/responders/PaloAltoNGFW_unblock_port/.Unblock_port.py.swp b/responders/PaloAltoNGFW_unblock_port/.Unblock_port.py.swp deleted file mode 100644 index 250cf29671ef19c5b0df4056331e4c2003749a86..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeHNO=u)V7_HS^*T2=(1qJcYJ3)HJo%Cdl$Qm7EknC>M-GrDZVOiSBbahfmPgh%A zlVnyz1i^y`FM1LL5icG*i(Wl=5Y~%&6Ff<-i$_^})qm47naS)y#FZ*|GgZ}Jz543) zS6@v?txvtaaLGF7Oc9imgxom(k^A|3kCN%P2$4c4-94@ZqD6yE5i2LDd7@2uIAl;m zM5^(Ukc#b1&V@ASUSl$DNESyT^mKKJ24XHy;_`*_Z@8Us9dz4ngaM7!Qp1V5L&!~+ zQNSoLMu8J#`l++YR-dSxwoW~~I>z2SHVPO8i~>dhqkvJsC}0#Y3K#|cPYS5$2zeI^ zx+7cEZ1#O*;5%!YFQb4_z$jo8FbWt2i~>dhqkvJsC}0#Y3K#`$Lj|Zu$TxQq^3zc` zkN^MYfB)}4NXW0iFThv8`v3=4fR}+Yz$xIy1B84AECV-BpboqM{CPhip8`w3BJezL z68QZ-LVg6k1wH^;z>B~`z#sP#@;&eg5CM+>Ki@;htH5Kx&ASQt0@wyF0Z#%y94F*! z;A7xJU<&x_E<%0-z5~{PS>OraabW)#AzuP-0<*v~z%k$`un!Hi4%f97rWgf`0=Jz4 z7E1ZDP_^dBPFSrG?pv-K(l&EltJ$<{*VVU_T-TlW`XZWrf(co-?rNlh!eU@m!1CY@^}K3g&>LKg!IFp0eL;#&R86E$UJu(-OyYK!n~C5i26bzP1|8Pa>vsbl ztNs~^Zmgj#c37fn&!i+=VOf$S=Y)&toijawL)S$|A$~TPs@loyc8{@VS9+D>7cp9a z9`(N~HxK{Aa_itJs?H7Mn#{`#b7dy#0 zpHDvn6;qux}zMlxT@yfP_w7J3x|KYUYA0>#Wsq zGjx~9frOzQXjZIjX5AXHvk?Ks6PysjNdMh?&&Q>gNe5DJfQgNT+fT)xl)gCr4 zi;xwIEPQTWxmtAQgpekQFGQRsb!otG+9jV0UQf%cBe&L;5tX!EwKcoLy(|}c%(wIb zt2yCRFu4-EAwma#rfs=QV#DU&b=AWoLdeu9dde&COu@(Q2yarZVdnML4*85 zlgVi2q2_~}2eQ~`z5}L%TtidmXugZXGHr=-Ilp)AxClkATsIBkB!qQX_jk{bR)B2V z|KqaYKs!b72lfMD%qTZ?i diff --git a/responders/PaloAltoNGFW_unblock_port/PaloAltoNGFW_unblock_port.json b/responders/PaloAltoNGFW_unblock_port/PaloAltoNGFW_unblock_port.json deleted file mode 100644 index dfb3e6246..000000000 --- a/responders/PaloAltoNGFW_unblock_port/PaloAltoNGFW_unblock_port.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "name": "PaloAltoNGFW_unblock_port", - "version": "1.0.0", - "author": "Maxim Konakin", - "url": "", - "license": "AGPL-V3", - "description": "Unblock domain", - "dataTypeList": ["thehive:alert"], - "command": "PaloAltoNGFW_unblock_port/Unblock_port.py", - "baseConfig": "PaloAltoNGFW_unblock_port", - "configurationItems": [ - { - "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_internal_Service_Group", - "description": "name_internal_Service_Group", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_external_Service_Group", - "description": "name_external_Service_Group", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_api_key", - "description": "TheHive API key with read access", - "type": "string", - "multi": false, - "required": true - } - ] -} diff --git a/responders/PaloAltoNGFW_unblock_port/README.md b/responders/PaloAltoNGFW_unblock_port/README.md deleted file mode 100644 index 3b0110cf7..000000000 --- a/responders/PaloAltoNGFW_unblock_port/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Block external IP address for Palo Alto NGFW - -Response module for block external IP address for Palo Alto NGFW - -# Installation - -need install: -1. pan-os-python -2. thehive4py - -# ToDo - -to work, you need to create Address_Group in PaloAltoNGFW and create security polites and name them in "name_internal_Service_Group" and "name_external_Service_Group". - - -principle of operation: -1. the value is selected from the alert the hive. -2. if ioc added in Service_Groups, script deleted ioc -3. if ioc in AddressObject, script deleted ioc \ No newline at end of file diff --git a/responders/PaloAltoNGFW_unblock_port/Unblock_port.py b/responders/PaloAltoNGFW_unblock_port/Unblock_port.py deleted file mode 100644 index c6c8cc835..000000000 --- a/responders/PaloAltoNGFW_unblock_port/Unblock_port.py +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python3 -# encoding: utf-8 - -from cortexutils.responder import Responder -from thehive4py.api import TheHiveApi -from panos import firewall -import panos.objects -import re -class Unblock_port(Responder): - def __init__(self): - Responder.__init__(self) - self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') - self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') - self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Service_Group = self.get_param('config.name_internal_Service_Group') - self.name_external_Service_Group = self.get_param('config.name_external_Service_Group') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) - - def run(self): - alertId = self.get_param('data.id') - response = self.api.get_alert(alertId) - data_list=[] - data=None - for i in response.json().get("artifacts"): - if "'port'," in str(i): - ioc = i.get("data") - data_list.append(i.get("data")) - elif "'protocol'," in str(i): - ioc = i.get("data") - data_list.append(i.get("data")) - data=" ".join(data_list) - protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() - port=re.findall(r'[0-9]+',str(data)); port="".join(port) - fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) - panos.objects.ServiceGroup.refreshall(fw) - raise IOError("to") - block_list = fw.find(self.name_internal_Service_Group, panos.objects.ServiceGroup) - port_list = block_list.about().get('value') - if port in port_list: - port_list.remove(port) - temp1 = panos.objects.ServiceGroup(self.name_internal_Service_Group, value=port_list) - fw.add(temp1) - temp1.apply() - - block_list = fw.find(self.name_external_Service_Group, panos.objects.ServiceGroup) - port_list = block_list.about().get('value') - if port in port_list: - port_list.remove(port) - temp1 = panos.objects.ServiceGroup(self.name_external_Service_Group, value=port_list) - fw.add(temp1) - temp1.apply() - - panos.objects.ServiceObject.refreshall(fw) - if port in str(fw.find(port, panos.objects.ServiceObject)): - deleted_ioc = fw.find(port, panos.objects.ServiceObject) - deleted_ioc.delete() - - self.report({'message': 'message sent'}) - -if __name__ == '__main__': - Unblock_port().run() From 888a9d07dd120d841c92d7f483c00d728c3e71d2 Mon Sep 17 00:00:00 2001 From: Konakin Maksim <60079363@leroymerlin.ru> Date: Wed, 13 Jan 2021 19:32:48 +0300 Subject: [PATCH 13/25] Fixed bugs and errors --- responders/PaloAltoNGFW/Block_external_domain.py | 1 + responders/PaloAltoNGFW/Block_external_ip.py | 3 +++ responders/PaloAltoNGFW/Block_external_port.py | 3 +++ responders/PaloAltoNGFW/Block_external_user.py | 1 + responders/PaloAltoNGFW/Block_internal_domain.py | 1 + responders/PaloAltoNGFW/Block_internal_ip.py | 3 +++ responders/PaloAltoNGFW/Block_internal_port.py | 4 ++++ responders/PaloAltoNGFW/Block_internal_user.py | 1 + responders/PaloAltoNGFW/Unblock_external_domain.py | 1 + responders/PaloAltoNGFW/Unblock_external_ip.py | 1 + responders/PaloAltoNGFW/Unblock_external_port.py | 2 ++ responders/PaloAltoNGFW/Unblock_external_user.py | 1 + responders/PaloAltoNGFW/Unblock_internal_domain.py | 1 + responders/PaloAltoNGFW/Unblock_internal_ip.py | 1 + responders/PaloAltoNGFW/Unblock_internal_port.py | 2 ++ responders/PaloAltoNGFW/Unblock_internal_user.py | 1 + responders/PaloAltoNGFW/requirements.txt | 3 ++- 17 files changed, 29 insertions(+), 1 deletion(-) diff --git a/responders/PaloAltoNGFW/Block_external_domain.py b/responders/PaloAltoNGFW/Block_external_domain.py index 5d0fc816b..28ccfc1ab 100644 --- a/responders/PaloAltoNGFW/Block_external_domain.py +++ b/responders/PaloAltoNGFW/Block_external_domain.py @@ -6,6 +6,7 @@ from panos import firewall import panos.objects import panos.policies +import json class Block_domain(Responder): def __init__(self): diff --git a/responders/PaloAltoNGFW/Block_external_ip.py b/responders/PaloAltoNGFW/Block_external_ip.py index 99db518bc..8548a149c 100644 --- a/responders/PaloAltoNGFW/Block_external_ip.py +++ b/responders/PaloAltoNGFW/Block_external_ip.py @@ -6,6 +6,7 @@ from panos import firewall import panos.objects import panos.policies +import json class Block_ip(Responder): def __init__(self): @@ -86,6 +87,8 @@ def run(self): temp_rule_atrib.remove("any") rule_atrib.update({"destination": temp_rule_atrib}) desired_rule_params = rule_atrib + else: + desired_rule_params = rule_atrib new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() diff --git a/responders/PaloAltoNGFW/Block_external_port.py b/responders/PaloAltoNGFW/Block_external_port.py index 5d14af2b3..96c4008e6 100644 --- a/responders/PaloAltoNGFW/Block_external_port.py +++ b/responders/PaloAltoNGFW/Block_external_port.py @@ -7,6 +7,7 @@ import panos.objects import re import panos.policies +import json class Block_port(Responder): def __init__(self): @@ -53,6 +54,8 @@ def run(self): for n in data: if n.get('dataType') == 'port': port=n.get('data') + if n.get('dataType') == 'protocol': + protocol=n.get('data') fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) panos.objects.ServiceObject.refreshall(fw) rulebase = panos.policies.Rulebase() diff --git a/responders/PaloAltoNGFW/Block_external_user.py b/responders/PaloAltoNGFW/Block_external_user.py index d7f741b1f..23f204cdc 100644 --- a/responders/PaloAltoNGFW/Block_external_user.py +++ b/responders/PaloAltoNGFW/Block_external_user.py @@ -5,6 +5,7 @@ from thehive4py.api import TheHiveApi from panos import firewall import panos.policies +import json class Block_user(Responder): def __init__(self): diff --git a/responders/PaloAltoNGFW/Block_internal_domain.py b/responders/PaloAltoNGFW/Block_internal_domain.py index 373353742..8b54e8964 100644 --- a/responders/PaloAltoNGFW/Block_internal_domain.py +++ b/responders/PaloAltoNGFW/Block_internal_domain.py @@ -6,6 +6,7 @@ from panos import firewall import panos.objects import panos.policies +import json class Block_domain(Responder): def __init__(self): diff --git a/responders/PaloAltoNGFW/Block_internal_ip.py b/responders/PaloAltoNGFW/Block_internal_ip.py index 0cf928840..2f09cb8b7 100644 --- a/responders/PaloAltoNGFW/Block_internal_ip.py +++ b/responders/PaloAltoNGFW/Block_internal_ip.py @@ -6,6 +6,7 @@ from panos import firewall import panos.objects import panos.policies +import json class Block_ip(Responder): def __init__(self): @@ -86,6 +87,8 @@ def run(self): temp_rule_atrib.remove("any") rule_atrib.update({"destination": temp_rule_atrib}) desired_rule_params = rule_atrib + else: + desired_rule_params = rule_atrib new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() diff --git a/responders/PaloAltoNGFW/Block_internal_port.py b/responders/PaloAltoNGFW/Block_internal_port.py index 52ec014d2..e8a98938c 100644 --- a/responders/PaloAltoNGFW/Block_internal_port.py +++ b/responders/PaloAltoNGFW/Block_internal_port.py @@ -7,6 +7,8 @@ import panos.objects import panos.policies import re +import json + class Block_port(Responder): def __init__(self): Responder.__init__(self) @@ -54,6 +56,8 @@ def run(self): for n in data: if n.get('dataType') == 'port': port=n.get('data') + if n.get('dataType') == 'protocol': + protocol=n.get('data') fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) panos.objects.ServiceObject.refreshall(fw) rulebase = panos.policies.Rulebase() diff --git a/responders/PaloAltoNGFW/Block_internal_user.py b/responders/PaloAltoNGFW/Block_internal_user.py index 0b2482e57..7ed5f4432 100644 --- a/responders/PaloAltoNGFW/Block_internal_user.py +++ b/responders/PaloAltoNGFW/Block_internal_user.py @@ -5,6 +5,7 @@ from thehive4py.api import TheHiveApi from panos import firewall import panos.policies +import json class Block_user(Responder): def __init__(self): diff --git a/responders/PaloAltoNGFW/Unblock_external_domain.py b/responders/PaloAltoNGFW/Unblock_external_domain.py index 1fbc18af7..5d18bd20b 100644 --- a/responders/PaloAltoNGFW/Unblock_external_domain.py +++ b/responders/PaloAltoNGFW/Unblock_external_domain.py @@ -6,6 +6,7 @@ from panos import firewall import panos.objects import panos.policies +import json class Unblock_domain(Responder): def __init__(self): diff --git a/responders/PaloAltoNGFW/Unblock_external_ip.py b/responders/PaloAltoNGFW/Unblock_external_ip.py index baef0c676..9f64bf178 100644 --- a/responders/PaloAltoNGFW/Unblock_external_ip.py +++ b/responders/PaloAltoNGFW/Unblock_external_ip.py @@ -5,6 +5,7 @@ from thehive4py.api import TheHiveApi from panos import firewall import panos.objects +import json class Unblock_ip(Responder): def __init__(self): diff --git a/responders/PaloAltoNGFW/Unblock_external_port.py b/responders/PaloAltoNGFW/Unblock_external_port.py index 23bf1a6b7..01869591f 100644 --- a/responders/PaloAltoNGFW/Unblock_external_port.py +++ b/responders/PaloAltoNGFW/Unblock_external_port.py @@ -6,6 +6,8 @@ from panos import firewall import panos.objects import re +import json + class Unblock_port(Responder): def __init__(self): Responder.__init__(self) diff --git a/responders/PaloAltoNGFW/Unblock_external_user.py b/responders/PaloAltoNGFW/Unblock_external_user.py index f155539c2..67308dd86 100644 --- a/responders/PaloAltoNGFW/Unblock_external_user.py +++ b/responders/PaloAltoNGFW/Unblock_external_user.py @@ -5,6 +5,7 @@ from thehive4py.api import TheHiveApi from panos import firewall import panos.policies +import json class Unblock_user(Responder): def __init__(self): diff --git a/responders/PaloAltoNGFW/Unblock_internal_domain.py b/responders/PaloAltoNGFW/Unblock_internal_domain.py index b7ade6483..691d5aeb6 100644 --- a/responders/PaloAltoNGFW/Unblock_internal_domain.py +++ b/responders/PaloAltoNGFW/Unblock_internal_domain.py @@ -6,6 +6,7 @@ from panos import firewall import panos.objects import panos.policies +import json class Unblock_domain(Responder): def __init__(self): diff --git a/responders/PaloAltoNGFW/Unblock_internal_ip.py b/responders/PaloAltoNGFW/Unblock_internal_ip.py index 459b3f916..ce571eedd 100644 --- a/responders/PaloAltoNGFW/Unblock_internal_ip.py +++ b/responders/PaloAltoNGFW/Unblock_internal_ip.py @@ -5,6 +5,7 @@ from thehive4py.api import TheHiveApi from panos import firewall import panos.objects +import json class Unblock_ip(Responder): def __init__(self): diff --git a/responders/PaloAltoNGFW/Unblock_internal_port.py b/responders/PaloAltoNGFW/Unblock_internal_port.py index ece0c4311..ba6d39746 100644 --- a/responders/PaloAltoNGFW/Unblock_internal_port.py +++ b/responders/PaloAltoNGFW/Unblock_internal_port.py @@ -6,6 +6,8 @@ from panos import firewall import panos.objects import re +import json + class Unblock_port(Responder): def __init__(self): Responder.__init__(self) diff --git a/responders/PaloAltoNGFW/Unblock_internal_user.py b/responders/PaloAltoNGFW/Unblock_internal_user.py index 7ba623d5d..9fbcad7b4 100644 --- a/responders/PaloAltoNGFW/Unblock_internal_user.py +++ b/responders/PaloAltoNGFW/Unblock_internal_user.py @@ -5,6 +5,7 @@ from thehive4py.api import TheHiveApi from panos import firewall import panos.policies +import json class Unblock_user(Responder): def __init__(self): diff --git a/responders/PaloAltoNGFW/requirements.txt b/responders/PaloAltoNGFW/requirements.txt index 1af2ae28a..2dbd1aeb3 100644 --- a/responders/PaloAltoNGFW/requirements.txt +++ b/responders/PaloAltoNGFW/requirements.txt @@ -1,3 +1,4 @@ cortexutils requests -panos \ No newline at end of file +panos +thehive4py \ No newline at end of file From fee2f8a244ae74773fa9aad15fa7b351c0a495cf Mon Sep 17 00:00:00 2001 From: Konakin Maksim <60079363@leroymerlin.ru> Date: Mon, 18 Jan 2021 21:16:19 +0300 Subject: [PATCH 14/25] add new version readme --- responders/PaloAltoNGFW/AddObservableType.jpg | Bin 0 -> 90710 bytes responders/PaloAltoNGFW/README.md | 11 ++++++++--- responders/PaloAltoNGFW/Responders.jpg | Bin 0 -> 77819 bytes 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 responders/PaloAltoNGFW/AddObservableType.jpg create mode 100644 responders/PaloAltoNGFW/Responders.jpg diff --git a/responders/PaloAltoNGFW/AddObservableType.jpg b/responders/PaloAltoNGFW/AddObservableType.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2c2f10e2d6dc7a12714f01d0b74ab72d35b535b1 GIT binary patch literal 90710 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 E4WTyZPXGV_ literal 0 HcmV?d00001 diff --git a/responders/PaloAltoNGFW/README.md b/responders/PaloAltoNGFW/README.md index 3af37eff5..368e60206 100644 --- a/responders/PaloAltoNGFW/README.md +++ b/responders/PaloAltoNGFW/README.md @@ -10,9 +10,13 @@ need install: 3. thehive4py # ToDo -Для работы responders, необходимо загрузить папку PaloAltoNGFW в директорию, где храняться другие responder. Далее перейти в загруженную папку и сделать запускаемыми скрипты на языке python командой chmod +x *.py +Для работы responders, необходимо загрузить папку PaloAltoNGFW в директорию, где храняться другие responder. Далее перейти в загруженную папку и сделать запускаемыми скрипты на языке python командой "chmod +x *.py" -Далее в веб консоли системы cortex, выбрать пункт "Organization" -> "Responders", выбрать интерисующий вас responder и настроить его так, что поля: +Далее необходимо: +Выполнить перезагрузку системы cortex; + +После перезагрузки в веб консоли cortex перейти на вкладку "Organization", выбрать организацию для которой будет выполнена настройка и перейти на вкладку "Responders", выбрать интерисующий Вас responder и настроить поля в соответсвии с их значениями: +![alt text](Responders.jpg) 1. Hostname_PaloAltoNGFW - сетевой адрес системы PaloAltoNGFW 2. User_PaloAltoNGFW - пользователь в системе PaloAltoNGFW 3. Password_PaloAltoNGFW - пароль для пользователя в системе PaloAltoNGFW @@ -44,4 +48,5 @@ need install: 2. FQDN - 'hostname' 3. порт - 'port' 4. имя пользователя - 'user-agent' -Примечание: данный тип необходимо создать в системе TheHive \ No newline at end of file +Примечание: данный тип необходимо создать в системе TheHive. По умолчанию TheHive не имеет типа данных "user-agent" в Observable type, поэтому мы должны добавить его в настройках администратора. +![alt text](AddObservableType.jpg) \ No newline at end of file diff --git a/responders/PaloAltoNGFW/Responders.jpg b/responders/PaloAltoNGFW/Responders.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3da9ba1db8378c22c16995b16280a44bc95f5def GIT binary patch literal 77819 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 Date: Thu, 11 Feb 2021 00:51:28 +0300 Subject: [PATCH 15/25] Fix error and redme.md --- .../PaloAltoNGFW/Block_external_port.py | 2 +- .../PaloAltoNGFW/Block_internal_port.py | 2 +- responders/PaloAltoNGFW/README.md | 36 +++++++++---------- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/responders/PaloAltoNGFW/Block_external_port.py b/responders/PaloAltoNGFW/Block_external_port.py index 96c4008e6..7ad5f4e17 100644 --- a/responders/PaloAltoNGFW/Block_external_port.py +++ b/responders/PaloAltoNGFW/Block_external_port.py @@ -86,7 +86,7 @@ def run(self): rule_atrib = i.about() temp_rule_atrib = rule_atrib.get("service") if "TheHive Black list external port" not in temp_rule_atrib: - temp_rule_atrib.append("Black list external port") + temp_rule_atrib.append("TheHive Black list external port") if "application-default" in temp_rule_atrib: temp_rule_atrib.remove("application-default") rule_atrib.update({"service": temp_rule_atrib}) diff --git a/responders/PaloAltoNGFW/Block_internal_port.py b/responders/PaloAltoNGFW/Block_internal_port.py index e8a98938c..63a4cf65d 100644 --- a/responders/PaloAltoNGFW/Block_internal_port.py +++ b/responders/PaloAltoNGFW/Block_internal_port.py @@ -88,7 +88,7 @@ def run(self): rule_atrib = i.about() temp_rule_atrib = rule_atrib.get("service") if "TheHive Black list internal port" not in temp_rule_atrib: - temp_rule_atrib.append("Black list internal port") + temp_rule_atrib.append("TheHive Black list internal port") if "application-default" in temp_rule_atrib: temp_rule_atrib.remove("application-default") rule_atrib.update({"service": temp_rule_atrib}) diff --git a/responders/PaloAltoNGFW/README.md b/responders/PaloAltoNGFW/README.md index 368e60206..d386103ec 100644 --- a/responders/PaloAltoNGFW/README.md +++ b/responders/PaloAltoNGFW/README.md @@ -20,33 +20,31 @@ need install: 1. Hostname_PaloAltoNGFW - сетевой адрес системы PaloAltoNGFW 2. User_PaloAltoNGFW - пользователь в системе PaloAltoNGFW 3. Password_PaloAltoNGFW - пароль для пользователя в системе PaloAltoNGFW -4. name_security_rule (не обязательное поле) - имя правила безопасности в системе PaloAltoNGFW. Установлены следующие стандартные наименования правил: -4.1 Для блокировки\разблокировки имени пользователей: -4.1.1 TheHive Block user internal communication -4.1.2 TheHive Block user external communication +4. name_security_rule (не обязательное поле) - имя правила безопасности в системе PaloAltoNGFW. Установлены следующие стандартные наименования правил: +4.1 Для блокировки\разблокировки имени пользователей: +4.1.1 TheHive Block user internal communication +4.1.2 TheHive Block user external communication -4.2 Для блокировки\разблокировки сетевых адресов: -4.2.1 TheHive Block internal IP address -4.2.2 TheHive Block external IP address +4.2 Для блокировки\разблокировки сетевых адресов: +4.2.1 TheHive Block internal IP address +4.2.2 TheHive Block external IP address -4.3 Для блокировки\разблокировки FQDN: -4.3.1 TheHive Block external Domain -4.3.2 TheHive Block internal Domain +4.3 Для блокировки\разблокировки FQDN: +4.3.1 TheHive Block external Domain +4.3.2 TheHive Block internal Domain -4.4 Для блокировки\разблокировки портов: -4.4.1 TheHive Black list internal port -4.4.2 TheHive Block external port +4.4 Для блокировки\разблокировки портов: +4.4.1 TheHive Block internal port +4.4.2 TheHive Block external port 4.5 thehive_instance - url адрес системы TheHive (используется только для типов case и alert) -4.6 thehive_api_key - API ключ для подключения к системе TheHive - -Примечание: указанные правила безопасноти должны быть созданы в PaloAltoNGFW, а так же расставлены в порядке их применения. - +4.6 thehive_api_key - API ключ для подключения к системе TheHive +Примечание: указанные правила безопасноти должны быть созданы в PaloAltoNGFW, а так же расставлены в порядке их применения. Типы используемых данных для работы в системе TheHive: 1. Сетевой адрес - 'ip' 2. FQDN - 'hostname' 3. порт - 'port' -4. имя пользователя - 'user-agent' -Примечание: данный тип необходимо создать в системе TheHive. По умолчанию TheHive не имеет типа данных "user-agent" в Observable type, поэтому мы должны добавить его в настройках администратора. +4. имя пользователя - 'user-agent' +Примечание: данный тип необходимо создать в системе TheHive. По умолчанию TheHive не имеет типа данных "user-agent" в Observable type, поэтому мы должны добавить его в настройках администратора. ![alt text](AddObservableType.jpg) \ No newline at end of file From 1bbc64ef3e87c3af1ac99f2791b1830f60f89b1d Mon Sep 17 00:00:00 2001 From: Konakin Maksim <60079363@leroymerlin.ru> Date: Fri, 12 Feb 2021 19:36:50 +0300 Subject: [PATCH 16/25] Add fix --- ...aloAltoNGFW_block_external_IP_address.json | 2 +- .../PaloAltoNGFW_block_external_domain.json | 2 +- .../PaloAltoNGFW_block_external_user.json | 2 +- ...aloAltoNGFW_block_internal_IP_address.json | 2 +- .../PaloAltoNGFW_block_internal_domain.json | 2 +- .../PaloAltoNGFW_block_internal_user.json | 2 +- ...oAltoNGFW_unblock_external_IP_address.json | 4 ++-- .../PaloAltoNGFW_unblock_external_domain.json | 2 +- .../PaloAltoNGFW_unblock_external_port.json | 4 ++-- .../PaloAltoNGFW_unblock_external_user.json | 2 +- ...oAltoNGFW_unblock_internal_IP_address.json | 4 ++-- .../PaloAltoNGFW_unblock_internal_domain.json | 2 +- .../PaloAltoNGFW_unblock_internal_port.json | 4 ++-- .../PaloAltoNGFW_unblock_internal_user.json | 2 +- responders/PaloAltoNGFW/README.md | 23 ++++++++++--------- 15 files changed, 30 insertions(+), 29 deletions(-) diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json index bb4b653f7..fb225a320 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json @@ -1,7 +1,7 @@ { "name": "PaloAltoNGFW_block_external_IP_address", "version": "2.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Block external IP address", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json index c97843939..3fb39f0b8 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json @@ -1,7 +1,7 @@ { "name": "PaloAltoNGFW_block_external_domain", "version": "2.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Block external domain", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json index d0200765f..33f03477c 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json @@ -1,7 +1,7 @@ { "name": "PaloAltoNGFW_block_external_user", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Block external user", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json index af97484c7..6ba5a7cf7 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json @@ -1,7 +1,7 @@ { "name": "PaloAltoNGFW_block_internal_IP_address", "version": "2.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Block internal IP address", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json index d806ca8af..082fe1f40 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json @@ -1,7 +1,7 @@ { "name": "PaloAltoNGFW_block_internal_domain", "version": "2.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Block internal domain", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json index dd8d712ea..df2ab8dc3 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json @@ -1,7 +1,7 @@ { "name": "PaloAltoNGFW_block_internal_user", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Block internal user", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json index c88b5aea1..8b8e201e1 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json @@ -1,13 +1,13 @@ { "name": "PaloAltoNGFW_unblock_external_IP_address", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Unblock ip", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Unblock_external_ip.py", - "baseConfig": "PaloAltoNGFW_unblock_ip", + "baseConfig": "PaloAltoNGFW_unblock_external_ip", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json index cdb23cde6..d53ff924f 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json @@ -1,7 +1,7 @@ { "name": "PaloAltoNGFW_unblock_external_domain", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Unblock domain", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json index 493e9571a..115a788e6 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json @@ -1,13 +1,13 @@ { "name": "PaloAltoNGFW_unblock_external_port", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Unblock domain", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Unblock_external_port.py", - "baseConfig": "PaloAltoNGFW_unblock_port", + "baseConfig": "PaloAltoNGFW_unblock_external_port", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json index 5a795abeb..5e265d28b 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json @@ -1,7 +1,7 @@ { "name": "PaloAltoNGFW_unblock_external_user", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Unblock external user", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json index 47b915f67..13fbc78bd 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json @@ -1,13 +1,13 @@ { "name": "PaloAltoNGFW_unblock_internal_IP_address", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Unblock ip", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Unblock_internal_ip.py", - "baseConfig": "PaloAltoNGFW_unblock_ip", + "baseConfig": "PaloAltoNGFW_unblock_internal_ip", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json index 06e218a45..3feb5f386 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json @@ -1,7 +1,7 @@ { "name": "PaloAltoNGFW_unblock_internal_domain", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Unblock domain", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json index 904dd9ec5..b2e104551 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json @@ -1,13 +1,13 @@ { "name": "PaloAltoNGFW_unblock_internal_port", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Unblock domain", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Unblock_internal_port.py", - "baseConfig": "PaloAltoNGFW_unblock_port", + "baseConfig": "PaloAltoNGFW_unblock_internal_port", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json index 4319fa601..e9a693c36 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json @@ -1,7 +1,7 @@ { "name": "PaloAltoNGFW_unblock_internal_user", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Unblock internal user", diff --git a/responders/PaloAltoNGFW/README.md b/responders/PaloAltoNGFW/README.md index d386103ec..01b144326 100644 --- a/responders/PaloAltoNGFW/README.md +++ b/responders/PaloAltoNGFW/README.md @@ -5,9 +5,10 @@ # Installation need install: -1. pan-os-python -2. thehive4py -3. thehive4py +1. cortexutils +2. requests +3. pan-os-python +4. thehive4py # ToDo Для работы responders, необходимо загрузить папку PaloAltoNGFW в директорию, где храняться другие responder. Далее перейти в загруженную папку и сделать запускаемыми скрипты на языке python командой "chmod +x *.py" @@ -22,20 +23,20 @@ need install: 3. Password_PaloAltoNGFW - пароль для пользователя в системе PaloAltoNGFW 4. name_security_rule (не обязательное поле) - имя правила безопасности в системе PaloAltoNGFW. Установлены следующие стандартные наименования правил: 4.1 Для блокировки\разблокировки имени пользователей: -4.1.1 TheHive Block user internal communication -4.1.2 TheHive Block user external communication +4.1.1 "TheHive Block user internal communication" +4.1.2 "TheHive Block user external communication" 4.2 Для блокировки\разблокировки сетевых адресов: -4.2.1 TheHive Block internal IP address -4.2.2 TheHive Block external IP address +4.2.1 "TheHive Block internal IP address" +4.2.2 "TheHive Block external IP address" 4.3 Для блокировки\разблокировки FQDN: -4.3.1 TheHive Block external Domain -4.3.2 TheHive Block internal Domain +4.3.1 "TheHive Block external Domain" +4.3.2 "TheHive Block internal Domain" 4.4 Для блокировки\разблокировки портов: -4.4.1 TheHive Block internal port -4.4.2 TheHive Block external port +4.4.1 "TheHive Block internal port" +4.4.2 "TheHive Block external port" 4.5 thehive_instance - url адрес системы TheHive (используется только для типов case и alert) From cfa10131ece394fb2489e3b26aad9d1bf66d517d Mon Sep 17 00:00:00 2001 From: Konakin Maksim <60079363@leroymerlin.ru> Date: Fri, 12 Feb 2021 20:16:07 +0300 Subject: [PATCH 17/25] add new version json files Add main config and config for unblock ip,domain,port --- .../PaloAltoNGFW_block_external_IP_address.json | 5 +++-- .../PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json | 5 +++-- .../PaloAltoNGFW/PaloAltoNGFW_block_external_port.json | 5 +++-- .../PaloAltoNGFW/PaloAltoNGFW_block_external_user.json | 5 +++-- .../PaloAltoNGFW_block_internal_IP_address.json | 5 +++-- .../PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json | 5 +++-- .../PaloAltoNGFW/PaloAltoNGFW_block_internal_port.json | 5 +++-- .../PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json | 5 +++-- .../PaloAltoNGFW_unblock_external_IP_address.json | 7 ++++--- .../PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json | 7 ++++--- .../PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json | 7 ++++--- .../PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json | 7 ++++--- .../PaloAltoNGFW_unblock_internal_IP_address.json | 7 ++++--- .../PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json | 7 ++++--- .../PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json | 7 ++++--- .../PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json | 5 +++-- 16 files changed, 55 insertions(+), 39 deletions(-) diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json index fb225a320..d4c3787d1 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json @@ -7,7 +7,7 @@ "description": "Block external IP address", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Block_external_ip.py", - "baseConfig": "PaloAltoNGFW_block_external_IP_address", + "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -35,7 +35,8 @@ "description": "name_external_name_security_rule_for_ip", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Block external IP address" }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json index 3fb39f0b8..733835ec8 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json @@ -7,7 +7,7 @@ "description": "Block external domain", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Block_external_domain.py", - "baseConfig": "PaloAltoNGFW_block_external_domain", + "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -28,7 +28,8 @@ "description": "User_PaloAltoNGFW", "type": "string", "multi": false, - "required": true + "required": true, + "defaultValue": "TheHive Block external Domain" }, { "name": "name_security_rule", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_port.json index e989e7470..99873f455 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_port.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_port.json @@ -7,7 +7,7 @@ "description": "Block external port", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Block_external_port.py", - "baseConfig": "PaloAltoNGFW_block_external_port", + "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -35,7 +35,8 @@ "description": "name_external_name_security_rule_for_port", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Block external port" }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json index 33f03477c..eeaf9ef25 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json @@ -7,7 +7,7 @@ "description": "Block external user", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Block_external_user.py", - "baseConfig": "PaloAltoNGFW_block_external_user", + "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -35,7 +35,8 @@ "description": "name_external_name_security_rule_for_users", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Block user external communication" }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json index 6ba5a7cf7..8b9c7ba09 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json @@ -7,7 +7,7 @@ "description": "Block internal IP address", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Block_internal_ip.py", - "baseConfig": "PaloAltoNGFW_block_internal_IP_address", + "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -35,7 +35,8 @@ "description": "name_internal_name_security_rule_for_ip", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": 'TheHive Block internal IP address' }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json index 082fe1f40..400fbc308 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json @@ -7,7 +7,7 @@ "description": "Block internal domain", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Block_internal_domain.py", - "baseConfig": "PaloAltoNGFW_block_internal_domain", + "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -35,7 +35,8 @@ "description": "name_internal_security_rule_for_domain", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Block internal Domain" }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_port.json index fb4e16a6f..f626937b5 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_port.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_port.json @@ -7,7 +7,7 @@ "description": "Block internal port", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Block_internal_port.py", - "baseConfig": "PaloAltoNGFW_block_internal_port", + "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -35,7 +35,8 @@ "description": "name_internal_name_security_rule_for_port", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Block internal port" }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json index df2ab8dc3..350daa622 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json @@ -7,7 +7,7 @@ "description": "Block internal user", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Block_internal_user.py", - "baseConfig": "PaloAltoNGFW_block_internal_user", + "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -35,7 +35,8 @@ "description": "name_internal_name_security_rule_for_users", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Block user internal communication" }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json index 8b8e201e1..ddebf94be 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json @@ -7,7 +7,7 @@ "description": "Unblock ip", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Unblock_external_ip.py", - "baseConfig": "PaloAltoNGFW_unblock_external_ip", + "baseConfig": "PaloAltoNGFW_unblock_ip", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -31,11 +31,12 @@ "required": true }, { - "name": "name_external_Address_Group", + "name": "name_Address_Group", "description": "name_external_Address_Group", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Black list external IP" }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json index d53ff924f..c8af518f3 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json @@ -7,7 +7,7 @@ "description": "Unblock domain", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Unblock_external_domain.py", - "baseConfig": "PaloAltoNGFW_unblock_external_domain", + "baseConfig": "PaloAltoNGFW_unblock_domain", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -31,11 +31,12 @@ "required": true }, { - "name": "name_external_Address_Group", + "name": "name_Address_Group", "description": "name_external_Address_Group_for_domain", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Black list external domain" }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json index 115a788e6..58b3c2730 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json @@ -7,7 +7,7 @@ "description": "Unblock domain", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Unblock_external_port.py", - "baseConfig": "PaloAltoNGFW_unblock_external_port", + "baseConfig": "PaloAltoNGFW_unblock_port", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -31,11 +31,12 @@ "required": true }, { - "name": "name_external_Service_Group", + "name": "name_Service_Group", "description": "name_external_Service_Group", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": 'TheHive Black list external port' }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json index 5e265d28b..2a8281af6 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json @@ -7,7 +7,7 @@ "description": "Unblock external user", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Unblock_external_user.py", - "baseConfig": "PaloAltoNGFW_unblock_external_user", + "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -32,10 +32,11 @@ }, { "name": "name_security_rule", - "description": "name_external_name_security_rule_for_users", + "description": "name_external_security_rule_for_users", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Block user external communication" }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json index 13fbc78bd..e77cd332b 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json @@ -7,7 +7,7 @@ "description": "Unblock ip", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Unblock_internal_ip.py", - "baseConfig": "PaloAltoNGFW_unblock_internal_ip", + "baseConfig": "PaloAltoNGFW_unblock_ip", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -31,11 +31,12 @@ "required": true }, { - "name": "name_internal_Address_Group", + "name": "name_Address_Group", "description": "name_internal_Address_Group", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Black list internal IP" }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json index 3feb5f386..c1f8199c5 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json @@ -7,7 +7,7 @@ "description": "Unblock domain", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Unblock_internal_domain.py", - "baseConfig": "PaloAltoNGFW_unblock_internal_domain", + "baseConfig": "PaloAltoNGFW_unblock_domain", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -31,11 +31,12 @@ "required": true }, { - "name": "name_internal_Address_Group", + "name": "name_Address_Group", "description": "name_internal_Address_Group_for_domain", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Black list internal domain" }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json index b2e104551..ab20e5c65 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json @@ -7,7 +7,7 @@ "description": "Unblock domain", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Unblock_internal_port.py", - "baseConfig": "PaloAltoNGFW_unblock_internal_port", + "baseConfig": "PaloAltoNGFW_unblock_port", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -31,11 +31,12 @@ "required": true }, { - "name": "name_internal_Service_Group", + "name": "name_Service_Group", "description": "name_internal_Service_Group", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": 'TheHive Black list internal port' }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json index e9a693c36..a2d8d139f 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json @@ -7,7 +7,7 @@ "description": "Unblock internal user", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Unblock_internal_user.py", - "baseConfig": "PaloAltoNGFW_unblock_internal_user", + "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -35,7 +35,8 @@ "description": "name_internal_name_security_rule_for_users", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Block user internal communication" }, { "name": "thehive_instance", From 79e32de6468dd999bfbbeb245579839303195481 Mon Sep 17 00:00:00 2001 From: Konakin Maksim <60079363@leroymerlin.ru> Date: Fri, 26 Feb 2021 00:20:56 +0300 Subject: [PATCH 18/25] add new vesion configs and readme --- ...PaloAltoNGFW_block_external_IP_address.json | 5 ++--- .../PaloAltoNGFW_block_external_domain.json | 5 ++--- .../PaloAltoNGFW_block_external_port.json | 3 +-- .../PaloAltoNGFW_block_external_user.json | 5 ++--- ...PaloAltoNGFW_block_internal_IP_address.json | 5 ++--- .../PaloAltoNGFW_block_internal_domain.json | 5 ++--- .../PaloAltoNGFW_block_internal_port.json | 3 +-- .../PaloAltoNGFW_block_internal_user.json | 5 ++--- ...loAltoNGFW_unblock_external_IP_address.json | 9 ++++----- .../PaloAltoNGFW_unblock_external_domain.json | 9 ++++----- .../PaloAltoNGFW_unblock_external_port.json | 9 ++++----- .../PaloAltoNGFW_unblock_external_user.json | 7 +++---- ...loAltoNGFW_unblock_internal_IP_address.json | 9 ++++----- .../PaloAltoNGFW_unblock_internal_domain.json | 9 ++++----- .../PaloAltoNGFW_unblock_internal_port.json | 9 ++++----- .../PaloAltoNGFW_unblock_internal_user.json | 5 ++--- responders/PaloAltoNGFW/README.md | 18 ++++++++++-------- responders/PaloAltoNGFW/requirements.txt | 2 +- 18 files changed, 54 insertions(+), 68 deletions(-) diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json index d4c3787d1..951fdde5a 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json @@ -1,7 +1,7 @@ { "name": "PaloAltoNGFW_block_external_IP_address", "version": "2.0.0", - "author": "Maxim Konakin, OSCD Initiative", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Block external IP address", @@ -35,8 +35,7 @@ "description": "name_external_name_security_rule_for_ip", "type": "string", "multi": false, - "required": false, - "defaultValue": "TheHive Block external IP address" + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json index 733835ec8..b7db75e06 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json @@ -1,7 +1,7 @@ { "name": "PaloAltoNGFW_block_external_domain", "version": "2.0.0", - "author": "Maxim Konakin, OSCD Initiative", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Block external domain", @@ -28,8 +28,7 @@ "description": "User_PaloAltoNGFW", "type": "string", "multi": false, - "required": true, - "defaultValue": "TheHive Block external Domain" + "required": true }, { "name": "name_security_rule", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_port.json index 99873f455..6478b3178 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_port.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_port.json @@ -35,8 +35,7 @@ "description": "name_external_name_security_rule_for_port", "type": "string", "multi": false, - "required": false, - "defaultValue": "TheHive Block external port" + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json index eeaf9ef25..318382aa7 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json @@ -1,7 +1,7 @@ { "name": "PaloAltoNGFW_block_external_user", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Initiative", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Block external user", @@ -35,8 +35,7 @@ "description": "name_external_name_security_rule_for_users", "type": "string", "multi": false, - "required": false, - "defaultValue": "TheHive Block user external communication" + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json index 8b9c7ba09..2cc0622ba 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json @@ -1,7 +1,7 @@ { "name": "PaloAltoNGFW_block_internal_IP_address", "version": "2.0.0", - "author": "Maxim Konakin, OSCD Initiative", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Block internal IP address", @@ -35,8 +35,7 @@ "description": "name_internal_name_security_rule_for_ip", "type": "string", "multi": false, - "required": false, - "defaultValue": 'TheHive Block internal IP address' + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json index 400fbc308..e519e65ea 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json @@ -1,7 +1,7 @@ { "name": "PaloAltoNGFW_block_internal_domain", "version": "2.0.0", - "author": "Maxim Konakin, OSCD Initiative", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Block internal domain", @@ -35,8 +35,7 @@ "description": "name_internal_security_rule_for_domain", "type": "string", "multi": false, - "required": false, - "defaultValue": "TheHive Block internal Domain" + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_port.json index f626937b5..3343dc0cc 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_port.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_port.json @@ -35,8 +35,7 @@ "description": "name_internal_name_security_rule_for_port", "type": "string", "multi": false, - "required": false, - "defaultValue": "TheHive Block internal port" + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json index 350daa622..d760ac968 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json @@ -1,7 +1,7 @@ { "name": "PaloAltoNGFW_block_internal_user", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Initiative", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Block internal user", @@ -35,8 +35,7 @@ "description": "name_internal_name_security_rule_for_users", "type": "string", "multi": false, - "required": false, - "defaultValue": "TheHive Block user internal communication" + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json index ddebf94be..7c2b892b9 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json @@ -1,13 +1,13 @@ { "name": "PaloAltoNGFW_unblock_external_IP_address", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Initiative", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Unblock ip", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Unblock_external_ip.py", - "baseConfig": "PaloAltoNGFW_unblock_ip", + "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -31,12 +31,11 @@ "required": true }, { - "name": "name_Address_Group", + "name": "name_external_Address_Group", "description": "name_external_Address_Group", "type": "string", "multi": false, - "required": false, - "defaultValue": "TheHive Black list external IP" + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json index c8af518f3..73f445c76 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json @@ -1,13 +1,13 @@ { "name": "PaloAltoNGFW_unblock_external_domain", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Initiative", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Unblock domain", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Unblock_external_domain.py", - "baseConfig": "PaloAltoNGFW_unblock_domain", + "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -31,12 +31,11 @@ "required": true }, { - "name": "name_Address_Group", + "name": "name_external_Address_Group", "description": "name_external_Address_Group_for_domain", "type": "string", "multi": false, - "required": false, - "defaultValue": "TheHive Black list external domain" + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json index 58b3c2730..08dde582a 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json @@ -1,13 +1,13 @@ { "name": "PaloAltoNGFW_unblock_external_port", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Initiative", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Unblock domain", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Unblock_external_port.py", - "baseConfig": "PaloAltoNGFW_unblock_port", + "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -31,12 +31,11 @@ "required": true }, { - "name": "name_Service_Group", + "name": "name_external_Service_Group", "description": "name_external_Service_Group", "type": "string", "multi": false, - "required": false, - "defaultValue": 'TheHive Black list external port' + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json index 2a8281af6..c8872767a 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json @@ -1,7 +1,7 @@ { "name": "PaloAltoNGFW_unblock_external_user", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Initiative", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Unblock external user", @@ -32,11 +32,10 @@ }, { "name": "name_security_rule", - "description": "name_external_security_rule_for_users", + "description": "name_external_name_security_rule_for_users", "type": "string", "multi": false, - "required": false, - "defaultValue": "TheHive Block user external communication" + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json index e77cd332b..5b39822da 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json @@ -1,13 +1,13 @@ { "name": "PaloAltoNGFW_unblock_internal_IP_address", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Initiative", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Unblock ip", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Unblock_internal_ip.py", - "baseConfig": "PaloAltoNGFW_unblock_ip", + "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -31,12 +31,11 @@ "required": true }, { - "name": "name_Address_Group", + "name": "name_internal_Address_Group", "description": "name_internal_Address_Group", "type": "string", "multi": false, - "required": false, - "defaultValue": "TheHive Black list internal IP" + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json index c1f8199c5..0f01adc9e 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json @@ -1,13 +1,13 @@ { "name": "PaloAltoNGFW_unblock_internal_domain", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Initiative", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Unblock domain", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Unblock_internal_domain.py", - "baseConfig": "PaloAltoNGFW_unblock_domain", + "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -31,12 +31,11 @@ "required": true }, { - "name": "name_Address_Group", + "name": "name_internal_Address_Group", "description": "name_internal_Address_Group_for_domain", "type": "string", "multi": false, - "required": false, - "defaultValue": "TheHive Black list internal domain" + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json index ab20e5c65..bcd68e95a 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json @@ -1,13 +1,13 @@ { "name": "PaloAltoNGFW_unblock_internal_port", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Initiative", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Unblock domain", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], "command": "PaloAltoNGFW/Unblock_internal_port.py", - "baseConfig": "PaloAltoNGFW_unblock_port", + "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", @@ -31,12 +31,11 @@ "required": true }, { - "name": "name_Service_Group", + "name": "name_internal_Service_Group", "description": "name_internal_Service_Group", "type": "string", "multi": false, - "required": false, - "defaultValue": 'TheHive Black list internal port' + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json index a2d8d139f..245fb2269 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json @@ -1,7 +1,7 @@ { "name": "PaloAltoNGFW_unblock_internal_user", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Initiative", + "author": "Maxim Konakin, OSCD Community", "url": "", "license": "AGPL-V3", "description": "Unblock internal user", @@ -35,8 +35,7 @@ "description": "name_internal_name_security_rule_for_users", "type": "string", "multi": false, - "required": false, - "defaultValue": "TheHive Block user internal communication" + "required": false }, { "name": "thehive_instance", diff --git a/responders/PaloAltoNGFW/README.md b/responders/PaloAltoNGFW/README.md index 01b144326..fcff774fd 100644 --- a/responders/PaloAltoNGFW/README.md +++ b/responders/PaloAltoNGFW/README.md @@ -5,10 +5,10 @@ # Installation need install: -1. cortexutils -2. requests -3. pan-os-python -4. thehive4py +1. pip install cortexutils +2. pip install requests +3. pip install pan-os-python +4. pip install thehive4py # ToDo Для работы responders, необходимо загрузить папку PaloAltoNGFW в директорию, где храняться другие responder. Далее перейти в загруженную папку и сделать запускаемыми скрипты на языке python командой "chmod +x *.py" @@ -16,7 +16,7 @@ need install: Далее необходимо: Выполнить перезагрузку системы cortex; -После перезагрузки в веб консоли cortex перейти на вкладку "Organization", выбрать организацию для которой будет выполнена настройка и перейти на вкладку "Responders", выбрать интерисующий Вас responder и настроить поля в соответсвии с их значениями: +После перезагрузки в веб консоли cortex перейти на вкладку "Organization", выбрать организацию для которой будет выполнена настройка и перейти на вкладку "Responders Config" и выполняем настройку полей в соответсвии с их значениями: ![alt text](Responders.jpg) 1. Hostname_PaloAltoNGFW - сетевой адрес системы PaloAltoNGFW 2. User_PaloAltoNGFW - пользователь в системе PaloAltoNGFW @@ -38,7 +38,8 @@ need install: 4.4.1 "TheHive Block internal port" 4.4.2 "TheHive Block external port" -4.5 thehive_instance - url адрес системы TheHive (используется только для типов case и alert) +4.5 thehive_instance - url адрес системы TheHive (используется только для типов case и alert). +Важно для каждой организации должен быть свой пользователь с API! 4.6 thehive_api_key - API ключ для подключения к системе TheHive Примечание: указанные правила безопасноти должны быть созданы в PaloAltoNGFW, а так же расставлены в порядке их применения. @@ -46,6 +47,7 @@ need install: 1. Сетевой адрес - 'ip' 2. FQDN - 'hostname' 3. порт - 'port' -4. имя пользователя - 'user-agent' -Примечание: данный тип необходимо создать в системе TheHive. По умолчанию TheHive не имеет типа данных "user-agent" в Observable type, поэтому мы должны добавить его в настройках администратора. +4. протокол - 'protocol' +5. имя пользователя - 'user-agent' +Примечание: типы 'port' и 'protocol' необходимо создать в системе TheHive. По умолчанию TheHive не имеет данных типов данных в Observable type, поэтому мы должны добавить его в настройках администратора. ![alt text](AddObservableType.jpg) \ No newline at end of file diff --git a/responders/PaloAltoNGFW/requirements.txt b/responders/PaloAltoNGFW/requirements.txt index 2dbd1aeb3..a827e6c55 100644 --- a/responders/PaloAltoNGFW/requirements.txt +++ b/responders/PaloAltoNGFW/requirements.txt @@ -1,4 +1,4 @@ cortexutils requests -panos +pan-os-python thehive4py \ No newline at end of file From 26871476211edadec2fa2095828bffb5a91396d5 Mon Sep 17 00:00:00 2001 From: Konakin Maksim <60079363@leroymerlin.ru> Date: Tue, 16 Mar 2021 19:26:53 +0300 Subject: [PATCH 19/25] add new version responders --- .../PaloAltoNGFW/Block_external_domain.py | 5 +- responders/PaloAltoNGFW/Block_external_ip.py | 5 +- .../PaloAltoNGFW/Block_external_port.py | 5 +- .../PaloAltoNGFW/Block_external_user.py | 9 +-- .../PaloAltoNGFW/Block_internal_domain.py | 5 +- responders/PaloAltoNGFW/Block_internal_ip.py | 5 +- .../PaloAltoNGFW/Block_internal_port.py | 5 +- .../PaloAltoNGFW/Block_internal_user.py | 9 +-- ...aloAltoNGFW_block_external_IP_address.json | 17 +++--- .../PaloAltoNGFW_block_external_domain.json | 19 ++++--- .../PaloAltoNGFW_block_external_user.json | 19 ++++--- ...aloAltoNGFW_block_internal_IP_address.json | 19 ++++--- .../PaloAltoNGFW_block_internal_domain.json | 19 ++++--- .../PaloAltoNGFW_block_internal_user.json | 19 ++++--- ...block_port_for_external_communication.json | 56 +++++++++++++++++++ ...block_port_for_internal_communication.json | 56 +++++++++++++++++++ ...oAltoNGFW_unblock_external_IP_address.json | 19 ++++--- .../PaloAltoNGFW_unblock_external_domain.json | 19 ++++--- .../PaloAltoNGFW_unblock_external_port.json | 19 ++++--- .../PaloAltoNGFW_unblock_external_user.json | 19 ++++--- ...oAltoNGFW_unblock_internal_IP_address.json | 19 ++++--- .../PaloAltoNGFW_unblock_internal_domain.json | 19 ++++--- .../PaloAltoNGFW_unblock_internal_port.json | 19 ++++--- .../PaloAltoNGFW_unblock_internal_user.json | 21 +++---- responders/PaloAltoNGFW/README.md | 6 +- .../PaloAltoNGFW/Unblock_external_domain.py | 5 +- .../PaloAltoNGFW/Unblock_external_ip.py | 6 +- .../PaloAltoNGFW/Unblock_external_port.py | 5 +- .../PaloAltoNGFW/Unblock_external_user.py | 3 +- .../PaloAltoNGFW/Unblock_internal_domain.py | 5 +- .../PaloAltoNGFW/Unblock_internal_ip.py | 5 +- .../PaloAltoNGFW/Unblock_internal_port.py | 5 +- .../PaloAltoNGFW/Unblock_internal_user.py | 5 +- 33 files changed, 306 insertions(+), 165 deletions(-) create mode 100644 responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_external_communication.json create mode 100644 responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_internal_communication.json diff --git a/responders/PaloAltoNGFW/Block_external_domain.py b/responders/PaloAltoNGFW/Block_external_domain.py index 28ccfc1ab..522e9c590 100644 --- a/responders/PaloAltoNGFW/Block_external_domain.py +++ b/responders/PaloAltoNGFW/Block_external_domain.py @@ -14,7 +14,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block external Domain') + self.name_security_rule = self.get_param('config.Security_rule_for_block_external_domain','TheHive Block external Domain') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -90,7 +90,8 @@ def run(self): new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() - self.report({'message': 'Responder comlited, aded %s into TheHive Black list external domain from %s' % (ioc,self.name_security_rule)}) + fw.commit() + self.report({'message': 'Responder successfully added %s into TheHive Black list external domain from %s' % (ioc,self.name_security_rule)}) if __name__ == '__main__': Block_domain().run() diff --git a/responders/PaloAltoNGFW/Block_external_ip.py b/responders/PaloAltoNGFW/Block_external_ip.py index 8548a149c..1e5e92e43 100644 --- a/responders/PaloAltoNGFW/Block_external_ip.py +++ b/responders/PaloAltoNGFW/Block_external_ip.py @@ -14,7 +14,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block external IP address') + self.name_security_rule = self.get_param('config.Security_rule_for_block_external_IP_address','TheHive Block external IP address') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -92,6 +92,7 @@ def run(self): new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() - self.report({'message': 'Responder comlited, added %s into TheHive Black list external IP from %s' % (ioc,self.name_security_rule)}) + fw.commit() + self.report({'message': 'Responder successfully added %s into TheHive Black list external IP from %s' % (ioc,self.name_security_rule)}) if __name__ == '__main__': Block_ip().run() diff --git a/responders/PaloAltoNGFW/Block_external_port.py b/responders/PaloAltoNGFW/Block_external_port.py index 7ad5f4e17..32a1d3599 100644 --- a/responders/PaloAltoNGFW/Block_external_port.py +++ b/responders/PaloAltoNGFW/Block_external_port.py @@ -15,7 +15,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block external port') + self.name_security_rule = self.get_param('config.Security_rule_for_block_port_external_communication','TheHive Block port for external communication') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -94,7 +94,8 @@ def run(self): new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() - self.report({'message': 'Responder comlited, added %s into TheHive Black list external port to %s' % (port,self.name_security_rule)}) + fw.commit() + self.report({'message': 'Responder successfully added %s into TheHive Black list external port to %s' % (port,self.name_security_rule)}) if __name__ == '__main__': Block_port().run() diff --git a/responders/PaloAltoNGFW/Block_external_user.py b/responders/PaloAltoNGFW/Block_external_user.py index 23f204cdc..0646f161f 100644 --- a/responders/PaloAltoNGFW/Block_external_user.py +++ b/responders/PaloAltoNGFW/Block_external_user.py @@ -13,7 +13,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block user external communication') + self.name_security_rule = self.get_param('config.Security_rule_for_block_external_user','TheHive Block user external communication') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -28,7 +28,7 @@ def run(self): user=None user_list_alert=[] for i in list(response.json().get("artifacts")): - if 'user-agent' in str(i): + if 'username' in str(i): ioc = i.get("data") for i in ioc: if i == "[" or i == "]": @@ -51,7 +51,7 @@ def run(self): a=None data = r.json() for n in data: - if n.get('dataType') == 'user-agent': + if n.get('dataType') == 'username': user=n.get('data') fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) rulebase = panos.policies.Rulebase() @@ -74,7 +74,8 @@ def run(self): new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() - self.report({'message': 'Responder comlited, added %s to %s' % (user,self.name_security_rule)}) + fw.commit() + self.report({'message': 'Responder successfully added %s to %s' % (user,self.name_security_rule)}) if __name__ == '__main__': Block_user().run() diff --git a/responders/PaloAltoNGFW/Block_internal_domain.py b/responders/PaloAltoNGFW/Block_internal_domain.py index 8b54e8964..583d160f2 100644 --- a/responders/PaloAltoNGFW/Block_internal_domain.py +++ b/responders/PaloAltoNGFW/Block_internal_domain.py @@ -14,7 +14,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block internal Domain') + self.name_security_rule = self.get_param('config.Security_rule_for_block_internal_domain','TheHive Block internal Domain') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -90,7 +90,8 @@ def run(self): new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() - self.report({'message': 'Responder comlited, added %s into TheHive Black list internal domain from %s' % (ioc,self.name_security_rule)}) + fw.commit() + self.report({'message': 'Responder successfully added %s into TheHive Black list internal domain from %s' % (ioc,self.name_security_rule)}) if __name__ == '__main__': Block_domain().run() diff --git a/responders/PaloAltoNGFW/Block_internal_ip.py b/responders/PaloAltoNGFW/Block_internal_ip.py index 2f09cb8b7..55b3417df 100644 --- a/responders/PaloAltoNGFW/Block_internal_ip.py +++ b/responders/PaloAltoNGFW/Block_internal_ip.py @@ -14,7 +14,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block internal IP address') + self.name_security_rule = self.get_param('config.Security_rule_for_block_internal_IP_address','TheHive Block internal IP address') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -92,6 +92,7 @@ def run(self): new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() - self.report({'message': 'Responder comlited, added %s into TheHive Black list internal IP from %s' % (ioc,self.name_security_rule)}) + fw.commit() + self.report({'message': 'Responder successfully added %s into TheHive Black list internal IP from %s' % (ioc,self.name_security_rule)}) if __name__ == '__main__': Block_ip().run() diff --git a/responders/PaloAltoNGFW/Block_internal_port.py b/responders/PaloAltoNGFW/Block_internal_port.py index 63a4cf65d..8b8200918 100644 --- a/responders/PaloAltoNGFW/Block_internal_port.py +++ b/responders/PaloAltoNGFW/Block_internal_port.py @@ -15,7 +15,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block internal port') + self.name_security_rule = self.get_param('config.Security_rule_for_blocking_port_internal_communication','TheHive Block port for internal communication') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -96,7 +96,8 @@ def run(self): new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() - self.report({'message': 'Responder comlited, added %s into TheHive Black list internal port from %s' % (port,self.name_security_rule)}) + fw.commit() + self.report({'message': 'Responder successfully added %s into TheHive Black list internal port from %s' % (port,self.name_security_rule)}) if __name__ == '__main__': Block_port().run() diff --git a/responders/PaloAltoNGFW/Block_internal_user.py b/responders/PaloAltoNGFW/Block_internal_user.py index 7ed5f4432..565d5f47e 100644 --- a/responders/PaloAltoNGFW/Block_internal_user.py +++ b/responders/PaloAltoNGFW/Block_internal_user.py @@ -13,7 +13,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block user internal communication') + self.name_security_rule = self.get_param('config.Security_rule_for_block_internal_user','TheHive Block user internal communication') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -28,7 +28,7 @@ def run(self): user=None user_list_alert=[] for i in list(response.json().get("artifacts")): - if 'user' in str(i): + if 'username' in str(i): ioc = i.get("data") for i in ioc: if i == "[" or i == "]": @@ -51,7 +51,7 @@ def run(self): a=None data = r.json() for n in data: - if n.get('dataType') == 'user-agent': + if n.get('dataType') == 'username': user=n.get('data') fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) rulebase = panos.policies.Rulebase() @@ -74,7 +74,8 @@ def run(self): new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() - self.report({'message': 'Responder comlited, added %s to %s' % (user,self.name_security_rule)}) + fw.commit() + self.report({'message': 'Responder successfully added %s to %s' % (user,self.name_security_rule)}) if __name__ == '__main__': Block_user().run() diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json index 951fdde5a..98a073823 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json @@ -11,41 +11,42 @@ "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", + "description": "Hostname PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { - "name": "name_security_rule", - "description": "name_external_name_security_rule_for_ip", + "name": "Security_rule_for_block_external_IP_address", + "description": "Name external name security rule for ip", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Block external IP address" }, { - "name": "thehive_instance", + "name": "Thehive_instance", "description": "URL of the Thehive instance to query", "type": "string", "multi": false, "required": true }, { - "name": "thehive_api_key", + "name": "Thehive_API_key", "description": "TheHive API key with read access", "type": "string", "multi": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json index b7db75e06..28a6965bf 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json @@ -11,41 +11,42 @@ "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", + "description": "Hostname PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { - "name": "name_security_rule", - "description": "name_internal_security_rule_for_domain", + "name": "Security_rule_for_block_external_domain", + "description": "Name internal security rule for domain", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Block external Domain" }, { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", + "name": "TheHive_instance", + "description": "URL of the TheHive instance to query", "type": "string", "multi": false, "required": true }, { - "name": "thehive_api_key", + "name": "TheHive_API_key", "description": "TheHive API key with read access", "type": "string", "multi": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json index 318382aa7..9b3731ef8 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json @@ -11,41 +11,42 @@ "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", + "description": "Hostname PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { - "name": "name_security_rule", - "description": "name_external_name_security_rule_for_users", + "name": "Security_rule_for_block_external_user", + "description": "Name external name security rule for users", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Block user external communication" }, { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", + "name": "TheHive_instance", + "description": "URL of the TheHive instance to query", "type": "string", "multi": false, "required": true }, { - "name": "thehive_api_key", + "name": "TheHive_API_key", "description": "TheHive API key with read access", "type": "string", "multi": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json index 2cc0622ba..1a4c6fc42 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json @@ -11,41 +11,42 @@ "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", + "description": "Hostname PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { - "name": "name_security_rule", - "description": "name_internal_name_security_rule_for_ip", + "name": "Security_rule_for_block_internal_IP_address", + "description": "Name internal name security rule for ip", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Block internal IP address" }, { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", + "name": "TheHive_instance", + "description": "URL of the TheHive instance to query", "type": "string", "multi": false, "required": true }, { - "name": "thehive_api_key", + "name": "TheHive_API_key", "description": "TheHive API key with read access", "type": "string", "multi": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json index e519e65ea..d0bc43622 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json @@ -11,41 +11,42 @@ "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", + "description": "Hostname PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { - "name": "name_security_rule", - "description": "name_internal_security_rule_for_domain", + "name": "Security_rule_for_block_internal_domain", + "description": "Name internal security rule for domain", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Block internal Domain" }, { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", + "name": "TheHive_instance", + "description": "URL of the TheHive instance to query", "type": "string", "multi": false, "required": true }, { - "name": "thehive_api_key", + "name": "TheHive_API_key", "description": "TheHive API key with read access", "type": "string", "multi": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json index d760ac968..a7fe1976e 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json @@ -11,41 +11,42 @@ "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", + "description": "Hostname PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { - "name": "name_security_rule", - "description": "name_internal_name_security_rule_for_users", + "name": "Security_rule_for_block_internal_user", + "description": "Name internal name security rule for users", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Block user internal communication" }, { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", + "name": "TheHive_instance", + "description": "URL of the TheHive instance to query", "type": "string", "multi": false, "required": true }, { - "name": "thehive_api_key", + "name": "TheHive_API_key", "description": "TheHive API key with read access", "type": "string", "multi": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_external_communication.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_external_communication.json new file mode 100644 index 000000000..2e0ad0a89 --- /dev/null +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_external_communication.json @@ -0,0 +1,56 @@ +{ + "name": "PaloAltoNGFW_block_port_for_external_communication", + "version": "2.0.0", + "author": "Maxim Konakin, OSCD Community", + "url": "", + "license": "AGPL-V3", + "description": "Block external port", + "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], + "command": "PaloAltoNGFW/Block_external_port.py", + "baseConfig": "PaloAltoNGFW_main", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Security_rule_for_block_port_external_communication", + "description": "Name external name security rule for port", + "type": "string", + "multi": false, + "required": false, + "defaultValue":"TheHive Block port for external communication" + }, + { + "name": "TheHive_instance", + "description": "URL of the TheHive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "TheHive_API_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_internal_communication.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_internal_communication.json new file mode 100644 index 000000000..9ef1d4af6 --- /dev/null +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_internal_communication.json @@ -0,0 +1,56 @@ +{ + "name": "PaloAltoNGFW_block_port_for_internal_communication" + "version": "2.0.0", + "author": "Maxim Konakin, OSCD Community", + "url": "", + "license": "AGPL-V3", + "description": "Block internal port", + "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], + "command": "PaloAltoNGFW/Block_internal_port.py", + "baseConfig": "PaloAltoNGFW_main", + "configurationItems": [ + { + "name": "Hostname_PaloAltoNGFW", + "description": "Hostname PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Password_PaloAltoNGFW", + "description": "User PaloAltoNGFW", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "Security_rule_for_blocking_port_internal_communication", + "description": "Name internal name security rule for port", + "type": "string", + "multi": false, + "required": false, + "defaultValue": "TheHive Block port for internal communication" + }, + { + "name": "TheHive_instance", + "description": "URL of the TheHive instance to query", + "type": "string", + "multi": false, + "required": true + }, + { + "name": "TheHive_API_key", + "description": "TheHive API key with read access", + "type": "string", + "multi": false, + "required": true + } + ] +} diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json index 7c2b892b9..248542c25 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json @@ -11,41 +11,42 @@ "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", + "description": "Hostname PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { - "name": "name_external_Address_Group", - "description": "name_external_Address_Group", + "name": "Address_group_for_unblock_external_IP_address", + "description": "Name external Address Group", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Black list external IP" }, { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", + "name": "TheHive_instance", + "description": "URL of the TheHive instance to query", "type": "string", "multi": false, "required": true }, { - "name": "thehive_api_key", + "name": "TheHive_API_key", "description": "TheHive API key with read access", "type": "string", "multi": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json index 73f445c76..ff2111bc7 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json @@ -11,41 +11,42 @@ "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", + "description": "Hostname PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { - "name": "name_external_Address_Group", - "description": "name_external_Address_Group_for_domain", + "name": "Address_group_for_unblock_external_domain", + "description": "Name external Address Group for domain", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Black list external domain" }, { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", + "name": "TheHive_instance", + "description": "URL of the TheHive instance to query", "type": "string", "multi": false, "required": true }, { - "name": "thehive_api_key", + "name": "TheHive_API_key", "description": "TheHive API key with read access", "type": "string", "multi": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json index 08dde582a..72337c197 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json @@ -11,41 +11,42 @@ "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", + "description": "Hostname PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { - "name": "name_external_Service_Group", - "description": "name_external_Service_Group", + "name": "Service_group_for_unblock_external_port", + "description": "Name external Service Group", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Black list external port" }, { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", + "name": "TheHive_instance", + "description": "URL of the TheHive instance to query", "type": "string", "multi": false, "required": true }, { - "name": "thehive_api_key", + "name": "TheHive_API_key", "description": "TheHive API key with read access", "type": "string", "multi": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json index c8872767a..11f8c3f34 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json @@ -11,41 +11,42 @@ "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", + "description": "Hostname PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { - "name": "name_security_rule", - "description": "name_external_name_security_rule_for_users", + "name": "Security_rule_for_unblock_external_user", + "description": "Name external name security rule for users", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Block user external communication" }, { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", + "name": "TheHive_instance", + "description": "URL of the TheHive instance to query", "type": "string", "multi": false, "required": true }, { - "name": "thehive_api_key", + "name": "TheHive_API_key", "description": "TheHive API key with read access", "type": "string", "multi": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json index 5b39822da..9d7c8cdde 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json @@ -11,41 +11,42 @@ "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", + "description": "Hostname PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { - "name": "name_internal_Address_Group", - "description": "name_internal_Address_Group", + "name": "Address_group_for_unblock_internal_IP_address", + "description": "Name internal Address Group", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Black list internal IP" }, { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", + "name": "Thehive_instance", + "description": "URL of the TheHive instance to query", "type": "string", "multi": false, "required": true }, { - "name": "thehive_api_key", + "name": "TheHive_API_key", "description": "TheHive API key with read access", "type": "string", "multi": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json index 0f01adc9e..f21e0cc1d 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json @@ -11,41 +11,42 @@ "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", + "description": "Hostname PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { - "name": "name_internal_Address_Group", - "description": "name_internal_Address_Group_for_domain", + "name": "Address_group_for_unblock_internal_domain", + "description": "Name internal Address Group for domain", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Black list internal domain" }, { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", + "name": "TheHive_instance", + "description": "URL of the TheHive instance to query", "type": "string", "multi": false, "required": true }, { - "name": "thehive_api_key", + "name": "TheHive_API_key", "description": "TheHive API key with read access", "type": "string", "multi": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json index bcd68e95a..cbec45ef5 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json @@ -11,41 +11,42 @@ "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", + "description": "Hostname PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { - "name": "name_internal_Service_Group", - "description": "name_internal_Service_Group", + "name": "Internal_service_group_for_unblock_internal_port", + "description": "Name internal Service Group", "type": "string", "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Black list internal port" }, { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", + "name": "TheHive_instance", + "description": "URL of the TheHive instance to query", "type": "string", "multi": false, "required": true }, { - "name": "thehive_api_key", + "name": "TheHive_API_key", "description": "TheHive API key with read access", "type": "string", "multi": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json index 245fb2269..c5e30f0f9 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json @@ -11,41 +11,42 @@ "configurationItems": [ { "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", + "description": "Hostname PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", + "description": "User PaloAltoNGFW", "type": "string", "multi": false, "required": true }, { - "name": "name_security_rule", - "description": "name_internal_name_security_rule_for_users", - "type": "string", + "name": "Security_rule_for_unblock_internal_user", + "description": "Internal name security rule for users", + "type": "string" "multi": false, - "required": false + "required": false, + "defaultValue": "TheHive Block user internal communication" }, { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", + "name": "TheHive_instance", + "description": "URL of the TheHive instance to query", "type": "string", "multi": false, "required": true }, { - "name": "thehive_api_key", + "name": "TheHive_API_key", "description": "TheHive API key with read access", "type": "string", "multi": false, diff --git a/responders/PaloAltoNGFW/README.md b/responders/PaloAltoNGFW/README.md index fcff774fd..d485c1cb5 100644 --- a/responders/PaloAltoNGFW/README.md +++ b/responders/PaloAltoNGFW/README.md @@ -35,8 +35,8 @@ need install: 4.3.2 "TheHive Block internal Domain" 4.4 Для блокировки\разблокировки портов: -4.4.1 "TheHive Block internal port" -4.4.2 "TheHive Block external port" +4.4.1 "TheHive Block port for internal communication" +4.4.2 "TheHive Block port for external communication" 4.5 thehive_instance - url адрес системы TheHive (используется только для типов case и alert). Важно для каждой организации должен быть свой пользователь с API! @@ -48,6 +48,6 @@ need install: 2. FQDN - 'hostname' 3. порт - 'port' 4. протокол - 'protocol' -5. имя пользователя - 'user-agent' +5. имя пользователя - 'username' Примечание: типы 'port' и 'protocol' необходимо создать в системе TheHive. По умолчанию TheHive не имеет данных типов данных в Observable type, поэтому мы должны добавить его в настройках администратора. ![alt text](AddObservableType.jpg) \ No newline at end of file diff --git a/responders/PaloAltoNGFW/Unblock_external_domain.py b/responders/PaloAltoNGFW/Unblock_external_domain.py index 5d18bd20b..6865a9a8e 100644 --- a/responders/PaloAltoNGFW/Unblock_external_domain.py +++ b/responders/PaloAltoNGFW/Unblock_external_domain.py @@ -14,7 +14,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_external_Address_Group_for_domain = self.get_param('config.name_external_Address_Group',"TheHive Black list external domain") + self.name_external_Address_Group_for_domain = self.get_param('config.Address_group_for_unblock_external_domain',"TheHive Black list external domain") self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -73,7 +73,8 @@ def run(self): except: self.report({'message': 'Responder did not comlite. Warning in AddressObject'}) - self.report({'message': 'Responder comlited, deleted %s from %s' % (ioc,self.name_external_Address_Group_for_domain)}) + self.report({'message': 'Responder successfully deleted %s from %s' % (ioc,self.name_external_Address_Group_for_domain)}) + fw.commit() if __name__ == '__main__': Unblock_domain().run() diff --git a/responders/PaloAltoNGFW/Unblock_external_ip.py b/responders/PaloAltoNGFW/Unblock_external_ip.py index 9f64bf178..363666373 100644 --- a/responders/PaloAltoNGFW/Unblock_external_ip.py +++ b/responders/PaloAltoNGFW/Unblock_external_ip.py @@ -13,7 +13,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_external_Address_Group = self.get_param('config.name_external_Address_Group',"TheHive Black list external IP") + self.name_external_Address_Group = self.get_param('config.Address_group_for_unblock_external_IP_address',"TheHive Black list external IP") self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -71,7 +71,7 @@ def run(self): except: self.report({'message': 'Responder did not comlite. Warning in AddressObject'}) - self.report({'message': 'Responder comlited, deleted %s from %s' % (ioc,self.name_external_Address_Group)}) - + self.report({'message': 'Responder successfully deleted %s from %s' % (ioc,self.name_external_Address_Group)}) + fw.commit() if __name__ == '__main__': Unblock_ip().run() diff --git a/responders/PaloAltoNGFW/Unblock_external_port.py b/responders/PaloAltoNGFW/Unblock_external_port.py index 01869591f..f7150d37f 100644 --- a/responders/PaloAltoNGFW/Unblock_external_port.py +++ b/responders/PaloAltoNGFW/Unblock_external_port.py @@ -14,7 +14,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_external_Service_Group = self.get_param('config.name_external_Service_Group','TheHive Black list external port') + self.name_external_Service_Group = self.get_param('config.Service_group_for_unblock_external_port','TheHive Black list external port') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -65,7 +65,8 @@ def run(self): panos.objects.ServiceObject.refreshall(fw) - self.report({'message': 'Responder comlited, deleted %s from %s' % (port,self.name_external_Service_Group)}) + self.report({'message': 'Responder successfully deleted %s from %s' % (port,self.name_external_Service_Group)}) + fw.commit() if __name__ == '__main__': Unblock_port().run() diff --git a/responders/PaloAltoNGFW/Unblock_external_user.py b/responders/PaloAltoNGFW/Unblock_external_user.py index 67308dd86..5d4186d71 100644 --- a/responders/PaloAltoNGFW/Unblock_external_user.py +++ b/responders/PaloAltoNGFW/Unblock_external_user.py @@ -70,7 +70,8 @@ def run(self): new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() - self.report({'message': 'Responder comlited, deleted %s from %s' % (user,self.name_security_rule)}) + self.report({'message': 'Responder successfully deleted %s from %s' % (user,self.name_security_rule)}) + fw.commit() if __name__ == '__main__': Unblock_user().run() diff --git a/responders/PaloAltoNGFW/Unblock_internal_domain.py b/responders/PaloAltoNGFW/Unblock_internal_domain.py index 691d5aeb6..fa21eb172 100644 --- a/responders/PaloAltoNGFW/Unblock_internal_domain.py +++ b/responders/PaloAltoNGFW/Unblock_internal_domain.py @@ -14,7 +14,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Address_Group_for_domain = self.get_param('config.name_external_Address_Group',"TheHive Black list internal domain") + self.name_internal_Address_Group_for_domain = self.get_param('config.Address_group_for_unblock_internal_domain',"TheHive Black list internal domain") self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -73,7 +73,8 @@ def run(self): except: self.report({'message': 'Responder did not comlite. Warning in AddressObject'}) - self.report({'message': 'Responder comlited, deleted %s from %s' % (ioc,self.name_internal_Address_Group_for_domain)}) + self.report({'message': 'Responder successfully deleted %s from %s' % (ioc,self.name_internal_Address_Group_for_domain)}) + fw.commit() if __name__ == '__main__': Unblock_domain().run() diff --git a/responders/PaloAltoNGFW/Unblock_internal_ip.py b/responders/PaloAltoNGFW/Unblock_internal_ip.py index ce571eedd..8e7156fb8 100644 --- a/responders/PaloAltoNGFW/Unblock_internal_ip.py +++ b/responders/PaloAltoNGFW/Unblock_internal_ip.py @@ -13,7 +13,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Address_Group = self.get_param('config.name_internal_Address_Group',"TheHive Black list internal IP") + self.name_internal_Address_Group = self.get_param('config.Address_group_for_unblock_internal_IP_address',"TheHive Black list internal IP") self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -71,7 +71,8 @@ def run(self): except: self.report({'message': 'Responder did not comlite. Warning in AddressObject'}) - self.report({'message': 'Responder comlited, deleted %s from %s' % (ioc,self.name_internal_Address_Group)}) + self.report({'message': 'Responder successfully deleted %s from %s' % (ioc,self.name_internal_Address_Group)}) + fw.commit() if __name__ == '__main__': Unblock_ip().run() diff --git a/responders/PaloAltoNGFW/Unblock_internal_port.py b/responders/PaloAltoNGFW/Unblock_internal_port.py index ba6d39746..465ec445a 100644 --- a/responders/PaloAltoNGFW/Unblock_internal_port.py +++ b/responders/PaloAltoNGFW/Unblock_internal_port.py @@ -14,7 +14,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Service_Group = self.get_param('config.name_internal_Service_Group','TheHive Black list internal port') + self.name_internal_Service_Group = self.get_param('config.Internal_service_group_for_unblock_internal_port','TheHive Black list internal port') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -65,7 +65,8 @@ def run(self): panos.objects.ServiceObject.refreshall(fw) - self.report({'message': 'Responder comlited, deleted %s from %s' % (port,self.name_internal_Service_Group)}) + self.report({'message': 'Responder successfully deleted %s from %s' % (port,self.name_internal_Service_Group)}) + fw.commit() if __name__ == '__main__': Unblock_port().run() diff --git a/responders/PaloAltoNGFW/Unblock_internal_user.py b/responders/PaloAltoNGFW/Unblock_internal_user.py index 9fbcad7b4..2433e8eb9 100644 --- a/responders/PaloAltoNGFW/Unblock_internal_user.py +++ b/responders/PaloAltoNGFW/Unblock_internal_user.py @@ -13,7 +13,7 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block user internal communication') + self.name_security_rule = self.get_param('config.Security_rule_for_unblock_internal_user','TheHive Block user internal communication') self.thehive_instance = self.get_param('config.thehive_instance') self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) @@ -70,7 +70,8 @@ def run(self): new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() - self.report({'message': 'Responder comlited, deleted %s from %s' % (user,self.name_security_rule)}) + self.report({'message': 'Responder successfully deleted %s from %s' % (user,self.name_security_rule)}) + fw.commit() if __name__ == '__main__': Unblock_user().run() From 5035ffa2402afdb89ddc143d9c0ae9f943326332 Mon Sep 17 00:00:00 2001 From: Konakin Maksim <60079363@leroymerlin.ru> Date: Tue, 6 Apr 2021 22:54:36 +0300 Subject: [PATCH 20/25] New version responders 1. Fix mistake with general config 2. Fix errors python code --- responders/PaloAltoNGFW/AddObservableType.jpg | Bin 90710 -> 38811 bytes .../PaloAltoNGFW/Block_external_domain.py | 24 ++++---- responders/PaloAltoNGFW/Block_external_ip.py | 22 +++---- .../PaloAltoNGFW/Block_external_port.py | 52 ++++++++++------- .../PaloAltoNGFW/Block_external_user.py | 12 ++-- .../PaloAltoNGFW/Block_internal_domain.py | 24 ++++---- responders/PaloAltoNGFW/Block_internal_ip.py | 22 +++---- .../PaloAltoNGFW/Block_internal_port.py | 54 +++++++++-------- .../PaloAltoNGFW/Block_internal_user.py | 12 ++-- ...aloAltoNGFW_block_external_IP_address.json | 12 ++-- .../PaloAltoNGFW_block_external_domain.json | 6 +- .../PaloAltoNGFW_block_external_port.json | 55 ------------------ .../PaloAltoNGFW_block_external_user.json | 8 +-- ...aloAltoNGFW_block_internal_IP_address.json | 6 +- .../PaloAltoNGFW_block_internal_domain.json | 6 +- .../PaloAltoNGFW_block_internal_port.json | 55 ------------------ .../PaloAltoNGFW_block_internal_user.json | 8 +-- ...block_port_for_external_communication.json | 8 +-- ...block_port_for_internal_communication.json | 12 ++-- ...oAltoNGFW_unblock_external_IP_address.json | 12 ++-- .../PaloAltoNGFW_unblock_external_domain.json | 10 ++-- .../PaloAltoNGFW_unblock_external_user.json | 10 ++-- ...oAltoNGFW_unblock_internal_IP_address.json | 14 ++--- .../PaloAltoNGFW_unblock_internal_domain.json | 10 ++-- .../PaloAltoNGFW_unblock_internal_user.json | 12 ++-- ...lock_port_for_external_communication.json} | 14 ++--- ...lock_port_for_internal_communication.json} | 14 ++--- responders/PaloAltoNGFW/README.md | 15 +++-- .../PaloAltoNGFW/Unblock_external_domain.py | 12 ++-- .../PaloAltoNGFW/Unblock_external_ip.py | 12 ++-- .../PaloAltoNGFW/Unblock_external_port.py | 38 +++++++----- .../PaloAltoNGFW/Unblock_external_user.py | 16 ++--- .../PaloAltoNGFW/Unblock_internal_domain.py | 12 ++-- .../PaloAltoNGFW/Unblock_internal_ip.py | 12 ++-- .../PaloAltoNGFW/Unblock_internal_port.py | 38 +++++++----- .../PaloAltoNGFW/Unblock_internal_user.py | 16 ++--- 36 files changed, 294 insertions(+), 371 deletions(-) delete mode 100644 responders/PaloAltoNGFW/PaloAltoNGFW_block_external_port.json delete mode 100644 responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_port.json rename responders/PaloAltoNGFW/{PaloAltoNGFW_unblock_internal_port.json => PaloAltoNGFW_unblock_port_for_external_communication.json} (72%) rename responders/PaloAltoNGFW/{PaloAltoNGFW_unblock_external_port.json => PaloAltoNGFW_unblock_port_for_internal_communication.json} (72%) diff --git a/responders/PaloAltoNGFW/AddObservableType.jpg b/responders/PaloAltoNGFW/AddObservableType.jpg index 2c2f10e2d6dc7a12714f01d0b74ab72d35b535b1..7a254db799bb539d0d960cbb335c625904e4ef9d 100644 GIT binary patch literal 38811 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 B1bP4f literal 90710 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 E4WTyZPXGV_ diff --git a/responders/PaloAltoNGFW/Block_external_domain.py b/responders/PaloAltoNGFW/Block_external_domain.py index 522e9c590..8e372d37c 100644 --- a/responders/PaloAltoNGFW/Block_external_domain.py +++ b/responders/PaloAltoNGFW/Block_external_domain.py @@ -15,9 +15,9 @@ def __init__(self): self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') self.name_security_rule = self.get_param('config.Security_rule_for_block_external_domain','TheHive Block external Domain') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + self.TheHive_instance = self.get_param('config.TheHive_instance') + self.TheHive_API_key = self.get_param('config.TheHive_API_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.TheHive_instance, self.TheHive_API_key) def run(self): self.instance_type = self.get_param('data._type') @@ -44,8 +44,8 @@ def run(self): "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, "range": "all" } - headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } - thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.TheHive_API_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.TheHive_instance) r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) if r.status_code != requests.codes.ok: self.error(json.dumps(r.text)) @@ -64,16 +64,16 @@ def run(self): fw.add(new_ioc_object) new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find("TheHive Black list external domain", panos.objects.AddressGroup) + block_list = fw.find("TheHive Block list external domain", panos.objects.AddressGroup) if block_list != None: ioc_list = block_list.about().get('static_value') if ioc not in ioc_list: ioc_list.append(ioc) - temp1 = panos.objects.AddressGroup("TheHive Black list external domain", static_value=ioc_list) + temp1 = panos.objects.AddressGroup("TheHive Block list external domain", static_value=ioc_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.AddressGroup("TheHive Black list external domain", static_value=ioc) + temp1 = panos.objects.AddressGroup("TheHive Block list external domain", static_value=ioc) fw.add(temp1) temp1.apply() desired_rule_params = None @@ -81,17 +81,19 @@ def run(self): if self.name_security_rule == i.about().get("name"): rule_atrib = i.about() temp_rule_atrib = rule_atrib.get("destination") - if "TheHive Black list external domain" not in temp_rule_atrib: - temp_rule_atrib.append("TheHive Black list external domain") + if "TheHive Block list external domain" not in temp_rule_atrib: + temp_rule_atrib.append("TheHive Block list external domain") if "any" in temp_rule_atrib: temp_rule_atrib.remove("any") rule_atrib.update({"destination": temp_rule_atrib}) desired_rule_params = rule_atrib + else: + desired_rule_params = rule_atrib new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() fw.commit() - self.report({'message': 'Responder successfully added %s into TheHive Black list external domain from %s' % (ioc,self.name_security_rule)}) + self.report({'message': 'Responder successfully added %s into TheHive Block list external domain from %s' % (ioc,self.name_security_rule)}) if __name__ == '__main__': Block_domain().run() diff --git a/responders/PaloAltoNGFW/Block_external_ip.py b/responders/PaloAltoNGFW/Block_external_ip.py index 1e5e92e43..4619c80ec 100644 --- a/responders/PaloAltoNGFW/Block_external_ip.py +++ b/responders/PaloAltoNGFW/Block_external_ip.py @@ -15,9 +15,9 @@ def __init__(self): self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') self.name_security_rule = self.get_param('config.Security_rule_for_block_external_IP_address','TheHive Block external IP address') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + self.TheHive_instance = self.get_param('config.TheHive_instance') + self.TheHive_API_key = self.get_param('config.TheHive_API_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.TheHive_instance, self.TheHive_API_key) def run(self): self.instance_type = self.get_param('data._type') @@ -44,8 +44,8 @@ def run(self): "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, "range": "all" } - headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } - thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.TheHive_API_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.TheHive_instance) r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) if r.status_code != requests.codes.ok: self.error(json.dumps(r.text)) @@ -64,16 +64,16 @@ def run(self): fw.add(new_ioc_object) new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find("TheHive Black list external IP", panos.objects.AddressGroup) + block_list = fw.find("TheHive Block list external IP address", panos.objects.AddressGroup) if block_list != None: ioc_list = block_list.about().get('static_value') if ioc not in ioc_list: ioc_list.append(ioc) - temp1 = panos.objects.AddressGroup("TheHive Black list external IP", static_value=ioc_list) + temp1 = panos.objects.AddressGroup("TheHive Block list external IP address", static_value=ioc_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.AddressGroup("TheHive Black list external IP", static_value=ioc) + temp1 = panos.objects.AddressGroup("TheHive Block list external IP address", static_value=ioc) fw.add(temp1) temp1.apply() desired_rule_params = None @@ -81,8 +81,8 @@ def run(self): if self.name_security_rule == i.about().get("name"): rule_atrib = i.about() temp_rule_atrib = rule_atrib.get("destination") - if "TheHive Black list external IP" not in temp_rule_atrib: - temp_rule_atrib.append("TheHive Black list external IP") + if "TheHive Block list external IP address" not in temp_rule_atrib: + temp_rule_atrib.append("TheHive Block list external IP address") if "any" in temp_rule_atrib: temp_rule_atrib.remove("any") rule_atrib.update({"destination": temp_rule_atrib}) @@ -93,6 +93,6 @@ def run(self): rulebase.add(new_rule) new_rule.apply() fw.commit() - self.report({'message': 'Responder successfully added %s into TheHive Black list external IP from %s' % (ioc,self.name_security_rule)}) + self.report({'message': 'Responder successfully added %s into TheHive Block list external IP address from %s' % (ioc,self.name_security_rule)}) if __name__ == '__main__': Block_ip().run() diff --git a/responders/PaloAltoNGFW/Block_external_port.py b/responders/PaloAltoNGFW/Block_external_port.py index 32a1d3599..a6dd6b571 100644 --- a/responders/PaloAltoNGFW/Block_external_port.py +++ b/responders/PaloAltoNGFW/Block_external_port.py @@ -16,27 +16,30 @@ def __init__(self): self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') self.name_security_rule = self.get_param('config.Security_rule_for_block_port_external_communication','TheHive Block port for external communication') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + self.TheHive_instance = self.get_param('config.TheHive_instance') + self.TheHive_API_key = self.get_param('config.TheHive_API_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.TheHive_instance, self.TheHive_API_key) def run(self): self.instance_type = self.get_param('data._type') if self.instance_type == 'case_artifact': - port = self.get_param('data.data') + data = self.get_param('data.data') + port=str(data).split('-')[0] + protocol=str(data).split('-')[1] + protocol=re.findall(r'[a-z]+',str(protocol)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(port)); port="".join(port) if self.instance_type == 'alert': alertId = self.get_param('data.id') response = self.api.get_alert(alertId) data_list=[] data=None for i in response.json().get("artifacts"): - if "'port'," in str(i): + if "'port-protocol'," in str(i): data_list.append(i.get("data")) - elif "'protocol'," in str(i): - data_list.append(i.get("data")) - data=" ".join(data_list) - protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() - port=re.findall(r'[0-9]+',str(data)); port="".join(port) + port=str(data_list).split('-')[0] + protocol=str(data_list).split('-')[1] + protocol=re.findall(r'[a-z]+',str(protocol)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(port)); port="".join(port) if self.instance_type == 'case': import requests case_id = self.get_param('data._id') @@ -44,18 +47,21 @@ def run(self): "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, "range": "all" } - headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } - thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.TheHive_API_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.TheHive_instance) r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) if r.status_code != requests.codes.ok: self.error(json.dumps(r.text)) a=None data = r.json() + data_list = [] for n in data: - if n.get('dataType') == 'port': - port=n.get('data') - if n.get('dataType') == 'protocol': - protocol=n.get('data') + if "'port-protocol'," in str(n): + data_list.append(n.get("data")) + port=str(data_list).split('-')[0] + protocol=str(data_list).split('-')[1] + protocol=re.findall(r'[a-z]+',str(protocol)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(port)); port="".join(port) fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) panos.objects.ServiceObject.refreshall(fw) rulebase = panos.policies.Rulebase() @@ -68,16 +74,16 @@ def run(self): panos.objects.ServiceGroup.refreshall(fw) - block_list = fw.find("TheHive Black list external port", panos.objects.ServiceGroup) + block_list = fw.find("TheHive Block list for external port communication", panos.objects.ServiceGroup) if block_list != None: port_list = block_list.about().get('value') if port not in port_list: port_list.append(port) - temp1 = panos.objects.ServiceGroup("TheHive Black list external port", value=port_list) + temp1 = panos.objects.ServiceGroup("TheHive Block list for external port communication", value=port_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.ServiceGroup("TheHive Black list external port", value=port) + temp1 = panos.objects.ServiceGroup("TheHive Block list for external port communication", value=port) fw.add(temp1) temp1.apply() desired_rule_params = None @@ -85,17 +91,19 @@ def run(self): if self.name_security_rule == str(i.about().get("name")): rule_atrib = i.about() temp_rule_atrib = rule_atrib.get("service") - if "TheHive Black list external port" not in temp_rule_atrib: - temp_rule_atrib.append("TheHive Black list external port") + if "TheHive Block list for external port communication" not in temp_rule_atrib: + temp_rule_atrib.append("TheHive Block list for external port communication") if "application-default" in temp_rule_atrib: temp_rule_atrib.remove("application-default") rule_atrib.update({"service": temp_rule_atrib}) desired_rule_params = rule_atrib + else: + desired_rule_params = rule_atrib new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() fw.commit() - self.report({'message': 'Responder successfully added %s into TheHive Black list external port to %s' % (port,self.name_security_rule)}) + self.report({'message': 'Responder successfully added %s into TheHive Block list for external port communication to %s' % (port,self.name_security_rule)}) if __name__ == '__main__': Block_port().run() diff --git a/responders/PaloAltoNGFW/Block_external_user.py b/responders/PaloAltoNGFW/Block_external_user.py index 0646f161f..d8d4e4b54 100644 --- a/responders/PaloAltoNGFW/Block_external_user.py +++ b/responders/PaloAltoNGFW/Block_external_user.py @@ -13,10 +13,10 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.Security_rule_for_block_external_user','TheHive Block user external communication') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + self.name_security_rule = self.get_param('config.Security_rule_for_block_external_user','TheHive Block external user') + self.TheHive_instance = self.get_param('config.TheHive_instance') + self.TheHive_API_key = self.get_param('config.TheHive_API_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.TheHive_instance, self.TheHive_API_key) def run(self): self.instance_type = self.get_param('data._type') @@ -43,8 +43,8 @@ def run(self): "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, "range": "all" } - headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } - thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.TheHive_API_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.TheHive_instance) r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) if r.status_code != requests.codes.ok: self.error(json.dumps(r.text)) diff --git a/responders/PaloAltoNGFW/Block_internal_domain.py b/responders/PaloAltoNGFW/Block_internal_domain.py index 583d160f2..671eef56e 100644 --- a/responders/PaloAltoNGFW/Block_internal_domain.py +++ b/responders/PaloAltoNGFW/Block_internal_domain.py @@ -15,9 +15,9 @@ def __init__(self): self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') self.name_security_rule = self.get_param('config.Security_rule_for_block_internal_domain','TheHive Block internal Domain') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + self.TheHive_instance = self.get_param('config.TheHive_instance') + self.TheHive_API_key = self.get_param('config.TheHive_API_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.TheHive_instance, self.TheHive_API_key) def run(self): self.instance_type = self.get_param('data._type') @@ -44,8 +44,8 @@ def run(self): "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, "range": "all" } - headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } - thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.TheHive_API_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.TheHive_instance) r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) if r.status_code != requests.codes.ok: self.error(json.dumps(r.text)) @@ -64,16 +64,16 @@ def run(self): fw.add(new_ioc_object) new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find("TheHive Black list internal domain", panos.objects.AddressGroup) + block_list = fw.find("TheHive Block list internal domain", panos.objects.AddressGroup) if block_list != None: ioc_list = block_list.about().get('static_value') if ioc not in ioc_list: ioc_list.append(ioc) - temp1 = panos.objects.AddressGroup("TheHive Black list internal domain", static_value=ioc_list) + temp1 = panos.objects.AddressGroup("TheHive Block list internal domain", static_value=ioc_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.AddressGroup("TheHive Black list internal domain", static_value=ioc) + temp1 = panos.objects.AddressGroup("TheHive Block list internal domain", static_value=ioc) fw.add(temp1) temp1.apply() desired_rule_params = None @@ -81,17 +81,19 @@ def run(self): if self.name_security_rule == i.about().get("name"): rule_atrib = i.about() temp_rule_atrib = rule_atrib.get("destination") - if "TheHive Black list internal domain" not in temp_rule_atrib: - temp_rule_atrib.append("TheHive Black list internal domain") + if "TheHive Block list internal domain" not in temp_rule_atrib: + temp_rule_atrib.append("TheHive Block list internal domain") if "any" in temp_rule_atrib: temp_rule_atrib.remove("any") rule_atrib.update({"destination": temp_rule_atrib}) desired_rule_params = rule_atrib + else: + desired_rule_params = rule_atrib new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() fw.commit() - self.report({'message': 'Responder successfully added %s into TheHive Black list internal domain from %s' % (ioc,self.name_security_rule)}) + self.report({'message': 'Responder successfully added %s into TheHive Block list internal domain from %s' % (ioc,self.name_security_rule)}) if __name__ == '__main__': Block_domain().run() diff --git a/responders/PaloAltoNGFW/Block_internal_ip.py b/responders/PaloAltoNGFW/Block_internal_ip.py index 55b3417df..0fefcc8f4 100644 --- a/responders/PaloAltoNGFW/Block_internal_ip.py +++ b/responders/PaloAltoNGFW/Block_internal_ip.py @@ -15,9 +15,9 @@ def __init__(self): self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') self.name_security_rule = self.get_param('config.Security_rule_for_block_internal_IP_address','TheHive Block internal IP address') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + self.TheHive_instance = self.get_param('config.TheHive_instance') + self.TheHive_API_key = self.get_param('config.TheHive_API_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.TheHive_instance, self.TheHive_API_key) def run(self): self.instance_type = self.get_param('data._type') @@ -44,8 +44,8 @@ def run(self): "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, "range": "all" } - headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } - thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.TheHive_API_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.TheHive_instance) r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) if r.status_code != requests.codes.ok: self.error(json.dumps(r.text)) @@ -64,16 +64,16 @@ def run(self): fw.add(new_ioc_object) new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) - block_list = fw.find("TheHive Black list internal IP", panos.objects.AddressGroup) + block_list = fw.find("TheHive Block list internal IP address", panos.objects.AddressGroup) if block_list != None: ioc_list = block_list.about().get('static_value') if ioc not in ioc_list: ioc_list.append(ioc) - temp1 = panos.objects.AddressGroup("TheHive Black list internal IP", static_value=ioc_list) + temp1 = panos.objects.AddressGroup("TheHive Block list internal IP address", static_value=ioc_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.AddressGroup("TheHive Black list internal IP", static_value=ioc) + temp1 = panos.objects.AddressGroup("TheHive Block list internal IP address", static_value=ioc) fw.add(temp1) temp1.apply() desired_rule_params = None @@ -81,8 +81,8 @@ def run(self): if self.name_security_rule == i.about().get("name"): rule_atrib = i.about() temp_rule_atrib = rule_atrib.get("destination") - if "TheHive Black list internal IP" not in temp_rule_atrib: - temp_rule_atrib.append("TheHive Black list internal IP") + if "TheHive Block list internal IP address" not in temp_rule_atrib: + temp_rule_atrib.append("TheHive Block list internal IP address") if "any" in temp_rule_atrib: temp_rule_atrib.remove("any") rule_atrib.update({"destination": temp_rule_atrib}) @@ -93,6 +93,6 @@ def run(self): rulebase.add(new_rule) new_rule.apply() fw.commit() - self.report({'message': 'Responder successfully added %s into TheHive Black list internal IP from %s' % (ioc,self.name_security_rule)}) + self.report({'message': 'Responder successfully added %s into TheHive Block list internal IP address from %s' % (ioc,self.name_security_rule)}) if __name__ == '__main__': Block_ip().run() diff --git a/responders/PaloAltoNGFW/Block_internal_port.py b/responders/PaloAltoNGFW/Block_internal_port.py index 8b8200918..6d124b023 100644 --- a/responders/PaloAltoNGFW/Block_internal_port.py +++ b/responders/PaloAltoNGFW/Block_internal_port.py @@ -16,29 +16,30 @@ def __init__(self): self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') self.name_security_rule = self.get_param('config.Security_rule_for_blocking_port_internal_communication','TheHive Block port for internal communication') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + self.TheHive_instance = self.get_param('config.TheHive_instance') + self.TheHive_API_key = self.get_param('config.TheHive_API_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.TheHive_instance, self.TheHive_API_key) def run(self): self.instance_type = self.get_param('data._type') if self.instance_type == 'case_artifact': - port = self.get_param('data.data') + data = self.get_param('data.data') + port=str(data).split('-')[0] + protocol=str(data).split('-')[1] + protocol=re.findall(r'[a-z]+',str(protocol)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(port)); port="".join(port) if self.instance_type == 'alert': alertId = self.get_param('data.id') response = self.api.get_alert(alertId) data_list=[] data=None for i in response.json().get("artifacts"): - if "'port'," in str(i): - ioc = i.get("data") + if "'port-protocol'," in str(i): data_list.append(i.get("data")) - elif "'protocol'," in str(i): - ioc = i.get("data") - data_list.append(i.get("data")) - data=" ".join(data_list) - protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() - port=re.findall(r'[0-9]+',str(data)); port="".join(port) + port=str(data_list).split('-')[0] + protocol=str(data_list).split('-')[1] + protocol=re.findall(r'[a-z]+',str(protocol)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(port)); port="".join(port) if self.instance_type == 'case': import requests case_id = self.get_param('data._id') @@ -46,18 +47,21 @@ def run(self): "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, "range": "all" } - headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } - thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.TheHive_API_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.TheHive_instance) r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) if r.status_code != requests.codes.ok: self.error(json.dumps(r.text)) a=None data = r.json() + data_list=[] for n in data: - if n.get('dataType') == 'port': - port=n.get('data') - if n.get('dataType') == 'protocol': - protocol=n.get('data') + if "'port-protocol'," in str(n): + data_list.append(n.get("data")) + port=str(data_list).split('-')[0] + protocol=str(data_list).split('-')[1] + protocol=re.findall(r'[a-z]+',str(protocol)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(port)); port="".join(port) fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) panos.objects.ServiceObject.refreshall(fw) rulebase = panos.policies.Rulebase() @@ -70,16 +74,16 @@ def run(self): panos.objects.ServiceGroup.refreshall(fw) - block_list = fw.find("TheHive Black list internal port", panos.objects.ServiceGroup) + block_list = fw.find("TheHive Block list for internal port communication", panos.objects.ServiceGroup) if block_list != None: port_list = block_list.about().get('value') if port not in port_list: port_list.append(port) - temp1 = panos.objects.ServiceGroup("TheHive Black list internal port", value=port_list) + temp1 = panos.objects.ServiceGroup("TheHive Block list for internal port communication", value=port_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.ServiceGroup("TheHive Black list internal port", value=port) + temp1 = panos.objects.ServiceGroup("TheHive Block list for internal port communication", value=port) fw.add(temp1) temp1.apply() desired_rule_params = None @@ -87,17 +91,19 @@ def run(self): if self.name_security_rule == i.about().get("name"): rule_atrib = i.about() temp_rule_atrib = rule_atrib.get("service") - if "TheHive Black list internal port" not in temp_rule_atrib: - temp_rule_atrib.append("TheHive Black list internal port") + if "TheHive Block list for internal port communication" not in temp_rule_atrib: + temp_rule_atrib.append("TheHive Block list for internal port communication") if "application-default" in temp_rule_atrib: temp_rule_atrib.remove("application-default") rule_atrib.update({"service": temp_rule_atrib}) desired_rule_params = rule_atrib + else: + desired_rule_params = rule_atrib new_rule = panos.policies.SecurityRule(**desired_rule_params) rulebase.add(new_rule) new_rule.apply() fw.commit() - self.report({'message': 'Responder successfully added %s into TheHive Black list internal port from %s' % (port,self.name_security_rule)}) + self.report({'message': 'Responder successfully added %s into TheHive Block list for internal port communication from %s' % (port,self.name_security_rule)}) if __name__ == '__main__': Block_port().run() diff --git a/responders/PaloAltoNGFW/Block_internal_user.py b/responders/PaloAltoNGFW/Block_internal_user.py index 565d5f47e..7253714ad 100644 --- a/responders/PaloAltoNGFW/Block_internal_user.py +++ b/responders/PaloAltoNGFW/Block_internal_user.py @@ -13,10 +13,10 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.Security_rule_for_block_internal_user','TheHive Block user internal communication') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + self.name_security_rule = self.get_param('config.Security_rule_for_block_internal_user','TheHive Block internal user') + self.TheHive_instance = self.get_param('config.TheHive_instance') + self.TheHive_API_key = self.get_param('config.TheHive_API_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.TheHive_instance, self.TheHive_API_key) def run(self): self.instance_type = self.get_param('data._type') @@ -43,8 +43,8 @@ def run(self): "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, "range": "all" } - headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } - thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.TheHive_API_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.TheHive_instance) r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) if r.status_code != requests.codes.ok: self.error(json.dumps(r.text)) diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json index 98a073823..91a3804bc 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_block_external_IP_address", "version": "2.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Block external IP address", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/Block_external_ip.py", + "command": "PaloAltoNGFW/block_external_ip.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { @@ -32,21 +32,21 @@ }, { "name": "Security_rule_for_block_external_IP_address", - "description": "Name external name security rule for ip", + "description": "Name external name security rule for IP address", "type": "string", "multi": false, "required": false, "defaultValue": "TheHive Block external IP address" }, { - "name": "Thehive_instance", - "description": "URL of the Thehive instance to query", + "name": "TheHive_instance", + "description": "URL of the TheHive instance to query", "type": "string", "multi": false, "required": true }, { - "name": "Thehive_API_key", + "name": "TheHive_API_key", "description": "TheHive API key with read access", "type": "string", "multi": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json index 28a6965bf..c83b281b4 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_block_external_domain", "version": "2.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Block external domain", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/Block_external_domain.py", + "command": "PaloAltoNGFW/block_external_domain.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { @@ -32,7 +32,7 @@ }, { "name": "Security_rule_for_block_external_domain", - "description": "Name internal security rule for domain", + "description": "Name external security rule for domains", "type": "string", "multi": false, "required": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_port.json deleted file mode 100644 index 6478b3178..000000000 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_port.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "PaloAltoNGFW_block_external_port", - "version": "2.0.0", - "author": "Maxim Konakin, OSCD Community", - "url": "", - "license": "AGPL-V3", - "description": "Block external port", - "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/Block_external_port.py", - "baseConfig": "PaloAltoNGFW_main", - "configurationItems": [ - { - "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_security_rule", - "description": "name_external_name_security_rule_for_port", - "type": "string", - "multi": false, - "required": false - }, - { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_api_key", - "description": "TheHive API key with read access", - "type": "string", - "multi": false, - "required": true - } - ] -} diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json index 9b3731ef8..eb341c3ed 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_block_external_user", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Block external user", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/Block_external_user.py", + "command": "PaloAltoNGFW/block_external_user.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { @@ -32,11 +32,11 @@ }, { "name": "Security_rule_for_block_external_user", - "description": "Name external name security rule for users", + "description": "Name security rule for external users", "type": "string", "multi": false, "required": false, - "defaultValue": "TheHive Block user external communication" + "defaultValue": "TheHive Block external user" }, { "name": "TheHive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json index 1a4c6fc42..1a676e9ed 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_block_internal_IP_address", "version": "2.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Block internal IP address", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/Block_internal_ip.py", + "command": "PaloAltoNGFW/block_internal_ip.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { @@ -32,7 +32,7 @@ }, { "name": "Security_rule_for_block_internal_IP_address", - "description": "Name internal name security rule for ip", + "description": "Name internal security rule for IP address", "type": "string", "multi": false, "required": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json index d0bc43622..2db73df17 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_block_internal_domain", "version": "2.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Block internal domain", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/Block_internal_domain.py", + "command": "PaloAltoNGFW/block_internal_domain.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { @@ -32,7 +32,7 @@ }, { "name": "Security_rule_for_block_internal_domain", - "description": "Name internal security rule for domain", + "description": "Name internal security rule for domains", "type": "string", "multi": false, "required": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_port.json deleted file mode 100644 index 3343dc0cc..000000000 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_port.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "PaloAltoNGFW_block_internal_port", - "version": "2.0.0", - "author": "Maxim Konakin, OSCD Community", - "url": "", - "license": "AGPL-V3", - "description": "Block internal port", - "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/Block_internal_port.py", - "baseConfig": "PaloAltoNGFW_main", - "configurationItems": [ - { - "name": "Hostname_PaloAltoNGFW", - "description": "Hostname_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "User_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "Password_PaloAltoNGFW", - "description": "User_PaloAltoNGFW", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "name_security_rule", - "description": "name_internal_name_security_rule_for_port", - "type": "string", - "multi": false, - "required": false - }, - { - "name": "thehive_instance", - "description": "URL of the Thehive instance to query", - "type": "string", - "multi": false, - "required": true - }, - { - "name": "thehive_api_key", - "description": "TheHive API key with read access", - "type": "string", - "multi": false, - "required": true - } - ] -} diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json index a7fe1976e..9cc7234ce 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_user.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_block_internal_user", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Block internal user", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/Block_internal_user.py", + "command": "PaloAltoNGFW/block_internal_user.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { @@ -32,11 +32,11 @@ }, { "name": "Security_rule_for_block_internal_user", - "description": "Name internal name security rule for users", + "description": "Name internal security rule for users", "type": "string", "multi": false, "required": false, - "defaultValue": "TheHive Block user internal communication" + "defaultValue": "TheHive Block internal user" }, { "name": "TheHive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_external_communication.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_external_communication.json index 2e0ad0a89..06c53f0ca 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_external_communication.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_external_communication.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_block_port_for_external_communication", "version": "2.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", - "description": "Block external port", + "description": "Block external port communication", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/Block_external_port.py", + "command": "PaloAltoNGFW/block_external_port.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { @@ -32,7 +32,7 @@ }, { "name": "Security_rule_for_block_port_external_communication", - "description": "Name external name security rule for port", + "description": "Name external security rule for port communications", "type": "string", "multi": false, "required": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_internal_communication.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_internal_communication.json index 9ef1d4af6..d29521939 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_internal_communication.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_internal_communication.json @@ -1,12 +1,12 @@ { - "name": "PaloAltoNGFW_block_port_for_internal_communication" + "name": "PaloAltoNGFW_block_port_for_internal_communication", "version": "2.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", - "description": "Block internal port", + "description": "Block internal port communication", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/Block_internal_port.py", + "command": "PaloAltoNGFW/block_internal_port.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { @@ -31,8 +31,8 @@ "required": true }, { - "name": "Security_rule_for_blocking_port_internal_communication", - "description": "Name internal name security rule for port", + "name": "Security_rule_for_block_port_internal_communication", + "description": "Name internal security rule for port communications", "type": "string", "multi": false, "required": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json index 248542c25..fe116b3dd 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_unblock_external_IP_address", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", - "description": "Unblock ip", + "description": "Unblock external ip", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/Unblock_external_ip.py", + "command": "PaloAltoNGFW/unblock_external_ip.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { @@ -31,12 +31,12 @@ "required": true }, { - "name": "Address_group_for_unblock_external_IP_address", - "description": "Name external Address Group", + "name": "Address_group_for_external_IP_address", + "description": "Name external Address Group for IP address", "type": "string", "multi": false, "required": false, - "defaultValue": "TheHive Black list external IP" + "defaultValue": "TheHive Block list external IP address" }, { "name": "TheHive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json index ff2111bc7..642037829 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_unblock_external_domain", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", - "description": "Unblock domain", + "description": "Unblock external domain", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/Unblock_external_domain.py", + "command": "PaloAltoNGFW/unblock_external_domain.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { @@ -32,11 +32,11 @@ }, { "name": "Address_group_for_unblock_external_domain", - "description": "Name external Address Group for domain", + "description": "Name external Address Group for domains", "type": "string", "multi": false, "required": false, - "defaultValue": "TheHive Black list external domain" + "defaultValue": "TheHive Block list external domain" }, { "name": "TheHive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json index 11f8c3f34..39b91b51b 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_unblock_external_user", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Unblock external user", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/Unblock_external_user.py", + "command": "PaloAltoNGFW/unblock_external_user.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { @@ -31,12 +31,12 @@ "required": true }, { - "name": "Security_rule_for_unblock_external_user", - "description": "Name external name security rule for users", + "name": "Security_rule_for_block_external_user", + "description": "Name security rule for external users", "type": "string", "multi": false, "required": false, - "defaultValue": "TheHive Block user external communication" + "defaultValue": "TheHive Block external user" }, { "name": "TheHive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json index 9d7c8cdde..14531041d 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_unblock_internal_IP_address", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", - "description": "Unblock ip", + "description": "Unblock internal ip", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/Unblock_internal_ip.py", + "command": "PaloAltoNGFW/unblock_internal_ip.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { @@ -31,15 +31,15 @@ "required": true }, { - "name": "Address_group_for_unblock_internal_IP_address", - "description": "Name internal Address Group", + "name": "Address_group_for_internal_IP_address", + "description": "Name internal Address Group for IP address", "type": "string", "multi": false, "required": false, - "defaultValue": "TheHive Black list internal IP" + "defaultValue": "TheHive Block list internal IP address" }, { - "name": "Thehive_instance", + "name": "TheHive_instance", "description": "URL of the TheHive instance to query", "type": "string", "multi": false, diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json index f21e0cc1d..f30058b93 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_unblock_internal_domain", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", - "description": "Unblock domain", + "description": "Unblock internal domain", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/Unblock_internal_domain.py", + "command": "PaloAltoNGFW/unblock_internal_domain.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { @@ -32,11 +32,11 @@ }, { "name": "Address_group_for_unblock_internal_domain", - "description": "Name internal Address Group for domain", + "description": "Name internal Address Group for domains", "type": "string", "multi": false, "required": false, - "defaultValue": "TheHive Black list internal domain" + "defaultValue": "TheHive Block list internal domain" }, { "name": "TheHive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json index c5e30f0f9..cbc0fb9a2 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json @@ -1,12 +1,12 @@ { "name": "PaloAltoNGFW_unblock_internal_user", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", "description": "Unblock internal user", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/Unblock_internal_user.py", + "command": "PaloAltoNGFW/unblock_internal_user.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { @@ -31,12 +31,12 @@ "required": true }, { - "name": "Security_rule_for_unblock_internal_user", - "description": "Internal name security rule for users", - "type": "string" + "name": "Security_rule_for_block_internal_user", + "description": "Name security rule for internal users", + "type": "string", "multi": false, "required": false, - "defaultValue": "TheHive Block user internal communication" + "defaultValue": "TheHive Block internal user" }, { "name": "TheHive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_external_communication.json similarity index 72% rename from responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json rename to responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_external_communication.json index cbec45ef5..96bcc0181 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_port.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_external_communication.json @@ -1,12 +1,12 @@ { - "name": "PaloAltoNGFW_unblock_internal_port", + "name": "PaloAltoNGFW_unblock_port_for_external_communication", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", - "description": "Unblock domain", + "description": "Unblock external port communication", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/Unblock_internal_port.py", + "command": "PaloAltoNGFW/unblock_external_port.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { @@ -31,12 +31,12 @@ "required": true }, { - "name": "Internal_service_group_for_unblock_internal_port", - "description": "Name internal Service Group", + "name": "Service_group_for_external_port_communication", + "description": "Name external Service Group for port communication", "type": "string", "multi": false, "required": false, - "defaultValue": "TheHive Black list internal port" + "defaultValue": "TheHive Block list for external port communication" }, { "name": "TheHive_instance", diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_internal_communication.json similarity index 72% rename from responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json rename to responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_internal_communication.json index 72337c197..57bc44916 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_port.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_internal_communication.json @@ -1,12 +1,12 @@ { - "name": "PaloAltoNGFW_unblock_external_port", + "name": "PaloAltoNGFW_unblock_port_for_internal_communication", "version": "1.0.0", - "author": "Maxim Konakin, OSCD Community", + "author": "Maxim Konakin, OSCD Initiative", "url": "", "license": "AGPL-V3", - "description": "Unblock domain", + "description": "Unblock internal port communication", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/Unblock_external_port.py", + "command": "PaloAltoNGFW/unblock_internal_port.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { @@ -31,12 +31,12 @@ "required": true }, { - "name": "Service_group_for_unblock_external_port", - "description": "Name external Service Group", + "name": "Service_group_for_internal_port_communication", + "description": "Name internal Service Group for port communication", "type": "string", "multi": false, "required": false, - "defaultValue": "TheHive Black list external port" + "defaultValue": "TheHive Block list for internal port communication" }, { "name": "TheHive_instance", diff --git a/responders/PaloAltoNGFW/README.md b/responders/PaloAltoNGFW/README.md index d485c1cb5..e808d9c7b 100644 --- a/responders/PaloAltoNGFW/README.md +++ b/responders/PaloAltoNGFW/README.md @@ -23,8 +23,8 @@ need install: 3. Password_PaloAltoNGFW - пароль для пользователя в системе PaloAltoNGFW 4. name_security_rule (не обязательное поле) - имя правила безопасности в системе PaloAltoNGFW. Установлены следующие стандартные наименования правил: 4.1 Для блокировки\разблокировки имени пользователей: -4.1.1 "TheHive Block user internal communication" -4.1.2 "TheHive Block user external communication" +4.1.1 "TheHive Block internal user" +4.1.2 "TheHive Block external user" 4.2 Для блокировки\разблокировки сетевых адресов: 4.2.1 "TheHive Block internal IP address" @@ -38,16 +38,15 @@ need install: 4.4.1 "TheHive Block port for internal communication" 4.4.2 "TheHive Block port for external communication" -4.5 thehive_instance - url адрес системы TheHive (используется только для типов case и alert). +4.5 TheHive_instance - url адрес системы TheHive (используется только для типов case и alert). Важно для каждой организации должен быть свой пользователь с API! -4.6 thehive_api_key - API ключ для подключения к системе TheHive +4.6 TheHive_API_key - API ключ для подключения к системе TheHive Примечание: указанные правила безопасноти должны быть созданы в PaloAltoNGFW, а так же расставлены в порядке их применения. Типы используемых данных для работы в системе TheHive: 1. Сетевой адрес - 'ip' 2. FQDN - 'hostname' -3. порт - 'port' -4. протокол - 'protocol' -5. имя пользователя - 'username' -Примечание: типы 'port' и 'protocol' необходимо создать в системе TheHive. По умолчанию TheHive не имеет данных типов данных в Observable type, поэтому мы должны добавить его в настройках администратора. +3. порт-протокол - 'port-protocol' +4. имя пользователя - 'username' +Примечание: типы 'port-protocol' и 'username' необходимо создать в системе TheHive. По умолчанию TheHive не имеет данных типов данных в Observable type, поэтому мы должны добавить его в настройках администратора. ![alt text](AddObservableType.jpg) \ No newline at end of file diff --git a/responders/PaloAltoNGFW/Unblock_external_domain.py b/responders/PaloAltoNGFW/Unblock_external_domain.py index 6865a9a8e..2de0c117c 100644 --- a/responders/PaloAltoNGFW/Unblock_external_domain.py +++ b/responders/PaloAltoNGFW/Unblock_external_domain.py @@ -14,10 +14,10 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_external_Address_Group_for_domain = self.get_param('config.Address_group_for_unblock_external_domain',"TheHive Black list external domain") - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + self.name_external_Address_Group_for_domain = self.get_param('config.Address_group_for_unblock_external_domain',"TheHive Block list external domain") + self.TheHive_instance = self.get_param('config.TheHive_instance') + self.TheHive_API_key = self.get_param('config.TheHive_API_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.TheHive_instance, self.TheHive_API_key) def run(self): self.instance_type = self.get_param('data._type') @@ -44,8 +44,8 @@ def run(self): "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, "range": "all" } - headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } - thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.TheHive_API_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.TheHive_instance) r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) if r.status_code != requests.codes.ok: self.error(json.dumps(r.text)) diff --git a/responders/PaloAltoNGFW/Unblock_external_ip.py b/responders/PaloAltoNGFW/Unblock_external_ip.py index 363666373..275f21c0d 100644 --- a/responders/PaloAltoNGFW/Unblock_external_ip.py +++ b/responders/PaloAltoNGFW/Unblock_external_ip.py @@ -13,10 +13,10 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_external_Address_Group = self.get_param('config.Address_group_for_unblock_external_IP_address',"TheHive Black list external IP") - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + self.name_external_Address_Group = self.get_param('config.Address_group_for_unblock_external_IP_address',"TheHive Block list external IP address") + self.TheHive_instance = self.get_param('config.TheHive_instance') + self.TheHive_API_key = self.get_param('config.TheHive_API_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.TheHive_instance, self.TheHive_API_key) def run(self): self.instance_type = self.get_param('data._type') @@ -43,8 +43,8 @@ def run(self): "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, "range": "all" } - headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } - thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.TheHive_API_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.TheHive_instance) r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) if r.status_code != requests.codes.ok: self.error(json.dumps(r.text)) diff --git a/responders/PaloAltoNGFW/Unblock_external_port.py b/responders/PaloAltoNGFW/Unblock_external_port.py index f7150d37f..8b0f52fec 100644 --- a/responders/PaloAltoNGFW/Unblock_external_port.py +++ b/responders/PaloAltoNGFW/Unblock_external_port.py @@ -14,28 +14,31 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_external_Service_Group = self.get_param('config.Service_group_for_unblock_external_port','TheHive Black list external port') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + self.name_external_Service_Group = self.get_param('config.Service_group_for_unblock_external_port','TheHive Block list for external port communication') + self.TheHive_instance = self.get_param('config.TheHive_instance') + self.TheHive_API_key = self.get_param('config.TheHive_API_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.TheHive_instance, self.TheHive_API_key) def run(self): self.instance_type = self.get_param('data._type') if self.instance_type == 'case_artifact': - port = self.get_param('data.data') + data = self.get_param('data.data') + port=str(data).split('-')[0] + protocol=str(data).split('-')[1] + protocol=re.findall(r'[a-z]+',str(protocol)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(port)); port="".join(port) if self.instance_type == 'alert': alertId = self.get_param('data.id') response = self.api.get_alert(alertId) data_list=[] data=None for i in response.json().get("artifacts"): - if "'port'," in str(i): + if "'port-protocol'," in str(i): data_list.append(i.get("data")) - elif "'protocol'," in str(i): - data_list.append(i.get("data")) - data=" ".join(data_list) - protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() - port=re.findall(r'[0-9]+',str(data)); port="".join(port) + port=str(data_list).split('-')[0] + protocol=str(data_list).split('-')[1] + protocol=re.findall(r'[a-z]+',str(protocol)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(port)); port="".join(port) if self.instance_type == 'case': import requests case_id = self.get_param('data._id') @@ -43,16 +46,21 @@ def run(self): "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, "range": "all" } - headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } - thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.TheHive_API_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.TheHive_instance) r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) if r.status_code != requests.codes.ok: self.error(json.dumps(r.text)) a=None data = r.json() + data_list=[] for n in data: - if n.get('dataType') == 'port': - port=n.get('data') + if "'port-protocol'," in str(n): + data_list.append(n.get("data")) + port=str(data_list).split('-')[0] + protocol=str(data_list).split('-')[1] + protocol=re.findall(r'[a-z]+',str(protocol)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(port)); port="".join(port) fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) panos.objects.ServiceGroup.refreshall(fw) block_list = fw.find(self.name_external_Service_Group, panos.objects.ServiceGroup) diff --git a/responders/PaloAltoNGFW/Unblock_external_user.py b/responders/PaloAltoNGFW/Unblock_external_user.py index 5d4186d71..e7f80280c 100644 --- a/responders/PaloAltoNGFW/Unblock_external_user.py +++ b/responders/PaloAltoNGFW/Unblock_external_user.py @@ -13,10 +13,10 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block user external communication') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + self.name_security_rule = self.get_param('config.name_security_rule','TheHive Block external user') + self.TheHive_instance = self.get_param('config.TheHive_instance') + self.TheHive_API_key = self.get_param('config.TheHive_API_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.TheHive_instance, self.TheHive_API_key) def run(self): self.instance_type = self.get_param('data._type') @@ -28,7 +28,7 @@ def run(self): user=None user_list_alert=[] for i in list(response.json().get("artifacts")): - if 'user' in str(i): + if 'username' in str(i): ioc = i.get("data") for i in ioc: if i == "[" or i == "]": @@ -43,15 +43,15 @@ def run(self): "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, "range": "all" } - headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } - thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.TheHive_API_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.TheHive_instance) r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) if r.status_code != requests.codes.ok: self.error(json.dumps(r.text)) a=None data = r.json() for n in data: - if n.get('dataType') == 'user-agent': + if n.get('dataType') == 'username': user=n.get('data') fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) rulebase = panos.policies.Rulebase() diff --git a/responders/PaloAltoNGFW/Unblock_internal_domain.py b/responders/PaloAltoNGFW/Unblock_internal_domain.py index fa21eb172..913030408 100644 --- a/responders/PaloAltoNGFW/Unblock_internal_domain.py +++ b/responders/PaloAltoNGFW/Unblock_internal_domain.py @@ -14,10 +14,10 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Address_Group_for_domain = self.get_param('config.Address_group_for_unblock_internal_domain',"TheHive Black list internal domain") - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + self.name_internal_Address_Group_for_domain = self.get_param('config.Address_group_for_unblock_internal_domain',"TheHive Block list internal domain") + self.TheHive_instance = self.get_param('config.TheHive_instance') + self.TheHive_API_key = self.get_param('config.TheHive_API_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.TheHive_instance, self.TheHive_API_key) def run(self): self.instance_type = self.get_param('data._type') @@ -44,8 +44,8 @@ def run(self): "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, "range": "all" } - headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } - thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.TheHive_API_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.TheHive_instance) r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) if r.status_code != requests.codes.ok: self.error(json.dumps(r.text)) diff --git a/responders/PaloAltoNGFW/Unblock_internal_ip.py b/responders/PaloAltoNGFW/Unblock_internal_ip.py index 8e7156fb8..223bad4e2 100644 --- a/responders/PaloAltoNGFW/Unblock_internal_ip.py +++ b/responders/PaloAltoNGFW/Unblock_internal_ip.py @@ -13,10 +13,10 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Address_Group = self.get_param('config.Address_group_for_unblock_internal_IP_address',"TheHive Black list internal IP") - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + self.name_internal_Address_Group = self.get_param('config.Address_group_for_unblock_internal_IP_address',"TheHive Block list internal IP address") + self.TheHive_instance = self.get_param('config.TheHive_instance') + self.TheHive_API_key = self.get_param('config.TheHive_API_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.TheHive_instance, self.TheHive_API_key) def run(self): self.instance_type = self.get_param('data._type') @@ -43,8 +43,8 @@ def run(self): "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, "range": "all" } - headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } - thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.TheHive_API_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.TheHive_instance) r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) if r.status_code != requests.codes.ok: self.error(json.dumps(r.text)) diff --git a/responders/PaloAltoNGFW/Unblock_internal_port.py b/responders/PaloAltoNGFW/Unblock_internal_port.py index 465ec445a..2dee01954 100644 --- a/responders/PaloAltoNGFW/Unblock_internal_port.py +++ b/responders/PaloAltoNGFW/Unblock_internal_port.py @@ -14,28 +14,31 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_internal_Service_Group = self.get_param('config.Internal_service_group_for_unblock_internal_port','TheHive Black list internal port') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + self.name_internal_Service_Group = self.get_param('config.Internal_service_group_for_unblock_internal_port','TheHive Block list for internal port communication') + self.TheHive_instance = self.get_param('config.TheHive_instance') + self.TheHive_API_key = self.get_param('config.TheHive_API_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.TheHive_instance, self.TheHive_API_key) def run(self): self.instance_type = self.get_param('data._type') if self.instance_type == 'case_artifact': - port = self.get_param('data.data') + data = self.get_param('data.data') + port=str(data).split('-')[0] + protocol=str(data).split('-')[1] + protocol=re.findall(r'[a-z]+',str(protocol)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(port)); port="".join(port) if self.instance_type == 'alert': alertId = self.get_param('data.id') response = self.api.get_alert(alertId) data_list=[] data=None for i in response.json().get("artifacts"): - if "'port'," in str(i): + if "'port-protocol'," in str(i): data_list.append(i.get("data")) - elif "'protocol'," in str(i): - data_list.append(i.get("data")) - data=" ".join(data_list) - protocol=re.findall(r'[a-z]+',str(data)); protocol=str("".join(protocol)).lower() - port=re.findall(r'[0-9]+',str(data)); port="".join(port) + port=str(data_list).split('-')[0] + protocol=str(data_list).split('-')[1] + protocol=re.findall(r'[a-z]+',str(protocol)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(port)); port="".join(port) if self.instance_type == 'case': import requests case_id = self.get_param('data._id') @@ -43,16 +46,21 @@ def run(self): "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, "range": "all" } - headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } - thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.TheHive_API_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.TheHive_instance) r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) if r.status_code != requests.codes.ok: self.error(json.dumps(r.text)) a=None data = r.json() + data_list=[] for n in data: - if n.get('dataType') == 'port': - port=n.get('data') + if "'port-protocol'," in str(n): + data_list.append(n.get("data")) + port=str(data_list).split('-')[0] + protocol=str(data_list).split('-')[1] + protocol=re.findall(r'[a-z]+',str(protocol)); protocol=str("".join(protocol)).lower() + port=re.findall(r'[0-9]+',str(port)); port="".join(port) fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) panos.objects.ServiceGroup.refreshall(fw) block_list = fw.find(self.name_internal_Service_Group, panos.objects.ServiceGroup) diff --git a/responders/PaloAltoNGFW/Unblock_internal_user.py b/responders/PaloAltoNGFW/Unblock_internal_user.py index 2433e8eb9..663acfb64 100644 --- a/responders/PaloAltoNGFW/Unblock_internal_user.py +++ b/responders/PaloAltoNGFW/Unblock_internal_user.py @@ -13,10 +13,10 @@ def __init__(self): self.hostname_PaloAltoNGFW = self.get_param('config.Hostname_PaloAltoNGFW') self.User_PaloAltoNGFW = self.get_param('config.User_PaloAltoNGFW') self.Password_PaloAltoNGFW = self.get_param('config.Password_PaloAltoNGFW') - self.name_security_rule = self.get_param('config.Security_rule_for_unblock_internal_user','TheHive Block user internal communication') - self.thehive_instance = self.get_param('config.thehive_instance') - self.thehive_api_key = self.get_param('config.thehive_api_key', 'YOUR_KEY_HERE') - self.api = TheHiveApi(self.thehive_instance, self.thehive_api_key) + self.name_security_rule = self.get_param('config.Security_rule_for_unblock_internal_user','TheHive Block internal user') + self.TheHive_instance = self.get_param('config.TheHive_instance') + self.TheHive_API_key = self.get_param('config.TheHive_API_key', 'YOUR_KEY_HERE') + self.api = TheHiveApi(self.TheHive_instance, self.TheHive_API_key) def run(self): self.instance_type = self.get_param('data._type') @@ -28,7 +28,7 @@ def run(self): user=None user_list_alert=[] for i in list(response.json().get("artifacts")): - if 'user' in str(i): + if 'username' in str(i): ioc = i.get("data") for i in ioc: if i == "[" or i == "]": @@ -43,15 +43,15 @@ def run(self): "query": { "_parent": { "_type": "case", "_query": { "_id": case_id } } }, "range": "all" } - headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.thehive_api_key) } - thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.thehive_instance) + headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(self.TheHive_API_key) } + thehive_api_url_case_search = '{}/api/case/artifact/_search'.format(self.TheHive_instance) r = requests.post(thehive_api_url_case_search, data=json.dumps(payload), headers=headers) if r.status_code != requests.codes.ok: self.error(json.dumps(r.text)) a=None data = r.json() for n in data: - if n.get('dataType') == 'user-agent': + if n.get('dataType') == 'username': user=n.get('data') fw = firewall.Firewall(self.hostname_PaloAltoNGFW, api_username=self.User_PaloAltoNGFW, api_password=self.Password_PaloAltoNGFW) rulebase = panos.policies.Rulebase() From 87a7ebca0133b802c6081ff6118a9b4bd59b25be Mon Sep 17 00:00:00 2001 From: Konakin Maksim <60079363@leroymerlin.ru> Date: Tue, 20 Apr 2021 15:19:14 +0300 Subject: [PATCH 21/25] Add new prefix for object --- .../PaloAltoNGFW/Block_external_domain.py | 10 +++++----- responders/PaloAltoNGFW/Block_external_ip.py | 10 +++++----- .../PaloAltoNGFW/Block_external_port.py | 11 ++++++----- .../PaloAltoNGFW/Block_internal_domain.py | 10 +++++----- responders/PaloAltoNGFW/Block_internal_ip.py | 10 +++++----- .../PaloAltoNGFW/Block_internal_port.py | 10 +++++----- ...aloAltoNGFW_block_external_IP_address.json | 2 +- .../PaloAltoNGFW_block_external_domain.json | 2 +- .../PaloAltoNGFW_block_external_user.json | 2 +- ...aloAltoNGFW_block_internal_IP_address.json | 2 +- .../PaloAltoNGFW_block_internal_domain.json | 2 +- ...block_port_for_external_communication.json | 2 +- ...block_port_for_internal_communication.json | 2 +- ...oAltoNGFW_unblock_external_IP_address.json | 2 +- .../PaloAltoNGFW_unblock_external_domain.json | 2 +- .../PaloAltoNGFW_unblock_external_user.json | 2 +- ...oAltoNGFW_unblock_internal_IP_address.json | 2 +- .../PaloAltoNGFW_unblock_internal_domain.json | 2 +- .../PaloAltoNGFW_unblock_internal_user.json | 2 +- ...block_port_for_external_communication.json | 2 +- ...block_port_for_internal_communication.json | 2 +- responders/PaloAltoNGFW/README.md | 10 ++++------ responders/PaloAltoNGFW/Responders.jpg | Bin 77819 -> 102646 bytes .../PaloAltoNGFW/Unblock_external_domain.py | 10 +++++----- .../PaloAltoNGFW/Unblock_external_ip.py | 10 +++++----- .../PaloAltoNGFW/Unblock_external_port.py | 6 +++--- .../PaloAltoNGFW/Unblock_internal_domain.py | 8 ++++---- .../PaloAltoNGFW/Unblock_internal_ip.py | 10 +++++----- .../PaloAltoNGFW/Unblock_internal_port.py | 4 ++-- 29 files changed, 74 insertions(+), 75 deletions(-) diff --git a/responders/PaloAltoNGFW/Block_external_domain.py b/responders/PaloAltoNGFW/Block_external_domain.py index 8e372d37c..d19209948 100644 --- a/responders/PaloAltoNGFW/Block_external_domain.py +++ b/responders/PaloAltoNGFW/Block_external_domain.py @@ -59,21 +59,21 @@ def run(self): rulebase = panos.policies.Rulebase() fw.add(rulebase) current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) - if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): - new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="TheHive Blocked domain",type="fqdn") + if f"the_hive-{ioc}" not in str(fw.find(f"the_hive-{ioc}", panos.objects.AddressObject)): + new_ioc_object = panos.objects.AddressObject(f"the_hive-{ioc}", ioc, description="TheHive Blocked domain",type="fqdn") fw.add(new_ioc_object) new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) block_list = fw.find("TheHive Block list external domain", panos.objects.AddressGroup) if block_list != None: ioc_list = block_list.about().get('static_value') - if ioc not in ioc_list: - ioc_list.append(ioc) + if f"the_hive-{ioc}" not in ioc_list: + ioc_list.append(f"the_hive-{ioc}") temp1 = panos.objects.AddressGroup("TheHive Block list external domain", static_value=ioc_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.AddressGroup("TheHive Block list external domain", static_value=ioc) + temp1 = panos.objects.AddressGroup("TheHive Block list external domain", static_value=f"the_hive-{ioc}") fw.add(temp1) temp1.apply() desired_rule_params = None diff --git a/responders/PaloAltoNGFW/Block_external_ip.py b/responders/PaloAltoNGFW/Block_external_ip.py index 4619c80ec..856541794 100644 --- a/responders/PaloAltoNGFW/Block_external_ip.py +++ b/responders/PaloAltoNGFW/Block_external_ip.py @@ -59,21 +59,21 @@ def run(self): rulebase = panos.policies.Rulebase() fw.add(rulebase) current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) - if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): - new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="TheHive Blocked ip address") + if f"the_hive-{ioc}" not in str(fw.find(f"the_hive-{ioc}", panos.objects.AddressObject)): + new_ioc_object = panos.objects.AddressObject(f"the_hive-{ioc}", ioc, description="TheHive Blocked ip address") fw.add(new_ioc_object) new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) block_list = fw.find("TheHive Block list external IP address", panos.objects.AddressGroup) if block_list != None: ioc_list = block_list.about().get('static_value') - if ioc not in ioc_list: - ioc_list.append(ioc) + if f"the_hive-{ioc}" not in ioc_list: + ioc_list.append(f"the_hive-{ioc}") temp1 = panos.objects.AddressGroup("TheHive Block list external IP address", static_value=ioc_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.AddressGroup("TheHive Block list external IP address", static_value=ioc) + temp1 = panos.objects.AddressGroup("TheHive Block list external IP address", static_value=f"the_hive-{ioc}") fw.add(temp1) temp1.apply() desired_rule_params = None diff --git a/responders/PaloAltoNGFW/Block_external_port.py b/responders/PaloAltoNGFW/Block_external_port.py index a6dd6b571..9968626a6 100644 --- a/responders/PaloAltoNGFW/Block_external_port.py +++ b/responders/PaloAltoNGFW/Block_external_port.py @@ -67,8 +67,9 @@ def run(self): rulebase = panos.policies.Rulebase() fw.add(rulebase) current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) - if port not in str(fw.find(port, panos.objects.ServiceObject)): - new_port_object = panos.objects.ServiceObject(port, protocol, description="TheHive Blocked port",destination_port=port) + raise IOError(fw.find(f"the_hive-{port}-{protocol}", panos.objects.ServiceObject)) + if f"the_hive-{port}-{protocol}" not in str(fw.find(f"the_hive-{port}-{protocol}", panos.objects.ServiceObject)): + new_port_object = panos.objects.ServiceObject(f"the_hive-{port}-{protocol}", protocol, description="TheHive Blocked port",destination_port=port) fw.add(new_port_object) new_port_object.create() @@ -77,13 +78,13 @@ def run(self): block_list = fw.find("TheHive Block list for external port communication", panos.objects.ServiceGroup) if block_list != None: port_list = block_list.about().get('value') - if port not in port_list: - port_list.append(port) + if f"the_hive-{port}-{protocol}" not in port_list: + port_list.append(f"the_hive-{port}-{protocol}") temp1 = panos.objects.ServiceGroup("TheHive Block list for external port communication", value=port_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.ServiceGroup("TheHive Block list for external port communication", value=port) + temp1 = panos.objects.ServiceGroup("TheHive Block list for external port communication", value=f"the_hive-{port}-{protocol}") fw.add(temp1) temp1.apply() desired_rule_params = None diff --git a/responders/PaloAltoNGFW/Block_internal_domain.py b/responders/PaloAltoNGFW/Block_internal_domain.py index 671eef56e..be391f179 100644 --- a/responders/PaloAltoNGFW/Block_internal_domain.py +++ b/responders/PaloAltoNGFW/Block_internal_domain.py @@ -59,21 +59,21 @@ def run(self): rulebase = panos.policies.Rulebase() fw.add(rulebase) current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) - if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): - new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="TheHive Blocked domain",type="fqdn") + if f"the_hive-{ioc}" not in str(fw.find(f"the_hive-{ioc}", panos.objects.AddressObject)): + new_ioc_object = panos.objects.AddressObject(f"the_hive-{ioc}", ioc, description="TheHive Blocked domain",type="fqdn") fw.add(new_ioc_object) new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) block_list = fw.find("TheHive Block list internal domain", panos.objects.AddressGroup) if block_list != None: ioc_list = block_list.about().get('static_value') - if ioc not in ioc_list: - ioc_list.append(ioc) + if f"the_hive-{ioc}" not in ioc_list: + ioc_list.append(f"the_hive-{ioc}") temp1 = panos.objects.AddressGroup("TheHive Block list internal domain", static_value=ioc_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.AddressGroup("TheHive Block list internal domain", static_value=ioc) + temp1 = panos.objects.AddressGroup("TheHive Block list internal domain", static_value=f"the_hive-{ioc}") fw.add(temp1) temp1.apply() desired_rule_params = None diff --git a/responders/PaloAltoNGFW/Block_internal_ip.py b/responders/PaloAltoNGFW/Block_internal_ip.py index 0fefcc8f4..ef2d09361 100644 --- a/responders/PaloAltoNGFW/Block_internal_ip.py +++ b/responders/PaloAltoNGFW/Block_internal_ip.py @@ -59,21 +59,21 @@ def run(self): rulebase = panos.policies.Rulebase() fw.add(rulebase) current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) - if ioc not in str(fw.find(ioc, panos.objects.AddressObject)): - new_ioc_object = panos.objects.AddressObject(ioc, ioc, description="TheHive Blocked ip address") + if f"the_hive-{ioc}" not in str(fw.find(f"the_hive-{ioc}", panos.objects.AddressObject)): + new_ioc_object = panos.objects.AddressObject(f"the_hive-{ioc}", ioc, description="TheHive Blocked ip address") fw.add(new_ioc_object) new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) block_list = fw.find("TheHive Block list internal IP address", panos.objects.AddressGroup) if block_list != None: ioc_list = block_list.about().get('static_value') - if ioc not in ioc_list: - ioc_list.append(ioc) + if f"the_hive-{ioc}" not in ioc_list: + ioc_list.append(f"the_hive-{ioc}") temp1 = panos.objects.AddressGroup("TheHive Block list internal IP address", static_value=ioc_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.AddressGroup("TheHive Block list internal IP address", static_value=ioc) + temp1 = panos.objects.AddressGroup("TheHive Block list internal IP address", static_value=f"the_hive-{ioc}") fw.add(temp1) temp1.apply() desired_rule_params = None diff --git a/responders/PaloAltoNGFW/Block_internal_port.py b/responders/PaloAltoNGFW/Block_internal_port.py index 6d124b023..e9a056e86 100644 --- a/responders/PaloAltoNGFW/Block_internal_port.py +++ b/responders/PaloAltoNGFW/Block_internal_port.py @@ -67,8 +67,8 @@ def run(self): rulebase = panos.policies.Rulebase() fw.add(rulebase) current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) - if port not in str(fw.find(port, panos.objects.ServiceObject)): - new_port_object = panos.objects.ServiceObject(port, protocol, description="TheHive Blocked port",destination_port=port) + if f"the_hive-{port}-{protocol}" not in str(fw.find(f"the_hive-{port}-{protocol}", panos.objects.ServiceObject)): + new_port_object = panos.objects.ServiceObject(f"the_hive-{port}-{protocol}", protocol, description="TheHive Blocked port",destination_port=port) fw.add(new_port_object) new_port_object.create() @@ -77,13 +77,13 @@ def run(self): block_list = fw.find("TheHive Block list for internal port communication", panos.objects.ServiceGroup) if block_list != None: port_list = block_list.about().get('value') - if port not in port_list: - port_list.append(port) + if f"the_hive-{port}-{protocol}" not in port_list: + port_list.append(f"the_hive-{port}-{protocol}") temp1 = panos.objects.ServiceGroup("TheHive Block list for internal port communication", value=port_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.ServiceGroup("TheHive Block list for internal port communication", value=port) + temp1 = panos.objects.ServiceGroup("TheHive Block list for internal port communication", value=f"the_hive-{port}-{protocol}") fw.add(temp1) temp1.apply() desired_rule_params = None diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json index 91a3804bc..d177c1b1a 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_IP_address.json @@ -35,7 +35,7 @@ "description": "Name external name security rule for IP address", "type": "string", "multi": false, - "required": false, + "required": true, "defaultValue": "TheHive Block external IP address" }, { diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json index c83b281b4..f04590178 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_domain.json @@ -35,7 +35,7 @@ "description": "Name external security rule for domains", "type": "string", "multi": false, - "required": false, + "required": true, "defaultValue": "TheHive Block external Domain" }, { diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json index eb341c3ed..954d2baef 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_external_user.json @@ -35,7 +35,7 @@ "description": "Name security rule for external users", "type": "string", "multi": false, - "required": false, + "required": true, "defaultValue": "TheHive Block external user" }, { diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json index 1a676e9ed..23a436085 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_IP_address.json @@ -35,7 +35,7 @@ "description": "Name internal security rule for IP address", "type": "string", "multi": false, - "required": false, + "required": true, "defaultValue": "TheHive Block internal IP address" }, { diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json index 2db73df17..ff5b22af2 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_internal_domain.json @@ -35,7 +35,7 @@ "description": "Name internal security rule for domains", "type": "string", "multi": false, - "required": false, + "required": true, "defaultValue": "TheHive Block internal Domain" }, { diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_external_communication.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_external_communication.json index 06c53f0ca..335075dcf 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_external_communication.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_external_communication.json @@ -35,7 +35,7 @@ "description": "Name external security rule for port communications", "type": "string", "multi": false, - "required": false, + "required": true, "defaultValue":"TheHive Block port for external communication" }, { diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_internal_communication.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_internal_communication.json index d29521939..7ac4fa5ee 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_internal_communication.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_internal_communication.json @@ -35,7 +35,7 @@ "description": "Name internal security rule for port communications", "type": "string", "multi": false, - "required": false, + "required": true, "defaultValue": "TheHive Block port for internal communication" }, { diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json index fe116b3dd..520ff95d0 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_IP_address.json @@ -35,7 +35,7 @@ "description": "Name external Address Group for IP address", "type": "string", "multi": false, - "required": false, + "required": true, "defaultValue": "TheHive Block list external IP address" }, { diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json index 642037829..8fd264886 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_domain.json @@ -35,7 +35,7 @@ "description": "Name external Address Group for domains", "type": "string", "multi": false, - "required": false, + "required": true, "defaultValue": "TheHive Block list external domain" }, { diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json index 39b91b51b..d74ad87df 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_external_user.json @@ -35,7 +35,7 @@ "description": "Name security rule for external users", "type": "string", "multi": false, - "required": false, + "required": true, "defaultValue": "TheHive Block external user" }, { diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json index 14531041d..34588e7b0 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_IP_address.json @@ -35,7 +35,7 @@ "description": "Name internal Address Group for IP address", "type": "string", "multi": false, - "required": false, + "required": true, "defaultValue": "TheHive Block list internal IP address" }, { diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json index f30058b93..6a164490b 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_domain.json @@ -35,7 +35,7 @@ "description": "Name internal Address Group for domains", "type": "string", "multi": false, - "required": false, + "required": true, "defaultValue": "TheHive Block list internal domain" }, { diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json index cbc0fb9a2..fbfcbc868 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_internal_user.json @@ -35,7 +35,7 @@ "description": "Name security rule for internal users", "type": "string", "multi": false, - "required": false, + "required": true, "defaultValue": "TheHive Block internal user" }, { diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_external_communication.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_external_communication.json index 96bcc0181..e801cc642 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_external_communication.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_external_communication.json @@ -35,7 +35,7 @@ "description": "Name external Service Group for port communication", "type": "string", "multi": false, - "required": false, + "required": true, "defaultValue": "TheHive Block list for external port communication" }, { diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_internal_communication.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_internal_communication.json index 57bc44916..08de9f0ac 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_internal_communication.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_internal_communication.json @@ -35,7 +35,7 @@ "description": "Name internal Service Group for port communication", "type": "string", "multi": false, - "required": false, + "required": true, "defaultValue": "TheHive Block list for internal port communication" }, { diff --git a/responders/PaloAltoNGFW/README.md b/responders/PaloAltoNGFW/README.md index e808d9c7b..7d48a0737 100644 --- a/responders/PaloAltoNGFW/README.md +++ b/responders/PaloAltoNGFW/README.md @@ -10,18 +10,16 @@ need install: 3. pip install pan-os-python 4. pip install thehive4py # ToDo - -Для работы responders, необходимо загрузить папку PaloAltoNGFW в директорию, где храняться другие responder. Далее перейти в загруженную папку и сделать запускаемыми скрипты на языке python командой "chmod +x *.py" - +Для работы responders, необходимо загрузить папку PaloAltoNGFW в директорию, где храняться другие responder. Далее необходимо: -Выполнить перезагрузку системы cortex; +- Выполнить перезагрузку системы cortex; -После перезагрузки в веб консоли cortex перейти на вкладку "Organization", выбрать организацию для которой будет выполнена настройка и перейти на вкладку "Responders Config" и выполняем настройку полей в соответсвии с их значениями: +- Для настройки респондера необходимо перейти в веб консоли cortex перейти на вкладку "Organization", выбрать организацию для которой будет выполнена настройка и перейти на вкладку "Responders Config" и выполняем настройку полей для "PaloAltoNGFW_main" в соответсвии с их значениями: ![alt text](Responders.jpg) 1. Hostname_PaloAltoNGFW - сетевой адрес системы PaloAltoNGFW 2. User_PaloAltoNGFW - пользователь в системе PaloAltoNGFW 3. Password_PaloAltoNGFW - пароль для пользователя в системе PaloAltoNGFW -4. name_security_rule (не обязательное поле) - имя правила безопасности в системе PaloAltoNGFW. Установлены следующие стандартные наименования правил: +4. Security_rule_* - имя правила безопасности в системе PaloAltoNGFW. Установлены следующие стандартные наименования правил: 4.1 Для блокировки\разблокировки имени пользователей: 4.1.1 "TheHive Block internal user" 4.1.2 "TheHive Block external user" diff --git a/responders/PaloAltoNGFW/Responders.jpg b/responders/PaloAltoNGFW/Responders.jpg index 3da9ba1db8378c22c16995b16280a44bc95f5def..332511821b5c3f920022d6935a7fde23cd4a108e 100644 GIT binary patch literal 102646 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 C$fXVd literal 77819 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 Date: Mon, 26 Apr 2021 21:23:23 +0300 Subject: [PATCH 22/25] rename files --- .../PaloAltoNGFW_block_port_for_external_communication.json | 2 +- .../PaloAltoNGFW_block_port_for_internal_communication.json | 2 +- .../PaloAltoNGFW_unblock_port_for_external_communication.json | 2 +- .../PaloAltoNGFW_unblock_port_for_internal_communication.json | 2 +- ...xternal_port.py => block_port_for_external_communication.py} | 1 - ...nternal_port.py => block_port_for_internal_communication.py} | 0 ...ernal_port.py => unblock_port_for_external_communication.py} | 0 ...ernal_port.py => unblock_port_for_internal_communication.py} | 0 8 files changed, 4 insertions(+), 5 deletions(-) rename responders/PaloAltoNGFW/{Block_external_port.py => block_port_for_external_communication.py} (98%) rename responders/PaloAltoNGFW/{Block_internal_port.py => block_port_for_internal_communication.py} (100%) rename responders/PaloAltoNGFW/{Unblock_external_port.py => unblock_port_for_external_communication.py} (100%) rename responders/PaloAltoNGFW/{Unblock_internal_port.py => unblock_port_for_internal_communication.py} (100%) diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_external_communication.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_external_communication.json index 335075dcf..8f6969940 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_external_communication.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_external_communication.json @@ -6,7 +6,7 @@ "license": "AGPL-V3", "description": "Block external port communication", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/block_external_port.py", + "command": "PaloAltoNGFW/block_port_for_external_communication.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_internal_communication.json b/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_internal_communication.json index 7ac4fa5ee..c14223685 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_internal_communication.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_block_port_for_internal_communication.json @@ -6,7 +6,7 @@ "license": "AGPL-V3", "description": "Block internal port communication", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/block_internal_port.py", + "command": "PaloAltoNGFW/block_port_for_internal_communication.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_external_communication.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_external_communication.json index e801cc642..50847f6ea 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_external_communication.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_external_communication.json @@ -6,7 +6,7 @@ "license": "AGPL-V3", "description": "Unblock external port communication", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/unblock_external_port.py", + "command": "PaloAltoNGFW/unblock_port_for_external_communication.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_internal_communication.json b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_internal_communication.json index 08de9f0ac..89c094e8e 100644 --- a/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_internal_communication.json +++ b/responders/PaloAltoNGFW/PaloAltoNGFW_unblock_port_for_internal_communication.json @@ -6,7 +6,7 @@ "license": "AGPL-V3", "description": "Unblock internal port communication", "dataTypeList": ["thehive:alert","thehive:case_artifact","thehive:case"], - "command": "PaloAltoNGFW/unblock_internal_port.py", + "command": "PaloAltoNGFW/unblock_port_for_internal_communication.py", "baseConfig": "PaloAltoNGFW_main", "configurationItems": [ { diff --git a/responders/PaloAltoNGFW/Block_external_port.py b/responders/PaloAltoNGFW/block_port_for_external_communication.py similarity index 98% rename from responders/PaloAltoNGFW/Block_external_port.py rename to responders/PaloAltoNGFW/block_port_for_external_communication.py index 9968626a6..5025a726a 100644 --- a/responders/PaloAltoNGFW/Block_external_port.py +++ b/responders/PaloAltoNGFW/block_port_for_external_communication.py @@ -67,7 +67,6 @@ def run(self): rulebase = panos.policies.Rulebase() fw.add(rulebase) current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) - raise IOError(fw.find(f"the_hive-{port}-{protocol}", panos.objects.ServiceObject)) if f"the_hive-{port}-{protocol}" not in str(fw.find(f"the_hive-{port}-{protocol}", panos.objects.ServiceObject)): new_port_object = panos.objects.ServiceObject(f"the_hive-{port}-{protocol}", protocol, description="TheHive Blocked port",destination_port=port) fw.add(new_port_object) diff --git a/responders/PaloAltoNGFW/Block_internal_port.py b/responders/PaloAltoNGFW/block_port_for_internal_communication.py similarity index 100% rename from responders/PaloAltoNGFW/Block_internal_port.py rename to responders/PaloAltoNGFW/block_port_for_internal_communication.py diff --git a/responders/PaloAltoNGFW/Unblock_external_port.py b/responders/PaloAltoNGFW/unblock_port_for_external_communication.py similarity index 100% rename from responders/PaloAltoNGFW/Unblock_external_port.py rename to responders/PaloAltoNGFW/unblock_port_for_external_communication.py diff --git a/responders/PaloAltoNGFW/Unblock_internal_port.py b/responders/PaloAltoNGFW/unblock_port_for_internal_communication.py similarity index 100% rename from responders/PaloAltoNGFW/Unblock_internal_port.py rename to responders/PaloAltoNGFW/unblock_port_for_internal_communication.py From d07a6ebc9c58172f810f8f509d76b3f71bb6b0bb Mon Sep 17 00:00:00 2001 From: Konakin Maksim <60079363@leroymerlin.ru> Date: Mon, 26 Apr 2021 21:35:54 +0300 Subject: [PATCH 23/25] Update version --- .../{Block_external_domain.py => block_external_domain.py} | 0 .../PaloAltoNGFW/{Block_external_ip.py => block_external_ip.py} | 0 .../{Block_external_user.py => block_external_user.py} | 0 .../{Block_internal_domain.py => block_internal_domain.py} | 0 .../PaloAltoNGFW/{Block_internal_ip.py => block_internal_ip.py} | 0 .../{Block_internal_user.py => block_internal_user.py} | 0 responders/PaloAltoNGFW/block_port_for_external_communication.py | 0 responders/PaloAltoNGFW/block_port_for_internal_communication.py | 0 .../{Unblock_external_domain.py => unblock_external_domain.py} | 0 .../{Unblock_external_ip.py => unblock_external_ip.py} | 0 .../{Unblock_external_user.py => unblock_external_user.py} | 0 .../{Unblock_internal_domain.py => unblock_internal_domain.py} | 0 .../{Unblock_internal_ip.py => unblock_internal_ip.py} | 0 .../{Unblock_internal_user.py => unblock_internal_user.py} | 0 .../PaloAltoNGFW/unblock_port_for_external_communication.py | 0 .../PaloAltoNGFW/unblock_port_for_internal_communication.py | 0 16 files changed, 0 insertions(+), 0 deletions(-) rename responders/PaloAltoNGFW/{Block_external_domain.py => block_external_domain.py} (100%) mode change 100644 => 100755 rename responders/PaloAltoNGFW/{Block_external_ip.py => block_external_ip.py} (100%) mode change 100644 => 100755 rename responders/PaloAltoNGFW/{Block_external_user.py => block_external_user.py} (100%) mode change 100644 => 100755 rename responders/PaloAltoNGFW/{Block_internal_domain.py => block_internal_domain.py} (100%) mode change 100644 => 100755 rename responders/PaloAltoNGFW/{Block_internal_ip.py => block_internal_ip.py} (100%) mode change 100644 => 100755 rename responders/PaloAltoNGFW/{Block_internal_user.py => block_internal_user.py} (100%) mode change 100644 => 100755 mode change 100644 => 100755 responders/PaloAltoNGFW/block_port_for_external_communication.py mode change 100644 => 100755 responders/PaloAltoNGFW/block_port_for_internal_communication.py rename responders/PaloAltoNGFW/{Unblock_external_domain.py => unblock_external_domain.py} (100%) mode change 100644 => 100755 rename responders/PaloAltoNGFW/{Unblock_external_ip.py => unblock_external_ip.py} (100%) mode change 100644 => 100755 rename responders/PaloAltoNGFW/{Unblock_external_user.py => unblock_external_user.py} (100%) mode change 100644 => 100755 rename responders/PaloAltoNGFW/{Unblock_internal_domain.py => unblock_internal_domain.py} (100%) mode change 100644 => 100755 rename responders/PaloAltoNGFW/{Unblock_internal_ip.py => unblock_internal_ip.py} (100%) mode change 100644 => 100755 rename responders/PaloAltoNGFW/{Unblock_internal_user.py => unblock_internal_user.py} (100%) mode change 100644 => 100755 mode change 100644 => 100755 responders/PaloAltoNGFW/unblock_port_for_external_communication.py mode change 100644 => 100755 responders/PaloAltoNGFW/unblock_port_for_internal_communication.py diff --git a/responders/PaloAltoNGFW/Block_external_domain.py b/responders/PaloAltoNGFW/block_external_domain.py old mode 100644 new mode 100755 similarity index 100% rename from responders/PaloAltoNGFW/Block_external_domain.py rename to responders/PaloAltoNGFW/block_external_domain.py diff --git a/responders/PaloAltoNGFW/Block_external_ip.py b/responders/PaloAltoNGFW/block_external_ip.py old mode 100644 new mode 100755 similarity index 100% rename from responders/PaloAltoNGFW/Block_external_ip.py rename to responders/PaloAltoNGFW/block_external_ip.py diff --git a/responders/PaloAltoNGFW/Block_external_user.py b/responders/PaloAltoNGFW/block_external_user.py old mode 100644 new mode 100755 similarity index 100% rename from responders/PaloAltoNGFW/Block_external_user.py rename to responders/PaloAltoNGFW/block_external_user.py diff --git a/responders/PaloAltoNGFW/Block_internal_domain.py b/responders/PaloAltoNGFW/block_internal_domain.py old mode 100644 new mode 100755 similarity index 100% rename from responders/PaloAltoNGFW/Block_internal_domain.py rename to responders/PaloAltoNGFW/block_internal_domain.py diff --git a/responders/PaloAltoNGFW/Block_internal_ip.py b/responders/PaloAltoNGFW/block_internal_ip.py old mode 100644 new mode 100755 similarity index 100% rename from responders/PaloAltoNGFW/Block_internal_ip.py rename to responders/PaloAltoNGFW/block_internal_ip.py diff --git a/responders/PaloAltoNGFW/Block_internal_user.py b/responders/PaloAltoNGFW/block_internal_user.py old mode 100644 new mode 100755 similarity index 100% rename from responders/PaloAltoNGFW/Block_internal_user.py rename to responders/PaloAltoNGFW/block_internal_user.py diff --git a/responders/PaloAltoNGFW/block_port_for_external_communication.py b/responders/PaloAltoNGFW/block_port_for_external_communication.py old mode 100644 new mode 100755 diff --git a/responders/PaloAltoNGFW/block_port_for_internal_communication.py b/responders/PaloAltoNGFW/block_port_for_internal_communication.py old mode 100644 new mode 100755 diff --git a/responders/PaloAltoNGFW/Unblock_external_domain.py b/responders/PaloAltoNGFW/unblock_external_domain.py old mode 100644 new mode 100755 similarity index 100% rename from responders/PaloAltoNGFW/Unblock_external_domain.py rename to responders/PaloAltoNGFW/unblock_external_domain.py diff --git a/responders/PaloAltoNGFW/Unblock_external_ip.py b/responders/PaloAltoNGFW/unblock_external_ip.py old mode 100644 new mode 100755 similarity index 100% rename from responders/PaloAltoNGFW/Unblock_external_ip.py rename to responders/PaloAltoNGFW/unblock_external_ip.py diff --git a/responders/PaloAltoNGFW/Unblock_external_user.py b/responders/PaloAltoNGFW/unblock_external_user.py old mode 100644 new mode 100755 similarity index 100% rename from responders/PaloAltoNGFW/Unblock_external_user.py rename to responders/PaloAltoNGFW/unblock_external_user.py diff --git a/responders/PaloAltoNGFW/Unblock_internal_domain.py b/responders/PaloAltoNGFW/unblock_internal_domain.py old mode 100644 new mode 100755 similarity index 100% rename from responders/PaloAltoNGFW/Unblock_internal_domain.py rename to responders/PaloAltoNGFW/unblock_internal_domain.py diff --git a/responders/PaloAltoNGFW/Unblock_internal_ip.py b/responders/PaloAltoNGFW/unblock_internal_ip.py old mode 100644 new mode 100755 similarity index 100% rename from responders/PaloAltoNGFW/Unblock_internal_ip.py rename to responders/PaloAltoNGFW/unblock_internal_ip.py diff --git a/responders/PaloAltoNGFW/Unblock_internal_user.py b/responders/PaloAltoNGFW/unblock_internal_user.py old mode 100644 new mode 100755 similarity index 100% rename from responders/PaloAltoNGFW/Unblock_internal_user.py rename to responders/PaloAltoNGFW/unblock_internal_user.py diff --git a/responders/PaloAltoNGFW/unblock_port_for_external_communication.py b/responders/PaloAltoNGFW/unblock_port_for_external_communication.py old mode 100644 new mode 100755 diff --git a/responders/PaloAltoNGFW/unblock_port_for_internal_communication.py b/responders/PaloAltoNGFW/unblock_port_for_internal_communication.py old mode 100644 new mode 100755 From 309c24a45817b977a637ee4c612035dd8ed0f4d5 Mon Sep 17 00:00:00 2001 From: Konakin Maksim <60079363@leroymerlin.ru> Date: Mon, 17 May 2021 09:42:40 +0300 Subject: [PATCH 24/25] changed prefix --- responders/PaloAltoNGFW/block_external_domain.py | 10 +++++----- responders/PaloAltoNGFW/block_external_ip.py | 10 +++++----- responders/PaloAltoNGFW/block_internal_domain.py | 10 +++++----- responders/PaloAltoNGFW/block_internal_ip.py | 10 +++++----- .../block_port_for_external_communication.py | 10 +++++----- .../block_port_for_internal_communication.py | 10 +++++----- responders/PaloAltoNGFW/unblock_external_domain.py | 10 +++++----- responders/PaloAltoNGFW/unblock_external_ip.py | 10 +++++----- responders/PaloAltoNGFW/unblock_internal_domain.py | 8 ++++---- responders/PaloAltoNGFW/unblock_internal_ip.py | 10 +++++----- .../unblock_port_for_external_communication.py | 6 +++--- .../unblock_port_for_internal_communication.py | 4 ++-- 12 files changed, 54 insertions(+), 54 deletions(-) diff --git a/responders/PaloAltoNGFW/block_external_domain.py b/responders/PaloAltoNGFW/block_external_domain.py index d19209948..311b01d95 100755 --- a/responders/PaloAltoNGFW/block_external_domain.py +++ b/responders/PaloAltoNGFW/block_external_domain.py @@ -59,21 +59,21 @@ def run(self): rulebase = panos.policies.Rulebase() fw.add(rulebase) current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) - if f"the_hive-{ioc}" not in str(fw.find(f"the_hive-{ioc}", panos.objects.AddressObject)): - new_ioc_object = panos.objects.AddressObject(f"the_hive-{ioc}", ioc, description="TheHive Blocked domain",type="fqdn") + if f"thehive-{ioc}" not in str(fw.find(f"thehive-{ioc}", panos.objects.AddressObject)): + new_ioc_object = panos.objects.AddressObject(f"thehive-{ioc}", ioc, description="TheHive Blocked domain",type="fqdn") fw.add(new_ioc_object) new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) block_list = fw.find("TheHive Block list external domain", panos.objects.AddressGroup) if block_list != None: ioc_list = block_list.about().get('static_value') - if f"the_hive-{ioc}" not in ioc_list: - ioc_list.append(f"the_hive-{ioc}") + if f"thehive-{ioc}" not in ioc_list: + ioc_list.append(f"thehive-{ioc}") temp1 = panos.objects.AddressGroup("TheHive Block list external domain", static_value=ioc_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.AddressGroup("TheHive Block list external domain", static_value=f"the_hive-{ioc}") + temp1 = panos.objects.AddressGroup("TheHive Block list external domain", static_value=f"thehive-{ioc}") fw.add(temp1) temp1.apply() desired_rule_params = None diff --git a/responders/PaloAltoNGFW/block_external_ip.py b/responders/PaloAltoNGFW/block_external_ip.py index 856541794..5080daeac 100755 --- a/responders/PaloAltoNGFW/block_external_ip.py +++ b/responders/PaloAltoNGFW/block_external_ip.py @@ -59,21 +59,21 @@ def run(self): rulebase = panos.policies.Rulebase() fw.add(rulebase) current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) - if f"the_hive-{ioc}" not in str(fw.find(f"the_hive-{ioc}", panos.objects.AddressObject)): - new_ioc_object = panos.objects.AddressObject(f"the_hive-{ioc}", ioc, description="TheHive Blocked ip address") + if f"thehive-{ioc}" not in str(fw.find(f"thehive-{ioc}", panos.objects.AddressObject)): + new_ioc_object = panos.objects.AddressObject(f"thehive-{ioc}", ioc, description="TheHive Blocked ip address") fw.add(new_ioc_object) new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) block_list = fw.find("TheHive Block list external IP address", panos.objects.AddressGroup) if block_list != None: ioc_list = block_list.about().get('static_value') - if f"the_hive-{ioc}" not in ioc_list: - ioc_list.append(f"the_hive-{ioc}") + if f"thehive-{ioc}" not in ioc_list: + ioc_list.append(f"thehive-{ioc}") temp1 = panos.objects.AddressGroup("TheHive Block list external IP address", static_value=ioc_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.AddressGroup("TheHive Block list external IP address", static_value=f"the_hive-{ioc}") + temp1 = panos.objects.AddressGroup("TheHive Block list external IP address", static_value=f"thehive-{ioc}") fw.add(temp1) temp1.apply() desired_rule_params = None diff --git a/responders/PaloAltoNGFW/block_internal_domain.py b/responders/PaloAltoNGFW/block_internal_domain.py index be391f179..b9d1ff337 100755 --- a/responders/PaloAltoNGFW/block_internal_domain.py +++ b/responders/PaloAltoNGFW/block_internal_domain.py @@ -59,21 +59,21 @@ def run(self): rulebase = panos.policies.Rulebase() fw.add(rulebase) current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) - if f"the_hive-{ioc}" not in str(fw.find(f"the_hive-{ioc}", panos.objects.AddressObject)): - new_ioc_object = panos.objects.AddressObject(f"the_hive-{ioc}", ioc, description="TheHive Blocked domain",type="fqdn") + if f"thehive-{ioc}" not in str(fw.find(f"thehive-{ioc}", panos.objects.AddressObject)): + new_ioc_object = panos.objects.AddressObject(f"thehive-{ioc}", ioc, description="TheHive Blocked domain",type="fqdn") fw.add(new_ioc_object) new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) block_list = fw.find("TheHive Block list internal domain", panos.objects.AddressGroup) if block_list != None: ioc_list = block_list.about().get('static_value') - if f"the_hive-{ioc}" not in ioc_list: - ioc_list.append(f"the_hive-{ioc}") + if f"thehive-{ioc}" not in ioc_list: + ioc_list.append(f"thehive-{ioc}") temp1 = panos.objects.AddressGroup("TheHive Block list internal domain", static_value=ioc_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.AddressGroup("TheHive Block list internal domain", static_value=f"the_hive-{ioc}") + temp1 = panos.objects.AddressGroup("TheHive Block list internal domain", static_value=f"thehive-{ioc}") fw.add(temp1) temp1.apply() desired_rule_params = None diff --git a/responders/PaloAltoNGFW/block_internal_ip.py b/responders/PaloAltoNGFW/block_internal_ip.py index ef2d09361..c19b3f588 100755 --- a/responders/PaloAltoNGFW/block_internal_ip.py +++ b/responders/PaloAltoNGFW/block_internal_ip.py @@ -59,21 +59,21 @@ def run(self): rulebase = panos.policies.Rulebase() fw.add(rulebase) current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) - if f"the_hive-{ioc}" not in str(fw.find(f"the_hive-{ioc}", panos.objects.AddressObject)): - new_ioc_object = panos.objects.AddressObject(f"the_hive-{ioc}", ioc, description="TheHive Blocked ip address") + if f"thehive-{ioc}" not in str(fw.find(f"thehive-{ioc}", panos.objects.AddressObject)): + new_ioc_object = panos.objects.AddressObject(f"thehive-{ioc}", ioc, description="TheHive Blocked ip address") fw.add(new_ioc_object) new_ioc_object.create() panos.objects.AddressGroup.refreshall(fw) block_list = fw.find("TheHive Block list internal IP address", panos.objects.AddressGroup) if block_list != None: ioc_list = block_list.about().get('static_value') - if f"the_hive-{ioc}" not in ioc_list: - ioc_list.append(f"the_hive-{ioc}") + if f"thehive-{ioc}" not in ioc_list: + ioc_list.append(f"thehive-{ioc}") temp1 = panos.objects.AddressGroup("TheHive Block list internal IP address", static_value=ioc_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.AddressGroup("TheHive Block list internal IP address", static_value=f"the_hive-{ioc}") + temp1 = panos.objects.AddressGroup("TheHive Block list internal IP address", static_value=f"thehive-{ioc}") fw.add(temp1) temp1.apply() desired_rule_params = None diff --git a/responders/PaloAltoNGFW/block_port_for_external_communication.py b/responders/PaloAltoNGFW/block_port_for_external_communication.py index 5025a726a..9793d549b 100755 --- a/responders/PaloAltoNGFW/block_port_for_external_communication.py +++ b/responders/PaloAltoNGFW/block_port_for_external_communication.py @@ -67,8 +67,8 @@ def run(self): rulebase = panos.policies.Rulebase() fw.add(rulebase) current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) - if f"the_hive-{port}-{protocol}" not in str(fw.find(f"the_hive-{port}-{protocol}", panos.objects.ServiceObject)): - new_port_object = panos.objects.ServiceObject(f"the_hive-{port}-{protocol}", protocol, description="TheHive Blocked port",destination_port=port) + if f"thehive-{port}-{protocol}" not in str(fw.find(f"thehive-{port}-{protocol}", panos.objects.ServiceObject)): + new_port_object = panos.objects.ServiceObject(f"thehive-{port}-{protocol}", protocol, description="TheHive Blocked port",destination_port=port) fw.add(new_port_object) new_port_object.create() @@ -77,13 +77,13 @@ def run(self): block_list = fw.find("TheHive Block list for external port communication", panos.objects.ServiceGroup) if block_list != None: port_list = block_list.about().get('value') - if f"the_hive-{port}-{protocol}" not in port_list: - port_list.append(f"the_hive-{port}-{protocol}") + if f"thehive-{port}-{protocol}" not in port_list: + port_list.append(f"thehive-{port}-{protocol}") temp1 = panos.objects.ServiceGroup("TheHive Block list for external port communication", value=port_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.ServiceGroup("TheHive Block list for external port communication", value=f"the_hive-{port}-{protocol}") + temp1 = panos.objects.ServiceGroup("TheHive Block list for external port communication", value=f"thehive-{port}-{protocol}") fw.add(temp1) temp1.apply() desired_rule_params = None diff --git a/responders/PaloAltoNGFW/block_port_for_internal_communication.py b/responders/PaloAltoNGFW/block_port_for_internal_communication.py index e9a056e86..d1c15c9e2 100755 --- a/responders/PaloAltoNGFW/block_port_for_internal_communication.py +++ b/responders/PaloAltoNGFW/block_port_for_internal_communication.py @@ -67,8 +67,8 @@ def run(self): rulebase = panos.policies.Rulebase() fw.add(rulebase) current_security_rules =panos.policies.SecurityRule.refreshall(rulebase) - if f"the_hive-{port}-{protocol}" not in str(fw.find(f"the_hive-{port}-{protocol}", panos.objects.ServiceObject)): - new_port_object = panos.objects.ServiceObject(f"the_hive-{port}-{protocol}", protocol, description="TheHive Blocked port",destination_port=port) + if f"thehive-{port}-{protocol}" not in str(fw.find(f"thehive-{port}-{protocol}", panos.objects.ServiceObject)): + new_port_object = panos.objects.ServiceObject(f"thehive-{port}-{protocol}", protocol, description="TheHive Blocked port",destination_port=port) fw.add(new_port_object) new_port_object.create() @@ -77,13 +77,13 @@ def run(self): block_list = fw.find("TheHive Block list for internal port communication", panos.objects.ServiceGroup) if block_list != None: port_list = block_list.about().get('value') - if f"the_hive-{port}-{protocol}" not in port_list: - port_list.append(f"the_hive-{port}-{protocol}") + if f"thehive-{port}-{protocol}" not in port_list: + port_list.append(f"thehive-{port}-{protocol}") temp1 = panos.objects.ServiceGroup("TheHive Block list for internal port communication", value=port_list) fw.add(temp1) temp1.apply() elif block_list == None: - temp1 = panos.objects.ServiceGroup("TheHive Block list for internal port communication", value=f"the_hive-{port}-{protocol}") + temp1 = panos.objects.ServiceGroup("TheHive Block list for internal port communication", value=f"thehive-{port}-{protocol}") fw.add(temp1) temp1.apply() desired_rule_params = None diff --git a/responders/PaloAltoNGFW/unblock_external_domain.py b/responders/PaloAltoNGFW/unblock_external_domain.py index ca7850869..565b7c7a0 100755 --- a/responders/PaloAltoNGFW/unblock_external_domain.py +++ b/responders/PaloAltoNGFW/unblock_external_domain.py @@ -59,21 +59,21 @@ def run(self): block_list = fw.find(self.name_external_Address_Group_for_domain, panos.objects.AddressGroup) ioc_list = block_list.about().get('static_value') - if f"the_hive-{ioc}" in ioc_list: - ioc_list.remove(f"the_hive-{ioc}") + if f"thehive-{ioc}" in ioc_list: + ioc_list.remove(f"thehive-{ioc}") temp1 = panos.objects.AddressGroup(self.name_external_Address_Group_for_domain, static_value=ioc_list) fw.add(temp1) temp1.apply() panos.objects.AddressObject.refreshall(fw) - if f"the_hive-{ioc}" in str(fw.find(f"the_hive-{ioc}", panos.objects.AddressObject)): + if f"thehive-{ioc}" in str(fw.find(f"thehive-{ioc}", panos.objects.AddressObject)): try: - deleted_ioc = fw.find(f"the_hive-{ioc}", panos.objects.AddressObject) + deleted_ioc = fw.find(f"thehive-{ioc}", panos.objects.AddressObject) deleted_ioc.delete() except: self.report({'message': 'Responder did not comlite. Warning in AddressObject'}) - self.report({'message': 'Responder successfully deleted %s from %s' % (f"the_hive-{ioc}",self.name_external_Address_Group_for_domain)}) + self.report({'message': 'Responder successfully deleted %s from %s' % (f"thehive-{ioc}",self.name_external_Address_Group_for_domain)}) fw.commit() if __name__ == '__main__': diff --git a/responders/PaloAltoNGFW/unblock_external_ip.py b/responders/PaloAltoNGFW/unblock_external_ip.py index 2516d15ed..3401795ea 100755 --- a/responders/PaloAltoNGFW/unblock_external_ip.py +++ b/responders/PaloAltoNGFW/unblock_external_ip.py @@ -57,21 +57,21 @@ def run(self): panos.objects.AddressGroup.refreshall(fw) block_list = fw.find(self.name_external_Address_Group, panos.objects.AddressGroup) ioc_list = block_list.about().get('static_value') - if f"the_hive-{ioc}" in ioc_list: - ioc_list.remove(f"the_hive-{ioc}") + if f"thehive-{ioc}" in ioc_list: + ioc_list.remove(f"thehive-{ioc}") temp1 = panos.objects.AddressGroup(self.name_external_Address_Group, static_value=ioc_list) fw.add(temp1) temp1.apply() panos.objects.AddressObject.refreshall(fw) - if f"the_hive-{ioc}" in str(fw.find(f"the_hive-{ioc}", panos.objects.AddressObject)): + if f"thehive-{ioc}" in str(fw.find(f"thehive-{ioc}", panos.objects.AddressObject)): try: - deleted_ioc = fw.find(f"the_hive-{ioc}", panos.objects.AddressObject) + deleted_ioc = fw.find(f"thehive-{ioc}", panos.objects.AddressObject) deleted_ioc.delete() except: self.report({'message': 'Responder did not comlite. Warning in AddressObject'}) - self.report({'message': 'Responder successfully deleted %s from %s' % (f"the_hive-{ioc}",self.name_external_Address_Group)}) + self.report({'message': 'Responder successfully deleted %s from %s' % (f"thehive-{ioc}",self.name_external_Address_Group)}) fw.commit() if __name__ == '__main__': Unblock_ip().run() diff --git a/responders/PaloAltoNGFW/unblock_internal_domain.py b/responders/PaloAltoNGFW/unblock_internal_domain.py index 5298357b9..1d5199599 100755 --- a/responders/PaloAltoNGFW/unblock_internal_domain.py +++ b/responders/PaloAltoNGFW/unblock_internal_domain.py @@ -59,16 +59,16 @@ def run(self): block_list = fw.find(self.name_internal_Address_Group_for_domain, panos.objects.AddressGroup) ioc_list = block_list.about().get('static_value') - if f"the_hive-{ioc}" in ioc_list: - ioc_list.remove(f"the_hive-{ioc}") + if f"thehive-{ioc}" in ioc_list: + ioc_list.remove(f"thehive-{ioc}") temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group_for_domain, static_value=ioc_list) fw.add(temp1) temp1.apply() panos.objects.AddressObject.refreshall(fw) - if f"the_hive-{ioc}" in str(fw.find(f"the_hive-{ioc}", panos.objects.AddressObject)): + if f"thehive-{ioc}" in str(fw.find(f"thehive-{ioc}", panos.objects.AddressObject)): try: - deleted_ioc = fw.find(f"the_hive-{ioc}", panos.objects.AddressObject) + deleted_ioc = fw.find(f"thehive-{ioc}", panos.objects.AddressObject) deleted_ioc.delete() except: self.report({'message': 'Responder did not comlite. Warning in AddressObject'}) diff --git a/responders/PaloAltoNGFW/unblock_internal_ip.py b/responders/PaloAltoNGFW/unblock_internal_ip.py index 1eb151c09..0b1206412 100755 --- a/responders/PaloAltoNGFW/unblock_internal_ip.py +++ b/responders/PaloAltoNGFW/unblock_internal_ip.py @@ -57,21 +57,21 @@ def run(self): panos.objects.AddressGroup.refreshall(fw) block_list = fw.find(self.name_internal_Address_Group, panos.objects.AddressGroup) ioc_list = block_list.about().get('static_value') - if f"the_hive-{ioc}" in ioc_list: - ioc_list.remove(f"the_hive-{ioc}") + if f"thehive-{ioc}" in ioc_list: + ioc_list.remove(f"thehive-{ioc}") temp1 = panos.objects.AddressGroup(self.name_internal_Address_Group, static_value=ioc_list) fw.add(temp1) temp1.apply() panos.objects.AddressObject.refreshall(fw) - if f"the_hive-{ioc}" in str(fw.find(f"the_hive-{ioc}", panos.objects.AddressObject)): + if f"thehive-{ioc}" in str(fw.find(f"thehive-{ioc}", panos.objects.AddressObject)): try: - deleted_ioc = fw.find(f"the_hive-{ioc}", panos.objects.AddressObject) + deleted_ioc = fw.find(f"thehive-{ioc}", panos.objects.AddressObject) deleted_ioc.delete() except: self.report({'message': 'Responder did not comlite. Warning in AddressObject'}) - self.report({'message': 'Responder successfully deleted %s from %s' % (f"the_hive-{ioc}",self.name_internal_Address_Group)}) + self.report({'message': 'Responder successfully deleted %s from %s' % (f"thehive-{ioc}",self.name_internal_Address_Group)}) fw.commit() if __name__ == '__main__': diff --git a/responders/PaloAltoNGFW/unblock_port_for_external_communication.py b/responders/PaloAltoNGFW/unblock_port_for_external_communication.py index 7170fbbe0..616230f10 100755 --- a/responders/PaloAltoNGFW/unblock_port_for_external_communication.py +++ b/responders/PaloAltoNGFW/unblock_port_for_external_communication.py @@ -65,15 +65,15 @@ def run(self): panos.objects.ServiceGroup.refreshall(fw) block_list = fw.find(self.name_external_Service_Group, panos.objects.ServiceGroup) port_list = block_list.about().get('value') - if f"the_hive-{port}-{protocol}" in port_list: - port_list.remove(f"the_hive-{port}-{protocol}") + if f"thehive-{port}-{protocol}" in port_list: + port_list.remove(f"thehive-{port}-{protocol}") temp1 = panos.objects.ServiceGroup(self.name_external_Service_Group, value=port_list) fw.add(temp1) temp1.apply() panos.objects.ServiceObject.refreshall(fw) - self.report({'message': 'Responder successfully deleted %s from %s' % (f"the_hive-{port}-{protocol}",self.name_external_Service_Group)}) + self.report({'message': 'Responder successfully deleted %s from %s' % (f"thehive-{port}-{protocol}",self.name_external_Service_Group)}) fw.commit() if __name__ == '__main__': diff --git a/responders/PaloAltoNGFW/unblock_port_for_internal_communication.py b/responders/PaloAltoNGFW/unblock_port_for_internal_communication.py index 5d9967e72..e8a116334 100755 --- a/responders/PaloAltoNGFW/unblock_port_for_internal_communication.py +++ b/responders/PaloAltoNGFW/unblock_port_for_internal_communication.py @@ -65,8 +65,8 @@ def run(self): panos.objects.ServiceGroup.refreshall(fw) block_list = fw.find(self.name_internal_Service_Group, panos.objects.ServiceGroup) port_list = block_list.about().get('value') - if f"the_hive-{port}-{protocol}" in port_list: - port_list.remove(f"the_hive-{port}-{protocol}") + if f"thehive-{port}-{protocol}" in port_list: + port_list.remove(f"thehive-{port}-{protocol}") temp1 = panos.objects.ServiceGroup(self.name_internal_Service_Group, value=port_list) fw.add(temp1) temp1.apply() From 0deee22e977480d2b670c127a94094dbaa183788 Mon Sep 17 00:00:00 2001 From: Konakin Maksim <60079363@leroymerlin.ru> Date: Thu, 20 May 2021 21:49:01 +0300 Subject: [PATCH 25/25] Revert "Merge branch 'master' into feature/oscd" This reverts commit f8d00bc29c71fdd27849c3d1f696f61b24f1f041, reversing changes made to 309c24a45817b977a637ee4c612035dd8ed0f4d5. --- .drone.yml | 38 +------------------ analyzers/MISPWarningLists/requirements.txt | 1 - .../warninglists_create_db.py | 2 +- analyzers/URLhaus/URLhaus_analyzer.py | 3 +- 4 files changed, 3 insertions(+), 41 deletions(-) diff --git a/.drone.yml b/.drone.yml index 495585ff8..c9409745c 100644 --- a/.drone.yml +++ b/.drone.yml @@ -57,14 +57,6 @@ steps: when: event: [tag] - - name: build report-templates zip package - image: thehiveproject/neurons-build-report-templates - when: - event: [tag] - - -# Bintray will not be used anymore. We keep it until Feb 21 - - name: upload catalogs to bintray image: thehiveproject/drone-bintray settings: @@ -99,32 +91,7 @@ steps: when: event: [tag] - - name: upload report-templates to bintray - image: thehiveproject/drone-bintray - settings: - user: {from_secret: bintray_user} - key: {from_secret: bintray_key} - subject: thehive-project - package: report-templates - version: latest - override: 1 - publish: 1 - commands: - - | - export PLUGIN_USER - export PLUGIN_KEY - export PLUGIN_SUBJECT - export PLUGIN_PACKAGE - export PLUGIN_VERSION - export PLUGIN_OVERRIDE - export PLUGIN_PUBLISH - upload \ - --file analyzers/report-templates.zip \ - --repo binary - when: - event: [tag] - - - name: upload catalogs and report-templates package to package server + - name: upload catalogs to package server image: appleboy/drone-scp settings: host: {from_secret: package_host} @@ -136,7 +103,6 @@ steps: - analyzers/analyzers-stable.json - responders/responders.json - responders/responders-stable.json - - analyzers/report-templates.zip strip_components: 1 when: event: [tag] @@ -146,8 +112,6 @@ steps: when: branch: [develop] - -# Bintray will not be used anymore. We keep it until Feb 21 - name: upload devel catalogs to bintray image: thehiveproject/drone-bintray settings: diff --git a/analyzers/MISPWarningLists/requirements.txt b/analyzers/MISPWarningLists/requirements.txt index 16edc58c8..10975ab77 100644 --- a/analyzers/MISPWarningLists/requirements.txt +++ b/analyzers/MISPWarningLists/requirements.txt @@ -4,4 +4,3 @@ ipaddress tld sqlalchemy psycopg2-binary -tqdm diff --git a/analyzers/MISPWarningLists/warninglists_create_db.py b/analyzers/MISPWarningLists/warninglists_create_db.py index 3d43dca4d..663b19f0b 100755 --- a/analyzers/MISPWarningLists/warninglists_create_db.py +++ b/analyzers/MISPWarningLists/warninglists_create_db.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python # coding: utf-8 import re diff --git a/analyzers/URLhaus/URLhaus_analyzer.py b/analyzers/URLhaus/URLhaus_analyzer.py index e68bd4887..2bf5f2276 100755 --- a/analyzers/URLhaus/URLhaus_analyzer.py +++ b/analyzers/URLhaus/URLhaus_analyzer.py @@ -35,8 +35,7 @@ def summary(self, raw): namespace = "URLhaus" if raw['query_status'] == 'no_results' \ - or (raw['query_status'] == 'ok' and not raw.get('md5_hash', None) \ - and not raw.get('sha256_hash', None)): + or raw['query_status'] == 'ok' and raw['md5_hash'] == None and raw['sha256_hash'] == None: taxonomies.append(self.build_taxonomy( 'info', namespace,