ps-banshee 1.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ps_banshee-1.1.0/LICENSE +21 -0
- ps_banshee-1.1.0/PKG-INFO +146 -0
- ps_banshee-1.1.0/README.md +115 -0
- ps_banshee-1.1.0/banshee/__init__.py +16 -0
- ps_banshee-1.1.0/banshee/_version.py +15 -0
- ps_banshee-1.1.0/banshee/app_config.py +40 -0
- ps_banshee-1.1.0/banshee/branding.py +36 -0
- ps_banshee-1.1.0/banshee/commands/__init__.py +12 -0
- ps_banshee-1.1.0/banshee/commands/args.py +44 -0
- ps_banshee-1.1.0/banshee/commands/cmd_classic_alerts.py +175 -0
- ps_banshee-1.1.0/banshee/commands/cmd_entity.py +54 -0
- ps_banshee-1.1.0/banshee/commands/cmd_ioc.py +236 -0
- ps_banshee-1.1.0/banshee/commands/cmd_lists.py +293 -0
- ps_banshee-1.1.0/banshee/commands/cmd_pcap_enrich.py +74 -0
- ps_banshee-1.1.0/banshee/commands/cmd_playbook_alerts.py +297 -0
- ps_banshee-1.1.0/banshee/commands/cmd_risklist.py +239 -0
- ps_banshee-1.1.0/banshee/commands/cmd_rules.py +185 -0
- ps_banshee-1.1.0/banshee/commands/epilogs.py +602 -0
- ps_banshee-1.1.0/banshee/commands/errors.py +20 -0
- ps_banshee-1.1.0/banshee/detection_rules/__init__.py +14 -0
- ps_banshee-1.1.0/banshee/detection_rules/detection_rules_search.py +210 -0
- ps_banshee-1.1.0/banshee/entity_match/__init__.py +17 -0
- ps_banshee-1.1.0/banshee/entity_match/constants.py +168 -0
- ps_banshee-1.1.0/banshee/entity_match/errors.py +20 -0
- ps_banshee-1.1.0/banshee/entity_match/lookup.py +42 -0
- ps_banshee-1.1.0/banshee/entity_match/search.py +52 -0
- ps_banshee-1.1.0/banshee/formatters/__init__.py +12 -0
- ps_banshee-1.1.0/banshee/formatters/output_formatters.py +45 -0
- ps_banshee-1.1.0/banshee/fusion_files/__init__.py +14 -0
- ps_banshee-1.1.0/banshee/fusion_files/feed_stat.py +66 -0
- ps_banshee-1.1.0/banshee/indicators/__init__.py +18 -0
- ps_banshee-1.1.0/banshee/indicators/constants.py +103 -0
- ps_banshee-1.1.0/banshee/indicators/helpers.py +24 -0
- ps_banshee-1.1.0/banshee/indicators/lookup.py +92 -0
- ps_banshee-1.1.0/banshee/indicators/rules.py +82 -0
- ps_banshee-1.1.0/banshee/indicators/search.py +80 -0
- ps_banshee-1.1.0/banshee/indicators/soar.py +57 -0
- ps_banshee-1.1.0/banshee/legacy_alerts/__init__.py +12 -0
- ps_banshee-1.1.0/banshee/legacy_alerts/alert_lookup.py +38 -0
- ps_banshee-1.1.0/banshee/legacy_alerts/alert_search.py +82 -0
- ps_banshee-1.1.0/banshee/legacy_alerts/alert_update.py +80 -0
- ps_banshee-1.1.0/banshee/legacy_alerts/constants.py +35 -0
- ps_banshee-1.1.0/banshee/legacy_alerts/rules_search.py +46 -0
- ps_banshee-1.1.0/banshee/lists/__init__.py +24 -0
- ps_banshee-1.1.0/banshee/lists/fetch_list.py +35 -0
- ps_banshee-1.1.0/banshee/lists/list_add.py +53 -0
- ps_banshee-1.1.0/banshee/lists/list_bulk_add.py +85 -0
- ps_banshee-1.1.0/banshee/lists/list_bulk_remove.py +85 -0
- ps_banshee-1.1.0/banshee/lists/list_clear.py +31 -0
- ps_banshee-1.1.0/banshee/lists/list_create.py +46 -0
- ps_banshee-1.1.0/banshee/lists/list_entities.py +42 -0
- ps_banshee-1.1.0/banshee/lists/list_entries.py +37 -0
- ps_banshee-1.1.0/banshee/lists/list_helpers.py +100 -0
- ps_banshee-1.1.0/banshee/lists/list_info.py +39 -0
- ps_banshee-1.1.0/banshee/lists/list_remove.py +46 -0
- ps_banshee-1.1.0/banshee/lists/list_search.py +57 -0
- ps_banshee-1.1.0/banshee/lists/list_status.py +37 -0
- ps_banshee-1.1.0/banshee/main.py +118 -0
- ps_banshee-1.1.0/banshee/pcap_enrich/__init__.py +14 -0
- ps_banshee-1.1.0/banshee/pcap_enrich/constants.py +18 -0
- ps_banshee-1.1.0/banshee/pcap_enrich/helpers.py +64 -0
- ps_banshee-1.1.0/banshee/pcap_enrich/pcap_enrich.py +251 -0
- ps_banshee-1.1.0/banshee/playbook_alerts/__init__.py +14 -0
- ps_banshee-1.1.0/banshee/playbook_alerts/alert_lookup.py +49 -0
- ps_banshee-1.1.0/banshee/playbook_alerts/alert_search.py +62 -0
- ps_banshee-1.1.0/banshee/playbook_alerts/alert_update.py +107 -0
- ps_banshee-1.1.0/banshee/playbook_alerts/constants.py +75 -0
- ps_banshee-1.1.0/banshee/risklist/__init__.py +17 -0
- ps_banshee-1.1.0/banshee/risklist/risklist_create.py +154 -0
- ps_banshee-1.1.0/banshee/risklist/risklist_fetch.py +89 -0
- ps_banshee-1.1.0/banshee/risklist/risklist_stat.py +58 -0
- ps_banshee-1.1.0/banshee/threat/__init__.py +16 -0
- ps_banshee-1.1.0/banshee/threat/constants.py +99 -0
- ps_banshee-1.1.0/banshee/threat/endpoints.py +20 -0
- ps_banshee-1.1.0/banshee/threat/fetch_threat_map.py +59 -0
- ps_banshee-1.1.0/ps_banshee.egg-info/PKG-INFO +146 -0
- ps_banshee-1.1.0/ps_banshee.egg-info/SOURCES.txt +110 -0
- ps_banshee-1.1.0/ps_banshee.egg-info/dependency_links.txt +1 -0
- ps_banshee-1.1.0/ps_banshee.egg-info/entry_points.txt +2 -0
- ps_banshee-1.1.0/ps_banshee.egg-info/requires.txt +22 -0
- ps_banshee-1.1.0/ps_banshee.egg-info/top_level.txt +1 -0
- ps_banshee-1.1.0/pyproject.toml +72 -0
- ps_banshee-1.1.0/setup.cfg +4 -0
- ps_banshee-1.1.0/tests/test_cmd_ca_lookup.py +60 -0
- ps_banshee-1.1.0/tests/test_cmd_ca_rules.py +29 -0
- ps_banshee-1.1.0/tests/test_cmd_ca_search.py +104 -0
- ps_banshee-1.1.0/tests/test_cmd_ca_update.py +95 -0
- ps_banshee-1.1.0/tests/test_cmd_entity_lookup.py +39 -0
- ps_banshee-1.1.0/tests/test_cmd_entity_search.py +73 -0
- ps_banshee-1.1.0/tests/test_cmd_ioc_bulk_lookup.py +84 -0
- ps_banshee-1.1.0/tests/test_cmd_ioc_lookup.py +191 -0
- ps_banshee-1.1.0/tests/test_cmd_ioc_rules.py +147 -0
- ps_banshee-1.1.0/tests/test_cmd_ioc_search.py +133 -0
- ps_banshee-1.1.0/tests/test_cmd_list_add.py +44 -0
- ps_banshee-1.1.0/tests/test_cmd_list_bulk_add.py +333 -0
- ps_banshee-1.1.0/tests/test_cmd_list_bulk_remove.py +333 -0
- ps_banshee-1.1.0/tests/test_cmd_list_clear.py +33 -0
- ps_banshee-1.1.0/tests/test_cmd_list_create.py +55 -0
- ps_banshee-1.1.0/tests/test_cmd_list_entities.py +49 -0
- ps_banshee-1.1.0/tests/test_cmd_list_info.py +45 -0
- ps_banshee-1.1.0/tests/test_cmd_list_remove.py +44 -0
- ps_banshee-1.1.0/tests/test_cmd_list_search.py +66 -0
- ps_banshee-1.1.0/tests/test_cmd_list_status.py +46 -0
- ps_banshee-1.1.0/tests/test_cmd_pba_lookup.py +134 -0
- ps_banshee-1.1.0/tests/test_cmd_pba_search.py +92 -0
- ps_banshee-1.1.0/tests/test_cmd_pba_update.py +124 -0
- ps_banshee-1.1.0/tests/test_cmd_pcap.py +216 -0
- ps_banshee-1.1.0/tests/test_cmd_risklist_create.py +225 -0
- ps_banshee-1.1.0/tests/test_cmd_risklist_fetch.py +163 -0
- ps_banshee-1.1.0/tests/test_cmd_risklist_stat.py +105 -0
- ps_banshee-1.1.0/tests/test_cmd_rules_search.py +194 -0
- ps_banshee-1.1.0/tests/test_main.py +169 -0
ps_banshee-1.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 RecordedFuture-ProfessionalServices
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ps-banshee
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: PS Banshee is a command line tool used to access Recorded Future Intelligence. PS Banshee is designed to get you working quickly with Recorded Future.
|
|
5
|
+
Author-email: Moise Medici <moise.medici@recordedfuture.com>, Ernest Bartosevic <ernest.bartosevic@recordedfuture.com>
|
|
6
|
+
Keywords: API,Recorded Future,Cyber Security Engineering,Threat Intelligence,command line tool,CLI,ioc enrichment
|
|
7
|
+
Requires-Python: <3.14,>=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: typer<0.16.0
|
|
11
|
+
Requires-Dist: pyshark==0.6
|
|
12
|
+
Requires-Dist: polars~=1.34.0
|
|
13
|
+
Requires-Dist: psengine~=2.4.0
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: build==1.0.3; extra == "dev"
|
|
16
|
+
Requires-Dist: ruff~=0.11.0; extra == "dev"
|
|
17
|
+
Requires-Dist: pytest==8.3.4; extra == "dev"
|
|
18
|
+
Requires-Dist: pytest-vcr==1.0.2; extra == "dev"
|
|
19
|
+
Requires-Dist: pytest-cov==6.0.0; extra == "dev"
|
|
20
|
+
Requires-Dist: pytest-mock==3.14.0; extra == "dev"
|
|
21
|
+
Requires-Dist: urllib3<2.3.0; extra == "dev"
|
|
22
|
+
Requires-Dist: mimesis>=12.1.0; extra == "dev"
|
|
23
|
+
Provides-Extra: docs
|
|
24
|
+
Requires-Dist: ruff~=0.11.0; extra == "docs"
|
|
25
|
+
Requires-Dist: mike~=2.1.3; extra == "docs"
|
|
26
|
+
Requires-Dist: mkdocs~=1.6.1; extra == "docs"
|
|
27
|
+
Requires-Dist: mkdocs-material~=9.6.18; extra == "docs"
|
|
28
|
+
Requires-Dist: mkdocstrings[python]>=0.18; extra == "docs"
|
|
29
|
+
Requires-Dist: griffe-typingdoc~=0.2.8; extra == "docs"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# PS Banshee
|
|
33
|
+
|
|
34
|
+
PS Banshee is a command-line interface (CLI) tool designed to provide quick and efficient access to Recorded Future Intelligence. Built for security professionals, PS Banshee helps streamline investigations and automate common security operations tasks.
|
|
35
|
+
|
|
36
|
+

|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Table of Contents
|
|
41
|
+
|
|
42
|
+
- [Features](#features)
|
|
43
|
+
- [Installation](#installation)
|
|
44
|
+
- [Usage](#usage)
|
|
45
|
+
- [Development Environment Setup](#development-environment-setup)
|
|
46
|
+
- [Documentation](#documentation)
|
|
47
|
+
- [Support](#support)
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Key Features
|
|
52
|
+
|
|
53
|
+
- IOC lookup and search
|
|
54
|
+
- Packet capture (pcap) analysis
|
|
55
|
+
- Recorded Future Alert search, lookup, and update
|
|
56
|
+
- Recorded Future Detection Rules (YARA, Snort, Sigma) search and download
|
|
57
|
+
- Recorded Future Entity search and lookup
|
|
58
|
+
- Recorded Future List & Watch List management
|
|
59
|
+
- Recorded Future Playbook Alert search, lookup, and update
|
|
60
|
+
- Recorded Future Risk List download, and creation
|
|
61
|
+
|
|
62
|
+
## Installation
|
|
63
|
+
|
|
64
|
+
PS Banshee is available on PyPI and can be installed using `pip` or `pipx`.
|
|
65
|
+
|
|
66
|
+
!!! tip "PS Banshee requires Python 3.9 or later (up to 3.13)."
|
|
67
|
+
|
|
68
|
+
### Recommended: pipx (isolated environment)
|
|
69
|
+
To install globally, run:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pipx install ps-banshee
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
!!! info "Installing pipx"
|
|
77
|
+
If you don't have pipx installed, see the [installation guide](https://github.com/pypa/pipx?tab=readme-ov-file#install-pipx).
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
### Alternative: pip (current environment)
|
|
81
|
+
To install in the current environment, run:
|
|
82
|
+
```bash
|
|
83
|
+
pip install ps-banshee
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Dependencies
|
|
87
|
+
|
|
88
|
+
`pipx` will automatically resolve all Python dependencies.
|
|
89
|
+
If you want to use the `pcap` command, you will also need:
|
|
90
|
+
|
|
91
|
+
- tshark 3.0.0 or later
|
|
92
|
+
|
|
93
|
+
### Command Auto Completion
|
|
94
|
+
|
|
95
|
+
After installing PS Banshee, you can enable command auto completion:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
banshee --install-completion
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Restart your shell to complete the installation. You can now use TAB to auto-complete commands.
|
|
102
|
+
|
|
103
|
+
## Usage
|
|
104
|
+
|
|
105
|
+
To see the list of available commands, run:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
banshee -h
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Authorization
|
|
112
|
+
|
|
113
|
+
PS Banshee requires a Recorded Future API key, which can be provided as the `-k` or `--api-key` argument, or set as the `RF_TOKEN` environment variable.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
banshee -k <RF_TOKEN> <command> <sub-command> <arguments>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Proxies
|
|
120
|
+
|
|
121
|
+
If you are behind a proxy, set the `HTTP_PROXY` and `HTTPS_PROXY` environment variables.
|
|
122
|
+
|
|
123
|
+
To disable SSL verification, use the `-s` flag:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
banshee -s ca rules
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Command Help
|
|
130
|
+
|
|
131
|
+
All commands support the `--help` (`-h`) option:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
banshee -h
|
|
135
|
+
banshee ca --help
|
|
136
|
+
banshee ioc lookup --help
|
|
137
|
+
banshee list bulk-add -h
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Support
|
|
141
|
+
|
|
142
|
+
Submit a [support request](https://support.recordedfuture.com/hc/en-us/requests/new) for help alternatively reach out to [support@recordedfuture.com](mailto:support@recordedfuture.com).
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
**PS Banshee is developed and maintained by the Recorded Future Professional Services Cyber Security Engineers 🚀**
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# PS Banshee
|
|
2
|
+
|
|
3
|
+
PS Banshee is a command-line interface (CLI) tool designed to provide quick and efficient access to Recorded Future Intelligence. Built for security professionals, PS Banshee helps streamline investigations and automate common security operations tasks.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
- [Features](#features)
|
|
12
|
+
- [Installation](#installation)
|
|
13
|
+
- [Usage](#usage)
|
|
14
|
+
- [Development Environment Setup](#development-environment-setup)
|
|
15
|
+
- [Documentation](#documentation)
|
|
16
|
+
- [Support](#support)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Key Features
|
|
21
|
+
|
|
22
|
+
- IOC lookup and search
|
|
23
|
+
- Packet capture (pcap) analysis
|
|
24
|
+
- Recorded Future Alert search, lookup, and update
|
|
25
|
+
- Recorded Future Detection Rules (YARA, Snort, Sigma) search and download
|
|
26
|
+
- Recorded Future Entity search and lookup
|
|
27
|
+
- Recorded Future List & Watch List management
|
|
28
|
+
- Recorded Future Playbook Alert search, lookup, and update
|
|
29
|
+
- Recorded Future Risk List download, and creation
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
PS Banshee is available on PyPI and can be installed using `pip` or `pipx`.
|
|
34
|
+
|
|
35
|
+
!!! tip "PS Banshee requires Python 3.9 or later (up to 3.13)."
|
|
36
|
+
|
|
37
|
+
### Recommended: pipx (isolated environment)
|
|
38
|
+
To install globally, run:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pipx install ps-banshee
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
!!! info "Installing pipx"
|
|
46
|
+
If you don't have pipx installed, see the [installation guide](https://github.com/pypa/pipx?tab=readme-ov-file#install-pipx).
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
### Alternative: pip (current environment)
|
|
50
|
+
To install in the current environment, run:
|
|
51
|
+
```bash
|
|
52
|
+
pip install ps-banshee
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Dependencies
|
|
56
|
+
|
|
57
|
+
`pipx` will automatically resolve all Python dependencies.
|
|
58
|
+
If you want to use the `pcap` command, you will also need:
|
|
59
|
+
|
|
60
|
+
- tshark 3.0.0 or later
|
|
61
|
+
|
|
62
|
+
### Command Auto Completion
|
|
63
|
+
|
|
64
|
+
After installing PS Banshee, you can enable command auto completion:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
banshee --install-completion
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Restart your shell to complete the installation. You can now use TAB to auto-complete commands.
|
|
71
|
+
|
|
72
|
+
## Usage
|
|
73
|
+
|
|
74
|
+
To see the list of available commands, run:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
banshee -h
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Authorization
|
|
81
|
+
|
|
82
|
+
PS Banshee requires a Recorded Future API key, which can be provided as the `-k` or `--api-key` argument, or set as the `RF_TOKEN` environment variable.
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
banshee -k <RF_TOKEN> <command> <sub-command> <arguments>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Proxies
|
|
89
|
+
|
|
90
|
+
If you are behind a proxy, set the `HTTP_PROXY` and `HTTPS_PROXY` environment variables.
|
|
91
|
+
|
|
92
|
+
To disable SSL verification, use the `-s` flag:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
banshee -s ca rules
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Command Help
|
|
99
|
+
|
|
100
|
+
All commands support the `--help` (`-h`) option:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
banshee -h
|
|
104
|
+
banshee ca --help
|
|
105
|
+
banshee ioc lookup --help
|
|
106
|
+
banshee list bulk-add -h
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Support
|
|
110
|
+
|
|
111
|
+
Submit a [support request](https://support.recordedfuture.com/hc/en-us/requests/new) for help alternatively reach out to [support@recordedfuture.com](mailto:support@recordedfuture.com).
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
**PS Banshee is developed and maintained by the Recorded Future Professional Services Cyber Security Engineers 🚀**
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
##################################### TERMS OF USE ###########################################
|
|
2
|
+
# The following code is provided for demonstration purpose only, and should not be used #
|
|
3
|
+
# without independent verification. Recorded Future makes no representations or warranties, #
|
|
4
|
+
# express, implied, statutory, or otherwise, regarding any aspect of this code or of the #
|
|
5
|
+
# information it may retrieve, and provides it both strictly “as-is” and without assuming #
|
|
6
|
+
# responsibility for any information it may retrieve. Recorded Future shall not be liable #
|
|
7
|
+
# for, and you assume all risk of using, the foregoing. By using this code, Customer #
|
|
8
|
+
# represents that it is solely responsible for having all necessary licenses, permissions, #
|
|
9
|
+
# rights, and/or consents to connect to third party APIs, and that it is solely responsible #
|
|
10
|
+
# for having all necessary licenses, permissions, rights, and/or consents to any data #
|
|
11
|
+
# accessed from any third party API. #
|
|
12
|
+
##############################################################################################
|
|
13
|
+
|
|
14
|
+
"""Base package for PS Banshee."""
|
|
15
|
+
|
|
16
|
+
from ._version import __version__ as version
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#################################### TERMS OF USE ###########################################
|
|
2
|
+
# The following code is provided for demonstration purpose only, and should not be used #
|
|
3
|
+
# without independent verification. Recorded Future makes no representations or warranties, #
|
|
4
|
+
# express, implied, statutory, or otherwise, regarding any aspect of this code or of the #
|
|
5
|
+
# information it may retrieve, and provides it both strictly “as-is” and without assuming #
|
|
6
|
+
# responsibility for any information it may retrieve. Recorded Future shall not be liable #
|
|
7
|
+
# for, and you assume all risk of using, the foregoing. By using this code, Customer #
|
|
8
|
+
# represents that it is solely responsible for having all necessary licenses, permissions, #
|
|
9
|
+
# rights, and/or consents to connect to third party APIs, and that it is solely responsible #
|
|
10
|
+
# for having all necessary licenses, permissions, rights, and/or consents to any data #
|
|
11
|
+
# accessed from any third party API. #
|
|
12
|
+
##############################################################################################
|
|
13
|
+
from importlib.metadata import version
|
|
14
|
+
|
|
15
|
+
__version__ = version('ps-banshee')
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#################################### TERMS OF USE ###########################################
|
|
2
|
+
# The following code is provided for demonstration purpose only, and should not be used #
|
|
3
|
+
# without independent verification. Recorded Future makes no representations or warranties, #
|
|
4
|
+
# express, implied, statutory, or otherwise, regarding any aspect of this code or of the #
|
|
5
|
+
# information it may retrieve, and provides it both strictly “as-is” and without assuming #
|
|
6
|
+
# responsibility for any information it may retrieve. Recorded Future shall not be liable #
|
|
7
|
+
# for, and you assume all risk of using, the foregoing. By using this code, Customer #
|
|
8
|
+
# represents that it is solely responsible for having all necessary licenses, permissions, #
|
|
9
|
+
# rights, and/or consents to connect to third party APIs, and that it is solely responsible #
|
|
10
|
+
# for having all necessary licenses, permissions, rights, and/or consents to any data #
|
|
11
|
+
# accessed from any third party API. #
|
|
12
|
+
##############################################################################################
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from psengine.config import Config
|
|
16
|
+
from pydantic import ValidationError
|
|
17
|
+
|
|
18
|
+
from ._version import __version__
|
|
19
|
+
from .commands.errors import InitConfigError
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def config_init(cmd: str, rf_token: str = None, no_ssl_verify: bool = False) -> Config:
|
|
23
|
+
"""Global configuration for the CLI.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
cmd (str): The command name + sub command, used to generate the app_id,
|
|
27
|
+
typically will be the name one of the banshee commands,
|
|
28
|
+
confor example: 'ca-search', or 'entity-lookup'.
|
|
29
|
+
rf_token (str, optional): The Recorded Future API token.
|
|
30
|
+
no_ssl_verify (bool, optional): Disable SSL verification.
|
|
31
|
+
"""
|
|
32
|
+
# invert no_ssl_verify
|
|
33
|
+
ssl_verify = not no_ssl_verify
|
|
34
|
+
app_id = f'banshee_{cmd}/{__version__}'
|
|
35
|
+
try:
|
|
36
|
+
Config.init(rf_token=rf_token, app_id=app_id, client_ssl_verify=ssl_verify)
|
|
37
|
+
except ValidationError as e:
|
|
38
|
+
if 'rf_token' in e.errors()[0]['loc']:
|
|
39
|
+
raise InitConfigError('Invalid Recorded Future API key') # noqa: B904
|
|
40
|
+
raise InitConfigError(e.errors()[0]['msg']) # noqa: B904
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#################################### TERMS OF USE ###########################################
|
|
2
|
+
# The following code is provided for demonstration purpose only, and should not be used #
|
|
3
|
+
# without independent verification. Recorded Future makes no representations or warranties, #
|
|
4
|
+
# express, implied, statutory, or otherwise, regarding any aspect of this code or of the #
|
|
5
|
+
# information it may retrieve, and provides it both strictly “as-is” and without assuming #
|
|
6
|
+
# responsibility for any information it may retrieve. Recorded Future shall not be liable #
|
|
7
|
+
# for, and you assume all risk of using, the foregoing. By using this code, Customer #
|
|
8
|
+
# represents that it is solely responsible for having all necessary licenses, permissions, #
|
|
9
|
+
# rights, and/or consents to connect to third party APIs, and that it is solely responsible #
|
|
10
|
+
# for having all necessary licenses, permissions, rights, and/or consents to any data #
|
|
11
|
+
# accessed from any third party API. #
|
|
12
|
+
##############################################################################################
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from typer import Typer
|
|
16
|
+
|
|
17
|
+
BRANDING = ':rocket: \033[93mBrought to you by the Cyber Security Engineers at Recorded Future\033[0m :rocket:' # noqa: E501
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def banshee_cmd(app: Typer, help_: str, epilog: str, *args, **kwargs):
|
|
21
|
+
"""Main decorator create banshee commands.
|
|
22
|
+
Under the hood, it adds branding to the help text of the command.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
app (Typer): The Typer app instance
|
|
27
|
+
help_ (str): The help text for the command
|
|
28
|
+
epilog (str): The epilog text for the command
|
|
29
|
+
*args: Additional arguments to pass to the command
|
|
30
|
+
**kwargs: Additional keyword arguments to pass to the command
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Typer: The updated Typer app instance
|
|
34
|
+
"""
|
|
35
|
+
help_ += f'\n\n{BRANDING}'
|
|
36
|
+
return app.command(help=help_, epilog=epilog, *args, **kwargs) # noqa: B026
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
##################################### TERMS OF USE ###########################################
|
|
2
|
+
# The following code is provided for demonstration purpose only, and should not be used #
|
|
3
|
+
# without independent verification. Recorded Future makes no representations or warranties, #
|
|
4
|
+
# express, implied, statutory, or otherwise, regarding any aspect of this code or of the #
|
|
5
|
+
# information it may retrieve, and provides it both strictly “as-is” and without assuming #
|
|
6
|
+
# responsibility for any information it may retrieve. Recorded Future shall not be liable #
|
|
7
|
+
# for, and you assume all risk of using, the foregoing. By using this code, Customer #
|
|
8
|
+
# represents that it is solely responsible for having all necessary licenses, permissions, #
|
|
9
|
+
# rights, and/or consents to connect to third party APIs, and that it is solely responsible #
|
|
10
|
+
# for having all necessary licenses, permissions, rights, and/or consents to any data #
|
|
11
|
+
# accessed from any third party API. #
|
|
12
|
+
##############################################################################################
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
##################################### TERMS OF USE ###########################################
|
|
2
|
+
# The following code is provided for demonstration purpose only, and should not be used #
|
|
3
|
+
# without independent verification. Recorded Future makes no representations or warranties, #
|
|
4
|
+
# express, implied, statutory, or otherwise, regarding any aspect of this code or of the #
|
|
5
|
+
# information it may retrieve, and provides it both strictly “as-is” and without assuming #
|
|
6
|
+
# responsibility for any information it may retrieve. Recorded Future shall not be liable #
|
|
7
|
+
# for, and you assume all risk of using, the foregoing. By using this code, Customer #
|
|
8
|
+
# represents that it is solely responsible for having all necessary licenses, permissions, #
|
|
9
|
+
# rights, and/or consents to connect to third party APIs, and that it is solely responsible #
|
|
10
|
+
# for having all necessary licenses, permissions, rights, and/or consents to any data #
|
|
11
|
+
# accessed from any third party API. #
|
|
12
|
+
##############################################################################################
|
|
13
|
+
|
|
14
|
+
from typing import Annotated, Optional
|
|
15
|
+
|
|
16
|
+
from typer import Option
|
|
17
|
+
|
|
18
|
+
################################
|
|
19
|
+
# Global options / arguments
|
|
20
|
+
################################
|
|
21
|
+
|
|
22
|
+
# How to use: api_key: RF_API_KEY = None
|
|
23
|
+
OPT_RF_API_KEY = Annotated[
|
|
24
|
+
Optional[str],
|
|
25
|
+
Option(
|
|
26
|
+
'--api-key', '-k', help='Recorded Future API Key', envvar='RF_TOKEN', show_default=False
|
|
27
|
+
),
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
# How to use: pretty: PRETTY_PRINT = False
|
|
31
|
+
OPT_PRETTY_PRINT = Annotated[
|
|
32
|
+
bool, Option('--pretty', '-p', help='Pretty print the results in a human readable format')
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
OPT_NO_SSL_VERIFY = Annotated[
|
|
37
|
+
Optional[bool],
|
|
38
|
+
Option(
|
|
39
|
+
'--no-ssl-verify',
|
|
40
|
+
'-s',
|
|
41
|
+
help="""Disable SSL Verification. Useful when using proxies. To
|
|
42
|
+
utilize a proxy set the environment variable HTTP_PROXY or HTTPS_PROXY.""",
|
|
43
|
+
),
|
|
44
|
+
]
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
##################################### TERMS OF USE ###########################################
|
|
2
|
+
# The following code is provided for demonstration purpose only, and should not be used #
|
|
3
|
+
# without independent verification. Recorded Future makes no representations or warranties, #
|
|
4
|
+
# express, implied, statutory, or otherwise, regarding any aspect of this code or of the #
|
|
5
|
+
# information it may retrieve, and provides it both strictly “as-is” and without assuming #
|
|
6
|
+
# responsibility for any information it may retrieve. Recorded Future shall not be liable #
|
|
7
|
+
# for, and you assume all risk of using, the foregoing. By using this code, Customer #
|
|
8
|
+
# represents that it is solely responsible for having all necessary licenses, permissions, #
|
|
9
|
+
# rights, and/or consents to connect to third party APIs, and that it is solely responsible #
|
|
10
|
+
# for having all necessary licenses, permissions, rights, and/or consents to any data #
|
|
11
|
+
# accessed from any third party API. #
|
|
12
|
+
##############################################################################################
|
|
13
|
+
|
|
14
|
+
import re
|
|
15
|
+
import sys
|
|
16
|
+
from typing import Annotated
|
|
17
|
+
|
|
18
|
+
from typer import Argument, BadParameter, Option, Typer
|
|
19
|
+
|
|
20
|
+
from ..branding import banshee_cmd
|
|
21
|
+
from ..legacy_alerts.alert_lookup import lookup_alert
|
|
22
|
+
from ..legacy_alerts.alert_search import search_alerts
|
|
23
|
+
from ..legacy_alerts.alert_update import update_alerts
|
|
24
|
+
from ..legacy_alerts.constants import AlertStatus
|
|
25
|
+
from ..legacy_alerts.rules_search import search_alert_rules
|
|
26
|
+
from .args import OPT_PRETTY_PRINT
|
|
27
|
+
from .epilogs import (
|
|
28
|
+
EPILOG_ALERT_LOOKUP,
|
|
29
|
+
EPILOG_ALERT_RULES_SEARCH,
|
|
30
|
+
EPILOG_ALERT_SEARCH,
|
|
31
|
+
EPILOG_ALERT_UPDATE,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
CMD_NAME = 'ca'
|
|
35
|
+
CMD_HELP = 'Search and lookup Classic Alerts'
|
|
36
|
+
CMD_RICH_HELP = 'Recorded Future Classic Alerts'
|
|
37
|
+
|
|
38
|
+
app = Typer(no_args_is_help=True)
|
|
39
|
+
|
|
40
|
+
ALERT_ID_INVALID_MSG = "Alert ID '{}' is not valid. Alert ID should be at least 6 characters long." # noqa: E501
|
|
41
|
+
|
|
42
|
+
###################################
|
|
43
|
+
# Callbacks
|
|
44
|
+
###################################
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def validate_alert_id(alert_id: str):
|
|
48
|
+
# if value is less than 6 char long
|
|
49
|
+
if len(alert_id) < 6:
|
|
50
|
+
raise BadParameter(ALERT_ID_INVALID_MSG.format(alert_id))
|
|
51
|
+
|
|
52
|
+
return alert_id
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def parse_alert_ids_input(value: list[str]):
|
|
56
|
+
if not value:
|
|
57
|
+
raise BadParameter('No Alert IDs supplied')
|
|
58
|
+
|
|
59
|
+
alert_ids = value
|
|
60
|
+
if isinstance(value, str):
|
|
61
|
+
alert_ids = [x for x in re.split(r'[\s]+', value) if x]
|
|
62
|
+
|
|
63
|
+
if not len(alert_ids):
|
|
64
|
+
raise BadParameter('No Alert IDs provided')
|
|
65
|
+
|
|
66
|
+
# Now check that each ID is valid
|
|
67
|
+
for alert_id in alert_ids:
|
|
68
|
+
validate_alert_id(alert_id)
|
|
69
|
+
|
|
70
|
+
return alert_ids
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def parse_triggered(value: str):
|
|
74
|
+
if not value.startswith('[') and not value.startswith('('):
|
|
75
|
+
value = f'-{value.strip()}'
|
|
76
|
+
|
|
77
|
+
return value
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
###################################
|
|
81
|
+
# Commands
|
|
82
|
+
###################################
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@banshee_cmd(app=app, help_='Lookup a single Classic Alert', epilog=EPILOG_ALERT_LOOKUP)
|
|
86
|
+
def lookup(
|
|
87
|
+
alert_id: Annotated[
|
|
88
|
+
str, Argument(help='Alert ID to lookup', callback=validate_alert_id, show_default=False)
|
|
89
|
+
],
|
|
90
|
+
pretty: OPT_PRETTY_PRINT = False,
|
|
91
|
+
):
|
|
92
|
+
lookup_alert(id_=alert_id, pretty=pretty)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@banshee_cmd(app=app, help_='Search for Classic Alerts', epilog=EPILOG_ALERT_SEARCH)
|
|
96
|
+
def search(
|
|
97
|
+
triggered: Annotated[
|
|
98
|
+
str,
|
|
99
|
+
Option(
|
|
100
|
+
'--triggered',
|
|
101
|
+
'-t',
|
|
102
|
+
callback=parse_triggered,
|
|
103
|
+
help='Filter on triggered time, e.g. 1d; 12h; [2024-08-01, 2024-08-14]; [2024-09-23 12:03:58.000, 2024-09-23 12:03:58.567)', # noqa: E501
|
|
104
|
+
show_default=True,
|
|
105
|
+
),
|
|
106
|
+
] = '1d',
|
|
107
|
+
alert_rules: Annotated[
|
|
108
|
+
list[str],
|
|
109
|
+
Option('--rule', '-r', help='Filter by an alert rule name (freetext)', show_default=False),
|
|
110
|
+
] = None,
|
|
111
|
+
status: Annotated[
|
|
112
|
+
AlertStatus, Option('-s', '--status', help='Filter by alert status', show_default=False)
|
|
113
|
+
] = None,
|
|
114
|
+
pretty: OPT_PRETTY_PRINT = False,
|
|
115
|
+
):
|
|
116
|
+
search_alerts(
|
|
117
|
+
triggered=triggered,
|
|
118
|
+
alert_rules=alert_rules,
|
|
119
|
+
status=status,
|
|
120
|
+
pretty=pretty,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@banshee_cmd(app=app, help_='Search Classic Alert rules', epilog=EPILOG_ALERT_RULES_SEARCH)
|
|
125
|
+
def rules(
|
|
126
|
+
freetext: Annotated[str, Argument(help='Freetext to search in alert rules')] = None,
|
|
127
|
+
pretty: OPT_PRETTY_PRINT = False,
|
|
128
|
+
):
|
|
129
|
+
search_alert_rules(pretty=pretty, freetext=freetext)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@banshee_cmd(app=app, help_='Update a classic alert', epilog=EPILOG_ALERT_UPDATE)
|
|
133
|
+
def update(
|
|
134
|
+
alert_ids: list[str] = Argument( # noqa: B008
|
|
135
|
+
... if sys.stdin.isatty() else None, # noqa: B008
|
|
136
|
+
show_default=False,
|
|
137
|
+
help='One or more whitespace separated Alert ID',
|
|
138
|
+
),
|
|
139
|
+
status: Annotated[
|
|
140
|
+
AlertStatus, Option('-s', '--status', help='New alert status', show_default=False)
|
|
141
|
+
] = None,
|
|
142
|
+
note: Annotated[str, Option('-n', '--note', help='Add a text note', show_default=False)] = None,
|
|
143
|
+
note_append: Annotated[
|
|
144
|
+
bool,
|
|
145
|
+
Option(
|
|
146
|
+
'-A',
|
|
147
|
+
'--append',
|
|
148
|
+
help='Append to the existing text note, instead of overwriting it.',
|
|
149
|
+
show_default=True,
|
|
150
|
+
),
|
|
151
|
+
] = False,
|
|
152
|
+
assignee: Annotated[
|
|
153
|
+
str,
|
|
154
|
+
Option(
|
|
155
|
+
'--assignee',
|
|
156
|
+
'-a',
|
|
157
|
+
help='New user to assign the alert(s) to. Accepts uhash or email address of the user, for example: uhash:3aXZxdkM12; analyst@acme.com', # noqa: E501
|
|
158
|
+
show_default=False,
|
|
159
|
+
),
|
|
160
|
+
] = None,
|
|
161
|
+
):
|
|
162
|
+
if alert_ids is None:
|
|
163
|
+
alert_ids = sys.stdin.read()
|
|
164
|
+
|
|
165
|
+
parsed_ids = parse_alert_ids_input(alert_ids)
|
|
166
|
+
|
|
167
|
+
if status is None and note is None and assignee is None:
|
|
168
|
+
raise BadParameter('At least one of --status, --note or --assignee must be privded.')
|
|
169
|
+
|
|
170
|
+
if note_append and note is None:
|
|
171
|
+
raise BadParameter('note argument must be provided when append option is set')
|
|
172
|
+
|
|
173
|
+
update_alerts(
|
|
174
|
+
alert_ids=parsed_ids, status=status, note=note, note_append=note_append, assignee=assignee
|
|
175
|
+
)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
##################################### TERMS OF USE ###########################################
|
|
2
|
+
# The following code is provided for demonstration purpose only, and should not be used #
|
|
3
|
+
# without independent verification. Recorded Future makes no representations or warranties, #
|
|
4
|
+
# express, implied, statutory, or otherwise, regarding any aspect of this code or of the #
|
|
5
|
+
# information it may retrieve, and provides it both strictly “as-is” and without assuming #
|
|
6
|
+
# responsibility for any information it may retrieve. Recorded Future shall not be liable #
|
|
7
|
+
# for, and you assume all risk of using, the foregoing. By using this code, Customer #
|
|
8
|
+
# represents that it is solely responsible for having all necessary licenses, permissions, #
|
|
9
|
+
# rights, and/or consents to connect to third party APIs, and that it is solely responsible #
|
|
10
|
+
# for having all necessary licenses, permissions, rights, and/or consents to any data #
|
|
11
|
+
# accessed from any third party API. #
|
|
12
|
+
##############################################################################################
|
|
13
|
+
|
|
14
|
+
from typing import Annotated
|
|
15
|
+
|
|
16
|
+
from typer import Argument, Option, Typer
|
|
17
|
+
|
|
18
|
+
from ..branding import banshee_cmd
|
|
19
|
+
from ..entity_match import EntityType, entity_lookup, entity_search
|
|
20
|
+
from .args import OPT_PRETTY_PRINT
|
|
21
|
+
from .epilogs import EPILOG_ENTITY_LOOKUP, EPILOG_ENTITY_SEARCH
|
|
22
|
+
|
|
23
|
+
CMD_NAME = 'entity'
|
|
24
|
+
CMD_HELP = 'Search and lookup entities'
|
|
25
|
+
CMD_RICH_HELP = 'Entity Match'
|
|
26
|
+
|
|
27
|
+
app = Typer(no_args_is_help=True)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@banshee_cmd(app=app, help_='Lookup an entity by its ID', epilog=EPILOG_ENTITY_LOOKUP)
|
|
31
|
+
def lookup(
|
|
32
|
+
entity_id: str = Argument(show_default=False, help='ID of the entity to lookup'),
|
|
33
|
+
pretty: OPT_PRETTY_PRINT = False,
|
|
34
|
+
):
|
|
35
|
+
entity_lookup(entity_id=entity_id, pretty=pretty)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@banshee_cmd(
|
|
39
|
+
app=app, help_='Search entities by name and optically by type', epilog=EPILOG_ENTITY_SEARCH
|
|
40
|
+
)
|
|
41
|
+
def search(
|
|
42
|
+
name: str = Argument(show_default=False, help='Name of the entity to search for'),
|
|
43
|
+
type_: Annotated[
|
|
44
|
+
list[EntityType],
|
|
45
|
+
Option(
|
|
46
|
+
'-t', '--type', help='One or more type of the entity to search for', show_default=False
|
|
47
|
+
),
|
|
48
|
+
] = None,
|
|
49
|
+
limit: Annotated[
|
|
50
|
+
int, Option('-l', '--limit', help='Limit number of results', min=1, max=100)
|
|
51
|
+
] = 100,
|
|
52
|
+
pretty: OPT_PRETTY_PRINT = False,
|
|
53
|
+
):
|
|
54
|
+
entity_search(name=name, type_=type_, limit=limit, pretty=pretty)
|