Compare commits
No commits in common. "master" and "v1.4.0" have entirely different histories.
|
@ -10,5 +10,3 @@
|
|||
# Locally genenerated mtz
|
||||
/*.mtz
|
||||
|
||||
|
||||
ansible/inventory.txt
|
||||
|
|
47
Dockerfile
|
@ -1,47 +0,0 @@
|
|||
# Install MISP-maltego remote transform as docker image.
|
||||
#
|
||||
# DO NOT USE THIS UNLESS YOU REALLY KNOW YOU NEED THIS
|
||||
# - Most people usually probably want to use the local transforms
|
||||
# - Others the 'ATT&CK - MISP' form the Transform Hub
|
||||
#
|
||||
# To build: "docker build MISP-maltego -t misp-maltego"
|
||||
# To run: "docker run -p 8080:8080/tcp misp-maltego" if you want to run and enable portforwarding
|
||||
# To stop: "docker ps" and "docker stop <instance_name>"
|
||||
#
|
||||
# Then configure your iTDS server
|
||||
# - to create all the transforms and seeds and point to your docker.
|
||||
# - export the objects, icons and machines to a mtz and associate to the seed
|
||||
# Paired Configurations:
|
||||
# - in Maltego > Export Config, and select
|
||||
# -- Entities > MISP
|
||||
# -- Icons > MISP + intelligence icons
|
||||
# -- Machines
|
||||
# Save as "paired_config.mtz", upload on TDS
|
||||
|
||||
|
||||
# TODO
|
||||
# - run the service with TLS, but that makes stuff more complex to automate
|
||||
|
||||
FROM python:3
|
||||
|
||||
RUN pip install PyMISP canari
|
||||
|
||||
# keep this for normal install
|
||||
RUN pip install MISP-maltego
|
||||
|
||||
# use this for install from your own local git repo
|
||||
# - first run "python setup.py sdist" to build the package
|
||||
# - change the version number below
|
||||
#COPY dist/MISP_maltego-1.4.1.tar.gz /usr/local/src/
|
||||
#RUN pip install /usr/local/src/MISP_maltego-1.4.1.tar.gz
|
||||
|
||||
ENV LC_ALL='C.UTF-8'
|
||||
ENV LANG='C.UTF-8'
|
||||
ENV PLUME_ROOT='/var/plume'
|
||||
RUN addgroup nobody
|
||||
RUN canari install-plume --accept-defaults
|
||||
RUN canari load-plume-package MISP_maltego --plume-dir /var/plume --accept-defaults
|
||||
|
||||
EXPOSE 8080/tcp
|
||||
|
||||
CMD ["/etc/init.d/plume", "start-docker"]
|
120
README.md
|
@ -1,13 +1,8 @@
|
|||
|
||||
|
||||
![logo](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/logo.png)
|
||||
|
||||
# Quick start guide
|
||||
This is a [Maltego](https://www.paterva.com/web7/) [MISP](https://www.misp-project.org) integration tool allowing you to view (read-only) data from a MISP instance.
|
||||
It also allows browsing through the [MITRE ATT&CK](https://attack.mitre.org/) entities. (no MISP connection needed)
|
||||
|
||||
This user guide should help you through the [installation](#installation) of **MISP-Maltego**, and should guide you how to use it through a few [use-cases](#use-cases). As this is a collaborative project, do not hesitate to propose changes, write other use-cases or raise [feature requests](https://github.com/MISP/MISP-maltego/issues) for missing features.
|
||||
It also allows browsing through the [MITRE ATT&CK](https://attack.mitre.org/) entities.
|
||||
|
||||
## Quick start
|
||||
Currently supported MISP elements are : Event, Attribute, Object (incl relations), Tag, Taxonomy, Galaxy (incl relations).
|
||||
|
||||
Once installed you can start by creating a `MISPEvent` entity, then load the Machine `EventToAll` or the transform `EventToAttributes`.
|
||||
|
@ -15,121 +10,24 @@ Once installed you can start by creating a `MISPEvent` entity, then load the Mac
|
|||
Alternatively initiate a transform on an existing Maltego entity.
|
||||
The currently supported entities are: `AS`, `DNSName`, `Domain`, `EmailAddress`, `File`, `Hash`, `IPv4Address`, `NSRecord`, `Person`, `PhoneNumber`, `URL`, `Website`
|
||||
|
||||
For MITRE ATT&CK pivoting, feel free to start with an `Attack Technique`, `Software`, `Threat Actor`, or `MISPGalaxy`. Create your entity, enter a keyword such as `%gama%` and use the `Search in MISP` transform to get started.
|
||||
|
||||
## Installation
|
||||
### Transform Hub
|
||||
Open the Transform Hub, locate **ATT&CK - MISP** and press the **Install** button.
|
||||
|
||||
Your transforms will go through Paterva's servers and ours. See the [Transform Hub Disclaimer](https://github.com/MISP/MISP-maltego/blob/master/TRANSFORM_HUB_DISCLAIMER.md) for more information.
|
||||
|
||||
- ATT&CK transforms do not require a MISP server or API key to be configured.
|
||||
- MISP transforms requires your MISP server to be reachable from the internet! To enter your MISP server URL and key click **Details** on the Transform Hub item and then **Settings** at the bottom right.
|
||||
|
||||
### Local Transform Installation
|
||||
If you trust nobody, or just want to connect to your local MISP server you can install everything as local transforms.
|
||||
|
||||
These instructions have been tested on Ubuntu 18.04 LTS, but should be similar on other systems.
|
||||
1. Download and install [Maltego](https://www.paterva.com/web7/downloads.php)
|
||||
2. Install using pip: `sudo pip3 install MISP-maltego`
|
||||
3. Generate the Maltego bundle: `canari create-profile MISP_maltego`
|
||||
4. Import this bundle in Maltego.
|
||||
1. Open Maltego
|
||||
2. Click on the home button (Maltego icon, top-left corner).
|
||||
3. Click on 'Import'
|
||||
4. Click on 'Import Configuration'.
|
||||
5. Load the `MISP_maltego.mtz` file and follow the prompts.
|
||||
5. Edit `$HOME/.canari/MISP_maltego.conf` and enter your `misp_url` and `misp_key`
|
||||
|
||||
## Custom Entities
|
||||
MISP-Maltego tries to use as much as possible the default Paterva entities, or the most popular from the community. It however comes with a few custom entities:
|
||||
* **MISPEvent**: A representation of an *Event* on MISP, containing *Attributes* (MISP) / *Entities* (Maltego)
|
||||
* **MISPObject**: A way to group associated attributes in a structured way.
|
||||
* **MISPGalaxy**: A *Tag* containing much more metadata. Please refer to the [MISP Galaxy](https://github.com/MISP/misp-galaxy) for more information. **MITRE ATT&CK** is for example completely available through MISPGalaxy entities (see use-cases for an example)
|
||||
* **Attack Technique**: Attack patterns or techniques, see [MITRE ATT&CK](https://attack.mitre.org/techniques/enterprise/) for more information.
|
||||
* **Threat Actor**: Threat actor or intrusion sets.
|
||||
* **Software**: Software is a generic term for custom or commercial code, operating system utilities, open-source software, or other tools used to conduct behavior modeled in ATT&CK.
|
||||
|
||||
# Use Cases
|
||||
## Transform on existing data
|
||||
In this use case we will be using already existing entities and will initiate a transform using MISP. The currently supported entities are: `AS`, `DNSName`, `Domain`, `EmailAddress`, `File`, `Hash`, `IPv4Address`, `NSRecord`, `Person`, `PhoneNumber`, `URL`, `Website`.
|
||||
|
||||
Example:
|
||||
* create an entity `domain` with the value `1dnscontrol.com`.
|
||||
* right click and choose *Local Transforms* > *MISP_maltego* > *Domain To Event*
|
||||
![animated screenshot](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/img/usecase1-transform.gif)
|
||||
* continue loading transforms on the *MISP Event*
|
||||
|
||||
## Transform from MISP Event ID
|
||||
While MISP already has a graphing capability we would like to use the power of Maltego to look at the data and expand the work.
|
||||
* Create a *MISP Event* and give it an `event id`, or `UUID`
|
||||
* One **manual** way is to right click and choose *Local Transforms* > *MISP_maltego* > *Event To Attributes*
|
||||
* Notice the event is transformed to *Attributes*, *Objects*, *Tags*, *Galaxies* and related *MISP Events*
|
||||
* You can now further transform on an *Object* > *Object To Attributes* and see the content of the object
|
||||
![machine transforms](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/img/usecase2-manual.gif)
|
||||
* Alternatively you can also use the **Maltego Machine** to speed up things.
|
||||
* Click on the *MISP Event* and in the left menu choose *Event to All* in the *Machines* section.
|
||||
![machine transforms](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/img/usecase2-machine-menu.png)
|
||||
* Notice that the whole event, objects and such will get expanded with data from your MISP instance.
|
||||
![animated screenshot](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/img/usecase2-machine.gif)
|
||||
* You can now further transform on any data.
|
||||
|
||||
## Which data is already in MISP?
|
||||
If you use MISP as central database it can be quite convenient to know which data is present in MISP, and which data is not; especially after using a number of other transforms.
|
||||
To permit this MISP-Maltego will always add a green bookmark to all the data that is present in MISP.
|
||||
![green bookmark](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/img/usecase3-bookmark.png)
|
||||
|
||||
|
||||
## Searching in MISP using keywords
|
||||
As with the MISP attribute search through the MISP Web UI you can use `%` wildcards at the front and end to specify the substring. You might be tempted to always use `%keyword%`, but bare in mind how databases indexes work; a search for `keyword%` will always be much faster than `%keyword`.
|
||||
![Search in MISP](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/img/search_in_misp.gif)
|
||||
|
||||
|
||||
## Transform from Galaxy
|
||||
Galaxies are actually tags with much more contextual data. Examples are threat actors, malware families, but also the whole MITRE ATT&CK data is available as Galaxy. All this data comes from the [MISP Galaxy](https://github.com/MISP/misp-galaxy) repository. Today the integration is not done using a MISP server because of limitations in MISP.
|
||||
You might encounter Galaxies when transforming from MISP Events or Attributes. An alternative use-case is by starting immediately from a Galaxy.
|
||||
There are 3 ways to manually create a good Galaxy Entity.
|
||||
1. Using a find capability (see below)
|
||||
2. Create the Galaxy and set the UUID. You can find the UUIDs in the [MISP Galaxy](https://github.com/MISP/misp-galaxy) repository.
|
||||
3. Create the Galaxy with the right tag name; for example: `misp-galaxy:`
|
||||
|
||||
To use the magical search feature:
|
||||
* Create a *MISP Galaxy* and type the keyword as value.
|
||||
* Run the *Galaxy To Relation* transform, notice the search results will appear as connected entities
|
||||
* Remove the non-relevant entities, including the your search-keyword
|
||||
![animated galaxy search](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/img/usecase4-galaxy-search.gif)
|
||||
|
||||
## Visualize MITRE ATT&CK
|
||||
Apply the same steps for MITRE ATT&CK browsing:
|
||||
|
||||
![animated ATTACK](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/img/usecase5-attack.gif)
|
||||
|
||||
You might end up with such a graph:
|
||||
|
||||
![ATTACK](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/img/usecase5-attack.png)
|
||||
|
||||
## Visualise common ATT&CK patterns
|
||||
Having access to a large amount of Threat information through MISP Threat Sharing communities gives you outstanding opportunities to aggregate this information and take the process of trying to understand how all this data fits together telling a broader story to the next level. We are transforming technical data or indicators of compromise (IOCs) into cyber threat intelligence. This is where the analytical challenge begins. [[read more](https://www.misp-project.org/2019/10/27/visualising_common_patterns_attack.html)]
|
||||
|
||||
|
||||
## Massively large MISP event? Think before you transform.
|
||||
In some communities such as the [COVID-19 MISP](https://www.misp-project.org/covid-19-misp/) some events contain tens of thousands attributes. Loading all the attributes from these events might not be a good idea if you do not have Maltego XL.
|
||||
You can see the amount of attributes and objects in the Event properties, so you can think before you click:
|
||||
|
||||
![object count](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/img/event_count_attr1.png)![attribute count](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/img/event_count_attr2.png)
|
||||
## Installation and User Guide:
|
||||
Installation is fairly easy by using `pip`, just read the steps in the [documentation](https://github.com/MISP/MISP-maltego/blob/master/doc/README.md).
|
||||
|
||||
The [User Guide](https://github.com/MISP/MISP-maltego/blob/master/doc/README.md#use-cases) gives some example use-cases.
|
||||
|
||||
|
||||
## Screenshot
|
||||
![Screenshot](https://github.com/MISP/MISP-maltego/blob/master/doc/screenshot.png)
|
||||
|
||||
![ATT&CK](https://github.com/MISP/MISP-maltego/blob/master/doc/attack.jpg)
|
||||
|
||||
|
||||
## License
|
||||
This software is licensed under [GNU Affero General Public License version 3](http://www.gnu.org/licenses/agpl-3.0.html)
|
||||
|
||||
* Copyright (C) 2018-2024 Christophe Vandeplas
|
||||
* Copyright (C) 2018 Christophe Vandeplas
|
||||
|
||||
Note: Before being rewritten from scratch this project was maintained by Emmanuel Bouillon. The code is available in the `v1` branch.
|
||||
|
||||
The logo is CC-BY-SA and was designed by Françoise Penninckx
|
||||
|
||||
The icons in the intelligence-icons folder are from [intelligence-icons](https://github.com/MISP/intelligence-icons) licensed CC-BY-SA - Françoise Penninckx, Brett Jordan
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
For security issues, please refer to the instructions in the main MISP repository: https://github.com/MISP/MISP/
|
|
@ -1,21 +0,0 @@
|
|||
# MISP Maltego Remote Transform Disclaimer
|
||||
**When using the MISP Maltego transforms using the Transform Hub (not the locally installed version) you need to know you are are sending data, including your MISP URL and API key to 3rd parties.**
|
||||
|
||||
The public Transform Distribution Server (TDS) is located on the Internet and is free for all to use. It’s a convenient way to immediately start writing remote transforms. Since this server is located on Paterva’s infrastructure data (entity, and settings) will be flowing from the Maltego GUI to this server. Paterva states they DO NOT store the details of your transforms (entities, MISP URL, API KEY).
|
||||
|
||||
Finally it will flow further to a server managed by the MISP-maltego developer(s), where the transform code runs and for MISP transforms connects to YOUR server. We DO NOT store or look at the details of your transforms (entities, MISP URL, API KEY). As you can see in the code (open source), this data is only used live in memory to provide the transform functionality. The only reasons why we would be seeing this data is by accident; while troubleshooting or by unintentional mis-configuration.
|
||||
|
||||
We do keep standard HTTP logs for troubleshooting and anonymous statistics, although these contain the IP addresses of Paterva's TDS server, and not yours.
|
||||
|
||||
**DO NOT use these Transform Hub transforms if you do not agree or if this is in violation with your MISP community.**
|
||||
|
||||
**If so, feel free to use the MISP-Maltego transforms locally, where all the code runs on your own system. Installation instructions can be found [here](https://github.com/MISP/MISP-maltego/blob/master/README.md#installation).**
|
||||
|
||||
You can also run this on your own iTDS server if you have the license. Have a look at the [Dockerfile](https://github.com/MISP/MISP-maltego/blob/master/Dockerfile) for more info.
|
||||
|
||||
|
||||
## More info
|
||||
For more information please read Paterva's and Canari's documentation:
|
||||
* [http://www.canariproject.com/en/latest/canari.quickstart.html#making-transforms-remote](http://www.canariproject.com/en/latest/canari.quickstart.html#making-transforms-remote)
|
||||
* [https://docs.maltego.com/support/solutions/articles/15000020198-what-is-itds-](https://docs.maltego.com/support/solutions/articles/15000020198-what-is-itds-)
|
||||
* [https://www.paterva.com/buy/maltego-servers.php](https://www.paterva.com/buy/maltego-servers.php)
|
|
@ -1,10 +0,0 @@
|
|||
This folder is meant to contain ansible automation scripts to install the MISP-maltego server.
|
||||
Users normally do not need to use this, except if you're using a private transform server.
|
||||
|
||||
|
||||
Paired Configurations:
|
||||
- in Maltego > Export Config, and select
|
||||
-- Entities > MISP
|
||||
-- Icons > MISP + intelligence icons
|
||||
-- Machines
|
||||
Save as "paired_config.mtz", upload on TDS
|
|
@ -1,41 +0,0 @@
|
|||
server {
|
||||
# dummy server for let's encrypt
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
root /var/www/html;
|
||||
server_name _;
|
||||
try_files $uri @redirect;
|
||||
|
||||
location @redirect {
|
||||
return 302 https://github.com/MISP/MISP-maltego;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
# true reverse proxy for plume
|
||||
listen 443 ssl default_server;
|
||||
listen [::]:443 ssl default_server;
|
||||
ssl_certificate /etc/letsencrypt/live/misp-maltego.misp-project.org/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/misp-maltego.misp-project.org/privkey.pem;
|
||||
|
||||
root /var/www/html;
|
||||
server_name _;
|
||||
|
||||
location /munin/ {
|
||||
alias /var/cache/munin/www/;
|
||||
index index.html;
|
||||
allow 127.0.0.1;
|
||||
deny all;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_pass http://127.0.0.1:8080;
|
||||
proxy_intercept_errors on;
|
||||
error_page 404 = @redirect; # redirect to the github when page not found
|
||||
}
|
||||
location @redirect {
|
||||
return 302 https://github.com/MISP/MISP-maltego;
|
||||
}
|
||||
}
|
|
@ -1,255 +0,0 @@
|
|||
---
|
||||
# Install MISP-maltego remote transform using ansible.
|
||||
#
|
||||
# DO NOT USE THIS UNLESS YOU REALLY KNOW YOU NEED THIS
|
||||
# - Most people usually probably want to use the local transforms
|
||||
# - Others the 'ATT&CK - MISP' from the Transform Hub
|
||||
#
|
||||
# First install your ubuntu system,
|
||||
# Then run ansible-playbook -i inventory.txt plume.yaml
|
||||
#
|
||||
# Then configure your iTDS server
|
||||
# - to create all the transforms and seeds and point to your docker.
|
||||
# - export the objects, icons and machines to a mtz and associate to the seed
|
||||
# Paired Configurations:
|
||||
# - in Maltego > Export Config, and select
|
||||
# -- Entities > MISP
|
||||
# -- Icons > MISP + intelligence icons
|
||||
# -- Machines
|
||||
# Save as "paired_config.mtz", upload on TDS
|
||||
|
||||
- hosts: all
|
||||
become: yes
|
||||
vars:
|
||||
misp_maltego_version: 1.4.4 # TODO change this !!!
|
||||
host_locale: en_US.UTF-8
|
||||
host_locale_dict: {
|
||||
LANG: "{{ host_locale }}",
|
||||
LC_COLLATE: "{{ host_locale }}",
|
||||
LC_CTYPE: "{{ host_locale }}",
|
||||
LC_MESSAGES: "{{ host_locale }}",
|
||||
LC_MONETARY: "{{ host_locale }}",
|
||||
LC_NUMERIC: "{{ host_locale }}",
|
||||
LC_TIME: "{{ host_locale }}",
|
||||
LC_ALL: "{{ host_locale }}",
|
||||
}
|
||||
|
||||
tasks:
|
||||
- name: install python3-pip
|
||||
package:
|
||||
name: python3-pip
|
||||
state: present
|
||||
- name: install python libs
|
||||
pip:
|
||||
executable: /usr/bin/pip3
|
||||
name: ['canari', 'pymisp']
|
||||
state: latest
|
||||
|
||||
# NGINX reverse proxy
|
||||
# ######
|
||||
- name: install nginx
|
||||
package:
|
||||
name: nginx
|
||||
state: present
|
||||
|
||||
- name: letsencrypt certbot ppa
|
||||
apt_repository:
|
||||
repo: ppa:certbot/certbot
|
||||
|
||||
- name: letsencrypt certbot install
|
||||
package:
|
||||
name: ['certbot', 'python-certbot-nginx']
|
||||
state: present
|
||||
|
||||
# FIXME generate the cert automagically, while answering the questions
|
||||
# creates: /etc/letsencrypt/live/misp-maltego.misp-project.org/privkey.pem
|
||||
# Requires input:
|
||||
# - email address
|
||||
# - agree terms
|
||||
# - no sharing email with EFF
|
||||
|
||||
- name: nginx disable default config
|
||||
file:
|
||||
path: /etc/nginx/sites-enabled/default
|
||||
state: absent
|
||||
|
||||
- name: nginx copy config
|
||||
copy:
|
||||
src: nginx.conf
|
||||
dest: /etc/nginx/sites-available/plume
|
||||
notify: restart nginx
|
||||
|
||||
- name: nginx enable plume config
|
||||
file:
|
||||
src: /etc/nginx/sites-available/plume
|
||||
dest: /etc/nginx/sites-enabled/plume
|
||||
state: link
|
||||
notify: restart nginx
|
||||
|
||||
- name: letsencrypt auto-renew
|
||||
cron:
|
||||
name: "letsencrypt auto-renew SSL certificate"
|
||||
special_time: daily
|
||||
job: "/usr/sbin/certbot -q renew"
|
||||
|
||||
# PLUME
|
||||
#######
|
||||
- name: create nobody group - needed by plume
|
||||
group:
|
||||
name: nobody
|
||||
state: present
|
||||
|
||||
- name: install canari plume
|
||||
shell:
|
||||
cmd: canari install-plume --accept-defaults
|
||||
creates: /var/plume/canari.conf
|
||||
environment:
|
||||
LC_ALL: 'C.UTF-8'
|
||||
LANG: 'C.UTF-8'
|
||||
|
||||
- name: Start service plume at boot
|
||||
file:
|
||||
src: /etc/init.d/plume
|
||||
dest: /etc/rc{{item}}.d/S20plume
|
||||
state: link
|
||||
with_items:
|
||||
- 3
|
||||
- 4
|
||||
- 5
|
||||
# LATER migrate to systemd service
|
||||
|
||||
|
||||
# use the public pip package
|
||||
- name: install MISP-maltego
|
||||
pip:
|
||||
executable: pip3
|
||||
name: ['MISP-maltego']
|
||||
state: latest
|
||||
notify: restart plume
|
||||
|
||||
# use local git repo instead, useful for development
|
||||
# - name: bundle MISP-maltego
|
||||
# delegate_to: 127.0.0.1
|
||||
# command:
|
||||
# cmd: python3 setup.py sdist
|
||||
# chdir: ../
|
||||
# become: no
|
||||
# - name: copy MISP-maltego
|
||||
# copy:
|
||||
# src: ../dist/MISP_maltego-{{misp_maltego_version}}.tar.gz
|
||||
# dest: /usr/local/src/
|
||||
# - name: install MISP-maltego
|
||||
# pip:
|
||||
# executable: /usr/bin/pip3
|
||||
# name: file:///usr/local/src/MISP_maltego-{{misp_maltego_version}}.tar.gz
|
||||
# state: forcereinstall
|
||||
# environment: "{{host_locale_dict}}"
|
||||
# notify: restart plume
|
||||
# - name: remove local MISP-maltego bundle
|
||||
# delegate_to: 127.0.0.1
|
||||
# file:
|
||||
# path: ../dist/MISP_maltego-{{misp_maltego_version}}.tar.gz
|
||||
# state: absent
|
||||
# become: no
|
||||
|
||||
- name: load plume package
|
||||
command:
|
||||
cmd: canari load-plume-package MISP_maltego --plume-dir /var/plume --accept-defaults
|
||||
chdir: /var/plume
|
||||
creates: /var/plume/MISP_maltego.conf
|
||||
environment:
|
||||
LC_ALL: 'C.UTF-8'
|
||||
LANG: 'C.UTF-8'
|
||||
PLUME_ROOT: '/var/plume'
|
||||
notify: restart plume
|
||||
|
||||
- name: Start service plume, if not started
|
||||
service:
|
||||
name: plume
|
||||
state: started
|
||||
|
||||
# MONITORING
|
||||
#############
|
||||
- name: install munin
|
||||
package:
|
||||
name: ['munin', 'munin-node', 'munin-plugins-extra']
|
||||
|
||||
- name: munin - enabling plugins
|
||||
file:
|
||||
state: link
|
||||
src: '/usr/share/munin/plugins/{{item}}'
|
||||
dest: '/etc/munin/plugins/{{item}}'
|
||||
loop:
|
||||
- nginx_request
|
||||
- nginx_status
|
||||
notify: restart munin-node
|
||||
|
||||
- name: munin - service active and running
|
||||
service:
|
||||
name: munin-node
|
||||
state: started
|
||||
enabled: yes
|
||||
|
||||
|
||||
# FIREWALLING
|
||||
#############
|
||||
- name: firewall logging
|
||||
ufw:
|
||||
logging: 'low'
|
||||
|
||||
- name: firewall inbound rate limited
|
||||
ufw:
|
||||
rule: limit
|
||||
port: '2245' # ssh
|
||||
proto: tcp
|
||||
direction: in
|
||||
|
||||
- name: firewall inbound
|
||||
ufw:
|
||||
rule: allow
|
||||
port: "{{item}}"
|
||||
proto: tcp
|
||||
direction: in
|
||||
loop:
|
||||
- '80' # nginx
|
||||
- '443' # nginx plume
|
||||
- '25324' # monitoring
|
||||
|
||||
- name: firewall outbound
|
||||
ufw:
|
||||
rule: allow
|
||||
port: "{{ item.port }}"
|
||||
proto: "{{ item.proto }}"
|
||||
direction: out
|
||||
loop:
|
||||
- { port: '53', proto: 'udp'}
|
||||
- { port: '123', proto: 'udp'}
|
||||
- { port: '53', proto: 'tcp'}
|
||||
- { port: '80', proto: 'tcp'}
|
||||
- { port: '443', proto: 'tcp'}
|
||||
- { port: '32526', proto: 'tcp'} # waagent
|
||||
|
||||
- name: firewall default rule
|
||||
ufw:
|
||||
state: enabled
|
||||
default: deny
|
||||
direction: '{{ item }}'
|
||||
loop:
|
||||
- incoming
|
||||
- outgoing
|
||||
|
||||
handlers:
|
||||
- name: restart plume
|
||||
service:
|
||||
name: plume
|
||||
state: restarted
|
||||
|
||||
- name: restart nginx
|
||||
service:
|
||||
name: nginx
|
||||
state: restarted
|
||||
|
||||
- name: restart munin-node
|
||||
service:
|
||||
name: munin-node
|
||||
state: restarted
|
|
@ -1,59 +0,0 @@
|
|||
---
|
||||
# Install MISP-maltego remote transform using ansible.
|
||||
|
||||
- hosts: all
|
||||
become: yes
|
||||
vars:
|
||||
misp_maltego_version: 1.4.5 # TODO change this !!!
|
||||
host_locale: en_US.UTF-8
|
||||
host_locale_dict: {
|
||||
LANG: "{{ host_locale }}",
|
||||
LC_COLLATE: "{{ host_locale }}",
|
||||
LC_CTYPE: "{{ host_locale }}",
|
||||
LC_MESSAGES: "{{ host_locale }}",
|
||||
LC_MONETARY: "{{ host_locale }}",
|
||||
LC_NUMERIC: "{{ host_locale }}",
|
||||
LC_TIME: "{{ host_locale }}",
|
||||
LC_ALL: "{{ host_locale }}",
|
||||
}
|
||||
|
||||
tasks:
|
||||
# use the public pip package
|
||||
- name: install MISP-maltego
|
||||
pip:
|
||||
executable: pip3
|
||||
name: ['MISP-maltego']
|
||||
state: latest
|
||||
notify: restart plume
|
||||
|
||||
# use local git repo instead, useful for development
|
||||
# - name: bundle MISP-maltego
|
||||
# delegate_to: 127.0.0.1
|
||||
# command:
|
||||
# cmd: python3 setup.py sdist
|
||||
# chdir: ../
|
||||
# become: no
|
||||
# - name: copy MISP-maltego
|
||||
# copy:
|
||||
# src: ../dist/MISP_maltego-{{misp_maltego_version}}.tar.gz
|
||||
# dest: /usr/local/src/
|
||||
# - name: install MISP-maltego
|
||||
# pip:
|
||||
# executable: /usr/bin/pip3
|
||||
# name: file:///usr/local/src/MISP_maltego-{{misp_maltego_version}}.tar.gz
|
||||
# state: forcereinstall
|
||||
# environment: "{{host_locale_dict}}"
|
||||
# notify: restart plume
|
||||
|
||||
# - name: remove local MISP-maltego bundle
|
||||
# delegate_to: 127.0.0.1
|
||||
# file:
|
||||
# path: ../dist/MISP_maltego-{{misp_maltego_version}}.tar.gz
|
||||
# state: absent
|
||||
# become: no
|
||||
|
||||
handlers:
|
||||
- name: restart plume
|
||||
service:
|
||||
name: plume
|
||||
state: restarted
|
|
@ -0,0 +1,78 @@
|
|||
# MISP-Maltego User Guide
|
||||
|
||||
This user guide should help you through the installation of **MISP-Maltego**, and should guide you how to use it through a few use-cases. As this is a collaborative project, do not hesitate to propose changes, write other use-cases or raise [feature requests](https://github.com/MISP/MISP-maltego/issues) for missing features.
|
||||
|
||||
## Installation
|
||||
These instructions have been tested on Ubuntu 18.04 LTS, but should be similar on other systems.
|
||||
1. Download and install [Maltego](https://www.paterva.com/web7/downloads.php)
|
||||
2. Install using pip: `sudo pip3 install MISP-maltego`
|
||||
3. Generate the Maltego bundle: `canari create-profile MISP_maltego`
|
||||
4. Import this bundle in Maltego.
|
||||
1. Open Maltego
|
||||
2. Click on the home button (Maltego icon, top-left corner).
|
||||
3. Click on 'Import'
|
||||
4. Click on 'Import Configuration'.
|
||||
5. Load the `MISP_maltego.mtz` file and follow the prompts.
|
||||
5. Edit `$HOME/.canari/MISP_maltego.conf` and enter your `misp_url` and `misp_key`
|
||||
|
||||
## Custom Entities
|
||||
MISP-Maltego tries to use as much as possible the default Paterva entities, or the most popular from the community. It however comes with a few custom entities:
|
||||
* **MISPEvent**: A representation of an *Event* on MISP, containing *Attributes* (MISP) / *Entities* (Maltego)
|
||||
* **MISPObject**: A way to group associated attributes in a structured way.
|
||||
* **MISPGalaxy**: A *Tag* containing much more metadata. Please refer to the [MISP Galaxy](https://github.com/MISP/misp-galaxy) for more information. **MITRE ATT&CK** is for example completely available through MISPGalaxy entities (see use-cases for an example)
|
||||
* **Attack Technique**: Attack patterns or techniques, see [MITRE ATT&CK](https://attack.mitre.org/techniques/enterprise/) for more information.
|
||||
* **Threat Actor**: Threat actor or intrusion sets.
|
||||
* **Software**: Software is a generic term for custom or commercial code, operating system utilities, open-source software, or other tools used to conduct behavior modeled in ATT&CK.
|
||||
|
||||
# Use Cases
|
||||
## Transform on existing data
|
||||
In this use case we will be using already existing entities and will initiate a transform using MISP. The currently supported entities are: `AS`, `DNSName`, `Domain`, `EmailAddress`, `File`, `Hash`, `IPv4Address`, `NSRecord`, `Person`, `PhoneNumber`, `URL`, `Website`.
|
||||
|
||||
Example:
|
||||
* create an entity `domain` with the value `1dnscontrol.com`.
|
||||
* right click and choose *Local Transforms* > *MISP_maltego* > *Domain To Event*
|
||||
![animated screenshot](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/img/usecase1-transform.gif)
|
||||
* continue loading transforms on the *MISP Event*
|
||||
|
||||
## Transform from MISP Event ID
|
||||
While MISP already has a graphing capability we would like to use the power of Maltego to look at the data and expand the work.
|
||||
* Create a *MISP Event* and give it an `event id`, or `UUID`
|
||||
* One **manual** way is to right click and choose *Local Transforms* > *MISP_maltego* > *Event To Attributes*
|
||||
* Notice the event is transformed to *Attributes*, *Objects*, *Tags*, *Galaxies* and related *MISP Events*
|
||||
* You can now further transform on an *Object* > *Object To Attributes* and see the content of the object
|
||||
![machine transforms](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/img/usecase2-manual.gif)
|
||||
* Alternatively you can also use the **Maltego Machine** to speed up things.
|
||||
* Click on the *MISP Event* and in the left menu choose *Event to All* in the *Machines* section.
|
||||
![machine transforms](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/img/usecase2-machine-menu.png)
|
||||
* Notice that the whole event, objects and such will get expanded with data from your MISP instance.
|
||||
![animated screenshot](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/img/usecase2-machine.gif)
|
||||
* You can now further transform on any data.
|
||||
|
||||
## Which data is already in MISP?
|
||||
If you use MISP as central database it can be quite convenient to know which data is present in MISP, and which data is not; especially after using a number of other transforms.
|
||||
To permit this MISP-Maltego will always add a green bookmark to all the data that is present in MISP.
|
||||
![green bookmark](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/img/usecase3-bookmark.png)
|
||||
|
||||
|
||||
## Transform from Galaxy
|
||||
Galaxies are actually tags with much more contextual data. Examples are threat actors, malware families, but also the whole MITRE ATT&CK data is available as Galaxy. All this data comes from the [MISP Galaxy](https://github.com/MISP/misp-galaxy) repository. Today the integration is not done using a MISP server because of limitations in MISP.
|
||||
You might encounter Galaxies when transforming from MISP Events or Attributes. An alternative use-case is by starting immediately from a Galaxy.
|
||||
There are 3 ways to manually create a good Galaxy Entity.
|
||||
1. Using a find capability (see below)
|
||||
2. Create the Galaxy and set the UUID. You can find the UUIDs in the [MISP Galaxy](https://github.com/MISP/misp-galaxy) repository.
|
||||
3. Create the Galaxy with the right tag name; for example: `misp-galaxy:`
|
||||
|
||||
To use the magical search feature:
|
||||
* Create a *MISP Galaxy* and type the keyword as value.
|
||||
* Run the *Galaxy To Relation* transform, notice the search results will appear as connected entities
|
||||
* Remove the non-relevant entities, including the your search-keyword
|
||||
![animated galaxy search](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/img/usecase4-galaxy-search.gif)
|
||||
|
||||
## Visualize MITRE ATT&CK
|
||||
Apply the same steps for MITRE ATT&CK browsing:
|
||||
|
||||
![animated ATTACK](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/img/usecase5-attack.gif)
|
||||
|
||||
You might end up with such a graph:
|
||||
|
||||
![ATTACK](https://raw.githubusercontent.com/MISP/MISP-maltego/master/doc/img/usecase5-attack.png)
|
After Width: | Height: | Size: 43 KiB |
BIN
doc/attack.png
Before Width: | Height: | Size: 121 KiB |
Before Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 184 KiB |
Before Width: | Height: | Size: 192 KiB After Width: | Height: | Size: 192 KiB |
Before Width: | Height: | Size: 333 KiB After Width: | Height: | Size: 333 KiB |
Before Width: | Height: | Size: 262 KiB After Width: | Height: | Size: 262 KiB |
BIN
doc/logo.png
Before Width: | Height: | Size: 4.0 KiB |
105
doc/logo.svg
|
@ -1,105 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1"
|
||||
id="svg108" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" sodipodi:docname="misp-logo.svg" inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="-8.6 13.1 128 128"
|
||||
enable-background="new -8.6 13.1 128 128" xml:space="preserve">
|
||||
<sodipodi:namedview fit-margin-top="0" inkscape:pageshadow="2" inkscape:pageopacity="0.0" inkscape:current-layer="layer1" inkscape:window-maximized="1" inkscape:window-y="27" inkscape:window-x="0" inkscape:window-height="1025" inkscape:window-width="1920" fit-margin-right="0" fit-margin-bottom="0" inkscape:document-units="mm" showgrid="false" inkscape:zoom="0.35" borderopacity="1.0" pagecolor="#ffffff" inkscape:cy="96.511905" bordercolor="#666666" fit-margin-left="0" inkscape:cx="-155.06677" id="base">
|
||||
</sodipodi:namedview>
|
||||
<g>
|
||||
<path fill="#C5411E" d="M73.1,104.6c-2.2-2-2.2-3.7-0.8-6.2c0-0.4-0.1-0.7-0.1-1c-0.3-0.3-0.6-0.7-0.9-1.1
|
||||
c-0.6-1.1-0.9-1.9-1.1-3.1c-0.1-0.4,0-1.6,0-1.6l-13.7,8l2.4-9.3c-2.7-0.7-5.7-2.1-5.7-4.7L53,83.4c-4.2-4-8-7.5-12.3-11.6
|
||||
c3.4-2.2,6.2-3.8,8.8-5.8c1.4-1,2-1.5,3.2-2.6V63c-0.3-5.7,4.7-8,6.2-8.4c0.6-1,0.6-1.3,1.1-3.8c0.7-3.9,0.7-7.6,0-11H44.9
|
||||
c0.7,1.7,1.1,3.5,1.1,5.6c0.2,6.6-3.7,10.8-8.9,14c-7,4.3-5.1,4.6-10.4-1.5c-2.4-2.8-4.3-6.3-5.4-9.8c-1-3-0.8-5.8,0.4-8.3h-3.8
|
||||
l8.3-19.6c-1.9,0.5-3.8,1.2-5.7,2.2C11,26.9,5.8,34.8,5.6,45.6c-0.2,8.4,3.8,15,8.9,21.1c1.2,1.4,2.3,2.8,3.2,3.9
|
||||
c-5.3,4.1-10.6,7.5-15,11.7c-7.9,7.5-10.8,17-8.5,27.7c3,14,12.4,22.1,26.1,24.8c4.8,1,13.9,0.9,13.9,0.9l0-15.2
|
||||
c-3.3,0.6-6.9,0.4-10.7-0.8c-7.9-2.4-12.9-9.3-12.9-21.3c0.1-4.9,5.4-10.2,12.1-14.6c5.2-3.4,5.2-3.4,9.6,1
|
||||
c5.7,5.9,11.4,11.8,17.2,17.5c1.8,1.7,2,3,0.7,5.2c-1.6,2.7-3.3,5-5.1,6.9l2.2,3.6l3.9-6.5h29.3C78.1,109.2,75.6,106.9,73.1,104.6z
|
||||
"/>
|
||||
</g>
|
||||
<g>
|
||||
<g id="g316" transform="translate(385.579,529.5928)">
|
||||
<g>
|
||||
<path fill="#2FA1DB" d="M-270.5-457v20.3c0,2.5-1.3,5.1-4.3,5.1h-0.4l1.4,5.6l-9.5-5.6h-24.9c-1.4,0-2.8-0.6-3.9-1.5
|
||||
c-0.5-0.4-1-1-1.3-1.5v0c-0.4-0.7-0.6-1.4-0.6-2.1v-0.9h32.6c3.3,0,5-2.6,5-5.4v-18.3h1.7C-271.8-461.4-270.5-459.5-270.5-457z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="g320-4" transform="translate(349.7253,569.1839)">
|
||||
<g>
|
||||
<path fill="#2FA1DB" d="M-250.4-513.7h-37.9c-1,0-2.1,0.3-3.1,0.8c-2.2,1.1-4.1,3.1-4.1,5.1v22.9c0,2.6,3.3,4.5,6.4,4.8l-2,7.7
|
||||
l13-7.6h27.7c3.3,0,6.4-2,6.4-4.9v-22.9C-244-510.7-247.1-513.7-250.4-513.7z M-280.6-494.9c-0.5,0.4-1.2,0.6-1.9,0.6
|
||||
c-0.3,0-0.6,0-0.9-0.1c-1.4-0.4-2.5-1.7-2.5-3.3c0-1.9,1.5-3.4,3.4-3.4c0.8,0,1.6,0.3,2.2,0.8c0.7,0.6,1.2,1.4,1.2,2.4
|
||||
c0,0.1,0,0.2,0,0.3C-279.1-496.5-279.7-495.5-280.6-494.9z M-266.3-497.7c0,1.1-0.6,2.1-1.4,2.7c-0.6,0.4-1.3,0.7-2,0.7
|
||||
c-1.9,0-3.4-1.5-3.4-3.4s1.5-3.4,3.4-3.4C-267.8-501.2-266.3-499.6-266.3-497.7C-266.3-497.7-266.3-497.7-266.3-497.7z
|
||||
M-256.9-494.3c-1.9,0-3.4-1.5-3.4-3.4s1.5-3.4,3.4-3.4c1.9,0,3.4,1.5,3.4,3.4S-255-494.3-256.9-494.3z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g id="path1078" inkscape:connector-curvature="0">
|
||||
<polygon fill="#5F6062" points="35.5,112.9 42.6,112.9 47.3,120.6 52,112.9 59.1,112.9 59.1,134.2 52.1,134.2 52.1,123.8
|
||||
47.3,131.3 47.2,131.3 42.4,123.8 42.4,134.2 35.5,134.2 "/>
|
||||
</g>
|
||||
|
||||
<g id="path1080" inkscape:export-ydpi="100" inkscape:export-xdpi="100" inkscape:export-filename="/home/adulau/misp.png" inkscape:connector-curvature="0">
|
||||
<rect x="62.5" y="112.9" fill="#5F6062" width="7" height="21.3"/>
|
||||
</g>
|
||||
<g id="g1084">
|
||||
<g id="g1090" transform="translate(297.5875,384.2569)">
|
||||
<path id="path1092" inkscape:connector-curvature="0" fill="#5F6062" d="M-226.3-253.6l3.7-4.5c2.3,1.7,4.9,2.5,7.3,2.5
|
||||
c1.3,0,1.8-0.3,1.8-0.9v-0.1c0-0.6-0.7-0.9-2.9-1.4c-4.7-1-8.8-2.3-8.8-6.7v-0.1c0-4,3.1-7.1,8.9-7.1c4,0,7,1,9.4,2.9l-3.4,4.7
|
||||
c-2-1.4-4.3-2.1-6.3-2.1c-1,0-1.5,0.4-1.5,0.9v0.1c0,0.6,0.6,0.9,2.8,1.3c5.4,1,8.9,2.5,8.9,6.8v0.1c0,4.4-3.6,7.1-9.2,7.1
|
||||
C-219.8-250.1-223.6-251.3-226.3-253.6L-226.3-253.6z"/>
|
||||
</g>
|
||||
<g id="g1094" transform="translate(340.0289,418.4302)">
|
||||
<path id="path1096" inkscape:connector-curvature="0" fill="#5F6062" d="M-237.2-305.6h-9.4v21.2h7v-6h2.3c5.7,0,9.5-2.7,9.5-7.7
|
||||
v-0.1C-227.8-303.1-231.6-305.6-237.2-305.6z M-234.7-297.6c0,1.5-1.2,2.3-3,2.3h-1.9v-4.7h1.9
|
||||
C-235.9-300-234.7-299.2-234.7-297.6L-234.7-297.6z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#C5411E" d="M75.2,32.9c-0.4-0.3-0.4-0.6-0.1-1c0.9-1.6,1.7-3.3,2.6-4.9c0.1-0.2,0.2-0.4,0.3-0.7c-0.7,0-1.4,0-2,0
|
||||
c-0.6-0.1-0.9,0.2-1.2,0.7c-0.6,1.2-1.2,2.4-1.8,3.5c-1.1-1.1-2.2-2.1-3.4-3.2c0.6-0.4,1.1-0.7,1.5-1c0.9-0.6,1.6-1.5,1.8-2.6
|
||||
c0.3-1.8-0.2-3.3-1.6-4.4c-1.6-1.2-3.3-1.3-5.1-0.5c-1.6,0.8-2.5,2.1-2.5,4c0,1.4,0.6,2.6,1.5,3.6c0.2,0.2,0.4,0.5,0.5,0.7
|
||||
c-0.9,0.7-1.8,1.3-2.6,2c-1.3,1.3-1.8,2.9-1.5,4.7c0.5,2.4,2.1,3.8,4.4,4.2c2.5,0.5,4.7,0.1,6.3-2.1c0.3-0.4,0.5-0.8,0.8-1.2
|
||||
c1.2,1.1,2.3,2.2,3.4,3.4c0.6-0.6,1.2-1.2,1.9-2C77.5,35,76.4,33.9,75.2,32.9z M67.1,21c0.7-0.6,1.5-0.6,2.3-0.2
|
||||
c0.8,0.4,1.2,1.1,1.2,2c0,1.1-0.6,1.8-1.5,2.4c-1.2,0.7-0.9,0.8-1.8-0.3c-0.4-0.5-0.7-1.1-0.9-1.7C66.1,22.4,66.4,21.6,67.1,21z
|
||||
M71.3,33.4c-1.1,1.9-2.7,2.7-4.5,2.1c-1.3-0.4-2.2-1.6-2.2-3.6c0-0.8,0.9-1.7,2.1-2.5c0.9-0.6,0.9-0.6,1.6,0.2c1,1,1.9,2,2.9,3
|
||||
C71.5,32.8,71.5,33,71.3,33.4z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#C5411E" d="M98.1,32c-0.6,3.5-5.3,6.4-9.9,6.1c-5-0.3-8.9-4.5-9-9.7c-0.1-5.1,3.6-9.4,8.7-10
|
||||
c4.4-0.5,9.5,2.5,10.2,6.2c-0.9,0-1.9,0-2.8,0c-0.2,0-0.4-0.2-0.5-0.4c-1.9-2.8-5-3.9-8-2.8c-2.9,1-4.9,4-4.7,7.3
|
||||
c0.3,4.3,3.6,7.3,7.8,6.8c2-0.2,3.6-1.3,4.7-2.9c0.3-0.4,0.5-0.5,1-0.5C96.5,32,97.3,32,98.1,32z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#C5411E" d="M39.7,37.5c-2.5-6.1-4.9-12.2-7.4-18.4c-0.1-0.2-0.4-0.4-0.6-0.4c-0.6-0.1-1.1,0-1.7,0
|
||||
c-0.5,0-0.7,0.2-0.8,0.6c-1.6,4-3.3,8.1-5,12.1c-0.9,2.1-1.7,4.2-2.6,6.4c1,0,1.8,0,2.7,0c0.5,0,0.6-0.2,0.8-0.6
|
||||
c0.4-1.2,0.9-2.3,1.3-3.5c0.1-0.4,0.4-0.5,0.8-0.5c2.4,0,4.7,0,7.1,0c0.4,0,0.6,0.1,0.8,0.5c0.5,1.2,0.9,2.4,1.4,3.5
|
||||
c0.1,0.2,0.2,0.5,0.4,0.5c1,0,2,0,3,0C39.7,37.6,39.7,37.5,39.7,37.5z M27.4,30.8c1.1-2.8,2.1-5.6,3.1-8.4c0.1,0,0.1,0,0.2,0
|
||||
c1.1,2.8,2.1,5.5,3.2,8.4H27.4z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#C5411E" d="M113.8,37.8c-1.3,0-2.4,0-3.5,0c-0.2,0-0.4-0.3-0.6-0.5c-2.1-2.5-4.2-5.1-6.3-7.7
|
||||
c-0.1-0.2-0.3-0.3-0.5-0.6v8.7h-3c0-0.2,0-0.5,0-0.7c0-5.9,0-11.7,0-17.6c0-0.6,0.2-0.8,0.8-0.7c0.5,0,0.9,0,1.4,0
|
||||
c0.9,0,0.9,0,0.9,0.9v7.9c0.1,0,0.1,0,0.2,0.1c0.1-0.2,0.3-0.4,0.4-0.5c2-2.6,4-5.2,6-7.8c0.3-0.4,0.6-0.5,1-0.5
|
||||
c0.8,0,1.6,0,2.5,0c-0.2,0.3-0.4,0.5-0.5,0.7c-2.2,2.8-4.3,5.5-6.5,8.3c-0.3,0.4-0.3,0.7,0,1.1c2.4,2.8,4.8,5.6,7.2,8.4
|
||||
C113.4,37.3,113.5,37.5,113.8,37.8z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#C5411E" d="M49.1,19.5c0,0.6,0,1.2,0,1.9c-1.3,0-2.4,0-3.6,0c-0.6,0-0.8,0.2-0.8,0.8c0,5,0,9.9,0,14.9
|
||||
c0,0.6-0.2,0.8-0.8,0.8c-0.6,0-1.1,0-1.7,0c-0.5,0-0.6-0.2-0.6-0.6c0-3,0-6,0-9c0-2,0-4,0-6.1c0-0.6-0.1-0.8-0.7-0.8c-1,0-2,0-3,0
|
||||
c-0.5,0-0.7-0.1-0.6-0.6c0.1-0.7-0.2-1.5,0.2-1.9c0.3-0.3,1.2-0.1,1.9-0.1c3,0,6,0,9,0C49,18.7,49.2,18.9,49.1,19.5z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#C5411E" d="M62,19.4c0,0.6,0,1.2,0,1.9h-1.5c-0.8,0-1.5,0-2.3,0c-0.6,0-0.6,0.3-0.6,0.7c0,3.6,0,7.2,0,10.8
|
||||
c0,1.4,0,2.9,0,4.3c0,0.4-0.1,0.6-0.6,0.6c-0.8,0-1.6,0-2.4,0v-0.8c0-4.1,0-8.2,0-12.3c0-1.1-0.1-2.2-0.1-3.3
|
||||
c-1.1,0-2.1-0.1-3.2-0.1c-0.2,0-0.4,0-0.6,0c-0.4,0-0.5-0.2-0.5-0.5c0-0.7,0.1-1.4,0.1-2c0.6,0,1.3-0.1,1.9-0.1c3,0,6.1,0,9.1,0
|
||||
C61.8,18.7,62.1,18.8,62,19.4z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 7.7 KiB |
8
setup.py
|
@ -2,19 +2,15 @@
|
|||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
with open("README.md", "r") as fh:
|
||||
long_description = fh.read()
|
||||
|
||||
setup(
|
||||
name='MISP_maltego',
|
||||
author='Christophe Vandeplas',
|
||||
# also update version in util.py
|
||||
version='1.4.6',
|
||||
version='1.4.0',
|
||||
author_email='christophe@vandeplas.com',
|
||||
maintainer='Christophe Vandeplas',
|
||||
url='https://github.com/MISP/MISP-maltego',
|
||||
description='Maltego transform for interacting with a MISP Threat Sharing community and with MITRE ATT&CK.',
|
||||
long_description=long_description,
|
||||
license='AGPLv3',
|
||||
packages=find_packages('src'),
|
||||
package_dir={'': 'src'},
|
||||
|
@ -36,7 +32,7 @@ setup(
|
|||
python_requires='>=3.5',
|
||||
install_requires=[
|
||||
'canari>=3.3.10,<4',
|
||||
'PyMISP>=2.4.127'
|
||||
'PyMISP>=2.4.114'
|
||||
],
|
||||
dependency_links=[
|
||||
# custom links for the install_requires
|
||||
|
|
|
@ -8,4 +8,3 @@ misp_debug = False
|
|||
check_updates = True
|
||||
|
||||
[MISP_maltego.remote]
|
||||
|
||||
|
|
|
@ -3,20 +3,14 @@ machine("misp.MISPEventToAll",
|
|||
author:"Christophe Vandeplas",
|
||||
description: "Automatically expands MISP Objects to their attributes") {
|
||||
start {
|
||||
paths {
|
||||
path {
|
||||
run("MISP_maltego.EventToAttributes")
|
||||
paths {
|
||||
path {
|
||||
run("MISP_maltego.AttributeToEvent")
|
||||
}
|
||||
paths {
|
||||
path {
|
||||
run("MISP_maltego.ObjectToAttributes")
|
||||
}
|
||||
}
|
||||
// run("MISP_maltego.AttributeToEvent")
|
||||
}
|
||||
path {
|
||||
run("MISP_maltego.EventToTags")
|
||||
run("MISP_maltego.GalaxyToRelations")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,14 +4,11 @@ machine("misp.MISPEventToAttributes",
|
|||
description: "Also automatically expands MISP Objects to their attributes") {
|
||||
start {
|
||||
paths {
|
||||
run("MISP_maltego.EventToAttributes")
|
||||
path {
|
||||
run("MISP_maltego.EventToObjects")
|
||||
run("MISP_maltego.ObjectToAttributes")
|
||||
}
|
||||
path {
|
||||
run("MISP_maltego.EventToAttributes")
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
from canari.maltego.entities import Unknown, Hashtag
|
||||
from canari.maltego.entities import Unknown
|
||||
from canari.maltego.transform import Transform
|
||||
from MISP_maltego.transforms.common.entities import MISPGalaxy
|
||||
from MISP_maltego.transforms.common.util import check_update, MISPConnection, event_to_entity, get_attribute_in_event, get_attribute_in_object, attribute_to_entity, get_entity_property, search_galaxy_cluster, galaxycluster_to_entity
|
||||
from canari.maltego.message import LinkDirection, Bookmark
|
||||
# from canari.framework import EnableDebugWindow
|
||||
from MISP_maltego.transforms.common.util import check_update, get_misp_connection, event_to_entity, object_to_entity, get_attribute_in_event, get_attribute_in_object, attribute_to_entity, get_entity_property
|
||||
from canari.maltego.message import LinkDirection
|
||||
|
||||
__author__ = 'Christophe Vandeplas'
|
||||
__copyright__ = 'Copyright 2018, MISP_maltego Project'
|
||||
|
@ -15,108 +15,46 @@ __email__ = 'christophe@vandeplas.com'
|
|||
__status__ = 'Development'
|
||||
|
||||
|
||||
class SearchInMISP(Transform):
|
||||
"""Use % at the front/end for wildcard search"""
|
||||
# @EnableDebugWindow
|
||||
class AttributeInMISP(Transform):
|
||||
"""Green bookmark if known in MISP"""
|
||||
display_name = 'in MISP?'
|
||||
input_type = Unknown
|
||||
display_name = 'Search in MISP'
|
||||
description = "Use % at the front/end for wildcard search"
|
||||
remote = True
|
||||
|
||||
def do_transform(self, request, response, config):
|
||||
response += check_update(config)
|
||||
link_label = 'Search result'
|
||||
|
||||
if 'properties.mispevent' in request.entity.fields:
|
||||
conn = MISPConnection(config, request.parameters)
|
||||
# if event_id
|
||||
maltego_misp_attribute = request.entity
|
||||
# skip MISP Events (value = int)
|
||||
try:
|
||||
if request.entity.value == '0':
|
||||
int(maltego_misp_attribute.value)
|
||||
return response
|
||||
eventid = int(request.entity.value)
|
||||
events_json = conn.misp.search(controller='events', eventid=eventid, with_attachments=False)
|
||||
for e in events_json:
|
||||
response += event_to_entity(e, link_label=link_label, link_direction=LinkDirection.OutputToInput)
|
||||
return response
|
||||
except ValueError:
|
||||
except Exception:
|
||||
pass
|
||||
# if event_info string as value
|
||||
events_json = conn.misp.search(controller='events', eventinfo=request.entity.value, with_attachments=False)
|
||||
for e in events_json:
|
||||
response += event_to_entity(e, link_label=link_label, link_direction=LinkDirection.OutputToInput)
|
||||
return response
|
||||
|
||||
# From galaxy or Hashtag
|
||||
if 'properties.mispgalaxy' in request.entity.fields or 'properties.temp' in request.entity.fields or 'twitter.hashtag' in request.entity.fields:
|
||||
if request.entity.value == '-':
|
||||
return response
|
||||
# First search in galaxies
|
||||
keyword = get_entity_property(request.entity, 'Temp')
|
||||
if not keyword:
|
||||
keyword = request.entity.value
|
||||
# assume the user is searching for a cluster based on a substring.
|
||||
# Search in the list for those that match and return galaxy entities'
|
||||
potential_clusters = search_galaxy_cluster(keyword)
|
||||
# LATER check if duplicates are possible
|
||||
if potential_clusters:
|
||||
for potential_cluster in potential_clusters:
|
||||
new_entity = galaxycluster_to_entity(potential_cluster, link_label=link_label)
|
||||
# LATER support the type_filter - unfortunately this is not possible, we need Canari to tell us the original entity type
|
||||
if isinstance(new_entity, MISPGalaxy):
|
||||
response += new_entity
|
||||
|
||||
# from Hashtag search also in tags
|
||||
if 'properties.temp' in request.entity.fields or 'twitter.hashtag' in request.entity.fields:
|
||||
keyword = get_entity_property(request.entity, 'Temp')
|
||||
if not keyword:
|
||||
keyword = request.entity.value
|
||||
conn = MISPConnection(config, request.parameters)
|
||||
result = conn.misp.direct_call('tags/search', {'name': keyword})
|
||||
for t in result:
|
||||
# skip misp-galaxies as we have processed them earlier on
|
||||
if t['Tag']['name'].startswith('misp-galaxy'):
|
||||
continue
|
||||
# In this case we do not filter away those we add as notes, as people might want to pivot on it explicitly.
|
||||
response += Hashtag(t['Tag']['name'], link_label=link_label, bookmark=Bookmark.Green)
|
||||
|
||||
return response
|
||||
|
||||
# for all other normal entities
|
||||
conn = MISPConnection(config, request.parameters)
|
||||
|
||||
misp = get_misp_connection(config)
|
||||
events_json = misp.search(controller='events', value=maltego_misp_attribute.value, with_attachments=False)
|
||||
# we need to do really rebuild the Entity from scratch as request.entity is of type Unknown
|
||||
# TODO First try to build the object, then only attributes (for those that are not in object, or for all?)
|
||||
# TODO check for the right version of MISP before, it needs to be 2.4.127 or higher.
|
||||
# obj_json = conn.misp.search(controller='objects', value=request.entity.value, with_attachments=False)
|
||||
# for o in obj_json:
|
||||
# for item in attribute_to_entity(attr, only_self=True, link_label=link_label):
|
||||
# response += item
|
||||
# # find the value as object, and return the object
|
||||
# if 'Object' in e['Event']:
|
||||
# for o in e['Event']['Object']:
|
||||
# if get_attribute_in_object(o, attribute_value=request.entity.value, substring=True).get('value'):
|
||||
# response += conn.object_to_entity(o, link_label=link_label)
|
||||
|
||||
attr_json = conn.misp.search(controller='attributes', value=request.entity.value, with_attachments=False)
|
||||
for a in attr_json['Attribute']:
|
||||
for item in attribute_to_entity(a, only_self=True, link_label=link_label):
|
||||
for e in events_json:
|
||||
attr = get_attribute_in_event(e, maltego_misp_attribute.value)
|
||||
if attr:
|
||||
for item in attribute_to_entity(attr, only_self=True):
|
||||
response += item
|
||||
|
||||
return response
|
||||
|
||||
|
||||
# placeholder for https://github.com/MISP/MISP-maltego/issues/11
|
||||
# waiting for support of CIDR search through the REST API
|
||||
# @EnableDebugWindow
|
||||
# class NetblockToAttributes(Transform):
|
||||
# display_name = 'to MISP Attributes'
|
||||
# input_type = Netblock
|
||||
# remote = True
|
||||
|
||||
# def do_transform(self, request, response, config):
|
||||
# maltego_misp_attribute = request.entity
|
||||
# misp = get_misp_connection(config, request.parameters)
|
||||
# misp = get_misp_connection(config)
|
||||
# import ipaddress
|
||||
# ip_start, ip_end = maltego_misp_attribute.value.split('-')
|
||||
# # LATER make this work with IPv4 and IPv6
|
||||
# # FIXME make this work with IPv4 and IPv6
|
||||
# # automagically detect the different CIDRs
|
||||
# cidrs = ipaddress.summarize_address_range(ipaddress.IPv4Address(ip_start), ipaddress.IPv4Address(ip_end))
|
||||
# for cidr in cidrs:
|
||||
|
@ -126,10 +64,10 @@ class SearchInMISP(Transform):
|
|||
# return response
|
||||
|
||||
|
||||
# @EnableDebugWindow
|
||||
class AttributeToEvent(Transform):
|
||||
display_name = 'to MISP Event'
|
||||
input_type = Unknown
|
||||
display_name = 'To MISP Events'
|
||||
remote = True
|
||||
|
||||
def do_transform(self, request, response, config):
|
||||
response += check_update(config)
|
||||
|
@ -143,37 +81,28 @@ class AttributeToEvent(Transform):
|
|||
# placeholder for https://github.com/MISP/MISP-maltego/issues/11
|
||||
pass
|
||||
|
||||
conn = MISPConnection(config, request.parameters)
|
||||
misp = get_misp_connection(config)
|
||||
# from Galaxy
|
||||
if 'properties.mispgalaxy' in request.entity.fields:
|
||||
tag_name = get_entity_property(request.entity, 'tag_name')
|
||||
if not tag_name:
|
||||
tag_name = request.entity.value
|
||||
events_json = conn.misp.search(controller='events', tags=tag_name, with_attachments=False)
|
||||
events_json = misp.search(controller='events', tags=tag_name, with_attachments=False)
|
||||
for e in events_json:
|
||||
response += event_to_entity(e, link_direction=LinkDirection.OutputToInput)
|
||||
return response
|
||||
# from Object
|
||||
elif 'properties.mispobject' in request.entity.fields:
|
||||
if request.entity.fields.get('event_id'):
|
||||
events_json = conn.misp.search(controller='events', eventid=request.entity.fields.get('event_id').value, with_attachments=False)
|
||||
events_json = misp.search(controller='events', eventid=request.entity.fields.get('event_id').value, with_attachments=False)
|
||||
for e in events_json:
|
||||
response += event_to_entity(e, link_direction=LinkDirection.OutputToInput)
|
||||
return response
|
||||
else:
|
||||
return response
|
||||
# from Hashtag
|
||||
elif 'properties.temp' in request.entity.fields or 'twitter.hashtag' in request.entity.fields:
|
||||
tag_name = get_entity_property(request.entity, 'Temp')
|
||||
if not tag_name:
|
||||
tag_name = request.entity.value
|
||||
events_json = conn.misp.search_index(tags=tag_name)
|
||||
for e in events_json:
|
||||
response += event_to_entity({'Event': e}, link_direction=LinkDirection.OutputToInput)
|
||||
return response
|
||||
# standard Entities (normal attributes)
|
||||
else:
|
||||
events_json = conn.misp.search(controller='events', value=request.entity.value, with_attachments=False)
|
||||
events_json = misp.search(controller='events', value=request.entity.value, with_attachments=False)
|
||||
|
||||
# return the MISPEvent or MISPObject of the attribute
|
||||
for e in events_json:
|
||||
|
@ -185,6 +114,6 @@ class AttributeToEvent(Transform):
|
|||
if 'Object' in e['Event']:
|
||||
for o in e['Event']['Object']:
|
||||
if get_attribute_in_object(o, attribute_value=request.entity.value).get('value'):
|
||||
response += conn.object_to_entity(o, link_direction=LinkDirection.OutputToInput)
|
||||
response += object_to_entity(o, link_direction=LinkDirection.OutputToInput)
|
||||
|
||||
return response
|
||||
|
|
|
@ -32,8 +32,6 @@ class MISPEvent(Entity):
|
|||
# threat_level = EnumEntityField('type.enum', choices=['Undefined', 'Low', 'Medium', 'High'], display_name='Threat Level')
|
||||
# analysis = EnumEntityField('type.enum', choices=['Initial', 'Ongoing', 'Completed'])
|
||||
# org = StringEntityField('type.str', display_name='Organisation')
|
||||
count_attributes = IntegerEntityField('count_attributes', display_name="# attributes", matching_rule=MatchingRule.Loose)
|
||||
count_objects = IntegerEntityField('count_objects', display_name="# objects", matching_rule=MatchingRule.Loose)
|
||||
|
||||
|
||||
class MISPObject(Entity):
|
||||
|
|
|
@ -1,764 +0,0 @@
|
|||
from canari.maltego.entities import Hash, Domain, IPv4Address, URL, DNSName, AS, Website, NSRecord, PhoneNumber, EmailAddress, File, Location, Company, Alias, Port, Twitter
|
||||
from MISP_maltego.transforms.common.entities import ThreatActor, Software, AttackTechnique
|
||||
|
||||
mapping_misp_to_maltego = {
|
||||
'AS': [AS],
|
||||
'domain': [Domain, NSRecord, Website, DNSName],
|
||||
'email-dst': [EmailAddress],
|
||||
'email-src': [EmailAddress],
|
||||
'filename': [File],
|
||||
'hostname': [Website, NSRecord, Domain, DNSName],
|
||||
'ip': [IPv4Address],
|
||||
'ip-dst': [IPv4Address],
|
||||
'ip-src': [IPv4Address],
|
||||
'md5': [Hash],
|
||||
'phone-number': [PhoneNumber],
|
||||
'sha1': [Hash],
|
||||
'sha224': [Hash],
|
||||
'sha256': [Hash],
|
||||
'sha384': [Hash],
|
||||
'sha512': [Hash],
|
||||
'sha512/224': [Hash],
|
||||
'sha512/256': [Hash],
|
||||
'ssdeep': [Hash],
|
||||
'impfuzzy': [Hash],
|
||||
'uri': [URL],
|
||||
'url': [URL],
|
||||
|
||||
'whois-registrant-email': [EmailAddress],
|
||||
'country-of-residence': [Location],
|
||||
'github-organisation': [Company],
|
||||
'github-username': [Alias],
|
||||
'imphash': [Hash],
|
||||
'jabber-id': [Alias],
|
||||
'passport-country': [Location],
|
||||
'place-of-birth': [Location],
|
||||
'port': [Port],
|
||||
'target-email': [EmailAddress],
|
||||
'target-location': [Location],
|
||||
'target-org': [Company],
|
||||
'target-user': [Alias],
|
||||
'twitter-id': [Twitter],
|
||||
# object mappings
|
||||
'nameserver': [NSRecord],
|
||||
# custom types created internally for technical reasons
|
||||
# 'regkey_value': [Unknown]
|
||||
}
|
||||
|
||||
mapping_galaxy_icon = {
|
||||
# "android": "malware", # "android",
|
||||
"btc": "ransomware",
|
||||
"bug": "vulnerability",
|
||||
# "cart-arrow-down": "malware", #"tds",
|
||||
"chain": "course_of_action",
|
||||
"door-open": "backdoor",
|
||||
"eye": "malware",
|
||||
"gavel": "tool",
|
||||
# "globe": "cert-eu-govsector",
|
||||
# "industry": "sector",
|
||||
# "internet-explorer": "exploit-kit",
|
||||
"key": "stealer",
|
||||
"map": "attack_pattern",
|
||||
"optin-monster": "malware",
|
||||
# "shield": "malpedia",
|
||||
# "shield": "preventive-measure",
|
||||
"sitemap": "botnet",
|
||||
"usd": "malware", # "banker",
|
||||
# "user-secret": "mitre-intrusion-set",
|
||||
"user-secret": "threat_actor",
|
||||
}
|
||||
|
||||
mapping_galaxy_type = {
|
||||
# 'amitt-misinformation-pattern': '',
|
||||
'android': Software,
|
||||
'backdoor': Software,
|
||||
'banker': Software,
|
||||
'botnet': Software,
|
||||
# 'branded-vulnerability': '',
|
||||
# 'cert-eu-govsector': '',
|
||||
'cloud-security': AttackTechnique,
|
||||
'exploit-kit': Software,
|
||||
'financial-fraud': AttackTechnique,
|
||||
'guidelines': AttackTechnique,
|
||||
'malpedia': Software,
|
||||
'microsoft-activity-group': ThreatActor,
|
||||
'mitre-attack-pattern': AttackTechnique,
|
||||
# 'mitre-course-of-action': '',
|
||||
'mitre-intrusion-set': ThreatActor,
|
||||
'mitre-malware': Software,
|
||||
'mitre-tool': Software,
|
||||
# 'preventive-measure': '',
|
||||
'ransomware': Software,
|
||||
'rat': Software,
|
||||
# 'region': '',
|
||||
# 'sector': '',
|
||||
'social-dark-patterns': AttackTechnique,
|
||||
'stealer': Software,
|
||||
'surveillance-vendor': ThreatActor,
|
||||
# 'target-information': '',
|
||||
'tds': Software,
|
||||
'threat-actor': ThreatActor,
|
||||
'tool': Software
|
||||
}
|
||||
|
||||
mapping_object_icon = {
|
||||
'ail-leak': '',
|
||||
'ais-info': '',
|
||||
'android-permission': '',
|
||||
'annotation': '',
|
||||
'anonymisation': 'AffiliationAnonymous',
|
||||
'asn': '',
|
||||
'attack-pattern': '',
|
||||
'authenticode-signerinfo': '',
|
||||
'av-signature': '',
|
||||
'bank-account': '',
|
||||
'bgp-hijack': '',
|
||||
'blog': 'URL',
|
||||
'btc-transaction': 'BankCard',
|
||||
'btc-wallet': 'BankAccount',
|
||||
'cap-alert': '',
|
||||
'cap-info': '',
|
||||
'cap-resource': '',
|
||||
'coin-address': 'BankAccount',
|
||||
'command': '',
|
||||
'command-line': '',
|
||||
'cookie': 'Cookies',
|
||||
'cortex': '',
|
||||
'cortex-taxonomy': '',
|
||||
'course-of-action': 'course_of_action',
|
||||
'covid19-csse-daily-report': '',
|
||||
'covid19-dxy-live-city': '',
|
||||
'covid19-dxy-live-province': '',
|
||||
'cowrie': '',
|
||||
'credential': '',
|
||||
'credit-card': 'BankCard',
|
||||
'crypto-material': 'Encrypt',
|
||||
'cytomic_orion': '',
|
||||
'cytomic_orion_machine': '',
|
||||
'dark-pattern': '',
|
||||
'ddos': '',
|
||||
'device': '',
|
||||
'diameter-attack': '',
|
||||
'dns-record': 'ServerDNS',
|
||||
'domain-crawled': '',
|
||||
'domain-ip': 'NetworkGlobal',
|
||||
'elf': '',
|
||||
'elf-section': '',
|
||||
'email': 'Email',
|
||||
'employee': 'Person',
|
||||
'exploit-poc': 'Person',
|
||||
'facial-composite': '',
|
||||
'fail2ban': '',
|
||||
'file': 'File',
|
||||
'forensic-case': '',
|
||||
'forensic-evidence': '',
|
||||
'forged-document': '',
|
||||
'geolocation': 'GPS',
|
||||
'gtp-attack': '',
|
||||
'http-request': 'URL',
|
||||
'ilr-impact': '',
|
||||
'ilr-notification-incident': '',
|
||||
'impersonation': 'GangBoss',
|
||||
'imsi-catcher': 'MobileNet',
|
||||
'instant-message': 'Form',
|
||||
'instant-message-group': '',
|
||||
'intelmq_event': '',
|
||||
'intelmq_report': '',
|
||||
'internal-reference': '',
|
||||
'interpol-notice': '',
|
||||
'iot-device': 'InternetISP',
|
||||
'iot-firmware': '',
|
||||
'ip-api-address': '',
|
||||
'ip-port': 'NetworkCard',
|
||||
'irc': '',
|
||||
'ja3': '',
|
||||
'leaked-document': 'InternetDocument',
|
||||
'legal-entity': 'Company',
|
||||
'lnk': 'File',
|
||||
'macho': '',
|
||||
'macho-section': '',
|
||||
'mactime-timeline-analysis': '',
|
||||
'malware-config': 'Virus',
|
||||
'meme-image': '',
|
||||
'microblog': '',
|
||||
'mutex': '',
|
||||
'netflow': '',
|
||||
'network-connection': 'NetworkSymmetric',
|
||||
'network-socket': '',
|
||||
'news-agency': '',
|
||||
'news-media': '',
|
||||
'organization': 'Company',
|
||||
'original-imported-file': 'File',
|
||||
'passive-dns': 'ServerDNS',
|
||||
'paste': 'InternetDocument',
|
||||
'pcap-metadata': '',
|
||||
'pe': 'File',
|
||||
'person': 'Person',
|
||||
'pe-section': '',
|
||||
'pgp-meta': '',
|
||||
'phishing': 'InternetDocument',
|
||||
'phishing-kit': '',
|
||||
'phone': 'PhoneNumber',
|
||||
'process': '',
|
||||
'python-etvx-event-log': '',
|
||||
'r2graphity': '',
|
||||
'regexp': '',
|
||||
'registry-key': 'RegistryErase',
|
||||
'regripper-NTUser': '',
|
||||
'regripper-sam-hive-single-user': '',
|
||||
'regripper-sam-hive-user-group': '',
|
||||
'regripper-software-hive-appInit-DLLS': '',
|
||||
'regripper-software-hive-application-paths': '',
|
||||
'regripper-software-hive-applications-installed': '',
|
||||
'regripper-software-hive-BHO': '',
|
||||
'regripper-software-hive-command-shell': '',
|
||||
'regripper-software-hive-general-windows-info': '',
|
||||
'regripper-software-hive-software-run': '',
|
||||
'regripper-software-hive-userprofile-winlogon': '',
|
||||
'regripper-system-hive-firewall-configuration': '',
|
||||
'regripper-system-hive-general-configuration': '',
|
||||
'regripper-system-hive-network-information': '',
|
||||
'regripper-system-hive-service-drivers': '',
|
||||
'report': 'Resume',
|
||||
'research-scanner': '',
|
||||
'rogue-dns': '',
|
||||
'rtir': '',
|
||||
'sandbox-report': 'Resume',
|
||||
'sb-signature': '',
|
||||
'scrippsco2-c13-daily': '',
|
||||
'scrippsco2-c13-monthly': '',
|
||||
'scrippsco2-co2-daily': '',
|
||||
'scrippsco2-co2-monthly': '',
|
||||
'scrippsco2-o18-daily': '',
|
||||
'scrippsco2-o18-monthly': '',
|
||||
'script': '',
|
||||
'shell-commands': '',
|
||||
'shodan-report': '',
|
||||
'shortened-link': 'URL',
|
||||
'short-message-service': '',
|
||||
'splunk': '',
|
||||
'ss7-attack': '',
|
||||
'ssh-authorized-keys': '',
|
||||
'stix2-pattern': '',
|
||||
'suricata': '',
|
||||
'target-system': 'sighting',
|
||||
'threatgrid-report': '',
|
||||
'timecode': '',
|
||||
'timesketch_message': '',
|
||||
'timesketch-timeline': '',
|
||||
'timestamp': '',
|
||||
'tor-hiddenservice': '',
|
||||
'tor-node': '',
|
||||
'tracking-id': '',
|
||||
'transaction': '',
|
||||
'translation': '',
|
||||
'trustar_report': '',
|
||||
'TSK-Chats': '',
|
||||
'TSK-Web-Bookmark': '',
|
||||
'TSK-Web-Cookie': '',
|
||||
'TSK-Web-Downloads': '',
|
||||
'TSK-Web-History': '',
|
||||
'TSK-Web-Search-Query': '',
|
||||
'url': 'URL',
|
||||
'user-account': 'User',
|
||||
'vehicle': 'Car',
|
||||
'victim': 'Victim',
|
||||
'virustotal-graph': '',
|
||||
'virustotal-report': '',
|
||||
'vulnerability': 'vulnerability',
|
||||
'weakness': 'vulnerability',
|
||||
'whois': 'VINNumber',
|
||||
'x509': 'MedicalRecord',
|
||||
'yabin': '',
|
||||
'yara': '',
|
||||
}
|
||||
|
||||
# All possible default icons shipped with Maltego - useful for auto_completion
|
||||
# AccessCard
|
||||
# AccessPoint
|
||||
# Accident
|
||||
# Accountant
|
||||
# Add
|
||||
# Admin
|
||||
# AdultFemale
|
||||
# AdultMale
|
||||
# AffiliationAndroid
|
||||
# AffiliationAnonymous
|
||||
# AffiliationApple
|
||||
# AffiliationBebo
|
||||
# AffiliationBlogger
|
||||
# AffiliationBuiltWith
|
||||
# AffiliationCloud
|
||||
# AffiliationColdfusion
|
||||
# AffiliationDigg
|
||||
# AffiliationDropbox
|
||||
# AffiliationEbay
|
||||
# AffiliationFacebook
|
||||
# AffiliationFlickr
|
||||
# AffiliationGoogleDrive
|
||||
# AffiliationGooglePlus
|
||||
# AffiliationInstagram
|
||||
# AffiliationKik
|
||||
# AffiliationLinkedIn
|
||||
# AffiliationLinux
|
||||
# AffiliationMeetup
|
||||
# AffiliationMyspace
|
||||
# AffiliationNewsvine
|
||||
# AffiliationOrkut
|
||||
# AffiliationPayPal
|
||||
# AffiliationPicasa
|
||||
# AffiliationPinterest
|
||||
# Affiliation
|
||||
# AffiliationReddit
|
||||
# AffiliationRSS
|
||||
# AffiliationSkype
|
||||
# AffiliationSnapchat
|
||||
# AffiliationSpock
|
||||
# AffiliationTinder
|
||||
# AffiliationTwitter
|
||||
# AffiliationWechat
|
||||
# AffiliationWhatsapp
|
||||
# AffiliationWiki
|
||||
# AffiliationWindows
|
||||
# AffiliationWWF
|
||||
# AffiliationYammer
|
||||
# AffiliationYelp
|
||||
# AffiliationYouTube
|
||||
# AffiliationZoomInfo
|
||||
# AircraftBomber
|
||||
# AircraftCarrier
|
||||
# AirCrash
|
||||
# Airport
|
||||
# Alarm
|
||||
# Alias
|
||||
# Alliance
|
||||
# Ammunition
|
||||
# Anarchy
|
||||
# Antenna
|
||||
# Apartments
|
||||
# Army
|
||||
# Artist
|
||||
# Assemble
|
||||
# Asteroid
|
||||
# Atom
|
||||
# Author
|
||||
# Baby
|
||||
# Backbone
|
||||
# Ballerina
|
||||
# BandAid
|
||||
# BankAccount
|
||||
# BankCard
|
||||
# Banner
|
||||
# Bear
|
||||
# Bee
|
||||
# Binary
|
||||
# BioAgent
|
||||
# Bit
|
||||
# BlueAura
|
||||
# Bomb
|
||||
# BookPDF
|
||||
# Book
|
||||
# BorderCheckpoint
|
||||
# Businessman
|
||||
# BusinessPhoneSystem
|
||||
# Bus
|
||||
# CableUSB
|
||||
# Camera
|
||||
# Captive
|
||||
# Cargo
|
||||
# Car
|
||||
# CashInTransit
|
||||
# Cash
|
||||
# CellNetwork
|
||||
# Cemetery
|
||||
# CEO
|
||||
# Certificate
|
||||
# Certification
|
||||
# Champion
|
||||
# CheckBox
|
||||
# Checkpoint
|
||||
# ChemicalAnalysis
|
||||
# Child
|
||||
# Church
|
||||
# CircularArea
|
||||
# City
|
||||
# Clock
|
||||
# ClusterOrange
|
||||
# Cluster
|
||||
# CoffeeShop
|
||||
# ColoredBall
|
||||
# Community
|
||||
# Company
|
||||
# ConferenceAudio
|
||||
# Connect
|
||||
# Contract
|
||||
# ControlTower
|
||||
# Cookies
|
||||
# CrimeScene
|
||||
# Criminal
|
||||
# CV
|
||||
# Dam
|
||||
# DatabaseConnect
|
||||
# DatabaseErase
|
||||
# Database
|
||||
# DateField
|
||||
# Deceased
|
||||
# Degree
|
||||
# Delete
|
||||
# Desert
|
||||
# Desktop
|
||||
# Destroy
|
||||
# Diamond
|
||||
# Diary
|
||||
# Dictator
|
||||
# Directions
|
||||
# Disabled
|
||||
# Disconnect
|
||||
# DNACode
|
||||
# Donation
|
||||
# Donkey
|
||||
# Drone
|
||||
# DrugDealer
|
||||
# Earthquake
|
||||
# Elderly
|
||||
# Elephant
|
||||
# Email
|
||||
# Encrypt
|
||||
# Environment
|
||||
# Erase
|
||||
# Event
|
||||
# Explosion
|
||||
# Factory
|
||||
# Farm
|
||||
# FastFood
|
||||
# Fax
|
||||
# FieldDelete
|
||||
# Field
|
||||
# File
|
||||
# FileSharing
|
||||
# Files
|
||||
# Filter
|
||||
# FingerPrint
|
||||
# FireForest
|
||||
# Firewall
|
||||
# Fix
|
||||
# FlightNumber
|
||||
# FlightPath
|
||||
# Flood
|
||||
# FloppyDisk
|
||||
# Form
|
||||
# GamingConsole
|
||||
# GangBoss
|
||||
# GangMember
|
||||
# Gang
|
||||
# GasStation
|
||||
# Gateway
|
||||
# Genealogy
|
||||
# Genetic
|
||||
# Geography
|
||||
# GhostSighting
|
||||
# GlobalWarming
|
||||
# Gorilla
|
||||
# GovermentOfficial
|
||||
# Government
|
||||
# GPS
|
||||
# Green2Grey
|
||||
# Green2Orange2Turquoise
|
||||
# Green2Red2Blue
|
||||
# Group
|
||||
# Guard
|
||||
# Gun
|
||||
# Hacker
|
||||
# Harbour
|
||||
# HardDisk
|
||||
# Harvest
|
||||
# Hashtag
|
||||
# Headphones
|
||||
# Helicopter
|
||||
# Home
|
||||
# HospitalLocation
|
||||
# Hostage
|
||||
# Hotel
|
||||
# Hurricane
|
||||
# HydroPower
|
||||
# IconManager
|
||||
# ID
|
||||
# IED
|
||||
# ImageField
|
||||
# Image
|
||||
# Influencer
|
||||
# InfoMessage
|
||||
# InternetDocument
|
||||
# InternetFastSpeed
|
||||
# InternetIP
|
||||
# InternetISP
|
||||
# InternetMIMEDocs
|
||||
# InternetMIMEFolder
|
||||
# InternetMIME
|
||||
# Internet
|
||||
# InternetUser
|
||||
# Invasion
|
||||
# ISBN
|
||||
# Island
|
||||
# Judge
|
||||
# KeyPrimary
|
||||
# Keys
|
||||
# KillerWhale
|
||||
# Knife
|
||||
# Last
|
||||
# LawEnforcementOfficer
|
||||
# Lawyer
|
||||
# Leader
|
||||
# License
|
||||
# LinkBroke
|
||||
# Link
|
||||
# List
|
||||
# Lobby
|
||||
# Location
|
||||
# Log
|
||||
# MacAddress
|
||||
# MaltegoGraph
|
||||
# ManyIn
|
||||
# Marijuana
|
||||
# MedicalRecord
|
||||
# Medicine
|
||||
# MeetingBusiness
|
||||
# MeetingSocial
|
||||
# Memorial
|
||||
# MergeCells
|
||||
# Messenger
|
||||
# MilitaryOfficer
|
||||
# Mine
|
||||
# MissileRPG
|
||||
# MissingPerson
|
||||
# MobileComputer
|
||||
# MobileNet
|
||||
# MobilePhone
|
||||
# MobileUser
|
||||
# Modem
|
||||
# Monitoring
|
||||
# Moon
|
||||
# Mosque
|
||||
# Motorbike
|
||||
# Movie
|
||||
# Murder
|
||||
# MusicAlbum
|
||||
# MusicSinger
|
||||
# MusicSongwriter
|
||||
# MXRecord
|
||||
# MySQL
|
||||
# Neighborhood
|
||||
# NetAdmin
|
||||
# NetworkAdmin
|
||||
# NetworkAsymetric
|
||||
# NetworkCardBlue
|
||||
# NetworkCard
|
||||
# NetworkConnector
|
||||
# NetworkDistribution
|
||||
# NetworkGlobal
|
||||
# NetworkHub
|
||||
# NetworkID
|
||||
# NetworkIntranet
|
||||
# NetworkISDN
|
||||
# NetworkMonitor
|
||||
# NetworkSoftware
|
||||
# NetworkSymmetric
|
||||
# News
|
||||
# Node
|
||||
# NSRecord
|
||||
# NuclearPlant
|
||||
# Nurse
|
||||
# Objects
|
||||
# OilField
|
||||
# OilSpill
|
||||
# OilWell
|
||||
# OnlineGroup
|
||||
# Orange2Green
|
||||
# Orange2Purple
|
||||
# Organization
|
||||
# OSIModel
|
||||
# Passport
|
||||
# PasswordPHP
|
||||
# Password
|
||||
# Patient
|
||||
# Person
|
||||
# PetrolBomb
|
||||
# PhoneConversation
|
||||
# PhoneLandlineOffice
|
||||
# PhoneLandlineResidential
|
||||
# PhoneNumber
|
||||
# Phrase
|
||||
# Pilot
|
||||
# Piracy
|
||||
# Pirate
|
||||
# Plane
|
||||
# Planet
|
||||
# Play
|
||||
# Poison
|
||||
# PoliticalParty
|
||||
# Port
|
||||
# PowerPlant
|
||||
# Prescription
|
||||
# PrisonCamp
|
||||
# Prisoner
|
||||
# Prison
|
||||
# Privilege
|
||||
# ProgressBar
|
||||
# Protester
|
||||
# Protest
|
||||
# Protocol
|
||||
# Purple2Turquoise
|
||||
# PurplePink2Green
|
||||
# PurplePink2Yellow2Blue
|
||||
# QRCode
|
||||
# Quarantine
|
||||
# QuestionDialog
|
||||
# Radar
|
||||
# Radio
|
||||
# Rain
|
||||
# Red2Blue
|
||||
# Red2Green
|
||||
# Red2Yellow
|
||||
# RefugeeCamp
|
||||
# RegistrationPlate
|
||||
# RegistryErase
|
||||
# RelationshipModel
|
||||
# Relationship
|
||||
# RemoteControl
|
||||
# Repeater
|
||||
# Reporter
|
||||
# Restaurant
|
||||
# Resume
|
||||
# Rhino
|
||||
# Rocket
|
||||
# Role
|
||||
# Route
|
||||
# Router
|
||||
# Royalty
|
||||
# RunningWater
|
||||
# Satellite
|
||||
# Savings
|
||||
# School
|
||||
# Science
|
||||
# Scientist
|
||||
# Script
|
||||
# SecurityCameraMonitoring
|
||||
# SecurityCheckpoints
|
||||
# Security
|
||||
# Seed
|
||||
# Sentiment
|
||||
# ServerBackup
|
||||
# ServerChat
|
||||
# ServerDNS
|
||||
# ServerFTP
|
||||
# ServerMicrosoftSQL
|
||||
# Server
|
||||
# ServerProxy
|
||||
# Service
|
||||
# SexOffender
|
||||
# Sharing
|
||||
# SharkAttack
|
||||
# ShipContainer
|
||||
# ShipCruise
|
||||
# ShipPirate
|
||||
# Ship
|
||||
# ShipSpeed
|
||||
# ShipTanker
|
||||
# ShipTrawler
|
||||
# ShipYacht
|
||||
# Shop
|
||||
# SIMCard
|
||||
# SiteFTP
|
||||
# SizeAllLinks
|
||||
# SizeInLinks
|
||||
# SizeOutLinks
|
||||
# SmileConfused
|
||||
# SmileMad
|
||||
# Smile
|
||||
# SmileSad
|
||||
# SMS
|
||||
# Sniffer
|
||||
# Snow
|
||||
# Socket
|
||||
# SoftwareBlocking
|
||||
# SoftwareCollaborative
|
||||
# SoftwareFTP
|
||||
# SoftwareManager
|
||||
# SoftwareMeeting
|
||||
# Software
|
||||
# Soldier
|
||||
# Solidarity
|
||||
# Space
|
||||
# SpaceStation
|
||||
# Spider
|
||||
# SplitCells
|
||||
# Spy
|
||||
# Spyware
|
||||
# SQLQuery
|
||||
# SSLCertificate
|
||||
# SSL
|
||||
# SSN
|
||||
# Star
|
||||
# Stop
|
||||
# SuicideBomber
|
||||
# SUNET
|
||||
# Suspect
|
||||
# SuspiciousPerson
|
||||
# Switch
|
||||
# Sybase
|
||||
# SynagogueTemple
|
||||
# Syndicate
|
||||
# Table
|
||||
# TabletTouch
|
||||
# Tag
|
||||
# Tank
|
||||
# TargetPerson
|
||||
# Target
|
||||
# Taxi
|
||||
# Technician
|
||||
# Temple
|
||||
# Terminal
|
||||
# TerroristLeader
|
||||
# TerroristMember
|
||||
# TerroristThug
|
||||
# Terror
|
||||
# TextField
|
||||
# Theatre
|
||||
# Ticket
|
||||
# TradeUnion
|
||||
# Train
|
||||
# TrainStation
|
||||
# Transform
|
||||
# Trojan
|
||||
# Truck
|
||||
# TsetseFly
|
||||
# Tsunami
|
||||
# Turquoise2Orange2Red
|
||||
# Turquoise2Yellow
|
||||
# TV
|
||||
# UFOAbduction
|
||||
# Underground
|
||||
# Universe
|
||||
# UnknownBody
|
||||
# Unknown
|
||||
# UPS
|
||||
# Urgent
|
||||
# URL
|
||||
# USB
|
||||
# UserID
|
||||
# User
|
||||
# Victim
|
||||
# VideoCamera
|
||||
# Videoconference
|
||||
# VINNumber
|
||||
# Virus
|
||||
# Voice
|
||||
# VOIP
|
||||
# VolcanoEruption
|
||||
# VPN
|
||||
# WAN
|
||||
# WebDir
|
||||
# Website
|
||||
# WiFi
|
||||
# WindFarm
|
||||
# WirelessRouter
|
|
@ -1,9 +1,7 @@
|
|||
from canari.maltego.entities import Hash, URL, File, Person, Hashtag
|
||||
from canari.maltego.entities import Hash, Domain, IPv4Address, URL, DNSName, AS, Website, NSRecord, PhoneNumber, EmailAddress, File, Person, Hashtag, Location, Company, Alias, Port, Twitter
|
||||
from canari.maltego.message import Label, LinkStyle, MaltegoException, Bookmark, LinkDirection, UIMessage, UIMessageType
|
||||
from canari.mode import is_local_exec_mode, is_remote_exec_mode
|
||||
from distutils.version import StrictVersion
|
||||
from MISP_maltego.transforms.common.entities import MISPEvent, MISPObject, MISPGalaxy
|
||||
from MISP_maltego.transforms.common.mappings import mapping_object_icon, mapping_misp_to_maltego, mapping_galaxy_icon, mapping_galaxy_type
|
||||
from MISP_maltego.transforms.common.entities import MISPEvent, MISPObject, MISPGalaxy, ThreatActor, Software, AttackTechnique
|
||||
from pymisp import ExpandedPyMISP as PyMISP
|
||||
import json
|
||||
import os
|
||||
|
@ -12,22 +10,123 @@ import requests
|
|||
import tempfile
|
||||
import time
|
||||
|
||||
__version__ = '1.4.6' # also update version in setup.py
|
||||
# FIXME from galaxy 'to MISP Event' is confusing
|
||||
|
||||
__version__ = '1.4.0' # also update version in setup.py
|
||||
|
||||
mapping_misp_to_maltego = {
|
||||
'AS': [AS],
|
||||
'domain': [Domain, NSRecord, Website, DNSName],
|
||||
'email-dst': [EmailAddress],
|
||||
'email-src': [EmailAddress],
|
||||
'filename': [File],
|
||||
'hostname': [Website, NSRecord, Domain, DNSName],
|
||||
'ip': [IPv4Address],
|
||||
'ip-dst': [IPv4Address],
|
||||
'ip-src': [IPv4Address],
|
||||
'md5': [Hash],
|
||||
'phone-number': [PhoneNumber],
|
||||
'sha1': [Hash],
|
||||
'sha224': [Hash],
|
||||
'sha256': [Hash],
|
||||
'sha384': [Hash],
|
||||
'sha512': [Hash],
|
||||
'sha512/224': [Hash],
|
||||
'sha512/256': [Hash],
|
||||
'ssdeep': [Hash],
|
||||
'impfuzzy': [Hash],
|
||||
'uri': [URL],
|
||||
'url': [URL],
|
||||
|
||||
'whois-registrant-email': [EmailAddress],
|
||||
'country-of-residence': [Location],
|
||||
'github-organisation': [Company],
|
||||
'github-username': [Alias],
|
||||
'imphash': [Hash],
|
||||
'jabber-id': [Alias],
|
||||
'passport-country': [Location],
|
||||
'place-of-birth': [Location],
|
||||
'port': [Port],
|
||||
'target-email': [EmailAddress],
|
||||
'target-location': [Location],
|
||||
'target-org': [Company],
|
||||
'target-user': [Alias],
|
||||
'twitter-id': [Twitter],
|
||||
# object mappings
|
||||
'nameserver': [NSRecord],
|
||||
# TODO add more object mappings
|
||||
# custom types created internally for technical reasons
|
||||
# 'rekey_value': [Unknown]
|
||||
}
|
||||
|
||||
mapping_galaxy_icon = {
|
||||
# "android": "malware", # "android",
|
||||
"btc": "ransomware",
|
||||
"bug": "vulnerability",
|
||||
# "cart-arrow-down": "malware", #"tds",
|
||||
"chain": "course_of_action",
|
||||
"door-open": "backdoor",
|
||||
"eye": "malware",
|
||||
"gavel": "tool",
|
||||
# "globe": "cert-eu-govsector",
|
||||
# "industry": "sector",
|
||||
# "internet-explorer": "exploit-kit",
|
||||
"key": "stealer",
|
||||
"map": "attack_pattern",
|
||||
"optin-monster": "malware",
|
||||
# "shield": "malpedia",
|
||||
# "shield": "preventive-measure",
|
||||
"sitemap": "botnet",
|
||||
"usd": "malware", # "banker",
|
||||
# "user-secret": "mitre-intrusion-set",
|
||||
"user-secret": "threat_actor",
|
||||
}
|
||||
|
||||
mapping_galaxy_type = {
|
||||
# 'amitt-misinformation-pattern': '',
|
||||
'android': Software,
|
||||
'backdoor': Software,
|
||||
'banker': Software,
|
||||
'botnet': Software,
|
||||
# 'branded-vulnerability': '',
|
||||
# 'cert-eu-govsector': '',
|
||||
'cloud-security': AttackTechnique,
|
||||
'exploit-kit': Software,
|
||||
'financial-fraud': AttackTechnique,
|
||||
'guidelines': AttackTechnique,
|
||||
'malpedia': Software,
|
||||
'microsoft-activity-group': ThreatActor,
|
||||
'mitre-attack-pattern': AttackTechnique,
|
||||
# 'mitre-course-of-action': '',
|
||||
'mitre-intrusion-set': ThreatActor,
|
||||
'mitre-malware': Software,
|
||||
'mitre-tool': Software,
|
||||
# 'preventive-measure': '',
|
||||
'ransomware': Software,
|
||||
'rat': Software,
|
||||
# 'region': '',
|
||||
# 'sector': '',
|
||||
'social-dark-patterns': AttackTechnique,
|
||||
'stealer': Software,
|
||||
'surveillance-vendor': ThreatActor,
|
||||
# 'target-information': '',
|
||||
'tds': Software,
|
||||
'threat-actor': ThreatActor,
|
||||
'tool': Software
|
||||
}
|
||||
|
||||
|
||||
tag_note_prefixes = ['tlp:', 'PAP:', 'de-vs:', 'euci:', 'fr-classif:', 'nato:']
|
||||
|
||||
misp_connection = None
|
||||
update_url = 'https://raw.githubusercontent.com/MISP/MISP-maltego/master/setup.py'
|
||||
local_path_root = os.path.join(tempfile.gettempdir(), 'MISP-maltego')
|
||||
local_path_version = os.path.join(local_path_root, 'versioncheck')
|
||||
if not os.path.exists(local_path_root):
|
||||
os.mkdir(local_path_root)
|
||||
os.chmod(local_path_root, mode=0o777) # temporary workaround - see https://github.com/redcanari/canari3/issues/61
|
||||
|
||||
|
||||
def check_update(config):
|
||||
# Do not check updates if running as remote transform
|
||||
if is_remote_exec_mode():
|
||||
return None
|
||||
# only raise the alert once a day/reboot to the user.
|
||||
try:
|
||||
if time.time() - os.path.getmtime(local_path_version) > 60 * 60 * 24: # check the timestamp of the file
|
||||
|
@ -61,116 +160,25 @@ def check_update(config):
|
|||
return None
|
||||
|
||||
|
||||
class MISPConnection():
|
||||
def __init__(self, config=None, parameters=None):
|
||||
self.misp = None
|
||||
|
||||
def get_misp_connection(config=None):
|
||||
global misp_connection
|
||||
if misp_connection:
|
||||
return misp_connection
|
||||
if not config:
|
||||
raise MaltegoException("ERROR: MISP connection not yet established, and config not provided as parameter.")
|
||||
if config['MISP_maltego.local.misp_verify'] in ['True', 'true', 1, 'yes', 'Yes']:
|
||||
misp_verify = True
|
||||
misp_debug = False
|
||||
misp_url = None
|
||||
misp_key = None
|
||||
try:
|
||||
if is_local_exec_mode():
|
||||
misp_url = config['MISP_maltego.local.misp_url']
|
||||
misp_key = config['MISP_maltego.local.misp_key']
|
||||
if config['MISP_maltego.local.misp_verify'] in ['False', 'false', 0, 'no', 'No']:
|
||||
else:
|
||||
misp_verify = False
|
||||
if config['MISP_maltego.local.misp_debug'] in ['True', 'true', 1, 'yes', 'Yes']:
|
||||
misp_debug = True
|
||||
else:
|
||||
misp_debug = False
|
||||
try:
|
||||
misp_url = parameters['mispurl'].value
|
||||
misp_key = parameters['mispkey'].value
|
||||
except AttributeError:
|
||||
raise MaltegoException("ERROR: mispurl and mispkey need to be set to something valid")
|
||||
self.misp = PyMISP(url=misp_url, key=misp_key, ssl=misp_verify, debug=misp_debug, tool='misp_maltego', timeout=(2, 60))
|
||||
misp_connection = PyMISP(config['MISP_maltego.local.misp_url'], config['MISP_maltego.local.misp_key'], misp_verify, 'json', misp_debug)
|
||||
except Exception:
|
||||
if is_local_exec_mode():
|
||||
raise MaltegoException("ERROR: Cannot connect to MISP server. Please verify your MISP_Maltego.conf settings.")
|
||||
else:
|
||||
raise MaltegoException("ERROR: Cannot connect to MISP server. Please verify your settings (MISP URL and API key), and ensure the MISP server is reachable from the internet.")
|
||||
|
||||
def object_to_entity(self, o, link_label=None, link_direction=LinkDirection.InputToOutput):
|
||||
# find a nice icon for it
|
||||
try:
|
||||
icon_url = mapping_object_icon[o['name']]
|
||||
except KeyError:
|
||||
# it's not in our mapping, just ignore and leave the default icon
|
||||
icon_url = None
|
||||
# Generate a human readable display-name:
|
||||
# - find the first RequiredOneOf that exists
|
||||
# - if none, use the first RequiredField
|
||||
# LATER further finetune the human readable version of this object
|
||||
o_template = self.misp.get_object_template(o['template_uuid'])
|
||||
human_readable = None
|
||||
try:
|
||||
found = False
|
||||
while not found: # the while loop is broken once something is found, or the requiredOneOf has no elements left
|
||||
required_ote_type = o_template['ObjectTemplate']['requirements']['requiredOneOf'].pop(0)
|
||||
for ote in o_template['ObjectTemplateElement']:
|
||||
if ote['object_relation'] == required_ote_type:
|
||||
required_a_type = ote['type']
|
||||
break
|
||||
for a in o['Attribute']:
|
||||
if a['type'] == required_a_type:
|
||||
human_readable = '{}:\n{}'.format(o['name'], a['value'])
|
||||
found = True
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
if not human_readable:
|
||||
try:
|
||||
found = False
|
||||
parts = []
|
||||
for required_ote_type in o_template['ObjectTemplate']['requirements']['required']:
|
||||
for ote in o_template['ObjectTemplateElement']:
|
||||
if ote['object_relation'] == required_ote_type:
|
||||
required_a_type = ote['type']
|
||||
break
|
||||
for a in o['Attribute']:
|
||||
if a['type'] == required_a_type:
|
||||
parts.append(a['value'])
|
||||
break
|
||||
human_readable = '{}:\n{}'.format(o['name'], '|'.join(parts))
|
||||
except Exception:
|
||||
human_readable = o['name']
|
||||
return MISPObject(
|
||||
human_readable,
|
||||
uuid=o['uuid'],
|
||||
event_id=int(o['event_id']),
|
||||
meta_category=o.get('meta_category'),
|
||||
description=o.get('description'),
|
||||
comment=o.get('comment'),
|
||||
icon_url=icon_url,
|
||||
link_label=link_label,
|
||||
link_direction=link_direction,
|
||||
bookmark=Bookmark.Green
|
||||
)
|
||||
|
||||
def object_to_relations(self, o, e):
|
||||
# process forward and reverse references, so just loop over all the objects of the event
|
||||
if 'Object' in e['Event']:
|
||||
for eo in e['Event']['Object']:
|
||||
if 'ObjectReference' in eo:
|
||||
for ref in eo['ObjectReference']:
|
||||
# we have found original object. Expand to the related object and attributes
|
||||
if eo['uuid'] == o['uuid']:
|
||||
# the reference is an Object
|
||||
if ref.get('Object'):
|
||||
# get the full object in the event, as our objectReference included does not contain everything we need
|
||||
sub_object = get_object_in_event(ref['Object']['uuid'], e)
|
||||
yield self.object_to_entity(sub_object, link_label=ref['relationship_type'])
|
||||
# the reference is an Attribute
|
||||
if ref.get('Attribute'):
|
||||
ref['Attribute']['event_id'] = ref['event_id'] # LATER remove this ugly workaround - object can't be requested directly from MISP using the uuid, and to find a full object we need the event_id
|
||||
for item in attribute_to_entity(ref['Attribute'], link_label=ref['relationship_type']):
|
||||
yield item
|
||||
|
||||
# reverse-lookup - this is another objects relating the original object
|
||||
if ref['referenced_uuid'] == o['uuid']:
|
||||
yield self.object_to_entity(eo, link_label=ref['relationship_type'], link_direction=LinkDirection.OutputToInput)
|
||||
raise MaltegoException("ERROR: Cannot connect to MISP server. Please verify your MISP_Maltego.conf settings")
|
||||
return misp_connection
|
||||
|
||||
|
||||
def entity_obj_to_entity(entity_obj, v, t, **kwargs):
|
||||
|
@ -219,7 +227,6 @@ def attribute_to_entity(a, link_label=None, event_tags=[], only_self=False):
|
|||
if a['type'] in ('url', 'uri'):
|
||||
yield(URL(url=a['value'], short_title=a['value'], link_label=link_label, notes=notes, bookmark=Bookmark.Green))
|
||||
return
|
||||
# FIXME implement attachment screenshot type
|
||||
|
||||
# attribute is from an object, and a relation gives better understanding of the type of attribute
|
||||
if a.get('object_relation') and mapping_misp_to_maltego.get(a['object_relation']):
|
||||
|
@ -250,7 +257,60 @@ def attribute_to_entity(a, link_label=None, event_tags=[], only_self=False):
|
|||
|
||||
# not supported in our maltego mapping are not handled
|
||||
|
||||
# LATER relationships from attributes - not yet supported by MISP yet, but there are references in the datamodel
|
||||
# LATER : relationships from attributes - not yet supported by MISP yet, but there are references in the datamodel
|
||||
|
||||
|
||||
def object_to_entity(o, link_label=None, link_direction=LinkDirection.InputToOutput):
|
||||
# Generate a human readable display-name:
|
||||
# - find the first RequiredOneOf that exists
|
||||
# - if none, use the first RequiredField
|
||||
# LATER further finetune the human readable version of this object
|
||||
misp = get_misp_connection()
|
||||
o_template = misp.get_object_template(o['template_uuid'])
|
||||
human_readable = None
|
||||
try:
|
||||
found = False
|
||||
while not found: # the while loop is broken once something is found, or the requiredOneOf has no elements left
|
||||
required_ote_type = o_template['ObjectTemplate']['requirements']['requiredOneOf'].pop(0)
|
||||
for ote in o_template['ObjectTemplateElement']:
|
||||
if ote['object_relation'] == required_ote_type:
|
||||
required_a_type = ote['type']
|
||||
break
|
||||
for a in o['Attribute']:
|
||||
if a['type'] == required_a_type:
|
||||
human_readable = '{}: {}'.format(o['name'], a['value'])
|
||||
found = True
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
if not human_readable:
|
||||
try:
|
||||
found = False
|
||||
parts = []
|
||||
for required_ote_type in o_template['ObjectTemplate']['requirements']['required']:
|
||||
for ote in o_template['ObjectTemplateElement']:
|
||||
if ote['object_relation'] == required_ote_type:
|
||||
required_a_type = ote['type']
|
||||
break
|
||||
for a in o['Attribute']:
|
||||
if a['type'] == required_a_type:
|
||||
parts.append(a['value'])
|
||||
break
|
||||
human_readable = '{}: {}'.format(o['name'], '|'.join(parts))
|
||||
except Exception:
|
||||
human_readable = o['name']
|
||||
pass
|
||||
return MISPObject(
|
||||
human_readable,
|
||||
uuid=o['uuid'],
|
||||
event_id=int(o['event_id']),
|
||||
meta_category=o.get('meta_category'),
|
||||
description=o.get('description'),
|
||||
comment=o.get('comment'),
|
||||
link_label=link_label,
|
||||
link_direction=link_direction,
|
||||
bookmark=Bookmark.Green
|
||||
)
|
||||
|
||||
|
||||
def object_to_attributes(o, e):
|
||||
|
@ -266,13 +326,37 @@ def object_to_attributes(o, e):
|
|||
yield item
|
||||
|
||||
|
||||
def object_to_relations(o, e):
|
||||
# process forward and reverse references, so just loop over all the objects of the event
|
||||
if 'Object' in e['Event']:
|
||||
for eo in e['Event']['Object']:
|
||||
if 'ObjectReference' in eo:
|
||||
for ref in eo['ObjectReference']:
|
||||
# we have found original object. Expand to the related object and attributes
|
||||
if eo['uuid'] == o['uuid']:
|
||||
# the reference is an Object
|
||||
if ref.get('Object'):
|
||||
# get the full object in the event, as our objectReference included does not contain everything we need
|
||||
sub_object = get_object_in_event(ref['Object']['uuid'], e)
|
||||
yield object_to_entity(sub_object, link_label=ref['relationship_type'])
|
||||
# the reference is an Attribute
|
||||
if ref.get('Attribute'):
|
||||
ref['Attribute']['event_id'] = ref['event_id'] # LATER remove this ugly workaround - object can't be requested directly from MISP using the uuid, and to find a full object we need the event_id
|
||||
for item in attribute_to_entity(ref['Attribute'], link_label=ref['relationship_type']):
|
||||
yield item
|
||||
|
||||
# reverse-lookup - this is another objects relating the original object
|
||||
if ref['referenced_uuid'] == o['uuid']:
|
||||
yield object_to_entity(eo, link_label=ref['relationship_type'], link_direction=LinkDirection.OutputToInput)
|
||||
|
||||
|
||||
def get_object_in_event(uuid, e):
|
||||
for o in e['Event']['Object']:
|
||||
if o['uuid'] == uuid:
|
||||
return o
|
||||
|
||||
|
||||
def get_attribute_in_object(o, attribute_type=False, attribute_value=False, drop=False, substring=False):
|
||||
def get_attribute_in_object(o, attribute_type=False, attribute_value=False, drop=False):
|
||||
'''Gets the first attribute of a specific type within an object'''
|
||||
found_attribute = {'value': ''}
|
||||
for i, a in enumerate(o['Attribute']):
|
||||
|
@ -285,87 +369,22 @@ def get_attribute_in_object(o, attribute_type=False, attribute_value=False, drop
|
|||
found_attribute = a.copy()
|
||||
if drop: # drop the attribute from the object
|
||||
o['Attribute'].pop(i)
|
||||
break
|
||||
if '|' in a['type'] or a['type'] == 'malware-sample':
|
||||
if attribute_value in a['value'].split('|'):
|
||||
found_attribute = a.copy()
|
||||
if drop: # drop the attribute from the object
|
||||
o['Attribute'].pop(i)
|
||||
break
|
||||
# substring matching
|
||||
if substring:
|
||||
keyword = attribute_value.strip('%')
|
||||
if attribute_value.startswith('%') and attribute_value.endswith('%'):
|
||||
if attribute_value in a['value']:
|
||||
found_attribute = a.copy()
|
||||
if drop: # drop the attribute from the object
|
||||
o['Attribute'].pop(i)
|
||||
break
|
||||
if '|' in a['type'] or a['type'] == 'malware-sample':
|
||||
val1, val2 = a['value'].split('|')
|
||||
if attribute_value in val1 or attribute_value in val2:
|
||||
found_attribute = a.copy()
|
||||
if drop: # drop the attribute from the object
|
||||
o['Attribute'].pop(i)
|
||||
break
|
||||
elif attribute_value.startswith('%'):
|
||||
if a['value'].endswith(keyword):
|
||||
found_attribute = a.copy()
|
||||
if drop: # drop the attribute from the object
|
||||
o['Attribute'].pop(i)
|
||||
break
|
||||
if '|' in a['type'] or a['type'] == 'malware-sample':
|
||||
val1, val2 = a['value'].split('|')
|
||||
if val1.endswith(keyword) or val2.endswith(keyword):
|
||||
found_attribute = a.copy()
|
||||
if drop: # drop the attribute from the object
|
||||
o['Attribute'].pop(i)
|
||||
break
|
||||
|
||||
elif attribute_value.endswith('%'):
|
||||
if a['value'].startswith(keyword):
|
||||
return a
|
||||
if '|' in a['type'] or a['type'] == 'malware-sample':
|
||||
val1, val2 = a['value'].split('|')
|
||||
if val1.startswith(keyword) or val2.startswith(keyword):
|
||||
found_attribute = a.copy()
|
||||
if drop: # drop the attribute from the object
|
||||
o['Attribute'].pop(i)
|
||||
break
|
||||
return found_attribute
|
||||
|
||||
|
||||
def get_attribute_in_event(e, attribute_value, substring=False):
|
||||
def get_attribute_in_event(e, attribute_value):
|
||||
for a in e['Event']["Attribute"]:
|
||||
if a['value'] == attribute_value:
|
||||
return a
|
||||
if '|' in a['type'] or a['type'] == 'malware-sample':
|
||||
if attribute_value in a['value'].split('|'):
|
||||
return a
|
||||
if substring:
|
||||
keyword = attribute_value.strip('%')
|
||||
if attribute_value.startswith('%') and attribute_value.endswith('%'):
|
||||
if attribute_value in a['value']:
|
||||
return a
|
||||
if '|' in a['type'] or a['type'] == 'malware-sample':
|
||||
val1, val2 = a['value'].split('|')
|
||||
if attribute_value in val1 or attribute_value in val2:
|
||||
return a
|
||||
elif attribute_value.startswith('%'):
|
||||
if a['value'].endswith(keyword):
|
||||
return a
|
||||
if '|' in a['type'] or a['type'] == 'malware-sample':
|
||||
val1, val2 = a['value'].split('|')
|
||||
if val1.endswith(keyword) or val2.endswith(keyword):
|
||||
return a
|
||||
|
||||
elif attribute_value.endswith('%'):
|
||||
if a['value'].startswith(keyword):
|
||||
return a
|
||||
if '|' in a['type'] or a['type'] == 'malware-sample':
|
||||
val1, val2 = a['value'].split('|')
|
||||
if val1.startswith(keyword) or val2.startswith(keyword):
|
||||
return a
|
||||
|
||||
return None
|
||||
|
||||
|
@ -388,7 +407,7 @@ def tag_matches_note_prefix(tag):
|
|||
return False
|
||||
|
||||
|
||||
def event_to_entity(e, link_style=LinkStyle.Normal, link_label=None, link_direction=LinkDirection.InputToOutput):
|
||||
def event_to_entity(e, link_style=LinkStyle.Normal, link_direction=LinkDirection.InputToOutput):
|
||||
tags = []
|
||||
if 'Tag' in e['Event']:
|
||||
for t in e['Event']['Tag']:
|
||||
|
@ -399,10 +418,7 @@ def event_to_entity(e, link_style=LinkStyle.Normal, link_label=None, link_direct
|
|||
uuid=e['Event']['uuid'],
|
||||
info=e['Event']['info'],
|
||||
link_style=link_style,
|
||||
link_label=link_label,
|
||||
link_direction=link_direction,
|
||||
count_attributes=len(e['Event'].get('Attribute') or ""),
|
||||
count_objects=len(e['Event'].get('Object') or ""),
|
||||
notes=notes,
|
||||
bookmark=Bookmark.Green)
|
||||
|
||||
|
@ -416,13 +432,14 @@ def galaxycluster_to_entity(c, link_label=None, link_direction=LinkDirection.Inp
|
|||
else:
|
||||
synonyms = ''
|
||||
|
||||
galaxy_cluster = get_galaxy_cluster(uuid=c['uuid'])
|
||||
galaxy_cluster = get_galaxy_cluster(c['uuid'])
|
||||
# map the 'icon' name from the cluster to the icon filename of the intelligence-icons repository
|
||||
try:
|
||||
icon_url = mapping_galaxy_icon[galaxy_cluster['icon']]
|
||||
except KeyError:
|
||||
# it's not in our mapping, just ignore and leave the default icon
|
||||
icon_url = None
|
||||
# it's not in our mapping, just ignore and leave the default Galaxy icon
|
||||
pass
|
||||
|
||||
# create the right sub-galaxy: ThreatActor, Software, AttackTechnique, ... or MISPGalaxy
|
||||
try:
|
||||
|
@ -445,9 +462,9 @@ def galaxycluster_to_entity(c, link_label=None, link_direction=LinkDirection.Inp
|
|||
|
||||
# LATER this uses the galaxies from github as the MISP web UI does not fully support the Galaxies in the webui.
|
||||
# See https://github.com/MISP/MISP/issues/3801
|
||||
galaxy_archive_url = 'https://github.com/MISP/misp-galaxy/archive/main.zip'
|
||||
galaxy_archive_url = 'https://github.com/MISP/misp-galaxy/archive/master.zip'
|
||||
local_path_uuid_mapping = os.path.join(local_path_root, 'MISP_maltego_galaxy_mapping.json')
|
||||
local_path_clusters = os.path.join(local_path_root, 'misp-galaxy-main', 'clusters')
|
||||
local_path_clusters = os.path.join(local_path_root, 'misp-galaxy-master', 'clusters')
|
||||
galaxy_cluster_uuids = None
|
||||
|
||||
|
||||
|
@ -467,12 +484,6 @@ def galaxy_update_local_copy(force=False):
|
|||
force = True
|
||||
|
||||
if force:
|
||||
# create a lock to prevent two processes doing the same, and writing to the file at the same time
|
||||
lockfile = local_path_uuid_mapping + '.lock'
|
||||
from pathlib import Path
|
||||
while os.path.exists(lockfile):
|
||||
time.sleep(0.3)
|
||||
Path(local_path_uuid_mapping + '.lock').touch()
|
||||
# download the latest zip of the public galaxy
|
||||
try:
|
||||
resp = requests.get(galaxy_archive_url)
|
||||
|
@ -480,8 +491,6 @@ def galaxy_update_local_copy(force=False):
|
|||
zf.extractall(local_path_root)
|
||||
zf.close()
|
||||
except Exception:
|
||||
# remove the lock
|
||||
os.remove(lockfile)
|
||||
raise(MaltegoException("ERROR: Could not download Galaxy data from htts://github.com/MISP/MISP-galaxy/. Please check internet connectivity."))
|
||||
|
||||
# generate the uuid mapping and save it to a file
|
||||
|
@ -516,9 +525,7 @@ def galaxy_update_local_copy(force=False):
|
|||
pass
|
||||
|
||||
with open(local_path_uuid_mapping, 'w') as f:
|
||||
json.dump(cluster_uuids, f)
|
||||
# remove the lock
|
||||
os.remove(lockfile)
|
||||
json.dump(cluster_uuids, f, sort_keys=True, indent=4)
|
||||
|
||||
|
||||
def galaxy_load_cluster_mapping():
|
||||
|
@ -528,7 +535,7 @@ def galaxy_load_cluster_mapping():
|
|||
return cluster_uuids
|
||||
|
||||
|
||||
def get_galaxy_cluster(uuid=None, tag=None, request_entity=None):
|
||||
def get_galaxy_cluster(uuid=None, tag=None):
|
||||
global galaxy_cluster_uuids
|
||||
if not galaxy_cluster_uuids:
|
||||
galaxy_cluster_uuids = galaxy_load_cluster_mapping()
|
||||
|
@ -539,13 +546,6 @@ def get_galaxy_cluster(uuid=None, tag=None, request_entity=None):
|
|||
for item in galaxy_cluster_uuids.values():
|
||||
if item['tag_name'] == tag:
|
||||
return item
|
||||
if request_entity:
|
||||
if request_entity.uuid:
|
||||
return get_galaxy_cluster(uuid=request_entity.uuid)
|
||||
elif request_entity.tag_name:
|
||||
return get_galaxy_cluster(tag=request_entity.tag_name)
|
||||
elif request_entity.name:
|
||||
return get_galaxy_cluster(tag=request_entity.name)
|
||||
|
||||
|
||||
def search_galaxy_cluster(keyword):
|
||||
|
@ -553,36 +553,8 @@ def search_galaxy_cluster(keyword):
|
|||
global galaxy_cluster_uuids
|
||||
if not galaxy_cluster_uuids:
|
||||
galaxy_cluster_uuids = galaxy_load_cluster_mapping()
|
||||
|
||||
# % only at start
|
||||
if keyword.startswith('%') and not keyword.endswith('%'):
|
||||
keyword = keyword.strip('%')
|
||||
for item in galaxy_cluster_uuids.values():
|
||||
if item['value'].lower().endswith(keyword):
|
||||
yield item
|
||||
else:
|
||||
if 'meta' in item and 'synonyms' in item['meta']:
|
||||
for synonym in item['meta']['synonyms']:
|
||||
if synonym.lower().endswith(keyword):
|
||||
yield item
|
||||
|
||||
# % only at end
|
||||
elif keyword.endswith('%') and not keyword.startswith('%'):
|
||||
keyword = keyword.strip('%')
|
||||
for item in galaxy_cluster_uuids.values():
|
||||
if item['value'].lower().startswith(keyword):
|
||||
yield item
|
||||
else:
|
||||
if 'meta' in item and 'synonyms' in item['meta']:
|
||||
for synonym in item['meta']['synonyms']:
|
||||
if synonym.lower().startswith(keyword):
|
||||
yield item
|
||||
|
||||
# search substring assuming % at start and end
|
||||
else:
|
||||
keyword = keyword.strip('%')
|
||||
for item in galaxy_cluster_uuids.values():
|
||||
if keyword in item['value'].lower():
|
||||
if keyword in item['tag_name'].lower():
|
||||
yield item
|
||||
else:
|
||||
if 'meta' in item and 'synonyms' in item['meta']:
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from canari.maltego.entities import Hashtag
|
||||
from canari.maltego.transform import Transform
|
||||
# from canari.framework import EnableDebugWindow
|
||||
from MISP_maltego.transforms.common.entities import MISPEvent, MISPObject
|
||||
from MISP_maltego.transforms.common.util import check_update, MISPConnection, attribute_to_entity, event_to_entity, galaxycluster_to_entity, object_to_attributes, tag_matches_note_prefix
|
||||
from MISP_maltego.transforms.common.util import check_update, get_misp_connection, attribute_to_entity, event_to_entity, galaxycluster_to_entity, object_to_entity, object_to_attributes, object_to_relations, tag_matches_note_prefix
|
||||
from canari.maltego.message import LinkStyle
|
||||
|
||||
|
||||
|
@ -15,7 +16,7 @@ __maintainer__ = 'Christophe Vandeplas'
|
|||
__email__ = 'christophe@vandeplas.com'
|
||||
__status__ = 'Development'
|
||||
|
||||
# TODO have a more human readable version of the MISP event value in the graph. change entity + event_to_entity + do_transform
|
||||
# FIXME have a more human readable version of the MISP event value in the graph. change entity + event_to_entity + do_transform
|
||||
|
||||
|
||||
class EventToTransform(Transform):
|
||||
|
@ -26,7 +27,7 @@ class EventToTransform(Transform):
|
|||
self.request = None
|
||||
self.response = None
|
||||
self.config = None
|
||||
self.conn = None
|
||||
self.misp = None
|
||||
self.event_json = None
|
||||
self.event_tags = None
|
||||
|
||||
|
@ -36,9 +37,9 @@ class EventToTransform(Transform):
|
|||
self.config = config
|
||||
self.response += check_update(config)
|
||||
maltego_misp_event = request.entity
|
||||
self.conn = MISPConnection(config, request.parameters)
|
||||
self.misp = get_misp_connection(config)
|
||||
event_id = maltego_misp_event.id
|
||||
search_result = self.conn.misp.search(controller='events', eventid=event_id, with_attachments=False)
|
||||
search_result = self.misp.search(controller='events', eventid=event_id, with_attachments=False)
|
||||
if search_result:
|
||||
self.event_json = search_result.pop()
|
||||
else:
|
||||
|
@ -76,18 +77,17 @@ class EventToTransform(Transform):
|
|||
|
||||
def gen_response_objects(self):
|
||||
for o in self.event_json['Event']['Object']:
|
||||
self.response += self.conn.object_to_entity(o)
|
||||
self.response += object_to_entity(o)
|
||||
|
||||
def gen_response_relations(self):
|
||||
for e in self.event_json['Event']['RelatedEvent']:
|
||||
self.response += event_to_entity(e, link_style=LinkStyle.DashDot)
|
||||
|
||||
|
||||
# @EnableDebugWindow
|
||||
class EventToAll(EventToTransform):
|
||||
input_type = MISPEvent
|
||||
display_name = 'To All'
|
||||
description = 'Expands an Event to Attributes, Objects, Tags, Galaxies'
|
||||
remote = True
|
||||
|
||||
def do_transform(self, request, response, config):
|
||||
if super().do_transform(request, response, config):
|
||||
|
@ -99,24 +99,22 @@ class EventToAll(EventToTransform):
|
|||
return self.response
|
||||
|
||||
|
||||
# @EnableDebugWindow
|
||||
class EventToAttributes(EventToTransform):
|
||||
input_type = MISPEvent
|
||||
display_name = 'To Attributes/Objects'
|
||||
remote = True
|
||||
description = 'Expands an Event to Attributes'
|
||||
|
||||
def do_transform(self, request, response, config):
|
||||
if super().do_transform(request, response, config):
|
||||
self.gen_response_attributes()
|
||||
self.gen_response_objects()
|
||||
|
||||
return self.response
|
||||
|
||||
|
||||
# @EnableDebugWindow
|
||||
class EventToTags(EventToTransform):
|
||||
input_type = MISPEvent
|
||||
display_name = 'To Tags'
|
||||
description = 'Expands an Event to Tags and Galaxies'
|
||||
remote = True
|
||||
|
||||
def do_transform(self, request, response, config):
|
||||
if super().do_transform(request, response, config):
|
||||
|
@ -126,10 +124,10 @@ class EventToTags(EventToTransform):
|
|||
return self.response
|
||||
|
||||
|
||||
# @EnableDebugWindow
|
||||
class EventToGalaxies(EventToTransform):
|
||||
input_type = MISPEvent
|
||||
display_name = 'To Galaxies / ATT&CK'
|
||||
remote = True
|
||||
description = 'Expands an Event to Galaxies'
|
||||
|
||||
def do_transform(self, request, response, config):
|
||||
if super().do_transform(request, response, config):
|
||||
|
@ -138,10 +136,10 @@ class EventToGalaxies(EventToTransform):
|
|||
return self.response
|
||||
|
||||
|
||||
# @EnableDebugWindow
|
||||
class EventToObjects(EventToTransform):
|
||||
input_type = MISPEvent
|
||||
display_name = 'To Objects'
|
||||
remote = True
|
||||
description = 'Expands an Event to Objects'
|
||||
|
||||
def do_transform(self, request, response, config):
|
||||
if super().do_transform(request, response, config):
|
||||
|
@ -150,10 +148,10 @@ class EventToObjects(EventToTransform):
|
|||
return self.response
|
||||
|
||||
|
||||
# @EnableDebugWindow
|
||||
class EventToRelations(EventToTransform):
|
||||
input_type = MISPEvent
|
||||
display_name = 'To Related Events'
|
||||
remote = True
|
||||
description = 'Expands an Event to related Events'
|
||||
|
||||
def do_transform(self, request, response, config):
|
||||
if super().do_transform(request, response, config):
|
||||
|
@ -162,41 +160,43 @@ class EventToRelations(EventToTransform):
|
|||
return self.response
|
||||
|
||||
|
||||
# @EnableDebugWindow
|
||||
class ObjectToAttributes(Transform):
|
||||
""""Expands an object to its attributes"""
|
||||
input_type = MISPObject
|
||||
display_name = 'To Attributes'
|
||||
remote = True
|
||||
description = 'Expands an Object to Attributes'
|
||||
|
||||
def do_transform(self, request, response, config):
|
||||
response += check_update(config)
|
||||
maltego_object = request.entity
|
||||
conn = MISPConnection(config, request.parameters)
|
||||
event_json = conn.misp.get_event(maltego_object.event_id)
|
||||
misp = get_misp_connection(config)
|
||||
event_json = misp.get_event(maltego_object.event_id)
|
||||
for o in event_json['Event']['Object']:
|
||||
if o['uuid'] == maltego_object.uuid:
|
||||
for entity in object_to_attributes(o, event_json):
|
||||
if entity:
|
||||
response += entity
|
||||
for entity in conn.object_to_relations(o, event_json):
|
||||
for entity in object_to_relations(o, event_json):
|
||||
if entity:
|
||||
response += entity
|
||||
|
||||
return response
|
||||
|
||||
|
||||
# @EnableDebugWindow
|
||||
class ObjectToRelations(Transform):
|
||||
"""Expands an object to the relations of the object"""
|
||||
input_type = MISPObject
|
||||
display_name = 'To Related Objects'
|
||||
remote = True
|
||||
description = 'Expands an Object to Relations'
|
||||
|
||||
def do_transform(self, request, response, config):
|
||||
response += check_update(config)
|
||||
maltego_object = request.entity
|
||||
conn = MISPConnection(config, request.parameters)
|
||||
event_json = conn.misp.get_event(maltego_object.event_id)
|
||||
misp = get_misp_connection(config)
|
||||
event_json = misp.get_event(maltego_object.event_id)
|
||||
for o in event_json['Event']['Object']:
|
||||
if o['uuid'] == maltego_object.uuid:
|
||||
for entity in conn.object_to_relations(o, event_json):
|
||||
for entity in object_to_relations(o, event_json):
|
||||
if entity:
|
||||
response += entity
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from canari.maltego.transform import Transform
|
||||
# from canari.framework import EnableDebugWindow
|
||||
from MISP_maltego.transforms.common.entities import MISPEvent, MISPGalaxy, ThreatActor, Software, AttackTechnique
|
||||
from MISP_maltego.transforms.common.util import check_update, MISPConnection, galaxycluster_to_entity, get_galaxy_cluster, get_galaxies_relating, search_galaxy_cluster, mapping_galaxy_icon
|
||||
from MISP_maltego.transforms.common.util import check_update, get_misp_connection, galaxycluster_to_entity, get_galaxy_cluster, get_galaxies_relating, search_galaxy_cluster, mapping_galaxy_icon
|
||||
from canari.maltego.message import UIMessageType, UIMessage, LinkDirection
|
||||
|
||||
|
||||
|
@ -15,26 +16,52 @@ __email__ = 'christophe@vandeplas.com'
|
|||
__status__ = 'Development'
|
||||
|
||||
|
||||
# @EnableDebugWindow
|
||||
class GalaxyToEvents(Transform):
|
||||
"""Expands a Galaxy to multiple MISP Events."""
|
||||
|
||||
# The transform input entity type.
|
||||
input_type = MISPGalaxy
|
||||
|
||||
def do_transform(self, request, response, config):
|
||||
response += check_update(config)
|
||||
maltego_misp_galaxy = request.entity
|
||||
misp = get_misp_connection(config)
|
||||
if maltego_misp_galaxy.tag_name:
|
||||
tag_name = maltego_misp_galaxy.tag_name
|
||||
else:
|
||||
tag_name = maltego_misp_galaxy.value
|
||||
events_json = misp.search(controller='events', tags=tag_name, with_attachments=False)
|
||||
for e in events_json:
|
||||
response += MISPEvent(e['Event']['id'], uuid=e['Event']['uuid'], info=e['Event']['info'], link_direction=LinkDirection.OutputToInput)
|
||||
return response
|
||||
|
||||
|
||||
# @EnableDebugWindow
|
||||
class GalaxyToTransform(Transform):
|
||||
input_type = None
|
||||
|
||||
def do_transform(self, request, response, config, type_filter=MISPGalaxy):
|
||||
response += check_update(config)
|
||||
maltego_misp_galaxy = request.entity
|
||||
|
||||
current_cluster = get_galaxy_cluster(request_entity=request.entity)
|
||||
current_cluster = None
|
||||
if maltego_misp_galaxy.uuid:
|
||||
current_cluster = get_galaxy_cluster(uuid=maltego_misp_galaxy.uuid)
|
||||
elif maltego_misp_galaxy.tag_name:
|
||||
current_cluster = get_galaxy_cluster(tag=maltego_misp_galaxy.tag_name)
|
||||
elif maltego_misp_galaxy.name:
|
||||
current_cluster = get_galaxy_cluster(tag=maltego_misp_galaxy.name)
|
||||
|
||||
# legacy - replaced by Search in MISP
|
||||
if not current_cluster and request.entity.name != '-':
|
||||
if not current_cluster and maltego_misp_galaxy.name != '-':
|
||||
# maybe the user is searching for a cluster based on a substring.
|
||||
# Search in the list for those that match and return galaxy entities
|
||||
potential_clusters = search_galaxy_cluster(request.entity.name)
|
||||
potential_clusters = search_galaxy_cluster(maltego_misp_galaxy.name)
|
||||
# TODO check if duplicates are possible
|
||||
if potential_clusters:
|
||||
for potential_cluster in potential_clusters:
|
||||
new_entity = galaxycluster_to_entity(potential_cluster, link_label='Search result')
|
||||
if isinstance(new_entity, type_filter):
|
||||
response += new_entity
|
||||
response += galaxycluster_to_entity(potential_cluster, link_label='Search result')
|
||||
return response
|
||||
# end of legacy
|
||||
|
||||
if not current_cluster:
|
||||
response += UIMessage("Galaxy Cluster UUID not in local mapping. Please update local cache; non-public UUID are not supported yet.", type=UIMessageType.Inform)
|
||||
|
@ -42,7 +69,7 @@ class GalaxyToTransform(Transform):
|
|||
c = current_cluster
|
||||
|
||||
# update existing object
|
||||
galaxy_cluster = get_galaxy_cluster(uuid=c['uuid'])
|
||||
galaxy_cluster = get_galaxy_cluster(c['uuid'])
|
||||
icon_url = None
|
||||
if 'icon' in galaxy_cluster: # map the 'icon' name from the cluster to the icon filename of the intelligence-icons repository
|
||||
try:
|
||||
|
@ -67,7 +94,7 @@ class GalaxyToTransform(Transform):
|
|||
# find related objects
|
||||
if 'related' in current_cluster:
|
||||
for related in current_cluster['related']:
|
||||
related_cluster = get_galaxy_cluster(uuid=related['dest-uuid'])
|
||||
related_cluster = get_galaxy_cluster(related['dest-uuid'])
|
||||
if related_cluster:
|
||||
new_entity = galaxycluster_to_entity(related_cluster, link_label=related['type'])
|
||||
if isinstance(new_entity, type_filter):
|
||||
|
@ -86,36 +113,32 @@ class GalaxyToTransform(Transform):
|
|||
|
||||
|
||||
class GalaxyToRelations(GalaxyToTransform):
|
||||
"""Expands a Galaxy to related Galaxies and Clusters"""
|
||||
input_type = MISPGalaxy
|
||||
display_name = 'To Related Galaxies'
|
||||
remote = True
|
||||
|
||||
def do_transform(self, request, response, config, type_filter=MISPGalaxy):
|
||||
return super().do_transform(request, response, config, type_filter)
|
||||
|
||||
|
||||
class GalaxyToSoftware(GalaxyToTransform):
|
||||
"""Expands a Galaxy to related Software/Tool Galaxies"""
|
||||
input_type = MISPGalaxy
|
||||
display_name = 'To Malware/Software/Tools'
|
||||
remote = True
|
||||
|
||||
def do_transform(self, request, response, config, type_filter=Software):
|
||||
return super().do_transform(request, response, config, type_filter)
|
||||
|
||||
|
||||
class GalaxyToThreatActor(GalaxyToTransform):
|
||||
"""Expands a Galaxy to related ThreatActor Galaxies"""
|
||||
input_type = MISPGalaxy
|
||||
display_name = 'To Threat Actors'
|
||||
remote = True
|
||||
|
||||
def do_transform(self, request, response, config, type_filter=ThreatActor):
|
||||
return super().do_transform(request, response, config, type_filter)
|
||||
|
||||
|
||||
class GalaxyToAttackTechnique(GalaxyToTransform):
|
||||
"""Expands a Galaxy to related Attack Techniques Galaxies"""
|
||||
input_type = MISPGalaxy
|
||||
display_name = 'To Attack Techniques'
|
||||
remote = True
|
||||
|
||||
def do_transform(self, request, response, config, type_filter=AttackTechnique):
|
||||
return super().do_transform(request, response, config, type_filter)
|
||||
|
|