├── tmc
├── README.md
├── static
│ ├── 404.jpg
│ ├── TMCv1.png
│ ├── glasses.png
│ ├── no-data.png
│ ├── custom.js
│ └── style.css
├── __pycache__
│ ├── db.cpython-36.pyc
│ ├── auth.cpython-36.pyc
│ ├── blog.cpython-36.pyc
│ ├── maps.cpython-36.pyc
│ └── __init__.cpython-36.pyc
├── config.py
├── templates
│ ├── maps
│ │ ├── 404.html
│ │ ├── no-data.html
│ │ ├── completed.html
│ │ ├── creation
│ │ │ ├── create-subtechnique.html
│ │ │ ├── create-technique.html
│ │ │ ├── create-tactic.html
│ │ │ ├── create-tool.html
│ │ │ └── create-adversary.html
│ │ ├── explore
│ │ │ ├── main.html
│ │ │ └── explore-element.html
│ │ └── welcome.html
│ ├── login.html
│ ├── auth
│ │ ├── login.html
│ │ └── register.html
│ └── index.html
├── queries
│ ├── q_get_countries.py
│ ├── q_insert_adversary_x_tool.py
│ ├── q_insert_event_x_industry.py
│ ├── q_insert_adversary_x_event.py
│ ├── q_get_events.py
│ ├── q_insert_tactic_x_technique.py
│ ├── q_get_industries.py
│ ├── q_insert_relation_into_tables.py
│ ├── q_insert_into_events.py
│ ├── q_insert_tool_x_techn.py
│ ├── q_insert_tool_x_subtechn.py
│ ├── q_get_element_id.py
│ ├── q_get_adversaries_x_industry.py
│ ├── q_get_techniques_per_industry.py
│ ├── q_get_adversaries_x_sorigin.py
│ ├── q_get_most_used_techniques.py
│ ├── q_insert_into_tables.py
│ ├── q_get_adversaries_sorigin.py
│ ├── q_get_tactics.py
│ ├── q_get_adversaries_x_event.py
│ ├── q_get_tools.py
│ ├── q_get_events_x_industry.py
│ ├── q_get_techniques.py
│ ├── q_get_adversaries_x_tool.py
│ ├── q_get_adversaries.py
│ ├── q_insert_adversary_into_tables.py
│ ├── q_get_subtechniques.py
│ ├── q_get_adversaries_x_technique.py
│ ├── __init__.py
│ ├── q_get_tools_techniques.py
│ ├── q_get_tools_x_techniques.py
│ ├── q_get_tools_x_subtechniques.py
│ └── q_get_adversaries_techniques.py
├── db.py
├── __init__.py
├── auth.py
├── processor.py
├── schema.sql
└── maps.py
├── MANIFEST.in
├── setup.cfg
├── requirements.txt
├── .gitignore
├── setup.py
└── README.md
/tmc/README.md:
--------------------------------------------------------------------------------
1 | # TMC
2 | Threat Mapping Catalogue
3 |
--------------------------------------------------------------------------------
/tmc/static/404.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intelforge/tmc/HEAD/tmc/static/404.jpg
--------------------------------------------------------------------------------
/tmc/static/TMCv1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intelforge/tmc/HEAD/tmc/static/TMCv1.png
--------------------------------------------------------------------------------
/tmc/static/glasses.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intelforge/tmc/HEAD/tmc/static/glasses.png
--------------------------------------------------------------------------------
/tmc/static/no-data.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intelforge/tmc/HEAD/tmc/static/no-data.png
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include tmc/schema.sql
2 | graft tmc/static
3 | graft tmc/templates
4 | global-exclude *.pyc
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [tool:pytest]
2 | testpaths = tests
3 |
4 | [coverage:run]
5 | branch = True
6 | source =
7 | tmc
--------------------------------------------------------------------------------
/tmc/__pycache__/db.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intelforge/tmc/HEAD/tmc/__pycache__/db.cpython-36.pyc
--------------------------------------------------------------------------------
/tmc/__pycache__/auth.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intelforge/tmc/HEAD/tmc/__pycache__/auth.cpython-36.pyc
--------------------------------------------------------------------------------
/tmc/__pycache__/blog.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intelforge/tmc/HEAD/tmc/__pycache__/blog.cpython-36.pyc
--------------------------------------------------------------------------------
/tmc/__pycache__/maps.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intelforge/tmc/HEAD/tmc/__pycache__/maps.cpython-36.pyc
--------------------------------------------------------------------------------
/tmc/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intelforge/tmc/HEAD/tmc/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | flask
2 | # functools
3 | click
4 | attackcti
5 | IPython
6 | six==1.15.0
7 | stix2==2.0.2
8 | taxii2-client==2.2.1
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/
2 | *.py[cod]
3 | *$py.class
4 |
5 | test/
6 |
7 | instance/
8 | *.sqlite
9 |
10 | export/
11 | tmc/config.py
--------------------------------------------------------------------------------
/tmc/config.py:
--------------------------------------------------------------------------------
1 | config_dict = {
2 |
3 | "tram": "http://localhost:9999",
4 | "navigator": "http://localhost:4200",
5 | "tmc": "http://localhost:5000"
6 | }
7 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import find_packages, setup
2 |
3 | setup(
4 | name='tmc',
5 | version='1.0.0',
6 | packages=find_packages(),
7 | include_package_data=True,
8 | zip_safe=False,
9 | install_requires=[
10 | 'flask',
11 | ],
12 | )
--------------------------------------------------------------------------------
/tmc/templates/maps/404.html:
--------------------------------------------------------------------------------
1 | {% extends 'index.html' %}
2 |
3 | {% block header %}
4 |
Sorry, we are experiencing some problems...
5 | {% endblock %}
6 |
7 | {% block content %}
8 |
9 |
10 |
11 | {% endblock %}
--------------------------------------------------------------------------------
/tmc/templates/maps/no-data.html:
--------------------------------------------------------------------------------
1 | {% extends 'index.html' %}
2 |
3 | {% block header %}
4 | There's nothing here yet! Try adding some data to the database first.
5 | {% endblock %}
6 |
7 | {% block content %}
8 |
9 |
10 |
11 | {% endblock %}
--------------------------------------------------------------------------------
/tmc/templates/maps/completed.html:
--------------------------------------------------------------------------------
1 | {% extends 'index.html' %}
2 |
3 | {% block header %}
4 | {% block title %}Thank you for your patience!{% endblock %}
5 | {{ message }}
6 | {% if g.user %}
7 |
8 | Explore
9 | {% endif %}
10 | {% endblock %}
11 |
12 |
13 |
14 | {% block content %}
15 |
16 | {% endblock %}
--------------------------------------------------------------------------------
/tmc/queries/q_get_countries.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db, make_dicts
3 |
4 | # Get list of all industries available in the database.
5 | def get_countries():
6 |
7 | db = get_db()
8 | try:
9 | db.row_factory = lambda cursor, row: row[0]
10 | query = db.execute(
11 | 'SELECT country FROM countries ORDER BY country').fetchall()
12 | return query
13 | except TypeError:
14 | #embed()
15 | return False #Change this for something more meaningful -- warning/alert
--------------------------------------------------------------------------------
/tmc/queries/q_insert_adversary_x_tool.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db
3 |
4 | # Insert relation adversary per tool
5 | def insert_adversary_x_tool(adversary_id, tool_id):
6 | author_id = g.user['id']
7 |
8 | g.db = get_db()
9 | query='INSERT INTO {} ({}, {}, {}) VALUES (?, ?, ?)'.format('adversaries_x_tools', 'author_id', 'adversary_id', 'tool_id')
10 |
11 | result = g.db.execute(query, (author_id, adversary_id, tool_id))
12 | g.db.commit()
13 | element_id = result.lastrowid
14 |
15 | return element_id
--------------------------------------------------------------------------------
/tmc/queries/q_insert_event_x_industry.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db
3 |
4 | # Insert relation adversary per tool
5 | def insert_event_x_industry(event_id, industry_id):
6 | author_id = g.user['id']
7 |
8 | g.db = get_db()
9 | query='INSERT INTO {} ({}, {}, {}) VALUES (?, ?, ?)'.format('events_x_industries', 'author_id', 'event_id', 'industry_id')
10 |
11 | result = g.db.execute(query, (author_id, event_id, industry_id))
12 | g.db.commit()
13 | element_id = result.lastrowid
14 |
15 | return element_id
--------------------------------------------------------------------------------
/tmc/queries/q_insert_adversary_x_event.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db
3 |
4 | # Insert relation adversary per tool
5 | def insert_adversary_x_event(adversary_id, event_id):
6 | author_id = g.user['id']
7 |
8 | g.db = get_db()
9 | query='INSERT INTO {} ({}, {}, {}) VALUES (?, ?, ?)'.format('adversaries_x_events', 'author_id', 'adversary_id', 'event_id')
10 |
11 | result = g.db.execute(query, (author_id, adversary_id, event_id))
12 | g.db.commit()
13 | element_id = result.lastrowid
14 |
15 | return element_id
--------------------------------------------------------------------------------
/tmc/queries/q_get_events.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db, make_dicts
3 |
4 | # Get list of all events available in the database.
5 | def get_events():
6 |
7 | db = get_db()
8 | try:
9 | db.row_factory = make_dicts
10 | query = db.execute(
11 | 'SELECT event_name as Event, event_description as Description, event_url as URL FROM events').fetchall()
12 | return query
13 | except TypeError:
14 | #embed()
15 | return False #Change this for something more meaningful -- warning/alert
--------------------------------------------------------------------------------
/tmc/queries/q_insert_tactic_x_technique.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db
3 |
4 | # Insert relation tactic_x_technique
5 | def insert_tactic_x_technique(tactic_id, technique_id):
6 | author_id = g.user['id']
7 |
8 | g.db = get_db()
9 | query='INSERT INTO {} ({}, {}, {}) VALUES (?, ?, ?)'.format('tactics_x_techniques', 'author_id', 'tactic_id', 'technique_id')
10 |
11 | result = g.db.execute(query, (author_id, tactic_id, technique_id))
12 | g.db.commit()
13 | element_id = result.lastrowid
14 |
15 | return element_id
--------------------------------------------------------------------------------
/tmc/queries/q_get_industries.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db, make_dicts
3 |
4 | # Get list of all industries available in the database.
5 | def get_industries():
6 |
7 | db = get_db()
8 | try:
9 | db.row_factory = make_dicts
10 | query = db.execute(
11 | 'SELECT id as db_id, industry_name as Industry FROM industries ORDER BY industry_name ASC').fetchall()
12 | return query
13 | except TypeError:
14 | #embed()
15 | return False #Change this for something more meaningful -- warning/alert
--------------------------------------------------------------------------------
/tmc/queries/q_insert_relation_into_tables.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db
3 |
4 | # Isert relation into db from any table
5 | def insert_relation_into_tables(table, relation_name, element_name, related_id, element_id):
6 |
7 | author_id = g.user['id']
8 |
9 | g.db = get_db()
10 | query='INSERT INTO {} ({}, {}, {}) VALUES (?, ?, ?)'.format(table, 'author_id', relation_name, element_name)
11 |
12 | result = g.db.execute(query, (author_id, related_id, element_id))
13 | g.db.commit()
14 | element_id = result.lastrowid
15 |
16 | return element_id
--------------------------------------------------------------------------------
/tmc/queries/q_insert_into_events.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db
3 |
4 | # Isert into db for any table
5 | def insert_into_events(event_name, event_description, event_url):
6 |
7 | author_id = g.user['id']
8 |
9 | g.db = get_db()
10 |
11 | query='INSERT INTO events ({}, {}, {}, {}) VALUES (?, ?, ?, ?)'.format('author_id', 'event_name', 'event_description', 'event_url')
12 |
13 | result = g.db.execute(query, (author_id, event_name, event_description, event_url))
14 | g.db.commit()
15 | element_id = result.lastrowid
16 |
17 | return element_id
--------------------------------------------------------------------------------
/tmc/queries/q_insert_tool_x_techn.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db
3 |
4 | # Insert relation tool_x_technique
5 | def insert_tool_x_techn(table, tool_id, technique_id):
6 | try:
7 | author_id = g.user['id']
8 | except (NameError, TypeError) as error:
9 | author_id = 1
10 |
11 | g.db = get_db()
12 | query='INSERT INTO {} ({}, {}, {}) VALUES (?, ?, ?)'.format(table, 'author_id', 'tool_id', 'technique_id')
13 |
14 | result = g.db.execute(query, (author_id, tool_id, technique_id))
15 | g.db.commit()
16 | element_id = result.lastrowid
17 |
18 | return element_id
19 |
--------------------------------------------------------------------------------
/tmc/queries/q_insert_tool_x_subtechn.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db
3 |
4 | # Insert relation tool_x_subtechnique
5 | def insert_tool_x_subtechn(table, tool_id, subtechnique_id):
6 | try:
7 | author_id = g.user['id']
8 | except (NameError, TypeError) as error:
9 | author_id = 1
10 |
11 | g.db = get_db()
12 | query='INSERT INTO {} ({}, {}, {}) VALUES (?, ?, ?)'.format(table, 'author_id', 'tool_id', 'subtechnique_id')
13 |
14 | result = g.db.execute(query, (author_id, tool_id, subtechnique_id))
15 | g.db.commit()
16 | element_id = result.lastrowid
17 |
18 | return element_id
19 |
--------------------------------------------------------------------------------
/tmc/queries/q_get_element_id.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db
3 |
4 | # Get table element by ID
5 | def get_element_id(table, column, value): #FROM MOBILE, TECHNIQUE 'COMPROMISE' needs fixing
6 |
7 | value2 = value.replace('-', ' ').lower()
8 |
9 | db = get_db()
10 | try:
11 | query = db.execute(
12 | 'SELECT id FROM {} WHERE lower({}) is ?'.format(table, column),
13 | (value2,)
14 | )
15 | result = query.fetchone()
16 | return result['id']
17 | except TypeError:
18 | #embed()
19 | return False #Change this for something more meaningful -- warning/alert
--------------------------------------------------------------------------------
/tmc/queries/q_get_adversaries_x_industry.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db, make_dicts
3 |
4 | # Get list of all adversaries per industry available in the database.
5 | def get_adversaries_x_industry():
6 |
7 | db = get_db()
8 | try:
9 | db.row_factory = make_dicts
10 | #db.row_factory = lambda cursor, row: {row: row[0]}
11 | query = db.execute(
12 | 'SELECT adversary_id as ID, adversary_name as Name, adversary_identifiers as Identifiers, adversary_description as Description FROM adversaries ORDER BY Name').fetchall()
13 | return query
14 | except TypeError:
15 | #embed()
16 | return False #Change this for something more meaningful -- warning/alert
--------------------------------------------------------------------------------
/tmc/queries/q_get_techniques_per_industry.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db, make_dicts
3 |
4 | # Get list of all techniques per industry available in the database.
5 | def get_techniques_per_industry():
6 |
7 | db = get_db()
8 | try:
9 | db.row_factory = make_dicts
10 | #db.row_factory = lambda cursor, row: {row: row[0]}
11 | query = db.execute(
12 | 'SELECT adversary_id as ID, adversary_name as Name, adversary_identifiers as Identifiers, adversary_description as Description FROM adversaries ORDER BY Name').fetchall()
13 | return query
14 | except TypeError:
15 | #embed()
16 | return False #Change this for something more meaningful -- warning/alert
--------------------------------------------------------------------------------
/tmc/queries/q_get_adversaries_x_sorigin.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db, make_dicts
3 |
4 | # Get list of all adversaries per suspected origin available in the database.
5 | def get_adversaries_x_sorigin():
6 |
7 | db = get_db()
8 | try:
9 | db.row_factory = make_dicts
10 | #db.row_factory = lambda cursor, row: {row: row[0]}
11 | query = db.execute(
12 | 'SELECT adversary_id as ID, adversary_name as Name, adversary_identifiers as Identifiers, adversary_description as Description FROM adversaries ORDER BY Name').fetchall()
13 | return query
14 | except TypeError:
15 | #embed()
16 | return False #Change this for something more meaningful -- warning/alert
--------------------------------------------------------------------------------
/tmc/templates/login.html:
--------------------------------------------------------------------------------
1 | {% extends 'index.html' %}
2 |
3 | {% block header %}
4 | {% block title %}Log In{% endblock %}
5 | {% endblock %}
6 |
7 | {% block content %}
8 |
25 | {% endblock %}
--------------------------------------------------------------------------------
/tmc/queries/q_get_most_used_techniques.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db, make_dicts
3 |
4 | # Get list of most used techniques
5 | def get_most_used_techniques():
6 |
7 | db = get_db()
8 | try:
9 | db.row_factory = make_dicts
10 | query = db.execute(
11 | 'SELECT t.technique_id as \'TechniqueID\', t.technique_name as Technique, count(*) as Hits FROM techniques t \
12 | inner join tools_x_techniques txt on txt.technique_id=t.id \
13 | GROUP by t.technique_name \
14 | ORDER BY Hits Desc').fetchall()
15 | return query
16 | except TypeError:
17 | #embed()
18 | return False #Change this for something more meaningful -- warning/alert
--------------------------------------------------------------------------------
/tmc/queries/q_insert_into_tables.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db
3 |
4 | # Isert into db for any table
5 | def insert_into_tables(table, element_id, element_name, element_description):
6 |
7 | table_id = table[:-1] + '_id'
8 | table_name = table[:-1] + '_name'
9 | table_description = table[:-1] + '_description'
10 |
11 | author_id = g.user['id']
12 |
13 | g.db = get_db()
14 |
15 | query='INSERT INTO {} ({}, {}, {}, {}) VALUES (?, ?, ?, ?)'.format(table, 'author_id', table_id, table_name, table_description)
16 |
17 | result = g.db.execute(query, (author_id, element_id, element_name, element_description))
18 | g.db.commit()
19 | element_id = result.lastrowid
20 |
21 | return element_id
--------------------------------------------------------------------------------
/tmc/templates/auth/login.html:
--------------------------------------------------------------------------------
1 | {% extends 'index.html' %}
2 |
3 | {% block header %}
4 | {% block title %}Log In{% endblock %}
5 | {% endblock %}
6 |
7 | {% block content %}
8 |
25 | {% endblock %}
--------------------------------------------------------------------------------
/tmc/templates/auth/register.html:
--------------------------------------------------------------------------------
1 | {% extends 'index.html' %}
2 |
3 | {% block header %}
4 | {% block title %}New Usuer{% endblock %}
5 | {% endblock %}
6 |
7 | {% block content %}
8 |
25 | {% endblock %}
--------------------------------------------------------------------------------
/tmc/queries/q_get_adversaries_sorigin.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db, make_dicts
3 |
4 | # Get list of all adversaries available in the database.
5 | def get_adversaries_sorigin():
6 |
7 | db = get_db()
8 | try:
9 | db.row_factory = make_dicts
10 | #db.row_factory = lambda cursor, row: {row: row[0]}
11 | query = db.execute(
12 | 'SELECT adversary_sorigin as \'Suspected Origin\', GROUP_CONCAT(adversary_name) as Adversary \
13 | FROM adversaries \
14 | where adversary_sorigin is not null \
15 | GROUP BY adversary_sorigin;').fetchall()
16 | return query
17 | except TypeError:
18 | #embed()
19 | return False #Change this for something more meaningful -- warning/alert
--------------------------------------------------------------------------------
/tmc/queries/q_get_tactics.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db, make_dicts
3 |
4 | # Get list of all techniques available in the database.
5 | def get_tactics(tactic=''):
6 | db = get_db()
7 | db.row_factory = make_dicts
8 | try:
9 | if not tactic:
10 | query = db.execute(
11 | 'SELECT id as \'db_id\', tactic_id as ID, tactic_name as Tactic, tactic_description as Description FROM tactics ORDER BY tactic_name ASC').fetchall()
12 | return query
13 | else:
14 | query = db.execute( 'SELECT * FROM tactics WHERE id is ?',
15 | (tactic,)
16 | ).fetchone()
17 | return query
18 |
19 | except TypeError:
20 | return False #Change this for something more meaningful -- warning/alert
--------------------------------------------------------------------------------
/tmc/queries/q_get_adversaries_x_event.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db, make_dicts
3 |
4 | # Get list of all adversaries per event available in the database.
5 | def get_adversaries_x_event():
6 |
7 | db = get_db()
8 | try:
9 | db.row_factory = make_dicts
10 | #db.row_factory = lambda cursor, row: {row: row[0]}
11 | query = db.execute(
12 | 'select a.adversary_id, a.adversary_name, event_name, event_description from events e \
13 | inner join adversaries_x_events ae on ae.event_id = e.id \
14 | inner join adversaries a on a.id = ae.adversary_id ORDER BY adversary_name').fetchall()
15 | return query
16 | except TypeError:
17 | #embed()
18 | return False #Change this for something more meaningful -- warning/alert
--------------------------------------------------------------------------------
/tmc/queries/q_get_tools.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db, make_dicts
3 |
4 | # Get list of all tools available in the database.
5 | def get_tools(tool=''):
6 | db = get_db()
7 | db.row_factory = make_dicts
8 | try:
9 | if not tool:
10 | query = db.execute(
11 | 'SELECT id as \'db_id\', tool_id as ID, tool_name as Tool, tool_description as Description, tool_identifiers as Identifiers FROM tools ORDER BY tool_name').fetchall()
12 | return query
13 | else:
14 | query = db.execute( 'SELECT * FROM tools WHERE id is ?',
15 | (tool,)
16 | ).fetchone()
17 | return query
18 | except TypeError:
19 | #embed()
20 | return False #Change this for something more meaningful -- warning/alert
--------------------------------------------------------------------------------
/tmc/queries/q_get_events_x_industry.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db, make_dicts
3 |
4 | # Get list of all events per industry available in the database.
5 | def get_events_x_industry():
6 |
7 | db = get_db()
8 | db.row_factory = make_dicts
9 | try:
10 | query = db.execute(
11 | 'select a.adversary_name, i.industry_name, e.event_name from events e \
12 | inner join events_x_industries ei on e.id = ei.event_id \
13 | inner join industries i on i.id = ei.industry_id \
14 | inner join adversaries_x_events ae on ae.event_id = e.id \
15 | inner join adversaries a on a.id = ae.adversary_id').fetchall()
16 | return query
17 | except TypeError:
18 | #embed()
19 | return False #Change this for something more meaningful -- warning/alert
--------------------------------------------------------------------------------
/tmc/queries/q_get_techniques.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db, make_dicts
3 |
4 | # Get list of all techniques available in the database.
5 | def get_techniques(technique=''):
6 | db = get_db()
7 | db.row_factory = make_dicts
8 | try:
9 | if not technique:
10 | query = db.execute(
11 | 'SELECT id as \'db_id\', technique_id as ID, technique_name as Technique, technique_description as Description FROM techniques ORDER BY technique_name ASC').fetchall()
12 | return query
13 | else:
14 | query = db.execute( 'SELECT * FROM techniques WHERE id is ?',
15 | (technique,)
16 | ).fetchone()
17 | return query
18 |
19 | except TypeError:
20 | return False #Change this for something more meaningful -- warning/alert
--------------------------------------------------------------------------------
/tmc/queries/q_get_adversaries_x_tool.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db, make_dicts
3 |
4 | # Get list of all adversaries per tool available in the database.
5 | def get_adversaries_x_tool():
6 |
7 | db = get_db()
8 | try:
9 | db.row_factory = make_dicts
10 | query = db.execute(
11 | "SELECT a.adversary_id As \'Adversary ID\', a.adversary_name as Adversary, t.tool_id as \'Tool ID\', t.tool_name as Tool \
12 | FROM adversaries a \
13 | inner join adversaries_x_tools axt on axt.adversary_id=a.id \
14 | inner join tools t on axt.tool_id=t.id \
15 | ORDER BY a.adversary_name").fetchall()
16 | return query
17 | except TypeError:
18 | #embed()
19 | return False #Change this for something more meaningful -- warning/alert
--------------------------------------------------------------------------------
/tmc/queries/q_get_adversaries.py:
--------------------------------------------------------------------------------
1 | from flask import ( g )
2 | from tmc.db import get_db, make_dicts
3 | from IPython import embed
4 |
5 | # Get list of all adversaries available in the database.
6 | def get_adversaries(adversary=''):
7 |
8 | db = get_db()
9 | db.row_factory = make_dicts
10 | try:
11 | if not adversary:
12 | query = db.execute('SELECT id as db_id, adversary_id as ID, adversary_name as Adversary, adversary_identifiers as Identifiers, adversary_description as Description \
13 | FROM adversaries ORDER BY adversary_name ASC').fetchall()
14 | return query
15 | else:
16 | query = db.execute(
17 | 'SELECT * FROM adversaries WHERE id is ?',
18 | (adversary,)
19 | ).fetchone()
20 | return query
21 | except TypeError:
22 | return False
--------------------------------------------------------------------------------
/tmc/queries/q_insert_adversary_into_tables.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db
3 |
4 | # Iserta adversary into db from table
5 | def insert_adversary_into_tables(table, element_id, element_name, element_description, element_identifiers):
6 |
7 | table_id = 'adversary_id'
8 | table_name = 'adversary_name'
9 | table_description = 'adversary_description'
10 | adversary_identifiers = 'adversary_identifiers'
11 |
12 | author_id = g.user['id']
13 |
14 | g.db = get_db()
15 | query='INSERT INTO {} ({}, {}, {}, {}, {}) VALUES (?, ?, ?, ?, ?)'.format(table, 'author_id', table_id, table_name, table_description, adversary_identifiers)
16 | result = g.db.execute(query, (author_id, element_id, element_name, element_description, element_identifiers))
17 | g.db.commit()
18 | element_id = result.lastrowid
19 |
20 | return element_id
--------------------------------------------------------------------------------
/tmc/queries/q_get_subtechniques.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db, make_dicts
3 |
4 | # Get list of all subtechniques available in the database.
5 | def get_subtechniques(subtechnique=''):
6 | db = get_db()
7 | db.row_factory = make_dicts
8 | try:
9 | if not subtechnique:
10 | query = db.execute(
11 | 'SELECT id as \'db_id\', subtechnique_id as ID, subtechnique_name as Subtechnique, subtechnique_description as Description FROM subtechniques ORDER BY subtechnique_name ASC').fetchall()
12 | return query
13 | else:
14 | query = db.execute( 'SELECT * FROM subtechniques WHERE id is ?',
15 | (subtechnique,)
16 | ).fetchone()
17 | return query
18 |
19 | except TypeError:
20 | return False #Change this for something more meaningful -- warning/alert
--------------------------------------------------------------------------------
/tmc/db.py:
--------------------------------------------------------------------------------
1 | import sqlite3
2 |
3 | import click
4 | from flask import current_app, g
5 | from flask.cli import with_appcontext
6 |
7 |
8 | def get_db():
9 | if 'db' not in g:
10 | g.db = sqlite3.connect(
11 | current_app.config['DATABASE'],
12 | detect_types=sqlite3.PARSE_DECLTYPES
13 | )
14 | g.db.row_factory = sqlite3.Row
15 |
16 | return g.db
17 |
18 |
19 | def close_db(e=None):
20 | db = g.pop('db', None)
21 |
22 | if db is not None:
23 | db.close()
24 |
25 |
26 | def init_db():
27 | db = get_db()
28 |
29 | with current_app.open_resource('schema.sql') as f:
30 | db.executescript(f.read().decode('utf8'))
31 |
32 |
33 | @click.command('init-db')
34 | @with_appcontext
35 | def init_db_command():
36 | """Clear the existing data and create new tables."""
37 | init_db()
38 | click.echo('Initialized the database.')
39 |
40 |
41 | def init_app(app):
42 | app.teardown_appcontext(close_db)
43 | app.cli.add_command(init_db_command)
44 |
45 | def make_dicts(cursor, row):
46 | return dict((cursor.description[idx][0], value)
47 | for idx, value in enumerate(row))
--------------------------------------------------------------------------------
/tmc/queries/q_get_adversaries_x_technique.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db, make_dicts
3 |
4 | # Get list of all adversaries per technique available in the database.
5 | def get_adversaries_x_technique():
6 |
7 | db = get_db()
8 | try:
9 | db.row_factory = make_dicts
10 | query = db.execute(
11 | 'SELECT a.adversary_id As \'Adversary ID\', a.adversary_name as Adversary, t.technique_id as \'Technique ID\', t.technique_name as Technique, s.subtechnique_id as \'Subtechnique ID\',s.subtechnique_name as Subtechnique \
12 | FROM adversaries a \
13 | inner join adversaries_x_tools axt on axt.adversary_id=a.id \
14 | inner join tools_x_techniques txt on txt.tool_id=axt.tool_id \
15 | inner join tools_x_subtechniques txst on txst.tool_id=axt.tool_id \
16 | inner join techniques t on t.id=txt.technique_id \
17 | inner join subtechniques s on s.id=txst.subtechnique_id \
18 | ORDER BY a.adversary_name ').fetchall() #LIMIT 100 OFFSET 200
19 | return query
20 | except TypeError:
21 | #embed()
22 | return False #Change this for something more meaningful -- warning/alert
--------------------------------------------------------------------------------
/tmc/queries/__init__.py:
--------------------------------------------------------------------------------
1 | __all__ = ["q_get_element_id",
2 | "q_insert_into_tables",
3 | "q_insert_into_events",
4 | "q_insert_adversary_x_event",
5 | "q_insert_adversary_x_tool",
6 | "q_insert_event_x_industry",
7 | "q_insert_tactic_x_technique",
8 | "q_insert_tool_x_techn",
9 | "q_get_tools_x_subtechniques",
10 | "q_insert_adversary_into_tables",
11 | "q_get_adversaries",
12 | "q_get_adversaries_sorigin",
13 | "q_get_adversaries_techniques",
14 | "q_get_tools_techniques",
15 | "q_get_countries",
16 | "q_get_industries",
17 | "q_get_events",
18 | "q_get_tools",
19 | "q_get_tactics",
20 | "q_get_techniques",
21 | "q_get_subtechniques",
22 | "q_get_adversaries_x_event",
23 | "q_get_adversaries_x_tool",
24 | "q_get_adversaries_x_technique",
25 | "q_get_adversaries_x_sorigin",
26 | "q_get_adversaries_x_industry",
27 | "q_get_tools_x_techniques",
28 | "q_get_events_x_industry",
29 | "q_get_most_used_techniques",
30 | "q_get_techniques_per_industry",
31 | "q_insert_relation_into_tables",
32 | "q_insert_tool_x_subtechn"
33 | ]
--------------------------------------------------------------------------------
/tmc/queries/q_get_tools_techniques.py:
--------------------------------------------------------------------------------
1 | from flask import ( g )
2 | from tmc.db import get_db, make_dicts
3 | from IPython import embed
4 |
5 | # Get list of adversary techniques available in the database.
6 | def get_tools_techniques(tool_id):
7 |
8 | db = get_db()
9 | db.row_factory = make_dicts
10 | try:
11 | query = db.execute('select t.tool_name as Tool, tec.technique_id as TechniqueID, \
12 | tec.technique_name as Technique, null as SubtechniqueID, null as Subtechnique \
13 | from tools t \
14 | inner join tools_x_techniques tt on t.id = tt.tool_id \
15 | inner join techniques tec on tec.id = tt.technique_id \
16 | where t.id=? \
17 | \
18 | UNION ALL \
19 | \
20 | select t.tool_name as Tool , tec.technique_id, tec.technique_name, stec.subtechnique_id, \
21 | stec.subtechnique_name from tools t \
22 | inner join tools_x_subtechniques st on t.id = st.tool_id \
23 | inner join techniques_x_subtechniques ts on st.subtechnique_id=ts.subtechnique_id \
24 | inner join techniques tec on tec.id=ts.technique_id \
25 | inner join subtechniques stec on stec.id = st.subtechnique_id \
26 | where t.id=? \
27 | ORDER BY t.tool_name, tec.technique_id, stec.subtechnique_id',
28 | (tool_id, tool_id, ))
29 | result = query.fetchall()
30 | return result
31 | except TypeError:
32 | return False
--------------------------------------------------------------------------------
/tmc/queries/q_get_tools_x_techniques.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db, make_dicts
3 |
4 | # Get list of all tools per technique available in the database.
5 | def get_tools_x_techniques(technique=''):
6 |
7 | db = get_db()
8 | db.row_factory = make_dicts
9 | try:
10 | if technique:
11 | query = db.execute(
12 | 'SELECT t.tool_id As \'ToolID\', t.tool_name as Tool, tec.technique_id as \'TechniqueID\', tec.technique_name as Technique \
13 | FROM tools t \
14 | inner join adversaries_x_tools axt on axt.tool_id=t.id \
15 | inner join tools_x_techniques txt on txt.technique_id=t.id \
16 | inner join techniques tec on tec.id=txt.technique_id \
17 | WHERE t.id=?', (technique, )).fetchall()
18 | return query
19 | else:
20 | query = db.execute(
21 | 'SELECT t.tool_id As \'ToolID\', t.tool_name as Tool, tec.technique_id as \'TechniqueID\', tec.technique_name as Technique \
22 | FROM tools t \
23 | inner join adversaries_x_tools axt on axt.tool_id=t.id \
24 | inner join tools_x_techniques txt on txt.technique_id=t.id \
25 | inner join techniques tec on tec.id=txt.technique_id \
26 | ORDER BY t.tool_name').fetchall()
27 | return query
28 | except TypeError:
29 | #embed()
30 | return False #Change this for something more meaningful -- warning/alert
--------------------------------------------------------------------------------
/tmc/templates/maps/creation/create-subtechnique.html:
--------------------------------------------------------------------------------
1 | {% extends 'index.html' %}
2 |
3 | {% block header %}
4 | {% if request_subtechnique %}
5 | Edit subtechnique
6 | {% else %}
7 | New subtechnique
8 | {% endif %}
9 | {% endblock %}
10 |
11 | {% block content %}
12 |
42 | {% endblock %}
--------------------------------------------------------------------------------
/tmc/__init__.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from flask import Flask
4 |
5 |
6 | def create_app(test_config=None):
7 | """Create and configure an instance of the Flask application."""
8 | app = Flask(__name__, instance_relative_config=True)
9 | app.config.from_mapping(
10 | # a default secret that should be overridden by instance config
11 | SECRET_KEY="dev",
12 | # store the database in the instance folder
13 | DATABASE=os.path.join(app.instance_path, "tmc.sqlite"),
14 | )
15 |
16 | if test_config is None:
17 | # load the instance config, if it exists, when not testing
18 | app.config.from_pyfile("config.py", silent=True)
19 | else:
20 | # load the test config if passed in
21 | app.config.update(test_config)
22 |
23 | # ensure the instance folder exists
24 | try:
25 | os.makedirs(app.instance_path)
26 | except OSError:
27 | pass
28 |
29 | @app.route("/hello")
30 | def hello():
31 | return "Hello, World!"
32 |
33 | # register the database commands
34 | from tmc import db
35 |
36 | db.init_app(app)
37 |
38 | # apply the blueprints to the app
39 | from tmc import auth, maps
40 |
41 | app.register_blueprint(auth.bp)
42 | app.register_blueprint(maps.bp)
43 |
44 | # make url_for('index') == url_for('maps.index')
45 | # in another app, you might define a separate main index here with
46 | # app.route, while giving the blog blueprint a url_prefix, but for
47 | # the tutorial the blog will be the main index
48 | app.add_url_rule("/", endpoint="index")
49 |
50 | return app
--------------------------------------------------------------------------------
/tmc/queries/q_get_tools_x_subtechniques.py:
--------------------------------------------------------------------------------
1 | from flask import ( g, redirect, url_for )
2 | from tmc.db import get_db, make_dicts
3 |
4 | # Get list of all tools per technique available in the database.
5 | def get_tools_x_subtechniques(subtechnique=''):
6 |
7 | db = get_db()
8 | db.row_factory = make_dicts
9 | try:
10 | if subtechnique:
11 | query = db.execute(
12 | 'SELECT t.tool_id As \'ToolID\', t.tool_name as Tool, subtec.subtechnique_id as \'SubtechniqueID\', subtec.subtechnique_name as Subtechnique \
13 | FROM tools t \
14 | inner join adversaries_x_tools axt on axt.tool_id=t.id \
15 | inner join tools_x_subtechniques txt on txt.subtechnique_id=t.id \
16 | inner join subtechniques subtec on subtec.id=txt.subtechnique_id \
17 | WHERE t.id=?', (subtechnique, )).fetchall()
18 | return query
19 | else:
20 | query = db.execute(
21 | 'SELECT t.tool_id As \'ToolID\', t.tool_name as Tool, subtec.subtechnique_id as \'SubtechniqueID\', subtec.subtechnique_name as Subtechnique \
22 | FROM tools t \
23 | inner join adversaries_x_tools axt on axt.tool_id=t.id \
24 | inner join tools_x_subtechniques txt on txt.subtechnique_id=t.id \
25 | inner join subtechniques subtec on subtec.id=txt.subtechnique_id \
26 | ORDER BY t.tool_name').fetchall()
27 | return query
28 | except TypeError:
29 | #embed()
30 | return False #Change this for something more meaningful -- warning/alert
--------------------------------------------------------------------------------
/tmc/queries/q_get_adversaries_techniques.py:
--------------------------------------------------------------------------------
1 | from flask import ( g )
2 | from tmc.db import get_db, make_dicts
3 |
4 | # Get list of adversary techniques available in the database.
5 | def get_adversaries_techniques(adversary_id):
6 |
7 | db = get_db()
8 | db.row_factory = make_dicts
9 | try:
10 | query = db.execute('select t.tool_name as Tool, tec.technique_id as TechniqueID, \
11 | tec.technique_name as Technique, null as SubtechniqueID, null as Subtechnique \
12 | from adversaries_x_tools at \
13 | inner join tools t on at.tool_id = t.id \
14 | inner join tools_x_techniques tt on t.id = tt.tool_id \
15 | inner join techniques tec on tec.id = tt.technique_id \
16 | where at.adversary_id=? \
17 | \
18 | UNION ALL\
19 | \
20 | select t.tool_name as Tool , tec.technique_id, tec.technique_name, stec.subtechnique_id \
21 | , stec.subtechnique_name from adversaries_x_tools at \
22 | inner join tools t on at.tool_id = t.id \
23 | inner join tools_x_subtechniques st on t.id = st.tool_id \
24 | inner join techniques_x_subtechniques ts on st.subtechnique_id=ts.subtechnique_id \
25 | inner join techniques tec on tec.id=ts.technique_id \
26 | inner join subtechniques stec on stec.id = st.subtechnique_id \
27 | where at.adversary_id=? \
28 | ORDER BY t.tool_name, tec.technique_id, stec.subtechnique_id' ,
29 | (adversary_id, adversary_id, ))
30 | result = query.fetchall()
31 | return result
32 | except TypeError:
33 | return False
--------------------------------------------------------------------------------
/tmc/static/custom.js:
--------------------------------------------------------------------------------
1 | $(function(){
2 | // Change first column background color.
3 | $("#firstColumn").click(function(){
4 | $("table tr td:first-child").css("background-color","#ff0000");
5 | });
6 | // Change second column background color.
7 | $("#secondColumn").click(function(){
8 | $("table tr td:nth-child(2)").css("background-color","#ff0000");
9 | });
10 | });
11 |
12 | $(document).ready(function() {
13 |
14 | var table = $('#explore_results').DataTable();
15 | var anchor = document.querySelectorAll('.disabled');
16 |
17 | var loc = location.href;
18 |
19 | $('#explore_results tbody').on( 'click', 'tr', function () {
20 | if ( $(this).hasClass('selected') ) {
21 | $(this).removeClass('selected');
22 | for (var i = 0; i < anchor.length; i++) {
23 | anchor[i].classList.add('disabled');
24 | }
25 | }
26 | else {
27 | table.$('tr.selected').removeClass('selected');
28 | $(this).addClass('selected');
29 | var column_count = table.$('tr.selected').children().length;
30 | var enables = table.$('tr.selected').children()[column_count-1].children;
31 | for (var i = 0; i < enables.length; i++) {
32 | enables[i].classList.remove('disabled');
33 | }
34 | }
35 | } );
36 |
37 | } );
38 |
39 | function clickRowListener(anchor) {
40 | var table = $('#explore_results').DataTable();
41 | var headers = document.querySelectorAll("th");
42 | var element_value = table.$('tr.selected').find('td').eq(0).text();
43 | var element_name = headers[2].innerText;
44 | var atb = anchor.getAttribute('title');
45 | var link = atb + "/" + element_name.toLowerCase() + "/" + element_value.toLowerCase();
46 | window.location.replace(link);
47 | }
48 |
49 |
50 | function open_tram()
51 | {
52 | var win=window.open('http://localhost:9999', '_blank');
53 | win.focus();
54 | }
--------------------------------------------------------------------------------
/tmc/templates/maps/creation/create-technique.html:
--------------------------------------------------------------------------------
1 | {% extends 'index.html' %}
2 |
3 | {% block header %}
4 | {% if request_technique %}
5 | Edit Technique
6 | {% else %}
7 | New Technique
8 | {% endif %}
9 | {% endblock %}
10 |
11 | {% block content %}
12 |
13 |
48 |
49 | {% endblock %}
--------------------------------------------------------------------------------
/tmc/static/style.css:
--------------------------------------------------------------------------------
1 | /***************
2 | #General
3 | ****************/
4 |
5 | html, body {
6 | background-color: #fff;
7 | color: #000;
8 | font-size: 1.05rem;
9 | }
10 |
11 | .btn-dark {
12 | background-color: #000;
13 | }
14 |
15 | label, .btn-dark {
16 | margin-top: 3%;
17 | }
18 |
19 | h2, p {
20 | color: #000;
21 | }
22 |
23 | .container:not(nav){
24 | border: solid 1px #000;
25 | margin-bottom: 15%;
26 | }
27 |
28 | .error_bckg {
29 | width:80%;
30 | display: block;
31 | margin: 0 auto;
32 | }
33 | /***************
34 | #Nav
35 | ****************/
36 |
37 | nav {
38 | margin-bottom: 2%;
39 |
40 | }
41 |
42 | #logo {
43 | width: 5%;
44 | }
45 |
46 |
47 | nav h1 {
48 | margin-top: 5%;
49 | display: inline-block;
50 | vertical-align: sub;
51 | }
52 |
53 | nav ul {
54 | list-style-type: none;
55 | text-align: right;
56 | }
57 |
58 | nav ul li {
59 | display: inline-block;
60 | padding-right: 2%;
61 | }
62 |
63 |
64 | ul li a {
65 | color: #000;
66 | }
67 |
68 | a:hover, ul li a:hover {
69 | color: #FF0000;
70 | }
71 |
72 |
73 | /***************
74 | #Body
75 | ****************/
76 |
77 | div.container {
78 | /* background-color: rgba(1,1,45,0.6);*/
79 | padding: 2%;
80 | }
81 |
82 | .btn:hover, .bnt-dark:hover {
83 | background-color: #424242;
84 | }
85 |
86 | /***************
87 | #Explore
88 | ****************/
89 | .create-menu ul, .action-list {
90 | text-decoration: none;
91 | text-align: right;
92 | }
93 |
94 | .create-menu ul li, i {
95 | display: inline-block;
96 | }
97 |
98 | .create-menu ul li {
99 | background-color: #000;
100 | border: 1px solid black;
101 | padding: 0.5% 0.9%;
102 | margin-left: 2%
103 | }
104 |
105 | .create-menu ul li a {
106 | color: #fff;
107 | font-size: 1em;
108 | }
109 |
110 | .row a, .row a.disabled {
111 | color: #000;
112 | margin-right: 3%;
113 | }
114 |
115 | #actions a {
116 | margin-right: 13%;
117 | display: block;
118 | padding-top: 15%;
119 | }
120 |
121 | .row a.disabled {
122 | cursor: not-allowed;
123 | opacity: 0.5;
124 | }
125 |
126 | table {
127 | margin-top: 3%;
128 | }
129 |
--------------------------------------------------------------------------------
/tmc/templates/maps/explore/main.html:
--------------------------------------------------------------------------------
1 | {% extends 'index.html' %}
2 |
3 | {% block header %}
4 | {% if g.user %}
5 |
14 | {% endif %}
15 | {% endblock %}\
16 |
17 | {% block content %}
18 |
19 | List database elements
20 |
21 |
29 |
30 | Explore database relationships
31 |
32 |
44 | {% endblock %}
--------------------------------------------------------------------------------
/tmc/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {% block title %}{% endblock %}TMC
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
38 |
39 |
40 |
41 |
42 |
43 | Threat Mapping Catalogue
44 |
45 |
56 |
57 |
58 |
59 |
60 | {% block header %}{% endblock %}
61 |
62 | {% for message in get_flashed_messages() %}
63 | {{ message }}
64 | {% endfor %}
65 | {% block content %}{% endblock %}
66 |
67 |
--------------------------------------------------------------------------------
/tmc/templates/maps/welcome.html:
--------------------------------------------------------------------------------
1 | {% extends 'index.html' %}
2 |
3 | {% block header %}
4 |
5 | {% block title %}Welcome!{% endblock %}
6 | Load one or multiple URLs to carry out the mapping against TRAM. Select which adversary, tool, and industry you want that mapping to be associated with.
7 | {% if g.user %}
8 |
12 | {% endif %}
13 | {% endblock %}
14 |
15 |
16 | {% block content %}
17 |
18 |
19 |
62 |
63 |
64 | {% endblock %}
65 |
--------------------------------------------------------------------------------
/tmc/auth.py:
--------------------------------------------------------------------------------
1 | import functools
2 |
3 | from flask import (
4 | Blueprint, flash, g, redirect, render_template, request, session, url_for
5 | )
6 | from werkzeug.security import check_password_hash, generate_password_hash
7 |
8 | from tmc.db import get_db
9 |
10 | bp = Blueprint('auth', __name__, url_prefix='/auth')
11 |
12 | @bp.route('/register', methods=('GET', 'POST'))
13 | def register():
14 | if request.method == 'POST':
15 | username = request.form['username']
16 | password = request.form['password']
17 | db = get_db()
18 | error = None
19 |
20 | if not username:
21 | error = 'Username is required.'
22 | elif not password:
23 | error = 'Password is required.'
24 | elif db.execute(
25 | 'SELECT id FROM users WHERE username = ?', (username,)
26 | ).fetchone() is not None:
27 | error = 'User {} is already registered.'.format(username)
28 |
29 | if error is None:
30 | db.execute(
31 | 'INSERT INTO users (username, password) VALUES (?, ?)',
32 | (username, generate_password_hash(password))
33 | )
34 | db.commit()
35 | return redirect(url_for('auth.login'))
36 |
37 | flash(error)
38 |
39 | return render_template('auth/register.html')
40 |
41 |
42 | @bp.route('/login', methods=('GET', 'POST'))
43 | def login():
44 | if request.method == 'POST':
45 | username = request.form['username']
46 | password = request.form['password']
47 | db = get_db()
48 | error = None
49 | user = db.execute(
50 | 'SELECT * FROM users WHERE username = ?', (username,)
51 | ).fetchone()
52 |
53 | if user is None:
54 | error = 'Incorrect username.'
55 | elif not check_password_hash(user['password'], password):
56 | error = 'Incorrect password.'
57 |
58 | if error is None:
59 | session.clear()
60 | session['user_id'] = user['id']
61 | return redirect(url_for('index'))
62 |
63 | flash(error)
64 |
65 | return render_template('auth/login.html')
66 |
67 |
68 | @bp.before_app_request
69 | def load_logged_in_user():
70 | user_id = session.get('user_id')
71 |
72 | if user_id is None:
73 | g.user = None
74 | else:
75 | g.user = get_db().execute(
76 | 'SELECT * FROM users WHERE id = ?', (user_id,)
77 | ).fetchone()
78 |
79 |
80 | @bp.route('/logout')
81 | def logout():
82 | session.clear()
83 | return redirect(url_for('index'))
84 |
85 |
86 | def login_required(view):
87 | @functools.wraps(view)
88 | def wrapped_view(**kwargs):
89 | if g.user is None:
90 | return redirect(url_for('auth.login'))
91 |
92 | return view(**kwargs)
93 |
94 | return wrapped_view
--------------------------------------------------------------------------------
/tmc/templates/maps/explore/explore-element.html:
--------------------------------------------------------------------------------
1 | {% extends 'index.html' %}
2 |
3 | {% block header %}
4 | {% if g.user %}
5 |
14 | {% endif %}
15 | {% endblock %}
16 |
17 |
18 |
19 |
20 | {% block content %}
21 |
22 |
63 |
64 | {% endblock %}
65 |
--------------------------------------------------------------------------------
/tmc/templates/maps/creation/create-tactic.html:
--------------------------------------------------------------------------------
1 | {% extends 'index.html' %}
2 |
3 | {% block header %}
4 | {% if request_tactic %}
5 | Edit tactic
6 | {% else %}
7 | New tactic
8 | {% endif %}
9 | {% endblock %}
10 |
11 | {% block content %}
12 |
13 |
45 |
46 |
47 | {% if request_tactic_techniques|length %}
48 |
49 |
50 |
51 |
52 | {% for element in element_th %}
53 | {{ element }}
54 | {% endfor %}
55 | Actions
56 |
57 |
58 |
59 | {% for element in request_tactic_techniques %}
60 |
61 | {% for key, value in element.items() %}
62 | {{ value }}
63 | {% endfor %}
64 |
65 |
66 |
67 |
68 |
69 | {% endfor %}
70 |
71 |
72 | {% endif %}
73 |
74 | {% endblock %}
--------------------------------------------------------------------------------
/tmc/templates/maps/creation/create-tool.html:
--------------------------------------------------------------------------------
1 | {% extends 'index.html' %}
2 |
3 | {% block header %}
4 | {% if request_tool %}
5 | Edit Tool
6 | {% else %}
7 | New Tool
8 | {% endif %}
9 | {% endblock %}
10 |
11 | {% block content %}
12 |
13 |
54 |
55 |
56 | {% if request_tools_techniques|length %}
57 |
58 |
59 |
60 |
61 | {% for element in element_th %}
62 | {{ element }}
63 | {% endfor %}
64 | Actions
65 |
66 |
67 |
68 | {% for element in request_tools_techniques %}
69 |
70 | {% for key, value in element.items() %}
71 | {{ value }}
72 | {% endfor %}
73 |
74 |
75 |
76 |
77 |
78 | {% endfor %}
79 |
80 |
81 | {% endif %}
82 |
83 | {% endblock %}
--------------------------------------------------------------------------------
/tmc/templates/maps/creation/create-adversary.html:
--------------------------------------------------------------------------------
1 | {% extends 'index.html' %}
2 |
3 | {% block header %}
4 | {% if request_adversary %}
5 | Edit Adversary
6 | {% else %}
7 | New Adversary
8 | {% endif %}
9 | {% endblock %}
10 |
11 | {% block content %}
12 |
13 |
54 |
55 |
56 | {% if request_adversary_techniques|length %}
57 |
58 |
59 |
60 |
61 | {% for element in element_th %}
62 | {{ element }}
63 | {% endfor %}
64 | Actions
65 |
66 |
67 |
68 | {% for element in request_adversary_techniques %}
69 | {% for key, value in element.items() %}
70 | {{ value }}
71 | {% endfor %}
72 |
73 |
74 |
75 |
76 |
77 | {% endfor %}
78 |
79 |
80 | {% endif %}
81 |
82 | {% endblock %}
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://www.gnu.org/licenses/gpl-3.0)
2 | [](https://github.com/ellerbrock/open-source-badges/)
3 | [](https://github.com/mkenney/software-guides/blob/master/STABILITY-BADGES.md#alpha)
4 |
5 | # tmc
6 | Threat Mapping Catalogue
7 |
8 | 
9 |
10 | ## Requirements
11 | - [python3](https://www.python.org/) (3.7+)
12 | - Flask
13 | - Sqlite
14 | - **TRAM adaptation** : (https://github.com/fierytermite/tram-1) [forked from fixed version by [@cyb3rR4v3n](https://twitter.com/cyb3rR4v3n)
15 | - **Attack Navigator adaptation** : (https://github.com/fierytermite/attack-navigator)
16 |
17 | For the navigator, you'll need to clone the branch 'tmc' in order to make it work:
18 |
19 | ```
20 | git clone --branch tmc https://github.com/fierytermite/attack-navigator
21 | ```
22 |
23 | Note!! In order to the Navigator Adaptation to work properly you would have to work around CORS blocked by policy. You can get away easily by using Chrome browser extension [Allow CORS: Access-Control-Allow-Origin](https://chrome.google.com/webstore/detail/allow-cors-access-control/lhobafahddgcelffkeicbaginigeejlf?). Keep in mind that CORS blocks are implemented for security reasons, so allow them wisely. You can still use TRAM and all other functionality without it.
24 |
25 | ## Installation
26 |
27 | Clone this github repository and from its root folder install its requirements:
28 | ```
29 | pip install -r requirements.txt
30 | ```
31 |
32 | You can set the enviornment in which the app is running by setting the FLASK_ENV variable to ```development``` or ```production```:
33 |
34 | ```
35 | export FLASK_ENV=
36 | ```
37 |
38 | Then run the following commands:
39 |
40 | ```
41 | export FLASK_APP=tmc
42 | flask init-db
43 | flask run
44 | ```
45 |
46 | Once the server has started, access the application through localhost:5000. **You will need to register an user and log in in order to use the application.**
47 |
48 | To load the database with the data from [ATT&CK](https://attack.mitre.org/) access the following path. Please be patiente, since this operation **really takes a while** (aprox 1h 30m, depending on your internet connection):
49 |
50 | ```
51 | localhost:5000/first-time
52 | ```
53 |
54 | Keep in mind that the next time you want to run the application, you **don't have to** initilizate the database, since doing it will erase any content loaded in it. Repeat the previous steps without that command:
55 |
56 | ```
57 | export FLASK_ENV=
58 | export FLASK_APP=tmc
59 | flask run
60 | ```
61 |
62 | # Making the APP public
63 |
64 | If you prefer, you can change the port and make the app publicly available by running the following command:
65 |
66 | ```
67 | flask run -p -h 0.0.0.0
68 | ```
69 |
70 | # Author
71 |
72 | * Valentina Palacin [@fierytermite](https://twitter.com/fierytermite)
73 |
74 | # License: MIT License
75 |
76 | MIT License
77 |
78 | Copyright (c) 2021 Valentina Palacin
79 |
80 | Permission is hereby granted, free of charge, to any person obtaining a copy
81 | of this software and associated documentation files (the "Software"), to deal
82 | in the Software without restriction, including without limitation the rights
83 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
84 | copies of the Software, and to permit persons to whom the Software is
85 | furnished to do so, subject to the following conditions:
86 |
87 | The above copyright notice and this permission notice shall be included in all
88 | copies or substantial portions of the Software.
89 |
90 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
91 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
92 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
93 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
94 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
95 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
96 | SOFTWARE.
97 |
98 | # TO-DOs
99 |
100 | - [x] Add Industry List
101 | - [x] Add mapping from TRAM
102 | - [x] Link TMC with TRAM
103 | - [x] Link TMC with Navigator
104 | - [ ] Automatically download the mapping from Navigator as SVG
105 | - [x] Export as CSV function
106 | - [x] Edit database views
107 | - [ ] Dockerize project
108 |
--------------------------------------------------------------------------------
/tmc/processor.py:
--------------------------------------------------------------------------------
1 | from flask import (
2 | g, redirect, render_template, request, url_for
3 | )
4 | from tmc.auth import login_required
5 | from attackcti import attack_client
6 | from tmc.db import get_db
7 | from IPython import embed
8 | import tmc.queries as q
9 | import logging
10 | logging.basicConfig(level=logging.INFO)
11 |
12 | # Global variable
13 | lift = ''
14 | lift = attack_client()
15 |
16 | # Classes
17 |
18 | class Adversary():
19 |
20 | def __init__(self, element):
21 | super().__init__()
22 | self.related_tools = lift.get_software_used_by_group(element)
23 | self.attack_identifiers = ''
24 | self.attack_id = element['external_references'][0]['external_id']
25 | self.adversary_name = element['name']
26 |
27 | try:
28 | self.adversary_description = element['description']
29 | except KeyError:
30 | self.adversary_description = ''
31 | try:
32 | aliases_list = element['aliases']
33 |
34 | for element in aliases_list:
35 | self.attack_identifiers += element + '; '
36 |
37 | except KeyError:
38 | self.attack_identifiers = ''
39 |
40 | self.adversary_id = insert_adversary(self.attack_id, self.adversary_name, self.adversary_description, self.attack_identifiers)
41 |
42 |
43 | class Events():
44 |
45 | def __init__(self, element):
46 | super().__init__()
47 |
48 |
49 | class Tools():
50 |
51 | def __init__(self, element):
52 | super().__init__()
53 | self.attack_id = element['external_references'][0]['external_id']
54 | self.tool_name = element['name']
55 | try:
56 | self.tool_description = element['description']
57 | except KeyError:
58 | self.tool_description = ''
59 | try:
60 | self.attack_identifiers = element['x_mitre_aliases']
61 | except KeyError:
62 | self.attack_identifiers = ''
63 | self.techniques_used = lift.get_techniques_used_by_software(element)
64 | self.tool_id = insert_tool(self.attack_id, self.tool_name, self.tool_description)
65 |
66 |
67 | class Tactics():
68 |
69 | def __init__(self, element):
70 | super().__init__()
71 | self.attack_id = element['external_references'][0]['external_id']
72 | self.tactic_name = element['name']
73 | self.tactic_description = element['description']
74 | self.tactic_id = insert_tactic(self.attack_id, self.tactic_name, self.tactic_description)
75 |
76 |
77 | class Techniques():
78 |
79 | def __init__(self, element):
80 | super().__init__()
81 | self.attack_id = element['external_references'][0]['external_id']
82 |
83 | if '.' in self.attack_id:
84 | technique_attack_id,subtechnique_attack_id = self.attack_id.split('.', 1)
85 | sub = Subtechniques(element, self.attack_id)
86 |
87 | self.technique_name = element['name']
88 | self.technique_description = element['description']
89 | self.related_tactic = element['kill_chain_phases'][0]['phase_name']
90 | self.technique_id = insert_technique(self.attack_id, self.technique_name, self.technique_description)
91 |
92 |
93 | class Subtechniques():
94 |
95 | def __init__(self, element, subtechnique_attack_id):
96 | super().__init__()
97 | self.attack_id = subtechnique_attack_id
98 | self.subtechnique_name = element['name']
99 | self.subtechnique_description = element['description']
100 | self.related_tactic = element['kill_chain_phases'][0]['phase_name']
101 | self.subtechnique_id = insert_subtechnique(self.attack_id, self.subtechnique_name, self.subtechnique_description)
102 |
103 |
104 | # ATT&CK FRAMEWORK INTERACTION
105 | def get_elements():
106 |
107 | tactics = lift.get_tactics()
108 | for element in tactics:
109 |
110 | if 'x_mitre_deprecated' in element:
111 | continue
112 | else:
113 | tac = Tactics(element)
114 |
115 | unsorted_techniques = lift.get_techniques()
116 | techniques = sorted(unsorted_techniques, key = lambda i: i['external_references'][0]['external_id'])
117 | for element in techniques:
118 |
119 | if element['revoked'] == True:
120 | continue
121 |
122 | technique_id = element['external_references'][0]['external_id']
123 |
124 | if '.' in technique_id:
125 | subtec = Subtechniques(element, technique_id)
126 | technique_attack_id,subtechnique_attack_id = technique_id.split('.', 1)
127 | related_technique=q.q_get_element_id.get_element_id('techniques', 'technique_id', technique_attack_id)
128 | insert_tecxsubtec(related_technique, subtec.subtechnique_id)
129 | else:
130 | tec = Techniques(element)
131 | insert_tacxtec(tec.technique_id, tec.related_tactic)
132 |
133 | tools = lift.get_software()
134 | for element in tools:
135 | t = Tools(element)
136 | insert_toolxtec(t.tool_name, t.tool_id, t.techniques_used)
137 |
138 | adversaries = lift.get_groups()
139 | for element in adversaries:
140 | adv = Adversary(element)
141 | insert_advxtool(adv.adversary_id, adv.related_tools)
142 |
143 |
144 | def insert_tactic(attack_id, tactic_name, tactic_description):
145 |
146 | existence = q.q_get_element_id.get_element_id('tactics', 'tactic_name', tactic_name)
147 | if not existence:
148 | insert_into_table = q.q_insert_into_tables.insert_into_tables('tactics', attack_id, tactic_name, tactic_description)
149 | logging.info('Created tactic %s' % tactic_name)
150 | return insert_into_table
151 | else:
152 | return existence
153 |
154 |
155 | # Adding ATT&CK Techniques
156 | def insert_technique(attack_id, technique_name, technique_description):
157 |
158 | insert_into_table = q.q_insert_into_tables.insert_into_tables('techniques', attack_id, technique_name, technique_description)
159 | logging.info('Created technique %s' % technique_name)
160 | return insert_into_table
161 |
162 |
163 | #REFACTOR THIS
164 | def insert_subtechnique(attack_id, subtechnique_name, subtechnique_description):
165 |
166 | insert_into_table = q.q_insert_into_tables.insert_into_tables('subtechniques', attack_id, subtechnique_name, subtechnique_description)
167 | logging.info('Created technique %s' % subtechnique_name)
168 | return insert_into_table
169 |
170 |
171 | # Adding ATT&CK Adversaries
172 | def insert_adversary(attack_id, adversary_name, adversary_description, attack_identifiers):
173 |
174 | insert_into_table = q.q_insert_adversary_into_tables.insert_adversary_into_tables('adversaries', attack_id, adversary_name, adversary_description, attack_identifiers)
175 | logging.info('Created adversary %s' % adversary_name)
176 | return insert_into_table
177 |
178 |
179 | # Adding ATT&CK Tools
180 | def insert_tool(attack_id, tool_name, tool_description):
181 |
182 | insert_into_table = q.q_insert_into_tables.insert_into_tables('tools', attack_id, tool_name, tool_description)
183 | logging.info('Created tool %s' % tool_name)
184 | return insert_into_table
185 |
186 |
187 | # Insert Tools x Techniques ----- this is gatherin technique att&ck id, instead of technique id
188 | def insert_toolxtec(tool_name, tool_id, techniques_used):
189 |
190 | for element in techniques_used:
191 |
192 | technique_attack_id = element['external_references'][0]['external_id']
193 |
194 | if '.' in technique_attack_id:
195 | subtechnique_id = q.q_get_element_id.get_element_id('subtechniques', 'subtechnique_id', technique_attack_id)
196 | result = q.q_insert_tool_x_subtechn.insert_tool_x_subtechn('tools_x_subtechniques', tool_id, subtechnique_id)
197 |
198 | else:
199 | technique_id = q.q_get_element_id.get_element_id('techniques', 'technique_id', technique_attack_id)
200 | result = q.q_insert_tool_x_techn.insert_tool_x_techn('tools_x_techniques', tool_id, technique_id)
201 | logging.info('Created relationship for %s' % tool_name)
202 | return result
203 |
204 |
205 |
206 | # Adding ATT&CK TacticxTechniques
207 | def insert_tacxtec(technique_id, related_tactic):
208 |
209 | error = []
210 | tactic = related_tactic.replace('-', ' ')
211 |
212 | if 'ics' in tactic:
213 | tactic=tactic.replace(' ics', '')
214 |
215 | tactic_id = q.q_get_element_id.get_element_id('tactics', 'tactic_name', tactic)
216 |
217 | if tactic_id == 0:
218 | logging.info('Unrecognized tactic in %s: ' % technique_id)
219 | else:
220 | try:
221 | tactic_x_technique = q.q_insert_tactic_x_technique.insert_tactic_x_technique(tactic_id, technique_id)
222 | logging.info('Created tactic relationship')
223 | except KeyError:
224 | logging.info('Raised KeyError exception with tactic in %s: ' % technique_id)
225 |
226 |
227 | # Insert relation insert_advxtool
228 | def insert_advxtool(adversary_id, related_tools):
229 |
230 | for tool in related_tools:
231 | tool_attack_id = tool['external_references'][0]['external_id']
232 | tool_id = q.q_get_element_id.get_element_id('tools', 'tool_id', tool_attack_id)
233 |
234 | result = q.q_insert_adversary_x_tool.insert_adversary_x_tool(adversary_id, tool_id)
235 | logging.info('Created adversary per tool relationship')
236 | return result
237 |
238 |
239 | # Insert Subtechniques x Techniques
240 | def insert_tecxsubtec(related_technique, subattack_id):
241 |
242 | insert_into_table = q.q_insert_relation_into_tables.insert_relation_into_tables('techniques_x_subtechniques', 'technique_id', 'subtechnique_id', related_technique, subattack_id)
243 | logging.info('Created technique per subtechnique relationship')
244 | return insert_into_table
245 |
--------------------------------------------------------------------------------
/tmc/schema.sql:
--------------------------------------------------------------------------------
1 | -- Initialize the database.
2 | -- Drop any existing data and create empty tables.
3 |
4 | DROP TABLE IF EXISTS adversaries;
5 | DROP TABLE IF EXISTS tactics;
6 | DROP TABLE IF EXISTS techniques;
7 | DROP TABLE IF EXISTS subtechniques;
8 | DROP TABLE IF EXISTS events;
9 | DROP TABLE IF EXISTS tools;
10 | DROP TABLE IF EXISTS industries;
11 | DROP TABLE IF EXISTS events_x_industries;
12 | DROP TABLE IF EXISTS adversaries_x_events;
13 | DROP TABLE IF EXISTS events_x_industry;
14 | DROP TABLE IF EXISTS adversaries_x_tools;
15 | DROP TABLE IF EXISTS tools_x_techniques;
16 | DROP TABLE IF EXISTS tools_x_subtechniques;
17 | DROP TABLE IF EXISTS tactics_x_techniques;
18 | DROP TABLE IF EXISTS techniques_x_subtechniques;
19 | DROP TABLE IF EXISTS countries;
20 | DROP TABLE IF EXISTS users;
21 |
22 |
23 | CREATE TABLE users (
24 | id INTEGER PRIMARY KEY AUTOINCREMENT,
25 | username TEXT UNIQUE NOT NULL,
26 | password TEXT NOT NULL
27 | );
28 |
29 | CREATE TABLE adversaries (
30 | id INTEGER PRIMARY KEY AUTOINCREMENT,
31 | author_id INTEGER NOT NULL,
32 | created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
33 | adversary_id TEXT NOT NULL,
34 | adversary_name TEXT NOT NULL,
35 | adversary_description TEXT NOT NULL,
36 | adversary_identifiers TEXT,
37 | adversary_sorigin TEXT,
38 | updated_date DATETIME,
39 | updated_by TEXT,
40 | FOREIGN KEY (author_id) REFERENCES users (id)
41 | );
42 |
43 | CREATE TABLE tactics (
44 | id INTEGER PRIMARY KEY AUTOINCREMENT,
45 | author_id INTEGER NOT NULL,
46 | created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
47 | tactic_id TEXT NOT NULL,
48 | tactic_name TEXT NOT NULL,
49 | tactic_description TEXT NOT NULL,
50 | updated_date DATETIME,
51 | updated_by TEXT,
52 | FOREIGN KEY (author_id) REFERENCES users (id)
53 | );
54 |
55 | CREATE TABLE techniques (
56 | id INTEGER PRIMARY KEY AUTOINCREMENT,
57 | author_id INTEGER NOT NULL,
58 | created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
59 | technique_id TEXT NOT NULL,
60 | technique_name TEXT NOT NULL,
61 | technique_description TEXT NOT NULL,
62 | updated_date DATETIME,
63 | updated_by TEXT,
64 | FOREIGN KEY (author_id) REFERENCES users (id)
65 | );
66 |
67 | CREATE TABLE subtechniques (
68 | id INTEGER PRIMARY KEY AUTOINCREMENT,
69 | author_id INTEGER NOT NULL,
70 | created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
71 | subtechnique_id TEXT NOT NULL,
72 | subtechnique_name TEXT NOT NULL,
73 | subtechnique_description TEXT NOT NULL,
74 | updated_date DATETIME,
75 | updated_by TEXT,
76 | FOREIGN KEY (author_id) REFERENCES users (id)
77 | );
78 |
79 | CREATE TABLE tools (
80 | id INTEGER PRIMARY KEY AUTOINCREMENT,
81 | author_id INTEGER NOT NULL,
82 | created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
83 | tool_id TEXT NOT NULL,
84 | tool_name TEXT NOT NULL,
85 | tool_description TEXT NOT NULL,
86 | tool_identifiers TEXT,
87 | updated_date DATETIME,
88 | updated_by TEXT,
89 | FOREIGN KEY (author_id) REFERENCES users (id)
90 | );
91 |
92 | CREATE TABLE events (
93 | id INTEGER PRIMARY KEY AUTOINCREMENT,
94 | author_id INTEGER NOT NULL,
95 | created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
96 | event_name TEXT NOT NULL,
97 | event_description TEXT NOT NULL,
98 | event_url TEXT,
99 | event_date DATETIME,
100 | FOREIGN KEY (author_id) REFERENCES users (id)
101 | );
102 |
103 | CREATE TABLE adversaries_x_tools (
104 | id INTEGER PRIMARY KEY AUTOINCREMENT,
105 | author_id INTEGER NOT NULL,
106 | created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
107 | adversary_id TEXT NOT NULL,
108 | tool_id TEXT NOT NULL,
109 | FOREIGN KEY (author_id) REFERENCES users (id),
110 | FOREIGN KEY (adversary_id) REFERENCES adversary (id),
111 | FOREIGN KEY (tool_id) REFERENCES tool (id)
112 | );
113 |
114 | CREATE TABLE adversaries_x_events (
115 | id INTEGER PRIMARY KEY AUTOINCREMENT,
116 | author_id INTEGER NOT NULL,
117 | created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
118 | adversary_id TEXT NOT NULL,
119 | event_id TEXT NOT NULL,
120 | FOREIGN KEY (author_id) REFERENCES users (id),
121 | FOREIGN KEY (adversary_id) REFERENCES adversary (id),
122 | FOREIGN KEY (event_id) REFERENCES event (id)
123 | );
124 |
125 | CREATE TABLE tools_x_techniques (
126 | id INTEGER PRIMARY KEY AUTOINCREMENT,
127 | author_id INTEGER NOT NULL,
128 | created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
129 | tool_id TEXT NOT NULL,
130 | technique_id TEXT NOT NULL,
131 | FOREIGN KEY (author_id) REFERENCES users (id),
132 | FOREIGN KEY (tool_id) REFERENCES tool (id),
133 | FOREIGN KEY (technique_id) REFERENCES technique (id)
134 | );
135 |
136 | CREATE TABLE tools_x_subtechniques (
137 | id INTEGER PRIMARY KEY AUTOINCREMENT,
138 | author_id INTEGER NOT NULL,
139 | created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
140 | tool_id TEXT NOT NULL,
141 | subtechnique_id TEXT NOT NULL,
142 | FOREIGN KEY (author_id) REFERENCES users (id),
143 | FOREIGN KEY (tool_id) REFERENCES tool (id),
144 | FOREIGN KEY (subtechnique_id) REFERENCES subtechnique (id)
145 | );
146 |
147 | CREATE TABLE tactics_x_techniques (
148 | id INTEGER PRIMARY KEY AUTOINCREMENT,
149 | author_id INTEGER NOT NULL,
150 | created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
151 | tactic_id TEXT NOT NULL,
152 | technique_id TEXT NOT NULL,
153 | FOREIGN KEY (author_id) REFERENCES users (id),
154 | FOREIGN KEY (tactic_id) REFERENCES tactic (id),
155 | FOREIGN KEY (technique_id) REFERENCES technique (id)
156 | );
157 |
158 | CREATE TABLE techniques_x_subtechniques (
159 | id INTEGER PRIMARY KEY AUTOINCREMENT,
160 | author_id INTEGER NOT NULL,
161 | created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
162 | technique_id TEXT NOT NULL,
163 | subtechnique_id TEXT NOT NULL,
164 | FOREIGN KEY (author_id) REFERENCES users (id),
165 | FOREIGN KEY (technique_id) REFERENCES technique (id),
166 | FOREIGN KEY (subtechnique_id) REFERENCES subtechnique (id)
167 | );
168 |
169 |
170 | -- Industries taken from STIX
171 | -- https://docs.oasis-open.org/cti/stix/v2.1/cs01/stix-v2.1-cs01.html#_oogrswk3onck
172 |
173 | CREATE TABLE industries (
174 | id INTEGER PRIMARY KEY AUTOINCREMENT,
175 | author_id INTEGER NOT NULL,
176 | created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
177 | industry_name TEXT NOT NULL,
178 | industry_description TEXT,
179 | FOREIGN KEY (author_id) REFERENCES users (id)
180 | );
181 |
182 | CREATE TABLE countries (
183 | id INTEGER PRIMARY KEY AUTOINCREMENT,
184 | author_id INTEGER NOT NULL,
185 | created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
186 | code TEXT NOT NULL,
187 | ctld TEXT NOT NULL,
188 | country TEXT NOT NULL,
189 | FOREIGN KEY (author_id) REFERENCES users (id)
190 | );
191 |
192 | CREATE TABLE events_x_industries (
193 | id INTEGER PRIMARY KEY AUTOINCREMENT,
194 | author_id INTEGER NOT NULL,
195 | created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
196 | event_id TEXT NOT NULL,
197 | industry_id TEXT NOT NULL,
198 | FOREIGN KEY (author_id) REFERENCES users (id),
199 | FOREIGN KEY (event_id) REFERENCES event (id),
200 | FOREIGN KEY (industry_id) REFERENCES industry (id)
201 | );
202 |
203 | INSERT INTO adversaries (author_id, adversary_id, adversary_name, adversary_description)
204 | VALUES (1, 1, 'Unknown', 'Unknown');
205 |
206 | INSERT INTO tools (author_id, tool_id, tool_name, tool_description)
207 | VALUES (1, 1, 'Unknown', 'Unknown');
208 |
209 | INSERT INTO industries (author_id, industry_name)
210 | VALUES (1, 'Agriculture'),
211 | (1, 'Aerospace'),
212 | (1, 'Automotive'),
213 | (1, 'Chemical'),
214 | (1, 'Commercial'),
215 | (1, 'Communications'),
216 | (1, 'Construction'),
217 | (1, 'Defense'),
218 | (1, 'Education'),
219 | (1, 'Energy'),
220 | (1, 'Entertainment'),
221 | (1, 'Financial Services'),
222 | (1, 'Government'),
223 | (1, 'Healthcare'),
224 | (1, 'Hospitality & Leisure'),
225 | (1, 'Infrastructure'),
226 | (1, 'Insurance'),
227 | (1, 'Manufacturing'),
228 | (1, 'Mining'),
229 | (1, 'Non-profit'),
230 | (1, 'Pharmaceuticals'),
231 | (1, 'Retail'),
232 | (1, 'Technology'),
233 | (1, 'Telecommunications'),
234 | (1, 'Transportation'),
235 | (1, 'Utilities'),
236 | (1, 'Unspecified'),
237 | (1, 'Unknown');
238 |
239 | INSERT INTO countries (author_id, code, ctld, country)
240 | VALUES (1, 'AFG', 'AF', 'Afghanistan'),
241 | (1, 'ALA', 'AX', 'Aland Islands'),
242 | (1, 'ALB', 'AL', 'Albania'),
243 | (1, 'DZA', 'DZ', 'Algeria'),
244 | (1, 'ASM', 'AS', 'American Samoa'),
245 | (1, 'AGO', 'AO', 'Angola'),
246 | (1, 'AIA', 'AI', 'Anguilla'),
247 | (1, 'ATA', 'AQ', 'Antarctica'),
248 | (1, 'ATG', 'AG', 'Antigua and Barbuda'),
249 | (1, 'ARG', 'AR', 'Argentina'),
250 | (1, 'ARM', 'AM', 'Armenia'),
251 | (1, 'ABW', 'AW', 'Aruba'),
252 | (1, 'AUS', 'AU', 'Australia'),
253 | (1, 'AUT', 'AT', 'Austria'),
254 | (1, 'AZE', 'AZ', 'Azerbaijan'),
255 | (1, 'BHS', 'BS', 'Bahamas'),
256 | (1, 'BHR', 'BH', 'Bahrain'),
257 | (1, 'BGD', 'BD', 'Bangladesh'),
258 | (1, 'BRB', 'BB', 'Barbados'),
259 | (1, 'BLR', 'BY', 'Belarus'),
260 | (1, 'BEL', 'BE', 'Belgium'),
261 | (1, 'BLZ', 'BZ', 'Belize'),
262 | (1, 'BEN', 'BJ', 'Benin'),
263 | (1, 'BMU', 'BM', 'Bermuda'),
264 | (1, 'BTN', 'BT', 'Bhutan'),
265 | (1, 'BOL', 'BO', 'Bolivia'),
266 | (1, 'BIH', 'BA', 'Bosnia and Herzegovina'),
267 | (1, 'BWA', 'BW', 'Botswana'),
268 | (1, 'BVT', 'BV', 'Bouvet Island'),
269 | (1, 'BRA', 'BR', 'Brazil'),
270 | (1, 'VGB', 'VG', 'British Virgin Islands'),
271 | (1, 'IOT', 'IO', 'British Indian Ocean Territory'),
272 | (1, 'BRN', 'BN', 'Brunei'),
273 | (1, 'BGR', 'BG', 'Bulgaria'),
274 | (1, 'BFA', 'BF', 'Burkina Faso'),
275 | (1, 'BDI', 'BI', 'Burundi'),
276 | (1, 'KHM', 'KH', 'Cambodia'),
277 | (1, 'CMR', 'CM', 'Cameroon'),
278 | (1, 'CAN', 'CA', 'Canada'),
279 | (1, 'CPV', 'CV', 'Cape Verde'),
280 | (1, 'CYM', 'KY', 'Cayman Islands'),
281 | (1, 'CAF', 'CF', 'Central African Republic'),
282 | (1, 'TCD', 'TD', 'Chad'),
283 | (1, 'CHL', 'CL', 'Chile'),
284 | (1, 'CHN', 'CN', 'China'),
285 | (1, 'HKG', 'HK', 'Hong Kong'),
286 | (1, 'MAC', 'MO', 'Macau'),
287 | (1, 'CXR', 'CX', 'Christmas Island'),
288 | (1, 'CCK', 'CC', 'Cocos Islands'),
289 | (1, 'COL', 'CO', 'Colombia'),
290 | (1, 'COM', 'KM', 'Comoros'),
291 | (1, 'COG', 'CG', 'Republic of the Congo'),
292 | (1, 'COD', 'CD', 'Democratic Republic of the Congo'),
293 | (1, 'COK', 'CK', 'Cook Islands'),
294 | (1, 'CRI', 'CR', 'Costa Rica'),
295 | (1, 'CIV', 'CI', 'Côte d''Ivoire'),
296 | (1, 'HRV', 'HR', 'Croatia'),
297 | (1, 'CUB', 'CU', 'Cuba'),
298 | (1, 'CYP', 'CY', 'Cyprus'),
299 | (1, 'CZE', 'CZ', 'Czech Republic'),
300 | (1, 'DNK', 'DK', 'Denmark'),
301 | (1, 'DJI', 'DJ', 'Djibouti'),
302 | (1, 'DMA', 'DM', 'Dominica'),
303 | (1, 'DOM', 'DO', 'Dominican Republic'),
304 | (1, 'ECU', 'EC', 'Ecuador'),
305 | (1, 'EGY', 'EG', 'Egypt'),
306 | (1, 'SLV', 'SV', 'El Salvador'),
307 | (1, 'GNQ', 'GQ', 'Equatorial Guinea'),
308 | (1, 'ERI', 'ER', 'Eritrea'),
309 | (1, 'EST', 'EE', 'Estonia'),
310 | (1, 'ETH', 'ET', 'Ethiopia'),
311 | (1, 'FLK', 'FK', 'Falkland Islands'),
312 | (1, 'FRO', 'FO', 'Faroe Islands'),
313 | (1, 'FJI', 'FJ', 'Fiji'),
314 | (1, 'FIN', 'FI', 'Finland'),
315 | (1, 'FRA', 'FR', 'France'),
316 | (1, 'GUF', 'GF', 'French Guiana'),
317 | (1, 'PYF', 'PF', 'French Polynesia'),
318 | (1, 'ATF', 'TF', 'French Southern Territories'),
319 | (1, 'GAB', 'GA', 'Gabon'),
320 | (1, 'GMB', 'GM', 'Gambia'),
321 | (1, 'GEO', 'GE', 'Georgia'),
322 | (1, 'DEU', 'DE', 'Germany'),
323 | (1, 'GHA', 'GH', 'Ghana'),
324 | (1, 'GIB', 'GI', 'Gibraltar'),
325 | (1, 'GRC', 'GR', 'Greece'),
326 | (1, 'GRL', 'GL', 'Greenland'),
327 | (1, 'GRD', 'GD', 'Grenada'),
328 | (1, 'GLP', 'GP', 'Guadeloupe'),
329 | (1, 'GUM', 'gu', 'Guam'),
330 | (1, 'GTM', 'GT', 'Guatemala'),
331 | (1, 'GGY', 'GG', 'Guernsey'),
332 | (1, 'GIN', 'GN', 'Guinea'),
333 | (1, 'GNB', 'GW', 'Guinea-Bissau'),
334 | (1, 'GUY', 'GY', 'Guyana'),
335 | (1, 'HTI', 'HT', 'Haiti'),
336 | (1, 'HMD', 'HM', 'Heard and Mcdonald Islands'),
337 | (1, 'VAT', 'VA', 'Vatican'),
338 | (1, 'HND', 'HN', 'Honduras'),
339 | (1, 'HUN', 'HU', 'Hungary'),
340 | (1, 'ISL', 'IS', 'Iceland'),
341 | (1, 'IND', 'IN', 'India'),
342 | (1, 'IDN', 'ID', 'Indonesia'),
343 | (1, 'IRN', 'IR', 'Iran'),
344 | (1, 'IRQ', 'IQ', 'Iraq'),
345 | (1, 'IRL', 'IE', 'Ireland'),
346 | (1, 'IMN', 'IM', 'Isle of Man'),
347 | (1, 'ISR', 'IL', 'Israel'),
348 | (1, 'ITA', 'IT', 'Italy'),
349 | (1, 'JAM', 'JM', 'Jamaica'),
350 | (1, 'JPN', 'JP', 'Japan'),
351 | (1, 'JEY', 'JE', 'Jersey'),
352 | (1, 'JOR', 'JO', 'Jordan'),
353 | (1, 'KAZ', 'KZ', 'Kazakhstan'),
354 | (1, 'KEN', 'KE', 'Kenya'),
355 | (1, 'KIR', 'KI', 'Kiribati'),
356 | (1, 'KOR', 'KR', 'South Korea'),
357 | (1, 'PRK', 'KP', 'North Korea'),
358 | (1, 'KWT', 'KW', 'Kuwait'),
359 | (1, 'KGZ', 'KG', 'Kyrgyzstan'),
360 | (1, 'LAO', 'LA', 'Laos'),
361 | (1, 'LVA', 'LV', 'Latvia'),
362 | (1, 'LBN', 'LB', 'Lebanon'),
363 | (1, 'LSO', 'LS', 'Lesotho'),
364 | (1, 'LBR', 'LR', 'Liberia'),
365 | (1, 'LBY', 'LY', 'Libya'),
366 | (1, 'LIE', 'LI', 'Liechtenstein'),
367 | (1, 'LTU', 'LT', 'Lithuania'),
368 | (1, 'LUX', 'LU', 'Luxembourg'),
369 | (1, 'MKD', 'MK', 'Macedonia'),
370 | (1, 'MDG', 'MG', 'Madagascar'),
371 | (1, 'MWI', 'MW', 'Malawi'),
372 | (1, 'MYS', 'MY', 'Malaysia'),
373 | (1, 'MDV', 'MV', 'Maldives'),
374 | (1, 'MLI', 'ML', 'Mali'),
375 | (1, 'MLT', 'MT', 'Malta'),
376 | (1, 'MHL', 'MH', 'Marshall Islands'),
377 | (1, 'MTQ', 'MQ', 'Martinique'),
378 | (1, 'MRT', 'MR', 'Mauritania'),
379 | (1, 'MUS', 'MU', 'Mauritius'),
380 | (1, 'MYT', 'YT', 'Mayotte'),
381 | (1, 'MEX', 'MX', 'Mexico'),
382 | (1, 'FSM', 'FM', 'Micronesia'),
383 | (1, 'MDA', 'MD', 'Moldova'),
384 | (1, 'MCO', 'MC', 'Monaco'),
385 | (1, 'MNG', 'MN', 'Mongolia'),
386 | (1, 'MNE', 'ME', 'Montenegro'),
387 | (1, 'MSR', 'MS', 'Montserrat'),
388 | (1, 'MAR', 'MA', 'Morocco'),
389 | (1, 'MOZ', 'MZ', 'Mozambique'),
390 | (1, 'MMR', 'MM', 'Myanmar'),
391 | (1, 'NAM', 'NA', 'Namibia'),
392 | (1, 'NRU', 'NR', 'Nauru'),
393 | (1, 'NPL', 'NP', 'Nepal'),
394 | (1, 'NLD', 'NL', 'Netherlands'),
395 | (1, 'ANT', 'AN', 'Netherlands Antilles'),
396 | (1, 'NCL', 'NC', 'New Caledonia'),
397 | (1, 'NZL', 'NZ', 'New Zealand'),
398 | (1, 'NIC', 'NI', 'Nicaragua'),
399 | (1, 'NER', 'NE', 'Niger'),
400 | (1, 'NGA', 'NG', 'Nigeria'),
401 | (1, 'NIU', 'NU', 'Niue'),
402 | (1, 'NFK', 'NF', 'Norfolk Island'),
403 | (1, 'MNP', 'MP', 'Northern Mariana Islands'),
404 | (1, 'NOR', 'NO', 'Norway'),
405 | (1, 'OMN', 'OM', 'Oman'),
406 | (1, 'PAK', 'PK', 'Pakistan'),
407 | (1, 'PLW', 'PW', 'Palau'),
408 | (1, 'PSE', 'PS', 'Palestine'),
409 | (1, 'PAN', 'PA', 'Panama'),
410 | (1, 'PNG', 'PG', 'Papua New Guinea'),
411 | (1, 'PRY', 'PY', 'Paraguay'),
412 | (1, 'PER', 'PE', 'Peru'),
413 | (1, 'PHL', 'PH', 'Philippines'),
414 | (1, 'PCN', 'PN', 'Pitcairn'),
415 | (1, 'POL', 'PL', 'Poland'),
416 | (1, 'PRT', 'PT', 'Portugal'),
417 | (1, 'PRI', 'PR', 'Puerto Rico'),
418 | (1, 'QAT', 'QA', 'Qatar'),
419 | (1, 'REU', 'RE', 'Réunion'),
420 | (1, 'ROU', 'RO', 'Romania'),
421 | (1, 'RUS', 'RU', 'Russia'),
422 | (1, 'RWA', 'RW', 'Rwanda'),
423 | (1, 'BES', 'BQ', 'Saba'),
424 | (1, 'BLM', 'BL', 'Saint-Barthélemy'),
425 | (1, 'SHN', 'SH', 'Saint Helena'),
426 | (1, 'KNA', 'KN', 'Saint Kitts and Nevis'),
427 | (1, 'LCA', 'LC', 'Saint Lucia'),
428 | (1, 'MAF', 'MF', 'Saint-Martin'),
429 | (1, 'SPM', 'PM', 'Saint Pierre and Miquelon'),
430 | (1, 'VCT', 'VC', 'Saint Vincent and Grenadines'),
431 | (1, 'WSM', 'WS', 'Samoa'),
432 | (1, 'SMR', 'SM', 'San Marino'),
433 | (1, 'STP', 'ST', 'Sao Tome and Principe'),
434 | (1, 'SAU', 'SA', 'Saudi Arabia'),
435 | (1, 'SEN', 'SN', 'Senegal'),
436 | (1, 'SRB', 'RS', 'Serbia'),
437 | (1, 'SYC', 'SC', 'Seychelles'),
438 | (1, 'SLE', 'SL', 'Sierra Leone'),
439 | (1, 'SGP', 'SG', 'Singapore'),
440 | (1, 'SVK', 'SK', 'Slovakia'),
441 | (1, 'SVN', 'SI', 'Slovenia'),
442 | (1, 'SLB', 'SB', 'Solomon Islands'),
443 | (1, 'SOM', 'SO', 'Somalia'),
444 | (1, 'ZAF', 'ZA', 'South Africa'),
445 | (1, 'SGS', 'GS', 'South Georgia and the South Sandwich Islands'),
446 | (1, 'SSD', 'SS', 'South Sudan'),
447 | (1, 'ESP', 'ES', 'Spain'),
448 | (1, 'LKA', 'LK', 'Sri Lanka'),
449 | (1, 'SDN', 'SD', 'Sudan'),
450 | (1, 'SUR', 'SR', 'Suriname'),
451 | (1, 'SJM', 'SJ', 'Svalbard and Jan Mayen Islands'),
452 | (1, 'SWZ', 'SZ', 'Swaziland'),
453 | (1, 'SWE', 'SE', 'Sweden'),
454 | (1, 'CHE', 'CH', 'Switzerland'),
455 | (1, 'SYR', 'SY', 'Syria'),
456 | (1, 'TWN', 'TW', 'Taiwan'),
457 | (1, 'TJK', 'TJ', 'Tajikistan'),
458 | (1, 'TZA', 'TZ', 'Tanzania'),
459 | (1, 'THA', 'TH', 'Thailand'),
460 | (1, 'TLS', 'TL', 'Timor-Leste'),
461 | (1, 'TGO', 'TG', 'Togo'),
462 | (1, 'TKL', 'TK', 'Tokelau'),
463 | (1, 'TON', 'TO', 'Tonga'),
464 | (1, 'TTO', 'TT', 'Trinidad and Tobago'),
465 | (1, 'TUN', 'TN', 'Tunisia'),
466 | (1, 'TUR', 'TR', 'Turkey'),
467 | (1, 'TKM', 'TM', 'Turkmenistan'),
468 | (1, 'TCA', 'TC', 'Turks and Caicos Islands'),
469 | (1, 'TUV', 'TV', 'Tuvalu'),
470 | (1, 'UGA', 'UG', 'Uganda'),
471 | (1, 'UKR', 'UA', 'Ukraine'),
472 | (1, 'ARE', 'AE', 'United Arab Emirates'),
473 | (1, 'GBR', 'UK', 'United Kingdom'),
474 | (1, 'USA', 'US', 'United States of America'),
475 | (1, 'UMI', 'UM', 'US Minor Outlying Islands'),
476 | (1, 'URY', 'UY', 'Uruguay'),
477 | (1, 'UZB', 'UZ', 'Uzbekistan'),
478 | (1, 'VUT', 'VU', 'Vanuatu'),
479 | (1, 'VEN', 'VE', 'Venezuela'),
480 | (1, 'VNM', 'VN', 'Vietnam'),
481 | (1, 'VIR', 'VI', 'Virgin Islands'),
482 | (1, 'WLF', 'WF', 'Wallis and Futuna Islands'),
483 | (1, 'ESH', 'EH', 'Western Sahara'),
484 | (1, 'YEM', 'YE', 'Yemen'),
485 | (1, 'ZMB', 'ZM', 'Zambia'),
486 | (1, 'ZWE', 'ZW', 'Zimbabwe'),
487 | (1, 'MMR', 'MM', 'Myanmar'),
488 | (1, 'CUW', 'CW', 'Curaçao'),
489 | (1, 'SXM', 'SX', 'Sint Maarten');
--------------------------------------------------------------------------------
/tmc/maps.py:
--------------------------------------------------------------------------------
1 | from flask import (
2 | Blueprint, flash, g, redirect, render_template, request, url_for
3 | )
4 | from werkzeug.exceptions import abort
5 | from tmc.auth import login_required
6 | from tmc.db import get_db
7 | from IPython import embed
8 | import tmc.queries as q
9 | from tmc.queries import *
10 | from random import random
11 | import tmc.processor as processor
12 | import tmc.config as config
13 | import time
14 | import json
15 | import ast
16 | import requests
17 | import csv
18 | import os
19 | import uuid
20 | import urllib
21 |
22 |
23 | bp = Blueprint('maps', __name__, template_folder='templates')
24 |
25 |
26 | # Loading ATT&CK to DB for the first time
27 | @bp.route('/first-time')
28 | @login_required
29 | def first_time():
30 |
31 | print('Interacting with ATTACKCTI...')
32 | processor.get_elements()
33 | message="You can now start exploring the database."
34 |
35 | return render_template('maps/completed.html', message=message)
36 |
37 |
38 | # Homepage
39 | @bp.route('/', methods=["GET", "POST"])
40 | def index():
41 |
42 | adversaries_list = q.q_get_adversaries.get_adversaries()
43 | tools_list = q.q_get_tools.get_tools()
44 | industries_list = q.q_get_industries.get_industries()
45 |
46 | return render_template('maps/welcome.html', adversaries_list=adversaries_list, tools_list=tools_list, industries_list=industries_list)
47 |
48 |
49 | @bp.route('/tram-interaction', methods=["GET", "POST"])
50 | def tram_mapping():
51 |
52 | if request.method == "POST":
53 |
54 | req = request.form
55 | adversary_dict = ast.literal_eval(req['adversary']) # convert string dict into real dict
56 | adversary = adversary_dict['db_id']
57 | tool_dict = ast.literal_eval(req['tool']) # convert string dict into real dict
58 | tool = tool_dict['db_id']
59 | industry_dict = ast.literal_eval(req['industry']) # convert string dict into real dict
60 | industry = industry_dict['db_id']
61 | event_name = req['event_name']
62 | event_description = req['event_description']
63 | event_url = req['url']
64 |
65 | # Creates the security event and all its relationships
66 | event = q.q_insert_into_events.insert_into_events(event_name, event_description, event_url)
67 | adv_x_event = q.q_insert_adversary_x_event.insert_adversary_x_event(adversary, event)
68 | event_x_ind = q.q_insert_event_x_industry.insert_event_x_industry(event, industry)
69 | # Sends the URL provided to TRAM for mapping
70 | tram_id=str(tool)+'_'+event_name
71 | print(tram_id)
72 | send_url_to_tram(tram_id, event_url)
73 | message = 'Please complete TRAM workflow before continuing. TMC will automatically process TRAM mapping when done. Please wait before continuing..'
74 |
75 | return render_template('maps/completed.html', message=message)
76 |
77 |
78 | # Issues POST request to TRAM with the report URL you want to process
79 | def send_url_to_tram(tram_id, event_url):
80 |
81 | tram_insert = {
82 | "index":"insert_report",
83 | "url": [event_url],
84 | "title": [tram_id],
85 | "request": True
86 | }
87 | url = config.config_dict['tram'] + "/rest"
88 | requests.post(url=url, json=tram_insert, headers={"content-type":"application/json"})
89 |
90 |
91 | # Process the techniques sent by TRAM issued POST request after analysis completion
92 | @bp.route('/tram-response', methods=['GET', 'POST'])
93 | def wait_tram_response():
94 |
95 | if request.method == 'POST':
96 | tram_response = json.loads(request.data)
97 | print(tram_response)
98 |
99 | try:
100 |
101 | tool_id = tram_response[0]['title'].split('_')[0]
102 |
103 | for element in tram_response:
104 | if '.' in element['attack_tid']:
105 | subtechnique_attack_id = element['attack_tid']
106 | db_id = q.q_get_element_id.get_element_id('subtechniques', 'subtechnique_id', subtechnique_attack_id)
107 | tool_x_techniques = q_insert_tool_x_subtechn.insert_tool_x_subtechn('tools_x_subtechniques', tool_id, db_id)
108 | else:
109 | technique_attack_id = element['attack_tid']
110 | db_id = q.q_get_element_id.get_element_id('techniques', 'technique_id', technique_attack_id)
111 | tools_x_subtechniques = q.q_insert_tool_x_techn.insert_tool_x_techn('tools_x_techniques', tool_id, db_id)
112 |
113 | message="Tram interaction has been completed. You can now explore your mapping in the TMC."
114 |
115 | except IndexError:
116 | message="TMC did not expcet a TRAM request for this report."
117 |
118 | return render_template('maps/completed.html', message=message)
119 |
120 | # Navigator Functions
121 |
122 |
123 | # Open Navigator
124 | @bp.route('/nav//')
125 | def open_in_nav(element, element_id):
126 | nav_dict = {
127 | "name":"Threat Mapping Catalogue",
128 | "versions": {
129 | "attack": "8",
130 | "navigator": "4.0",
131 | "layer": "4.0"
132 | },
133 | "description": element + " related techniques",
134 | "domain":"mitre-enterprise",
135 | "gradient":{
136 | "colors":[
137 | "#778ca3",
138 | "#778ca3"
139 | ],
140 | "minValue":0,
141 | "maxValue":100
142 | },
143 | "legendItems":[
144 | {
145 | "label":"Has at least one test",
146 | "color":"#ce232e"
147 | }
148 | ],
149 | "techniques":[]
150 | }
151 |
152 | element_techniques = ''
153 |
154 | # Both queries bring techniques & subtechniques
155 | if element == 'adversary':
156 | element_techniques = q_get_adversaries_techniques.get_adversaries_techniques(element_id)
157 | elif element == 'tool':
158 | element_techniques = q_get_tools_techniques.get_tools_techniques(element_id)
159 |
160 | for technique in element_techniques:
161 | if technique['SubtechniqueID']:
162 | new_technique = {
163 | "techniqueID": technique['SubtechniqueID'],
164 | "score":100,
165 | "enabled":True
166 | }
167 | else:
168 | new_technique = {
169 | "techniqueID": technique['TechniqueID'],
170 | "score":100,
171 | "enabled":True
172 | }
173 |
174 | nav_dict['techniques'].append(new_technique)
175 |
176 | # Creates a json file with the retrieved information from the database
177 | filename = create_nav_file(nav_dict, element, element_id)
178 | # Creates the url with the path to the created file to send it to the navigator
179 | encoded_path = urllib.parse.quote_plus(str(config.config_dict['tmc'])+'/static/export/'+str(filename))
180 | encoded_url = str(config.config_dict['navigator']+'/fetch/'+encoded_path)
181 |
182 | return redirect(encoded_url)
183 |
184 |
185 | def create_nav_file(nav_dict, element, element_id):
186 | filename = element + '_' + str(element_id) + '_' + str(uuid.uuid1()) + '.json'
187 | directory = os.path.dirname(os.path.realpath(__file__)) + '/static/export/'
188 | filepath = directory + filename
189 |
190 | with open(filepath, 'w+') as fh:
191 | json.dump(nav_dict, fh)
192 | fh.close()
193 |
194 | return filename
195 |
196 | # Export Results
197 | @bp.route('/export//')
198 | def export_file(element, element_id):
199 |
200 | # Both queries bring techniques & subtechniques
201 | if element == 'adversary':
202 | element_techniques = q_get_adversaries_techniques.get_adversaries_techniques(element_id)
203 | create_csv_file(element_techniques, element, element_id)
204 | elif element == 'tool':
205 | element_techniques = q_get_tools_techniques.get_tools_techniques(element_id)
206 | create_csv_file(element_techniques, element, element_id)
207 |
208 | return render_template('maps/explore/main.html')
209 |
210 | def create_csv_file(element_techniques, element, element_id):
211 |
212 | headers = 'Tool \t Technique ID \t Technique \t Subtechnique ID \t Subtechnique'
213 | filename = element + '_' + str(element_id) + '_techniques_mapped_' + str(uuid.uuid1()) +'.csv'
214 | parent = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..'))
215 | filepath = parent + '/export/' + filename
216 |
217 |
218 | with open(filepath, 'w+', newline='') as new_file:
219 | new_file.write(headers +'\n')
220 | for line in element_techniques:
221 | for key, value in line.items():
222 | new_file.write(str(value) + '\t')
223 | new_file.write('\n')
224 | new_file.close()
225 |
226 | '''
227 | # Download SVG ---------------
228 | @bp.route('/svg//')
229 | def download_svg(element, element_id):
230 |
231 | # Both queries bring techniques & subtechniques
232 | if element == 'adversary':
233 | element_techniques = q_get_adversaries_techniques.get_adversaries_techniques(element_id)
234 | elif element == 'tool':
235 | element_techniques = q_get_tools_techniques.get_tools_techniques(element_id)
236 |
237 |
238 | return render_template('maps/explore/main.html')
239 | '''
240 |
241 | # List all posible actions to display data
242 | @bp.route('/explore')
243 | def explore():
244 |
245 | return render_template('maps/explore/main.html')
246 |
247 |
248 | # Displays all adversaries in the DB
249 | @bp.route('/explore-adversaries')
250 | def explore_adversaries():
251 |
252 | title='Adversaries'
253 | adversaries = q.q_get_adversaries.get_adversaries()
254 | adversaries_th = adversaries[0].keys()
255 |
256 | return render_template('maps/explore/explore-element.html', title=title, element_th=adversaries_th, paginated_element=adversaries)
257 |
258 |
259 | # Displays all events in the DB
260 | @bp.route('/explore-events')
261 | def explore_events():
262 |
263 | title='Events'
264 | events = q.q_get_events.get_events()
265 | try:
266 | events_th = events[0].keys() #add test for no elements
267 | except IndexError:
268 | return render_template('maps/no-data.html')
269 | else:
270 | return render_template('maps/explore/explore-element.html', title=title, events=events, element_th=events_th, paginated_element=events)
271 |
272 |
273 | # Displays all tools in the DB
274 | @bp.route('/explore-tools')
275 | def explore_tools():
276 |
277 | title='Tools'
278 | tools = q.q_get_tools.get_tools()
279 | tools_th = tools[0].keys()
280 |
281 | return render_template('maps/explore/explore-element.html', title=title, tools=tools, element_th=tools_th, paginated_element=tools)
282 |
283 |
284 | # Displays all tactics in the DB
285 | @bp.route('/explore-tactics')
286 | def explore_tactics():
287 |
288 | title='Tactics'
289 | tactics = q.q_get_tactics.get_tactics()
290 | tactics_th = tactics[0].keys()
291 |
292 | return render_template('maps/explore/explore-element.html', title=title, tactics=tactics, element_th=tactics_th, paginated_element=tactics)
293 |
294 |
295 | # Displays all technique in the DB
296 | @bp.route('/explore-techniques')
297 | def explore_techniques():
298 |
299 | title='Techniques'
300 | techniques = q.q_get_techniques.get_techniques()
301 | techniques_th = techniques[0].keys()
302 |
303 | return render_template('maps/explore/explore-element.html', title=title, techniques=techniques, element_th=techniques_th, paginated_element=techniques)
304 |
305 |
306 | # Displays all subtechniques in the DB
307 | @bp.route('/explore-subtechniques')
308 | def explore_subtechniques():
309 |
310 | title='Subtechniques'
311 | subtechniques = q.q_get_subtechniques.get_subtechniques()
312 | subtechniques_th = subtechniques[0].keys()
313 |
314 | return render_template('maps/explore/explore-element.html', title=title, techniques=subtechniques, element_th=subtechniques_th, paginated_element=subtechniques)
315 |
316 |
317 | # DB Analysis Screens
318 |
319 | # Display Adversaries per event
320 | @bp.route('/adversaries-x-event')
321 | def get_adversaries_x_event():
322 |
323 | title='Adversaries per event'
324 |
325 | adversaries_x_event = q.q_get_adversaries_x_event.get_adversaries_x_event()
326 | adversaries_x_event_th = adversaries_x_event[0].keys()
327 |
328 | if not adversaries_x_event:
329 | return render_template('maps/no-data.html')
330 |
331 | return render_template('maps/explore/explore-element.html', title=title, element_th=adversaries_x_event_th, paginated_element=adversaries_x_event)
332 |
333 |
334 | # Display Adversaries per suspected origin
335 | @bp.route('/adversaries-x-sorigin')
336 | def get_adversaries_x_sorigin():
337 |
338 | title='Adversaries Suspected Origin'
339 | adversaries_x_sorigin = q.q_get_adversaries_sorigin.get_adversaries_sorigin()
340 |
341 | try:
342 | adversaries_x_sorigin_th = adversaries_x_sorigin[0].keys()
343 |
344 | except IndexError:
345 | return render_template('maps/no-data.html')
346 |
347 | return render_template('maps/explore/explore-element.html', title=title, element_th=adversaries_x_sorigin_th, paginated_element=adversaries_x_sorigin)
348 |
349 |
350 | # Display Adversaries per industry
351 | @bp.route('/adversaries-x-industry')
352 | def get_adversaries_x_industry():
353 |
354 | adversaries_x_industry = ''
355 |
356 | if not adversaries_x_industry:
357 | return render_template('maps/no-data.html')
358 |
359 | else:
360 | return render_template('maps/explore/explore-element.html', title=title, element_th=adversaries_x_sorigin_th, paginated_element=adversaries_x_sorigin)
361 |
362 |
363 | # Display events by industry
364 | @bp.route('/events-x-industry')
365 | def get_events_x_industry():
366 |
367 | title = 'Events per industry'
368 | events_x_industry = q.q_get_events_x_industry.get_events_x_industry()
369 | events_x_industry_th = events_x_industry[0].keys()
370 |
371 | if not events_x_industry:
372 | return render_template('maps/no-data.html')
373 |
374 | else:
375 | return render_template('maps/explore/explore-element.html', title=title, element_th=events_x_industry_th, paginated_element=events_x_industry)
376 |
377 |
378 | # Display Techniques per industry
379 | @bp.route('/techniques-per-industry')
380 | def get_techniques_per_industry():
381 |
382 | techniques_per_industry = ''
383 |
384 | if not techniques_per_industry:
385 | return render_template('maps/no-data.html')
386 |
387 | else:
388 |
389 | return render_template('maps/explore/explore-element.html', title=title, element_th=adversaries_x_sorigin_th, paginated_element=adversaries_x_sorigin)
390 |
391 |
392 | # Display Adversaries per tool
393 | @bp.route('/adversaries-x-tool')
394 | def get_adversaries_x_tool():
395 |
396 | title='Adversaries per tool'
397 |
398 | adversaries_x_tool = q.q_get_adversaries_x_tool.get_adversaries_x_tool()
399 | adversaries_x_tool_th = adversaries_x_tool[0].keys()
400 |
401 | return render_template('maps/explore/explore-element.html', title=title, element_th=adversaries_x_tool_th, paginated_element=adversaries_x_tool)
402 |
403 |
404 | # Display Adversaries per technique
405 | @bp.route('/adversaries-x-technique')
406 | def get_adversaries_x_technique():
407 |
408 | title = 'Adversaries per technique'
409 |
410 | adversaries_x_technique = q.q_get_adversaries_x_technique.get_adversaries_x_technique()
411 | adversaries_x_technique_th = adversaries_x_technique[0].keys()
412 |
413 | return render_template('maps/explore/explore-element.html', title=title, element_th=adversaries_x_technique_th, paginated_element=adversaries_x_technique)
414 |
415 |
416 | # Display Tools per techniques
417 | @bp.route('/tools-x-techniques')
418 | def get_tools_x_techniques():
419 |
420 | title = 'Tools per technique'
421 |
422 | tools_x_techniques = q.q_get_tools_x_techniques.get_tools_x_techniques()
423 | tools_x_techniques_th = tools_x_techniques[0].keys()
424 |
425 | return render_template('maps/explore/explore-element.html', title=title, element_th=tools_x_techniques_th, paginated_element=tools_x_techniques)
426 |
427 |
428 | # Display Most used techniques
429 | @bp.route('/most-used-technique')
430 | def get_most_used_techniques():
431 |
432 | title = 'Most used techniques'
433 |
434 | most_used_techniques = q.q_get_most_used_techniques.get_most_used_techniques()
435 | most_used_techniques_th = most_used_techniques[0].keys()
436 |
437 | return render_template('maps/explore/explore-element.html', title=title, element_th=most_used_techniques_th, paginated_element=most_used_techniques)
438 |
439 |
440 | # Creates the new event in the database
441 | @bp.route('/create-events', methods=('GET', 'POST'))
442 | @login_required
443 | def create_event():
444 |
445 | return render_template('maps/creation/create-adversary.html')
446 |
447 |
448 | # DB INTERACTION FROM FRONT-END
449 |
450 | @bp.route('/create-adversary', methods=('GET', 'POST'))
451 | @login_required
452 | def create_adversary():
453 |
454 | countries_list = q.q_get_countries.get_countries()
455 |
456 | if request.method == "POST":
457 | adversary_id = request.form['adversary_id']
458 | adversary_name = request.form['adversary_name']
459 | adversary_description = request.form['description']
460 | adversary_identifiers = request.form['adversary_identifiers']
461 | adversary_origin = request.form['sorigin']
462 | error = None
463 |
464 | if not adversary_name:
465 | error = 'Adversary name is required.'
466 |
467 | if error is not None:
468 | flash(error)
469 | else:
470 | db = get_db()
471 | db.execute(
472 | 'INSERT INTO adversaries (adversary_id, adversary_name, adversary_description, adversary_identifiers, adversary_sorigin, author_id)'
473 | ' VALUES (?, ?, ?, ?, ?, ?)',
474 | (adversary_id, adversary_name, adversary_description, adversary_identifiers, adversary_origin, g.user['id'])
475 | )
476 | db.commit()
477 | message = 'Successfully created Adversary'
478 | return render_template('maps/completed.html', message=message)
479 |
480 | return render_template('maps/creation/create-adversary.html', countries_list=countries_list, request_adversary = '')
481 |
482 |
483 | @bp.route('/edit/adversary/', methods=('GET', 'POST'))
484 | def render_edit_adversary(element):
485 |
486 | countries_list = q.q_get_countries.get_countries()
487 | request_adversary=q.q_get_adversaries.get_adversaries(element)
488 | request_adversary_techniques=q.q_get_adversaries_techniques.get_adversaries_techniques(element)
489 |
490 | if request_adversary_techniques:
491 | adversary_techniques_th = request_adversary_techniques[0].keys()
492 | else:
493 | adversary_techniques_th = ''
494 |
495 | if not request_adversary:
496 | return render_template('maps/404.html')
497 | else:
498 | return render_template('maps/creation/create-adversary.html', request_adversary_techniques=request_adversary_techniques, element_th=adversary_techniques_th, request_adversary=request_adversary, countries_list=countries_list)
499 |
500 |
501 | @bp.route('/edit-adversary', methods=('GET', 'POST'))
502 | @login_required
503 | def edit_adversary():
504 | try:
505 | if request.method == 'POST':
506 | edited = request.form
507 | db_id = edited['db_id']
508 | adversary_id = edited['adversary_id']
509 | adversary_name = edited['adversary_name']
510 | adversary_identifiers = edited['adversary_identifiers']
511 | adversary_sorigin = edited['sorigin']
512 | adversary_description = edited['description']
513 | updated_date = time.strftime('%Y-%m-%d %H:%M:%S')
514 |
515 | db = get_db()
516 | db.execute(
517 | 'UPDATE adversaries SET adversary_id=?, adversary_name=?, adversary_description=?, adversary_identifiers=?, adversary_sorigin=?, updated_date=?, updated_by=? WHERE id=?',
518 | (adversary_id, adversary_name, adversary_description, adversary_identifiers, adversary_sorigin, updated_date, g.user['id'], db_id,)
519 | )
520 | db.commit()
521 |
522 | message = 'Successfully created adversaries'
523 |
524 | return render_template('maps/completed.html', message=message)
525 | except:
526 | return render_template('maps/404.html')
527 |
528 |
529 | # Creates the new tool in the database
530 | @bp.route('/create-tool', methods=('GET', 'POST'))
531 | @login_required
532 | def create_tool():
533 | adversary_list = q.q_get_adversaries.get_adversaries()
534 |
535 | if request.method == "POST":
536 |
537 | tool_id = request.form['tool_id']
538 | tool_name = request.form['tool_name']
539 | tool_identifiers = request.form['tool_identifiers']
540 | adversary_id = rast.literal_eval(request.form['related_adversary'])['db_id']
541 | tool_description = request.form['description']
542 | updated_date = time.strftime('%Y-%m-%d %H:%M:%S')
543 |
544 | db = get_db()
545 | db.execute(
546 | 'INSERT INTO tools (tool_id, tool_name, tool_description, tool_description, author_id)'
547 | ' VALUES (?, ?, ?, ?, ?)',
548 | (tool_id, tool_name, tool_description, tool_description, g.user['id'])
549 | )
550 | db.commit()
551 | q_insert_adversary_x_tool.insert_adversary_x_tool(adversary_id, tool_id)
552 | message = 'Successfully created tool'
553 |
554 | return render_template('maps/completed.html', message=message)
555 |
556 | return render_template('maps/creation/create-tool.html', adversary_list=adversary_list)
557 |
558 |
559 | @bp.route('/edit/tool/', methods=('GET', 'POST'))
560 | def render_edit_tool(element):
561 | request_tool = q.q_get_tools.get_tools(element)
562 | adversary_list = q.q_get_adversaries.get_adversaries()
563 | request_tools_techniques = q.q_get_tools_techniques.get_tools_techniques(element)
564 |
565 | if request_tools_techniques:
566 | tool_techniques_th = request_tools_techniques[0].keys()
567 | else:
568 | tool_techniques_th = ''
569 |
570 | if not request_tool:
571 | return render_template('maps/404.html')
572 | else:
573 | return render_template('maps/creation/create-tool.html', request_tools_techniques=request_tools_techniques, element_th=tool_techniques_th, request_tool=request_tool, adversary_list=adversary_list)
574 |
575 |
576 | @bp.route('/edit-tool', methods=('GET', 'POST'))
577 | @login_required
578 | def edit_tool():
579 |
580 | try:
581 | if request.method == 'POST':
582 | edited = request.form
583 | db_id = edited['db_id']
584 | tool_id = edited['tool_id']
585 | tool_name = edited['tool_name']
586 | tool_identifiers = edited['tool_identifiers']
587 | adversary_id = ast.literal_eval(request.form['related_adversary'])['db_id']
588 | tool_description = edited['tool_description']
589 | updated_date = time.strftime('%Y-%m-%d %H:%M:%S')
590 |
591 | db = get_db()
592 | db.execute(
593 | 'UPDATE tools SET tool_id=?, tool_name=?, tool_description=?, tool_identifiers=?, updated_date=?, updated_by=? WHERE id=?',
594 | (tool_id, tool_name, tool_description, tool_identifiers, updated_date, g.user['id'], db_id,)
595 | )
596 | db.commit()
597 | q_insert_adversary_x_tool.insert_adversary_x_tool(adversary_id, tool_id)
598 |
599 | return redirect('/explore-tools')
600 | except:
601 | return render_template('maps/404.html')
602 |
603 |
604 | # Creates the new technique in the database
605 | @bp.route('/create-technique', methods=('GET', 'POST'))
606 | @login_required
607 | def create_technique():
608 |
609 | tactics_list = q.q_get_tactics.get_tactics()
610 |
611 | if request.method == "POST":
612 |
613 | technique_id = request.form['id']
614 | technique_name = request.form['name']
615 | technique_description = request.form['description']
616 | unprocessed_tactic = request.form['tactic']
617 | processed_tactic_str =request.form['tactic'].replace('\'','\"')
618 | technique_tactic = json.loads(processed_tactic_str)
619 | tactic = technique_tactic['Name']
620 |
621 | db = get_db()
622 | result = db.execute(
623 | 'INSERT INTO techniques (technique_id, technique_name, technique_description, author_id)'
624 | ' VALUES (?, ?, ?, ?)',
625 | (technique_id, technique_name, technique_description, g.user['id'])
626 | )
627 | db.commit()
628 | technique_db_id = result.lastrowid
629 | tactic_id = q.q_get_element_id.get_element_id('tactics', 'tactic_name', tactic)
630 | q_insert_tactic_x_technique.insert_tactic_x_technique(tactic_id, technique_db_id)
631 |
632 | message = 'Successfully created technique'
633 |
634 | return render_template('maps/completed.html', message=message)
635 |
636 | return render_template('maps/creation/create-technique.html', tactics_list=tactics_list)
637 |
638 |
639 | @bp.route('/edit/technique/', methods=('GET', 'POST'))
640 | def render_edit_technique(element):
641 |
642 | tactics_list = q.q_get_tactics.get_tactics()
643 | request_technique=q.q_get_techniques.get_techniques(element)
644 | request_related_tools=q.q_get_tools_x_techniques.get_tools_x_techniques(element)
645 |
646 | if request_related_tools:
647 | request_related_tools_th = request_related_tools[0].keys()
648 | else:
649 | request_related_tools_th = ''
650 |
651 | if not request_technique:
652 | return render_template('maps/404.html')
653 | else:
654 | return render_template('maps/creation/create-technique.html', request_related_tools=request_related_tools, element_th=request_related_tools_th, request_technique=request_technique, tactics_list=tactics_list)
655 |
656 |
657 | @bp.route('/edit-technique', methods=('GET', 'POST'))
658 | @login_required
659 | def edit_technique():
660 | try:
661 | if request.method == 'POST':
662 | edited = request.form
663 |
664 | db_id = edited['db_id']
665 | technique_id = edited['technique_id']
666 | technique_name = edited['technique_name']
667 | tactic_id = ast.literal_eval(request.form['related_tactic'])['db_id']
668 | technique_description = edited['description']
669 | updated_date = time.strftime('%Y-%m-%d %H:%M:%S')
670 |
671 | db = get_db()
672 | db.execute(
673 | 'UPDATE tools SET technique_id=?, technique_name=?, technique_description=?, updated_date=?, updated_by=? WHERE id=?',
674 | (technique_id, technique_name, technique_description, updated_date, g.user['id'], db_id,)
675 | )
676 | db.commit()
677 |
678 | q_insert_tactic_x_technique.insert_tactic_x_technique(tactic_id, technique_db_id)
679 |
680 | return redirect('/explore-techniques')
681 | except:
682 | return render_template('maps/404.html')
683 |
684 |
685 | # Creates the new subtechnique in the database
686 | @bp.route('/create-subtechnique', methods=('GET', 'POST'))
687 | def create_subtechnique():
688 |
689 | techniques_list = q.q_get_techniques.get_techniques()
690 |
691 | if request.method == "POST":
692 | subtechnique_id = request.form['db_id']
693 | subtechnique_name = request.form['subtechnique_name']
694 | technique_id = ast.literal_eval(request.form['related_technique'])['db_id']
695 | subtechnique_description = request.form['description']
696 |
697 | db = get_db()
698 | result = db.execute(
699 | 'INSERT INTO subtechniques (subtechnique_id, subtechnique_name, subtechnique_description, author_id)'
700 | ' VALUES (?, ?, ?, ?)',
701 | (subtechnique_id, subtechnique_name, subtechnique_description, g.user['id'])
702 | )
703 | db.commit()
704 | subtechnique_db_id = result.lastrowid
705 |
706 | insert_into_table = q.q_insert_relation_into_tables.insert_relation_into_tables('techniques_x_subtechniques', 'technique_id', 'subtechnique_id', technique_id, subtechnique_db_id)
707 |
708 | message = 'Successfully created subtechnique'
709 |
710 | return render_template('maps/completed.html', message=message)
711 |
712 | return render_template('maps/creation/create-subtechnique.html', techniques_list=techniques_list)
713 |
714 |
715 | @bp.route('/edit/subtechnique/', methods=('GET', 'POST'))
716 | def render_edit_subtechnique(element):
717 |
718 | techniques_list = q.q_get_techniques.get_techniques()
719 | request_subtechnique=q.q_get_subtechniques.get_subtechniques(element)
720 | request_related_tools=q.q_get_tools_x_subtechniques.get_tools_x_subtechniques(element)
721 |
722 | if request_related_tools:
723 | request_related_tools_th = request_related_tools[0].keys()
724 | else:
725 | request_related_tools_th = ''
726 |
727 | if not request_subtechnique:
728 | return render_template('maps/404.html')
729 | else:
730 | return render_template('maps/creation/create-subtechnique.html', request_related_tools=request_related_tools, element_th=request_related_tools_th, request_subtechnique=request_subtechnique, techniques_list=techniques_list)
731 |
732 |
733 | @bp.route('/edit-subtechnique', methods=('GET', 'POST'))
734 | @login_required
735 | def edit_subtechnique():
736 | try:
737 | if request.method == 'POST':
738 | edited = request.form
739 |
740 | db_id = edited['db_id']
741 | subtechnique_id = edited['subtechnique_id']
742 | subtechnique_name = edited['subtechnique_name']
743 | subtechnique_tactic = edited['subtechnique_tactic']
744 | subtechnique_description = edited['description']
745 | updated_date = time.strftime('%Y-%m-%d %H:%M:%S')
746 |
747 | db = get_db()
748 | db.execute(
749 | 'UPDATE techniques SET subtechnique_id=?, subtechnique_name=?, subtechnique_description=?, updated_date=?, updated_by=? WHERE id=?',
750 | (subtechnique_id, subtechnique_name, subtechnique_description, updated_date, g.user['id'], db_id,)
751 | )
752 | db.commit()
753 |
754 | return redirect('/explore-subtechniques')
755 | except:
756 | return render_template('maps/404.html')
757 |
758 |
759 |
760 | @bp.route('/edit/tactic/', methods=('GET', 'POST'))
761 | def render_edit_tactic(element):
762 |
763 | request_tactic=q.q_get_tactics.get_tactics(element)
764 | request_related_tactics=q.q_get_related_tactics.get_related_tactics(element)
765 |
766 | if request_related_tactics:
767 | request_tactics_th = request_related_tactics[0].keys()
768 | else:
769 | request_related_tactics_th = ''
770 |
771 | if request_tactic is False:
772 | return render_template('maps/404.html')
773 | else:
774 | return render_template('maps/creation/create-adversary.html', request_related_tactics=request_related_tactics, element_th=request_tactics_th, request_tactic=request_tactic)
775 |
776 |
777 | @bp.route('/edit-tactic', methods=('GET', 'POST'))
778 | @login_required
779 | def edit_tactic():
780 | try:
781 | if request.method == 'POST':
782 | edited = request.form
783 |
784 | db_id = edited['db_id']
785 | tactic_id = edited['adversary_id']
786 | tactic_name = edited['adversary_name']
787 | tactic_description = edited['description']
788 | updated_date = time.strftime('%Y-%m-%d %H:%M:%S')
789 |
790 | db = get_db()
791 | db.execute(
792 | 'UPDATE tactics SET tactic_id=?, tactic_name=?, tactic_description=?, updated_date=?, updated_by=? WHERE id=?',
793 | (tactic_id, tactic_name, tactic_description, updated_date, g.user['id'], db_id,)
794 | )
795 | db.commit()
796 |
797 | return redirect('/explore-tactics')
798 | except:
799 | return render_template('maps/404.html')
800 |
--------------------------------------------------------------------------------