├── nav-app
├── src
│ ├── app
│ │ ├── tab
│ │ │ ├── tab.component.scss
│ │ │ ├── tab.component.html
│ │ │ ├── tab.component.ts
│ │ │ └── tab.component.spec.ts
│ │ ├── app.component.scss
│ │ ├── help
│ │ │ ├── help.component.ts
│ │ │ ├── help.component.scss
│ │ │ └── help.component.spec.ts
│ │ ├── data.service.spec.ts
│ │ ├── config.service.spec.ts
│ │ ├── globals.ts
│ │ ├── app.component.html
│ │ ├── viewmodels.service.spec.ts
│ │ ├── tabs
│ │ │ ├── dynamic-tabs.directive.ts
│ │ │ ├── tabs.component.spec.ts
│ │ │ └── tabs.component.scss
│ │ ├── exporter
│ │ │ ├── exporter.component.scss
│ │ │ └── exporter.component.spec.ts
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ ├── config.service.ts
│ │ └── data.service.ts
│ ├── environments
│ │ ├── environment.prod.ts
│ │ └── environment.ts
│ ├── favicon.ico
│ ├── faviconO.ico
│ ├── typings.d.ts
│ ├── assets
│ │ ├── NavigatorLayerFileFormatv1.pdf
│ │ ├── NavigatorLayerFileFormatv2.pdf
│ │ ├── image_scoreVariableExample.png
│ │ ├── NavigatorLayerFileFormatv1_1.pdf
│ │ ├── NavigatorLayerFileFormatv1_2.pdf
│ │ ├── NavigatorLayerFileFormatv1_3.pdf
│ │ ├── NavigatorLayerFileFormatv2_1.pdf
│ │ ├── icons
│ │ │ ├── ic_file_upload_black_24px.svg
│ │ │ ├── ic_file_upload_gray_24px.svg
│ │ │ ├── ic_done_black_24px.svg
│ │ │ ├── ic_file_download_black_24px.svg
│ │ │ ├── ic_done_gray_24px.svg
│ │ │ ├── ic_filter_list_black_24px.svg
│ │ │ ├── ic_format_size_black_24px.svg
│ │ │ ├── ic_keyboard_arrow_up_black_24px.svg
│ │ │ ├── ic_keyboard_arrow_down_black_24px.svg
│ │ │ ├── ic_keyboard_arrow_right_black_24px.svg
│ │ │ ├── ic_playlist_add_black_24px.svg
│ │ │ ├── ic_playlist_add_gray_24px.svg
│ │ │ ├── ic_remove_circle_black_24px.svg
│ │ │ ├── ic_view_large_black_24px.svg
│ │ │ ├── ic_view_list_black_24px.svg
│ │ │ ├── ic_view_list_grey_24px.svg
│ │ │ ├── ic_clear_black_24px.svg
│ │ │ ├── ic_check_box_outline_blank_black_24px.svg
│ │ │ ├── ic_clear_gray_24px.svg
│ │ │ ├── ic_close_black_24px.svg
│ │ │ ├── ic_insert_comment_black_24px.svg
│ │ │ ├── ic_insert_comment_gray_24px.svg
│ │ │ ├── ic_insert_chart_black_24px.svg
│ │ │ ├── ic_content_copy_black_24px.svg
│ │ │ ├── ic_description_black_24px.svg
│ │ │ ├── ic_insert_chart_gray_24px.svg
│ │ │ ├── ic_check_box_black_24px.svg
│ │ │ ├── ic_save_black_24px.svg
│ │ │ ├── ic_save_gray_24px.svg
│ │ │ ├── ic_view_medium_black_24px.svg
│ │ │ ├── ic_view_small_black_24px.svg
│ │ │ ├── baseline-grid_on-24px.svg
│ │ │ ├── ic_camera_alt_black_24px.svg
│ │ │ ├── ic_visibility_black_24px.svg
│ │ │ ├── ic_visibility_gray_24px.svg
│ │ │ ├── ic_lock_black_24px.svg
│ │ │ ├── ic_search_gray_24px.svg
│ │ │ ├── ic_layers_clear_black_24px.svg
│ │ │ ├── ic_layers_clear_gray_24px.svg
│ │ │ ├── ic_lock_open_black_24px.svg
│ │ │ ├── ic_search_black_24px.svg
│ │ │ ├── ic_texture_black_24px.svg
│ │ │ ├── ic_texture_gray_24px.svg
│ │ │ ├── ic_photo_size_select_large_black_24px.svg
│ │ │ ├── ic_format_color_fill_black_24px.svg
│ │ │ ├── ic_sort_numerically_black_24px.svg
│ │ │ ├── ic_sort_alphabetically_black_24px.svg
│ │ │ ├── ic_format_color_fill_gray_nobottom_24px.svg
│ │ │ ├── ic_format_color_fill_black_nobottom_24px.svg
│ │ │ ├── ic_sort_alphabetically_ascending_black_24px.svg
│ │ │ ├── ic_sort_numerically_ascending_black_24px.svg
│ │ │ ├── ic_sort_alphabetically_descending_black_24px.svg
│ │ │ ├── ic_palette_black_24px.svg
│ │ │ ├── ic_sort_numerically_descending_black_24px.svg
│ │ │ ├── ic_color_lens_black_24px.svg
│ │ │ └── ic_visibility_off_black_24px.svg
│ │ └── config.json
│ ├── tsconfig.app.json
│ ├── colors.scss
│ ├── index.html
│ ├── main.ts
│ ├── tsconfig.spec.json
│ ├── test.ts
│ ├── polyfills.ts
│ └── styles.scss
├── e2e
│ ├── app.po.ts
│ ├── tsconfig.e2e.json
│ └── app.e2e-spec.ts
├── Dockerfile
├── .editorconfig
├── patch-webpack.js
├── tsconfig.json
├── .gitignore
├── protractor.conf.js
├── karma.conf.js
├── package.json
├── tslint.json
└── angular.json
├── README.md
├── NOTICE.txt
├── CONTRIBUTING.md
├── layers
├── attack_layers
│ └── attack_layers_simple.py
├── README.md
├── data
│ ├── csv
│ │ └── simple_input.csv
│ ├── samples
│ │ ├── ATTACKcon
│ │ │ ├── Black_Pins.json
│ │ │ ├── Red_Pins.json
│ │ │ ├── Gold_Pins.json
│ │ │ ├── Blue_Pins.json
│ │ │ └── Submitter_Responses.json
│ │ └── Bear_APT.json
│ └── update_layers
│ │ ├── October_2018_Updates_Mobile.json
│ │ └── October_2018_Updates_Enterprise.json
├── LAYERFORMATv1.md
├── LAYERFORMATv1_1.md
├── LAYERFORMATv1_2.md
├── LAYERFORMATv1_3.md
├── LAYERFORMATv2.md
└── LAYERFORMATv2_1.md
└── LICENSE.txt
/nav-app/src/app/tab/tab.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true
3 | };
4 |
--------------------------------------------------------------------------------
/nav-app/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitre/attack-navigator/HEAD/nav-app/src/favicon.ico
--------------------------------------------------------------------------------
/nav-app/src/faviconO.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitre/attack-navigator/HEAD/nav-app/src/faviconO.ico
--------------------------------------------------------------------------------
/nav-app/src/typings.d.ts:
--------------------------------------------------------------------------------
1 | /* SystemJS module definition */
2 | declare var module: NodeModule;
3 | interface NodeModule {
4 | id: string;
5 | }
6 |
--------------------------------------------------------------------------------
/nav-app/src/assets/NavigatorLayerFileFormatv1.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitre/attack-navigator/HEAD/nav-app/src/assets/NavigatorLayerFileFormatv1.pdf
--------------------------------------------------------------------------------
/nav-app/src/assets/NavigatorLayerFileFormatv2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitre/attack-navigator/HEAD/nav-app/src/assets/NavigatorLayerFileFormatv2.pdf
--------------------------------------------------------------------------------
/nav-app/src/assets/image_scoreVariableExample.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitre/attack-navigator/HEAD/nav-app/src/assets/image_scoreVariableExample.png
--------------------------------------------------------------------------------
/nav-app/src/assets/NavigatorLayerFileFormatv1_1.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitre/attack-navigator/HEAD/nav-app/src/assets/NavigatorLayerFileFormatv1_1.pdf
--------------------------------------------------------------------------------
/nav-app/src/assets/NavigatorLayerFileFormatv1_2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitre/attack-navigator/HEAD/nav-app/src/assets/NavigatorLayerFileFormatv1_2.pdf
--------------------------------------------------------------------------------
/nav-app/src/assets/NavigatorLayerFileFormatv1_3.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitre/attack-navigator/HEAD/nav-app/src/assets/NavigatorLayerFileFormatv1_3.pdf
--------------------------------------------------------------------------------
/nav-app/src/assets/NavigatorLayerFileFormatv2_1.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitre/attack-navigator/HEAD/nav-app/src/assets/NavigatorLayerFileFormatv2_1.pdf
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ATT&CK™ Navigator
2 |
3 | ### This repository has been deprecated. Please visit our new ATT&CK Navigator repository in the mitre-attack GitHub organization at https://github.com/mitre-attack/attack-navigator!
4 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_file_upload_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_file_upload_gray_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_done_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_file_download_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/app/app.component.scss:
--------------------------------------------------------------------------------
1 | tabs {
2 | // font-family: 'Roboto Mono', monospace;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
4 | font-size: 9pt;
5 |
6 | }
7 |
--------------------------------------------------------------------------------
/nav-app/src/app/tab/tab.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_done_gray_24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_filter_list_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_format_size_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_keyboard_arrow_up_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/e2e/app.po.ts:
--------------------------------------------------------------------------------
1 | import { browser, by, element } from 'protractor';
2 |
3 | export class AppPage {
4 | navigateTo() {
5 | return browser.get('/');
6 | }
7 |
8 | getParagraphText() {
9 | return element(by.css('app-root h1')).getText();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_keyboard_arrow_down_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_keyboard_arrow_right_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/Dockerfile:
--------------------------------------------------------------------------------
1 | # Build stage
2 |
3 | FROM node:latest
4 |
5 | WORKDIR /nav-app/
6 |
7 | # copy over needed files
8 | COPY . ./
9 |
10 | # install packages and build
11 | RUN npm install --unsafe-perm && npm rebuild node-sass --force
12 |
13 | EXPOSE 4200
14 |
15 | CMD npm start
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_playlist_add_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_playlist_add_gray_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_remove_circle_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_view_large_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_view_list_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_view_list_grey_24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_clear_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_check_box_outline_blank_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_clear_gray_24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_close_black_24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/nav-app/src/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "allowJs": true,
5 | "outDir": "../out-tsc/app",
6 | "baseUrl": "./",
7 | "module": "es2015",
8 | "types": []
9 | },
10 | "exclude": [
11 | "test.ts",
12 | "**/*.spec.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/nav-app/e2e/tsconfig.e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/e2e",
5 | "baseUrl": "./",
6 | "module": "commonjs",
7 | "target": "es5",
8 | "types": [
9 | "jasmine",
10 | "jasminewd2",
11 | "node"
12 | ]
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_insert_comment_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_insert_comment_gray_24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_insert_chart_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_content_copy_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_description_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_insert_chart_gray_24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_check_box_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_save_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_save_gray_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_view_medium_black_24px.svg:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/nav-app/src/colors.scss:
--------------------------------------------------------------------------------
1 | $table-background-color: rgb(255, 255, 255);
2 | $column-hover-color: rgb(235, 235, 235);
3 | $cell-border-color: darken($column-hover-color, 20%);
4 | $cell-highlight-color: rgb(96, 197, 255);
5 | $hover-cell-font-color: rgb(0, 0, 0);
6 | $panel-dark: #ddd;
7 | $panel-light: lighten($panel-dark, 8%);
8 | $tab-text-color: #555;
9 | $button-dark: #b8b8b8;
--------------------------------------------------------------------------------
/nav-app/e2e/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { AppPage } from './app.po';
2 |
3 | describe('nav-app App', () => {
4 | let page: AppPage;
5 |
6 | beforeEach(() => {
7 | page = new AppPage();
8 | });
9 |
10 | it('should display welcome message', () => {
11 | page.navigateTo();
12 | expect(page.getParagraphText()).toEqual('Welcome to app!');
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_view_small_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ATT&CK™ Navigator
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/nav-app/src/app/help/help.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import * as globals from "../globals";
3 | @Component({
4 | selector: 'help',
5 | templateUrl: './help.component.html',
6 | styleUrls: ['./help.component.scss']
7 | })
8 | export class HelpComponent {
9 | nav_version: string = globals.nav_version;
10 | constructor() { }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/nav-app/src/app/help/help.component.scss:
--------------------------------------------------------------------------------
1 | @import "../../colors.scss";
2 |
3 | .help {
4 | font-size: 11pt;
5 | }
6 |
7 | .content {
8 | padding: 5px;
9 | }
10 |
11 | // table of contents
12 | .toc {
13 | list-style: none;
14 | ul {
15 | list-style: none;
16 | }
17 | }
18 |
19 | code {
20 | color: black;
21 | border: 1px solid $panel-dark;
22 | padding: 1px 2px;
23 | }
24 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/baseline-grid_on-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_camera_alt_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_visibility_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_visibility_gray_24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_lock_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app/app.module';
5 | import { environment } from './environments/environment';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | platformBrowserDynamic().bootstrapModule(AppModule)
12 | .catch(err => console.log(err));
13 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_search_gray_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // The file contents for the current environment will overwrite these during build.
2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do
3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead.
4 | // The list of which env maps to which file can be found in `.angular-cli.json`.
5 |
6 | export const environment = {
7 | production: false
8 | };
9 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_layers_clear_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_layers_clear_gray_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_lock_open_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_search_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/spec",
5 | "baseUrl": "./",
6 | "module": "commonjs",
7 | "target": "es5",
8 | "types": [
9 | "jasmine",
10 | "node"
11 | ]
12 | },
13 | "files": [
14 | "test.ts",
15 | "polyfills.ts"
16 | ],
17 | "include": [
18 | "**/*.spec.ts",
19 | "**/*.d.ts"
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/nav-app/src/app/data.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed, inject } from '@angular/core/testing';
2 |
3 | import { DataService } from './data.service';
4 |
5 | describe('DataService', () => {
6 | beforeEach(() => {
7 | TestBed.configureTestingModule({
8 | providers: [DataService]
9 | });
10 | });
11 |
12 | it('should be created', inject([DataService], (service: DataService) => {
13 | expect(service).toBeTruthy();
14 | }));
15 | });
16 |
--------------------------------------------------------------------------------
/nav-app/src/app/config.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed, inject } from '@angular/core/testing';
2 |
3 | import { ConfigService } from './config.service';
4 |
5 | describe('ConfigService', () => {
6 | beforeEach(() => {
7 | TestBed.configureTestingModule({
8 | providers: [ConfigService]
9 | });
10 | });
11 |
12 | it('should be created', inject([ConfigService], (service: ConfigService) => {
13 | expect(service).toBeTruthy();
14 | }));
15 | });
16 |
--------------------------------------------------------------------------------
/nav-app/src/app/globals.ts:
--------------------------------------------------------------------------------
1 | // ___ _ ___ ___ _ _ __ ___ ___ ___ _ ___ _ ___ ___
2 | // / __| | / _ \| _ ) /_\ | | \ \ / /_\ | _ \_ _| /_\ | _ ) | | __/ __|
3 | // | (_ | |_| (_) | _ \/ _ \| |__ \ V / _ \| /| | / _ \| _ \ |__| _|\__ \
4 | // \___|____\___/|___/_/ \_\____| \_/_/ \_\_|_\___/_/ \_\___/____|___|___/
5 | //
6 | 'use strict';
7 |
8 | export const nav_version: string="2.2"
9 | export const layer_version: string="2.1"
10 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_texture_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_texture_gray_24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/nav-app/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 | MITRE ATT&CKTM Navigator v{{nav_version}}
9 |
10 |
11 |
14 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_photo_size_select_large_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/app/viewmodels.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed, inject } from '@angular/core/testing';
2 |
3 | import { ViewModelsService } from './viewmodels.service';
4 |
5 | describe('ViewmodelsService', () => {
6 | beforeEach(() => {
7 | TestBed.configureTestingModule({
8 | providers: [ViewModelsService]
9 | });
10 | });
11 |
12 | it('should be created', inject([ViewModelsService], (service: ViewModelsService) => {
13 | expect(service).toBeTruthy();
14 | }));
15 | });
16 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_format_color_fill_black_24px.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/nav-app/patch-webpack.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const f = 'node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/browser.js';
3 |
4 | fs.readFile(f, 'utf8', function (err,data) {
5 | if (err) {
6 | return console.log(err);
7 | }
8 | let result = data.replace(/node: false/g, "node: {crypto: true, stream: true, fs: 'empty', net: 'empty'}");
9 |
10 | fs.writeFile(f, result, 'utf8', function (err) {
11 | if (err) return console.log(err);
12 | });
13 | });
--------------------------------------------------------------------------------
/nav-app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "outDir": "./dist/out-tsc",
5 | "sourceMap": true,
6 | "declaration": false,
7 | "moduleResolution": "node",
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "target": "es5",
11 | "typeRoots": [
12 | "node_modules/@types"
13 | ],
14 | "lib": [
15 | "es2017",
16 | "dom"
17 | ],
18 | "module": "es2015",
19 | "baseUrl": "./",
20 | }
21 | }
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_sort_numerically_black_24px.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_sort_alphabetically_black_24px.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_format_color_fill_gray_nobottom_24px.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_format_color_fill_black_nobottom_24px.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/nav-app/src/app/tabs/dynamic-tabs.directive.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This directive is used as an anchor to get access
3 | * to the ViewContainerRef which here is exposed via
4 | * the public member `viewContainer`
5 | *
6 | * Theres an ALTERNATIVE to explicitly using the anchor directive.
7 | * Read in the blog post
8 | */
9 |
10 | import { Directive, ViewContainerRef } from '@angular/core';
11 |
12 | @Directive({
13 | selector: '[dynamic-tabs]'
14 | })
15 | export class DynamicTabsDirective {
16 | constructor(public viewContainer: ViewContainerRef){}
17 | }
18 |
--------------------------------------------------------------------------------
/nav-app/src/app/tab/tab.component.ts:
--------------------------------------------------------------------------------
1 | // https://embed.plnkr.co/wWKnXzpm8V31wlvu64od/s
2 | import { Component, Input } from '@angular/core';
3 |
4 | @Component({
5 | selector: 'tab',
6 | templateUrl: './tab.component.html',
7 | styleUrls: ['./tab.component.scss']
8 | })
9 | export class TabComponent {
10 | @Input('tabTitle') title: string;
11 | @Input() active = false;
12 | @Input() isCloseable = false;
13 | @Input() template;
14 | @Input() dataContext;
15 | @Input() showScoreVariables = false;
16 | @Input() isDataTable: boolean;
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/nav-app/src/app/exporter/exporter.component.scss:
--------------------------------------------------------------------------------
1 | .svgcontainer {
2 | overflow-x: auto
3 | }
4 |
5 | .dropdown-container {
6 | padding: 10px;
7 | ul {
8 | padding-left: 0;
9 | li {
10 | list-style: none;
11 | text-align: left;
12 | input.has-suffix {
13 | text-align: right;
14 | &::-webkit-inner-spin-button,
15 | &::-webkit-outer-spin-button {
16 | display: none
17 | }
18 | -moz-appearance: textfield;
19 | }
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_sort_alphabetically_ascending_black_24px.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_sort_numerically_ascending_black_24px.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_sort_alphabetically_descending_black_24px.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_palette_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_sort_numerically_descending_black_24px.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_color_lens_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /dist
5 | /tmp
6 | /out-tsc
7 |
8 | # dependencies
9 | /node_modules
10 |
11 | # IDEs and editors
12 | /.idea
13 | .project
14 | .classpath
15 | .c9/
16 | *.launch
17 | .settings/
18 | *.sublime-workspace
19 |
20 | # IDE - VSCode
21 | .vscode/*
22 | !.vscode/settings.json
23 | !.vscode/tasks.json
24 | !.vscode/launch.json
25 | !.vscode/extensions.json
26 |
27 | # misc
28 | /.sass-cache
29 | /connect.lock
30 | /coverage
31 | /libpeerconnection.log
32 | npm-debug.log
33 | testem.log
34 | /typings
35 |
36 | # e2e
37 | /e2e/*.js
38 | /e2e/*.map
39 |
40 | # System Files
41 | .DS_Store
42 | Thumbs.db
43 |
--------------------------------------------------------------------------------
/nav-app/src/app/tab/tab.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { TabComponent } from './tab.component';
4 |
5 | describe('TabComponent', () => {
6 | let component: TabComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ TabComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(TabComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/nav-app/src/assets/icons/ic_visibility_off_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/nav-app/src/app/help/help.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { HelpComponent } from './help.component';
4 |
5 | describe('HelpComponent', () => {
6 | let component: HelpComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ HelpComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(HelpComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/nav-app/src/app/tabs/tabs.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { TabsComponent } from './tabs.component';
4 |
5 | describe('TabsComponent', () => {
6 | let component: TabsComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ TabsComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(TabsComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/nav-app/src/app/exporter/exporter.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { ExporterComponent } from './exporter.component';
4 |
5 | describe('ExporterComponent', () => {
6 | let component: ExporterComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ ExporterComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(ExporterComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/NOTICE.txt:
--------------------------------------------------------------------------------
1 | Copyright 2018 The MITRE Corporation
2 |
3 | Approved for Public Release; Distribution Unlimited. Case Number 18-0128.
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 |
17 | This project makes use of ATT&CK™
18 | ATT&CK™ Terms of Use - https://attack.mitre.org/resources/terms-of-use/
19 |
--------------------------------------------------------------------------------
/nav-app/protractor.conf.js:
--------------------------------------------------------------------------------
1 | // Protractor configuration file, see link for more information
2 | // https://github.com/angular/protractor/blob/master/lib/config.ts
3 |
4 | const { SpecReporter } = require('jasmine-spec-reporter');
5 |
6 | exports.config = {
7 | allScriptsTimeout: 11000,
8 | specs: [
9 | './e2e/**/*.e2e-spec.ts'
10 | ],
11 | capabilities: {
12 | 'browserName': 'chrome'
13 | },
14 | directConnect: true,
15 | baseUrl: 'http://localhost:4200/',
16 | framework: 'jasmine',
17 | jasmineNodeOpts: {
18 | showColors: true,
19 | defaultTimeoutInterval: 30000,
20 | print: function() {}
21 | },
22 | onPrepare() {
23 | require('ts-node').register({
24 | project: 'e2e/tsconfig.e2e.json'
25 | });
26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/nav-app/src/app/app.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed, async } from '@angular/core/testing';
2 | import { AppComponent } from './app.component';
3 | describe('AppComponent', () => {
4 | beforeEach(async(() => {
5 | TestBed.configureTestingModule({
6 | declarations: [
7 | AppComponent
8 | ],
9 | }).compileComponents();
10 | }));
11 | it('should create the app', async(() => {
12 | const fixture = TestBed.createComponent(AppComponent);
13 | const app = fixture.debugElement.componentInstance;
14 | expect(app).toBeTruthy();
15 | }));
16 | it(`should have as title 'app'`, async(() => {
17 | const fixture = TestBed.createComponent(AppComponent);
18 | const app = fixture.debugElement.componentInstance;
19 | expect(app.title).toEqual('app');
20 | }));
21 | it('should render title in a h1 tag', async(() => {
22 | const fixture = TestBed.createComponent(AppComponent);
23 | fixture.detectChanges();
24 | const compiled = fixture.debugElement.nativeElement;
25 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!');
26 | }));
27 | });
28 |
--------------------------------------------------------------------------------
/nav-app/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage-istanbul-reporter'),
13 | require('@angular-devkit/build-angular/plugins/karma')
14 | ],
15 | client:{
16 | clearContext: false // leave Jasmine Spec Runner output visible in browser
17 | },
18 | coverageIstanbulReporter: {
19 | dir: require('path').join(__dirname, 'coverage'), reports: [ 'html', 'lcovonly' ],
20 | fixWebpackSourcePaths: true
21 | },
22 |
23 | reporters: ['progress', 'kjhtml'],
24 | port: 9876,
25 | colors: true,
26 | logLevel: config.LOG_INFO,
27 | autoWatch: true,
28 | browsers: ['Chrome'],
29 | singleRun: false,
30 | webpack: { node: { fs: 'empty', } } //https://github.com/angular/angular-cli/issues/8357
31 | });
32 | };
33 |
--------------------------------------------------------------------------------
/nav-app/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/dist/long-stack-trace-zone';
4 | import 'zone.js/dist/proxy.js';
5 | import 'zone.js/dist/sync-test';
6 | import 'zone.js/dist/jasmine-patch';
7 | import 'zone.js/dist/async-test';
8 | import 'zone.js/dist/fake-async-test';
9 | import { getTestBed } from '@angular/core/testing';
10 | import {
11 | BrowserDynamicTestingModule,
12 | platformBrowserDynamicTesting
13 | } from '@angular/platform-browser-dynamic/testing';
14 |
15 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
16 | declare const __karma__: any;
17 | declare const require: any;
18 |
19 | // Prevent Karma from running prematurely.
20 | __karma__.loaded = function () {};
21 |
22 | // First, initialize the Angular testing environment.
23 | getTestBed().initTestEnvironment(
24 | BrowserDynamicTestingModule,
25 | platformBrowserDynamicTesting()
26 | );
27 | // Then we find all the tests.
28 | const context = require.context('./', true, /\.spec\.ts$/);
29 | // And load the modules.
30 | context.keys().map(context);
31 | // Finally, start Karma to run the tests.
32 | __karma__.start();
33 |
--------------------------------------------------------------------------------
/nav-app/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ViewChild, DoCheck, HostListener } from '@angular/core';
2 | import {DataService, Technique} from './data.service'; //import the DataService component so we can use it
3 | import {TabsComponent} from './tabs/tabs.component';
4 | import * as globals from "./globals";
5 |
6 | @Component({
7 | selector: 'app-root',
8 | templateUrl: './app.component.html',
9 | styleUrls: ['./app.component.scss'],
10 | providers: [DataService] //add this provider to make sure we know we need DataService for this component
11 | })
12 | export class AppComponent {
13 | @ViewChild(TabsComponent) tabsComponent;
14 |
15 | nav_version: string = globals.nav_version;
16 |
17 | @HostListener('window:beforeunload', ['$event'])
18 | promptNavAway($event) {
19 | //this text only shows in the data, not visible to user as far as I can tell
20 | //however, if it's not included the window doesn't open.
21 | $event.returnValue='Are you sure you want to navigate away? Your data may be lost!';
22 | }
23 |
24 | constructor(private dataService: DataService) {
25 | Array.prototype.includes = function(value): boolean {
26 | // console.log("checking include")
27 | for (let i = 0; i < this.length; i++) {
28 | if (this[i] === value) return true
29 | }
30 | return false;
31 | }
32 | }
33 |
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to contribute
2 |
3 | Thanks for contributing to `attack-navigator`!
4 |
5 | You are welcome to comment on issues, open new issues, and open pull requests.
6 |
7 | Pull requests should target the **develop** branch of the repository.
8 |
9 | Also, if you contribute any source code, we need you to agree to the following Developer's Certificate of Origin below.
10 |
11 | ## Developer's Certificate of Origin v1.1
12 |
13 | ```
14 | By making a contribution to this project, I certify that:
15 |
16 | (a) The contribution was created in whole or in part by me and I
17 | have the right to submit it under the open source license
18 | indicated in the file; or
19 |
20 | (b) The contribution is based upon previous work that, to the best
21 | of my knowledge, is covered under an appropriate open source
22 | license and I have the right under that license to submit that
23 | work with modifications, whether created in whole or in part
24 | by me, under the same open source license (unless I am
25 | permitted to submit under a different license), as indicated
26 | in the file; or
27 |
28 | (c) The contribution was provided directly to me by some other
29 | person who certified (a), (b) or (c) and I have not modified
30 | it.
31 |
32 | (d) I understand and agree that this project and the contribution
33 | are public and that a record of the contribution (including all
34 | personal information I submit with it, including my sign-off) is
35 | maintained indefinitely and may be redistributed consistent with
36 | this project or the open source license(s) involved.
37 | ```
38 |
--------------------------------------------------------------------------------
/nav-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nav-app",
3 | "version": "1.0.0",
4 | "license": "Apache",
5 | "scripts": {
6 | "ng": "ng",
7 | "start": "ng serve --host 0.0.0.0",
8 | "build": "ng build",
9 | "test": "ng test",
10 | "lint": "ng lint",
11 | "e2e": "ng e2e",
12 | "postinstall": "node patch-webpack.js"
13 | },
14 | "private": true,
15 | "dependencies": {
16 | "@angular/animations": "^7.0.4",
17 | "@angular/cdk": "^7.0.4",
18 | "@angular/common": "^7.0.4",
19 | "@angular/compiler": "^7.0.4",
20 | "@angular/core": "^7.0.4",
21 | "@angular/forms": "^7.0.4",
22 | "@angular/http": "^7.0.4",
23 | "@angular/material": "^7.0.4",
24 | "@angular/platform-browser": "^7.0.4",
25 | "@angular/platform-browser-dynamic": "^7.0.4",
26 | "@angular/router": "^7.0.4",
27 | "@types/file-saver": "^2.0.0",
28 | "classlist.js": "^1.1.20150312",
29 | "core-js": "^2.5.7",
30 | "d3": "^5.7.0",
31 | "file-saver": "^2.0.0",
32 | "is_js": "^0.9.0",
33 | "load-json-file": "^5.1.0",
34 | "mathjs": "^5.2.3",
35 | "ngx-color-picker": "^7.0.2",
36 | "rxjs": "^6.3.3",
37 | "rxjs-compat": "^6.0.0-rc.0",
38 | "tinygradient": "^0.4.2",
39 | "zone.js": "^0.8.26"
40 | },
41 | "devDependencies": {
42 | "@angular-devkit/build-angular": "~0.10.0",
43 | "@angular/cli": "^7.0.6",
44 | "@angular/compiler-cli": "^7.0.4",
45 | "@angular/language-service": "^7.0.4",
46 | "@types/jasmine": "~3.3.0",
47 | "@types/jasminewd2": "~2.0.6",
48 | "@types/node": "~10.12.9",
49 | "codelyzer": "~4.5.0",
50 | "exceljs": "^1.6.3",
51 | "jasmine-core": "~3.3.0",
52 | "jasmine-spec-reporter": "~4.2.1",
53 | "karma": "~3.1.1",
54 | "karma-chrome-launcher": "~2.2.0",
55 | "karma-cli": "~1.0.1",
56 | "karma-coverage-istanbul-reporter": "^2.0.4",
57 | "karma-jasmine": "~2.0.1",
58 | "karma-jasmine-html-reporter": "^1.4.0",
59 | "protractor": "^5.4.1",
60 | "ts-node": "~7.0.1",
61 | "tslint": "~5.11.0",
62 | "typescript": "~3.1.6"
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/nav-app/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { BrowserModule } from '@angular/platform-browser';
2 | import { NgModule } from '@angular/core';
3 | import { HttpModule } from '@angular/http';
4 | import 'rxjs/add/operator/map'
5 |
6 | // material
7 | import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
8 | import {MatSelectModule, MatInputModule} from '@angular/material';
9 | import {MatButtonModule} from '@angular/material/button';
10 | import {FormsModule, ReactiveFormsModule} from '@angular/forms';
11 | import {MatTooltipModule} from '@angular/material/tooltip';
12 | import {MatMenuModule} from '@angular/material/menu';
13 | import {MatExpansionModule} from '@angular/material/expansion';
14 | import { ColorPickerModule } from 'ngx-color-picker';
15 |
16 | import { AppComponent } from './app.component';
17 | import { DataTableComponent } from './datatable/data-table.component';
18 | import { TabsComponent } from './tabs/tabs.component';
19 | import {DynamicTabsDirective} from './tabs/dynamic-tabs.directive';
20 | import { TabComponent } from './tab/tab.component';
21 | import { HelpComponent } from './help/help.component';
22 | import { ExporterComponent } from './exporter/exporter.component';
23 |
24 |
25 | @NgModule({
26 | declarations: [
27 | AppComponent,
28 | DataTableComponent,
29 | TabsComponent,
30 | TabComponent,
31 | DynamicTabsDirective,
32 | HelpComponent,
33 | ExporterComponent,
34 | ],
35 | imports: [
36 | BrowserModule,
37 | HttpModule,
38 | BrowserAnimationsModule,
39 | MatSelectModule,
40 | FormsModule,
41 | ReactiveFormsModule,
42 | MatInputModule,
43 | MatButtonModule,
44 | MatTooltipModule,
45 | MatMenuModule,
46 | MatExpansionModule,
47 | ColorPickerModule,
48 | ],
49 | exports: [
50 | MatSelectModule,
51 | MatInputModule,
52 | MatButtonModule,
53 | MatTooltipModule,
54 | MatMenuModule,
55 | MatExpansionModule,
56 | ],
57 | providers: [],
58 | bootstrap: [AppComponent],
59 | entryComponents: [ TabComponent ]
60 | })
61 | export class AppModule { }
62 |
--------------------------------------------------------------------------------
/layers/attack_layers/attack_layers_simple.py:
--------------------------------------------------------------------------------
1 | # attack_layers_simple.py - the "hello, world" for ATT&CK Navigator layer generation
2 | # Takes a simple CSV file containing ATT&CK technique IDs and counts of groups, software and articles/reports that reference this technique
3 | # and generates an ATT&CK Navigator layer file with techniques scored and color-coded based on an algorithm
4 | # This sample is intended to demonstrate generating layers from external data sources such as CSV files.
5 |
6 | import argparse
7 | import csv
8 | import json
9 | import sys
10 |
11 | # Static ATT&CK Navigator layer JSON fields
12 | VERSION = "2.1"
13 | NAME = "example"
14 | DESCRIPTION = "hello, world"
15 | DOMAIN = "mitre-enterprise"
16 |
17 | # Main
18 | def main():
19 |
20 | # handle arguments
21 | parser = argparse.ArgumentParser()
22 | parser.add_argument("-i", "--input", action="store", dest="input_fn", default="attack.csv",
23 | required=True, help="input ATT&CK csv file with tactic ID, groups, software, etc... fields")
24 |
25 | args = parser.parse_args()
26 |
27 | # Base ATT&CK Navigator layer
28 | layer_json = {
29 | "version": VERSION,
30 | "name": NAME,
31 | "description": DESCRIPTION,
32 | "domain": DOMAIN,
33 | "techniques": []
34 | }
35 |
36 | # parse csv file, calculating a score for each technique and adding that to the layer
37 | with open(args.input_fn, "rb") as csvfile:
38 | reader = csv.DictReader(csvfile, delimiter=",")
39 | for row in reader:
40 | # score each technique based on a simple formula
41 | technique = {
42 | "techniqueID": row["TechID"],
43 | "score": (int(row["Software"]) + int(row["Groups"]))*2 + int(row["References"])
44 | }
45 |
46 | layer_json["techniques"].append(technique)
47 |
48 |
49 | # add a color gradient (white -> red) to layer
50 | # ranging from zero (white) to the maximum score in the file (red)
51 | layer_json["gradient"] = {
52 | "colors": [
53 | "#ffffff",
54 | "#ff6666"
55 | ],
56 | "minValue": 0,
57 | "maxValue": max([technique["score"] for technique in layer_json["techniques"]])
58 | }
59 |
60 | # output JSON
61 | json.dump(layer_json, sys.stdout, indent=4)
62 |
63 |
64 | if __name__ == "__main__":
65 | main()
66 |
--------------------------------------------------------------------------------
/nav-app/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/
22 | import 'core-js/es6/symbol';
23 | import 'core-js/es6/object';
24 | import 'core-js/es6/function';
25 | import 'core-js/es6/parse-int';
26 | import 'core-js/es6/parse-float';
27 | import 'core-js/es6/number';
28 | import 'core-js/es6/math';
29 | import 'core-js/es6/string';
30 | import 'core-js/es6/date';
31 | import 'core-js/es6/array';
32 | import 'core-js/es6/regexp';
33 | import 'core-js/es6/map';
34 | import 'core-js/es6/weak-map';
35 | import 'core-js/es6/set';
36 |
37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
38 | import 'classlist.js'; // Run `npm install --save classlist.js`.
39 |
40 | /** IE10 and IE11 requires the following for the Reflect API. */
41 | import 'core-js/es6/reflect';
42 |
43 |
44 | /** Evergreen browsers require these. **/
45 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
46 |
47 |
48 |
49 | /**
50 | * Required to support Web Animations `@angular/platform-browser/animations`.
51 | * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
52 | **/
53 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
54 |
55 |
56 |
57 | /***************************************************************************************************
58 | * Zone JS is required by Angular itself.
59 | */
60 | import 'zone.js/dist/zone'; // Included with Angular CLI.
61 |
62 |
63 |
64 | /***************************************************************************************************
65 | * APPLICATION IMPORTS
66 | */
67 |
68 | /**
69 | * Date, currency, decimal and percent pipes.
70 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
71 | */
72 | // import 'intl'; // Run `npm install --save intl`.
73 | /**
74 | * Need to import at least one locale-data with intl.
75 | */
76 | // import 'intl/locale-data/jsonp/en';
77 |
--------------------------------------------------------------------------------
/layers/README.md:
--------------------------------------------------------------------------------
1 | # ATT&CK Navigator Layers
2 |
3 | This folder contains a basic script that demonstrates how layer files can be generated for use in the ATT&CK Navigator. Sample layer files are found in the **data/samples** sub-folder.
4 |
5 | The **data/update_layers** folder currently contains a layer file that is based on the April 2018 ATT&CK content update.
6 |
7 | If you want to learn more about the format of layer files, **LAYERFORMATv2_1.md** describes version 2.1 of the MITRE ATT&CK Navigator Layer file format.
8 |
9 | *Also, feel free to come up with your own ideas for layer file generation, and contribute them to the community by making a pull request to the ATT&CK Navigator!*
10 |
11 | ## Simple Example
12 |
13 | The script **attack_layers_simple.py** generates layer files based on the contents of a CSV file. CSV files with pre-calculated data can be ingested and used to apply evaluation criteria - in this case an arbitrary formula - to every ATT&CK technique.
14 |
15 | It's important to emphasize that the scores generated here are **arbitrary**! This formula is used just for the purpose of this script, to provide an example of how to add scores to techniques. We also chose to supply **software**, **groups**, and **references** via CSV file for the purposes of this script to create the scores, but any data or metadata related to ATT&CK techniques may be supplied or used to add scores and other fields to the layer files.
16 |
17 | The code excerpt below shows how **attack_layers_simple.py** adds scores to techniques:
18 |
19 | ```python
20 | # parse csv file, calculating a score for each technique and adding that to the layer
21 | with open(args.input_fn, "rb") as csvfile:
22 | reader = csv.DictReader(csvfile, delimiter=",")
23 | for row in reader:
24 | # score each technique based on a simple formula
25 | technique = {
26 | "techniqueID": row["TechID"],
27 | "score": (int(row["Software"]) + int(row["Groups"]))*2 + int(row["References"])
28 | }
29 |
30 | layer_json["techniques"].append(technique)
31 |
32 | ```
33 |
34 | **attack_layers_simple.py** adds all of the required layer fields as outlined in **LAYERFORMATv2_1.md**. Additionally, a *gradient* field is added that specifies a color range that will be applied to the techniques based on their scores. In **attack_layers_simple.py**, we specify min/max values that match the min/max of the set of technique scores that were calculated.
35 |
36 |
37 | ```python
38 | # add a color gradient (white -> red) to layer, ranging
39 | # from zero (white) to the maximum score in the file (red)
40 | layer_json["gradient"] = {
41 | "colors": [
42 | "#ffffff", # White
43 | "#ff6666" # Red
44 | ],
45 | "minValue": 0,
46 | "maxValue": max([technique["score"] for technique in layer_json["techniques"]])
47 | }
48 | ```
49 | See **data/csv** for an example csv file that can be ingested by **attack_layers_simple.py** (simple_input.csv) and **data/samples** to view a layer file output by this code (heatmap_layer.json).
50 |
51 | ## Sample Layer Files
52 | We included a few sample layer files in **data/samples**. Each has a unique description that explains the coverage of that particular layer. You can upload these files to the Navigator to see the correlation between the layer files and the Navigator application.
53 |
--------------------------------------------------------------------------------
/layers/data/csv/simple_input.csv:
--------------------------------------------------------------------------------
1 | TechID,Software,Groups,References
2 | T1001,12,2,15
3 | T1002,6,10,25
4 | T1003,26,21,66
5 | T1004,1,0,5
6 | T1005,9,9,26
7 | T1006,0,0,7
8 | T1007,11,5,19
9 | T1008,13,2,13
10 | T1009,3,2,10
11 | T1010,4,1,11
12 | T1011,1,0,1
13 | T1012,12,4,23
14 | T1013,0,0,4
15 | T1014,4,2,14
16 | T1015,0,4,15
17 | T1016,30,11,40
18 | T1017,0,1,1
19 | T1018,9,6,20
20 | T1019,2,0,9
21 | T1020,4,0,9
22 | T1021,2,3,5
23 | T1022,11,6,26
24 | T1023,11,0,16
25 | T1024,22,2,26
26 | T1025,9,2,15
27 | T1026,2,1,4
28 | T1027,32,10,50
29 | T1028,1,1,5
30 | T1029,2,0,3
31 | T1030,2,1,4
32 | T1031,4,0,7
33 | T1032,28,7,37
34 | T1033,23,9,37
35 | T1034,1,0,13
36 | T1035,8,0,15
37 | T1036,21,11,41
38 | T1037,1,0,6
39 | T1038,5,1,18
40 | T1039,3,3,10
41 | T1040,2,1,8
42 | T1041,7,5,9
43 | T1042,0,0,8
44 | T1043,23,5,25
45 | T1044,1,0,7
46 | T1045,5,5,15
47 | T1046,6,5,15
48 | T1047,6,6,17
49 | T1048,5,2,9
50 | T1049,12,8,25
51 | T1050,22,3,38
52 | T1051,0,0,0
53 | T1052,4,0,6
54 | T1053,16,12,46
55 | T1054,0,0,0
56 | T1055,18,1,45
57 | T1056,31,9,49
58 | T1057,35,12,51
59 | T1058,1,0,5
60 | T1059,37,15,55
61 | T1060,39,11,57
62 | T1061,0,0,5
63 | T1062,0,0,4
64 | T1063,19,2,24
65 | T1064,5,14,21
66 | T1065,4,4,9
67 | T1066,3,4,10
68 | T1067,4,2,7
69 | T1068,6,4,17
70 | T1069,8,4,15
71 | T1070,5,4,9
72 | T1071,41,9,47
73 | T1072,1,1,2
74 | T1073,8,3,13
75 | T1074,15,7,26
76 | T1075,3,3,7
77 | T1076,1,11,18
78 | T1077,8,6,25
79 | T1078,4,15,26
80 | T1079,3,0,7
81 | T1080,2,1,8
82 | T1081,6,2,12
83 | T1082,40,12,55
84 | T1083,39,11,53
85 | T1084,2,1,7
86 | T1085,16,4,21
87 | T1086,11,18,36
88 | T1087,14,9,25
89 | T1088,9,3,21
90 | T1089,10,5,15
91 | T1090,11,4,18
92 | T1091,8,3,17
93 | T1092,2,1,6
94 | T1093,5,1,13
95 | T1094,5,3,10
96 | T1095,13,1,16
97 | T1096,2,0,9
98 | T1097,2,1,14
99 | T1098,2,1,7
100 | T1099,13,3,24
101 | T1100,5,6,8
102 | T1101,1,0,3
103 | T1102,11,4,16
104 | T1103,2,0,9
105 | T1104,2,1,4
106 | T1105,40,14,51
107 | T1106,5,0,12
108 | T1107,34,14,56
109 | T1108,2,4,11
110 | T1109,0,1,1
111 | T1110,1,5,8
112 | T1111,1,0,8
113 | T1112,11,0,17
114 | T1113,23,6,36
115 | T1114,4,2,11
116 | T1115,4,0,11
117 | T1116,7,6,20
118 | T1117,2,2,7
119 | T1118,0,0,1
120 | T1119,5,4,14
121 | T1120,9,3,17
122 | T1121,0,0,2
123 | T1122,4,1,12
124 | T1123,4,0,9
125 | T1124,6,2,16
126 | T1125,2,0,7
127 | T1126,1,1,7
128 | T1127,1,0,14
129 | T1128,1,0,6
130 | T1129,0,0,1
131 | T1130,2,0,7
132 | T1131,1,0,4
133 | T1132,14,2,15
134 | T1133,0,5,8
135 | T1134,3,2,16
136 | T1135,3,2,12
137 | T1136,4,2,6
138 | T1137,0,1,9
139 | T1138,0,1,3
140 | T1139,0,0,1
141 | T1140,3,3,10
142 | T1141,0,0,2
143 | T1142,0,0,2
144 | T1143,0,0,1
145 | T1144,0,0,4
146 | T1145,1,0,4
147 | T1146,0,0,1
148 | T1147,0,0,1
149 | T1148,0,0,1
150 | T1149,0,0,2
151 | T1150,0,0,1
152 | T1151,0,0,1
153 | T1152,0,0,1
154 | T1153,0,0,0
155 | T1154,0,0,0
156 | T1155,0,0,1
157 | T1156,0,0,0
158 | T1157,0,0,2
159 | T1158,1,0,3
160 | T1159,1,0,8
161 | T1160,0,0,4
162 | T1161,0,0,2
163 | T1162,0,0,5
164 | T1163,0,0,2
165 | T1164,0,0,2
166 | T1165,0,0,2
167 | T1166,0,0,0
168 | T1167,0,0,3
169 | T1168,1,0,7
170 | T1169,0,0,1
171 | T1170,0,1,7
172 | T1171,1,0,8
173 | T1172,1,1,3
174 | T1173,1,2,10
175 | T1174,1,0,4
176 | T1175,1,0,12
177 | T1176,0,0,10
178 | T1177,1,0,8
179 | T1178,1,0,11
180 | T1179,1,0,15
181 | T1180,1,0,3
182 | T1181,1,0,12
183 | T1182,0,0,6
184 | T1183,0,0,9
185 | T1184,0,0,5
186 | T1185,1,0,4
187 | T1186,0,0,11
188 | T1187,0,1,7
189 | T1188,1,1,2
190 |
--------------------------------------------------------------------------------
/nav-app/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": [
3 | "node_modules/codelyzer"
4 | ],
5 | "rules": {
6 | "arrow-return-shorthand": true,
7 | "callable-types": true,
8 | "class-name": true,
9 | "comment-format": [
10 | true,
11 | "check-space"
12 | ],
13 | "curly": true,
14 | "eofline": true,
15 | "forin": true,
16 | "import-blacklist": [
17 | true,
18 | "rxjs/Rx"
19 | ],
20 | "import-spacing": true,
21 | "indent": [
22 | true,
23 | "spaces"
24 | ],
25 | "interface-over-type-literal": true,
26 | "label-position": true,
27 | "max-line-length": [
28 | true,
29 | 140
30 | ],
31 | "member-access": false,
32 | "member-ordering": [
33 | true,
34 | {
35 | "order": [
36 | "static-field",
37 | "instance-field",
38 | "static-method",
39 | "instance-method"
40 | ]
41 | }
42 | ],
43 | "no-arg": true,
44 | "no-bitwise": true,
45 | "no-console": [
46 | true,
47 | "debug",
48 | "info",
49 | "time",
50 | "timeEnd",
51 | "trace"
52 | ],
53 | "no-construct": true,
54 | "no-debugger": true,
55 | "no-duplicate-super": true,
56 | "no-empty": false,
57 | "no-empty-interface": true,
58 | "no-eval": true,
59 | "no-inferrable-types": [
60 | true,
61 | "ignore-params"
62 | ],
63 | "no-misused-new": true,
64 | "no-non-null-assertion": true,
65 | "no-shadowed-variable": true,
66 | "no-string-literal": false,
67 | "no-string-throw": true,
68 | "no-switch-case-fall-through": true,
69 | "no-trailing-whitespace": true,
70 | "no-unnecessary-initializer": true,
71 | "no-unused-expression": true,
72 | "no-use-before-declare": true,
73 | "no-var-keyword": true,
74 | "object-literal-sort-keys": false,
75 | "one-line": [
76 | true,
77 | "check-open-brace",
78 | "check-catch",
79 | "check-else",
80 | "check-whitespace"
81 | ],
82 | "prefer-const": true,
83 | "quotemark": [
84 | true,
85 | "single"
86 | ],
87 | "radix": true,
88 | "semicolon": [
89 | true,
90 | "always"
91 | ],
92 | "triple-equals": [
93 | true,
94 | "allow-null-check"
95 | ],
96 | "typedef-whitespace": [
97 | true,
98 | {
99 | "call-signature": "nospace",
100 | "index-signature": "nospace",
101 | "parameter": "nospace",
102 | "property-declaration": "nospace",
103 | "variable-declaration": "nospace"
104 | }
105 | ],
106 | "typeof-compare": true,
107 | "unified-signatures": true,
108 | "variable-name": false,
109 | "whitespace": [
110 | true,
111 | "check-branch",
112 | "check-decl",
113 | "check-operator",
114 | "check-separator",
115 | "check-type"
116 | ],
117 | "directive-selector": [
118 | true,
119 | "attribute",
120 | "app",
121 | "camelCase"
122 | ],
123 | "component-selector": [
124 | true,
125 | "element",
126 | "app",
127 | "kebab-case"
128 | ],
129 | "use-input-property-decorator": true,
130 | "use-output-property-decorator": true,
131 | "use-host-property-decorator": true,
132 | "no-input-rename": true,
133 | "no-output-rename": true,
134 | "use-life-cycle-interface": true,
135 | "use-pipe-transform-interface": true,
136 | "component-class-suffix": true,
137 | "directive-class-suffix": true,
138 | "invoke-injectable": true
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/nav-app/src/assets/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "enterprise_attack_url": "https://raw.githubusercontent.com/mitre/cti/master/enterprise-attack/enterprise-attack.json",
3 | "pre_attack_url": "https://raw.githubusercontent.com/mitre/cti/master/pre-attack/pre-attack.json",
4 | "mobile_data_url": "https://raw.githubusercontent.com/mitre/cti/master/mobile-attack/mobile-attack.json",
5 | "taxii_server": {
6 | "enabled": false,
7 | "url": "https://cti-taxii.mitre.org/",
8 | "collections": {
9 | "enterprise_attack": "95ecc380-afe9-11e4-9b6c-751b66dd541e",
10 | "pre_attack": "062767bd-02d2-4b72-84ba-56caef0f8658",
11 | "mobile_attack": "2f669986-b40b-4423-b720-4396ca6a462b"
12 | }
13 | },
14 |
15 | "domain": "mitre-enterprise",
16 |
17 | "custom_context_menu_items": [
18 |
19 | ],
20 |
21 | "default_layers": {
22 | "enabled": false,
23 | "urls": ["assets/example.json", "https://raw.githubusercontent.com/mitre-attack/attack-navigator/master/layers/data/samples/Bear_APT.json"]
24 | },
25 |
26 | "comment_color": "yellow",
27 |
28 | "features": [
29 | {"name": "tabs", "enabled": true, "description": "Disable to remove the ability to open new tabs."},
30 | {"name": "selecting_techniques", "enabled": true, "description": "Disable to remove the ability to select techniques."},
31 | {"name": "header", "enabled": true, "description": "Disable to remove the header containing 'MITRE ATT&CK Navigator' and the link to the help page. The help page can still be accessed from the new tab menu."},
32 | {"name": "selection_controls", "enabled": true, "description": "Disable to to disable all subfeatures", "subfeatures": [
33 | {"name": "search", "enabled": true, "description": "Disable to remove the technique search panel from the interface."},
34 | {"name": "multiselect", "enabled": true, "description": "Disable to remove the multiselect panel from interface."},
35 | {"name": "deselect_all", "enabled": true, "description": "Disable to remove the deselect all button from the interface."}
36 | ]},
37 | {"name": "layer_controls", "enabled": true, "description": "Disable to to disable all subfeatures", "subfeatures": [
38 | {"name": "layer_info", "enabled": true, "description": "Disable to remove the layer info (name, description and metadata) panel from the interface. Note that the layer can still be renamed in the tab."},
39 | {"name": "download_layer", "enabled": true, "description": "Disable to remove the button to download the layer."},
40 | {"name": "export_render", "enabled": true, "description": "Disable to the remove the button to render the current layer."},
41 | {"name": "export_excel", "enabled": true, "description": "Disable to the remove the button to export the current layer to MS Excel (.xlsx) format."},
42 | {"name": "filters", "enabled": true, "description": "Disable to the remove the filters panel from interface."},
43 | {"name": "sorting", "enabled": true, "description": "Disable to the remove the sorting button from the interface."},
44 | {"name": "color_setup", "enabled": true, "description": "Disable to the remove the color setup panel from interface, containing customization controls for scoring gradient and tactic row color."},
45 | {"name": "toggle_hide_disabled", "enabled": true, "description": "Disable to the remove the hide disabled techniques button from the interface."},
46 | {"name": "toggle_view_mode", "enabled": true, "description": "Disable to the remove the toggle view mode button from interface."},
47 | {"name": "legend", "enabled": true, "description": "Disable to the remove the legend panel from the interface."}
48 | ]},
49 | {"name": "technique_controls", "enabled": true, "description": "Disable to to disable all subfeatures", "subfeatures": [
50 | {"name": "disable_techniques", "enabled": true, "description": "Disable to the remove the ability to disable techniques."},
51 | {"name": "manual_color", "enabled": true, "description": "Disable to the remove the ability to assign manual colors to techniques."},
52 | {"name": "scoring", "enabled": true, "description": "Disable to the remove the ability to score techniques."},
53 | {"name": "comments", "enabled": true, "description": "Disable to the remove the ability to add comments to techniques."},
54 | {"name": "clear_annotations", "enabled": true, "description": "Disable to remove the button to clear all annotations on the selected techniques."}
55 | ]}
56 | ]
57 | }
58 |
--------------------------------------------------------------------------------
/layers/data/samples/ATTACKcon/Black_Pins.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Black Pins",
3 | "version": "2.1",
4 | "domain": "mitre-enterprise",
5 | "description": "ATT&CKcon Matrix Question: With your ATT&CK-mapped detections, which ones generate the most true positives?\n",
6 | "filters": {
7 | "stages": [
8 | "act"
9 | ],
10 | "platforms": [
11 | "windows",
12 | "linux",
13 | "mac"
14 | ]
15 | },
16 | "sorting": 0,
17 | "viewMode": 0,
18 | "hideDisabled": false,
19 | "techniques": [
20 | {
21 | "techniqueID": "T1172",
22 | "tactic": "command-and-control",
23 | "score": 1,
24 | "color": "",
25 | "comment": "",
26 | "enabled": true
27 | },
28 | {
29 | "techniqueID": "T1086",
30 | "tactic": "execution",
31 | "score": 1,
32 | "color": "",
33 | "comment": "",
34 | "enabled": true
35 | },
36 | {
37 | "techniqueID": "T1060",
38 | "tactic": "persistence",
39 | "score": 1,
40 | "color": "",
41 | "comment": "",
42 | "enabled": true
43 | },
44 | {
45 | "techniqueID": "T1116",
46 | "tactic": "defense-evasion",
47 | "score": 2,
48 | "color": "",
49 | "comment": "",
50 | "enabled": true
51 | },
52 | {
53 | "techniqueID": "T1003",
54 | "tactic": "credential-access",
55 | "score": 3,
56 | "color": "",
57 | "comment": "",
58 | "enabled": true
59 | },
60 | {
61 | "techniqueID": "T1081",
62 | "tactic": "credential-access",
63 | "score": 1,
64 | "color": "",
65 | "comment": "",
66 | "enabled": true
67 | },
68 | {
69 | "techniqueID": "T1094",
70 | "tactic": "command-and-control",
71 | "score": 1,
72 | "color": "",
73 | "comment": "",
74 | "enabled": true
75 | },
76 | {
77 | "techniqueID": "T1041",
78 | "tactic": "exfiltration",
79 | "score": 1,
80 | "color": "",
81 | "comment": "",
82 | "enabled": true
83 | },
84 | {
85 | "techniqueID": "T1143",
86 | "tactic": "defense-evasion",
87 | "score": 1,
88 | "color": "",
89 | "comment": "",
90 | "enabled": true
91 | },
92 | {
93 | "techniqueID": "T1056",
94 | "tactic": "collection",
95 | "score": 1,
96 | "color": "",
97 | "comment": "",
98 | "enabled": true
99 | },
100 | {
101 | "techniqueID": "T1056",
102 | "tactic": "credential-access",
103 | "score": 1,
104 | "color": "",
105 | "comment": "",
106 | "enabled": true
107 | },
108 | {
109 | "techniqueID": "T1208",
110 | "tactic": "credential-access",
111 | "score": 1,
112 | "color": "",
113 | "comment": "",
114 | "enabled": true
115 | },
116 | {
117 | "techniqueID": "T1036",
118 | "tactic": "defense-evasion",
119 | "score": 1,
120 | "color": "",
121 | "comment": "",
122 | "enabled": true
123 | },
124 | {
125 | "techniqueID": "T1046",
126 | "tactic": "discovery",
127 | "score": 4,
128 | "color": "",
129 | "comment": "",
130 | "enabled": true
131 | },
132 | {
133 | "techniqueID": "T1075",
134 | "tactic": "lateral-movement",
135 | "score": 2,
136 | "color": "",
137 | "comment": "",
138 | "enabled": true
139 | },
140 | {
141 | "techniqueID": "T1186",
142 | "tactic": "defense-evasion",
143 | "score": 1,
144 | "color": "",
145 | "comment": "",
146 | "enabled": true
147 | },
148 | {
149 | "techniqueID": "T1219",
150 | "tactic": "command-and-control",
151 | "score": 1,
152 | "color": "",
153 | "comment": "",
154 | "enabled": true
155 | },
156 | {
157 | "techniqueID": "T1193",
158 | "tactic": "initial-access",
159 | "score": 3,
160 | "color": "",
161 | "comment": "",
162 | "enabled": true
163 | },
164 | {
165 | "techniqueID": "T1192",
166 | "tactic": "initial-access",
167 | "score": 4,
168 | "color": "",
169 | "comment": "",
170 | "enabled": true
171 | },
172 | {
173 | "techniqueID": "T1082",
174 | "tactic": "discovery",
175 | "score": 1,
176 | "color": "",
177 | "comment": "",
178 | "enabled": true
179 | },
180 | {
181 | "techniqueID": "T1100",
182 | "tactic": "persistence",
183 | "score": 1,
184 | "color": "",
185 | "comment": "",
186 | "enabled": true
187 | },
188 | {
189 | "techniqueID": "T1100",
190 | "tactic": "privilege-escalation",
191 | "score": 1,
192 | "color": "",
193 | "comment": "",
194 | "enabled": true
195 | }
196 | ],
197 | "gradient": {
198 | "colors": [
199 | "#cfcfcf",
200 | "#3c3c3c"
201 | ],
202 | "minValue": 1,
203 | "maxValue": 8
204 | },
205 | "legendItems": [],
206 | "showTacticRowBackground": true,
207 | "tacticRowBackground": "#205b8f",
208 | "selectTechniquesAcrossTactics": true
209 | }
--------------------------------------------------------------------------------
/nav-app/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "nav-app": {
7 | "root": "",
8 | "sourceRoot": "src",
9 | "projectType": "application",
10 | "architect": {
11 | "build": {
12 | "builder": "@angular-devkit/build-angular:browser",
13 | "options": {
14 | "outputPath": "dist",
15 | "index": "src/index.html",
16 | "main": "src/main.ts",
17 | "tsConfig": "src/tsconfig.app.json",
18 | "polyfills": "src/polyfills.ts",
19 | "assets": [
20 | "src/assets",
21 | "src/favicon.ico"
22 | ],
23 | "styles": [
24 | "src/styles.scss"
25 | ],
26 | "scripts": [
27 | "node_modules/file-saver/dist/FileSaver.js",
28 | "node_modules/mathjs/dist/math.js",
29 | "node_modules/tinycolor2/tinycolor.js",
30 | "node_modules/d3/dist/d3.js",
31 | "node_modules/tinygradient/tinygradient.js"
32 | ]
33 | },
34 | "configurations": {
35 | "production": {
36 | "optimization": true,
37 | "outputHashing": "all",
38 | "sourceMap": false,
39 | "extractCss": true,
40 | "namedChunks": false,
41 | "aot": true,
42 | "extractLicenses": true,
43 | "vendorChunk": false,
44 | "buildOptimizer": true,
45 | "fileReplacements": [
46 | {
47 | "replace": "src/environments/environment.ts",
48 | "with": "src/environments/environment.prod.ts"
49 | }
50 | ]
51 | }
52 | }
53 | },
54 | "serve": {
55 | "builder": "@angular-devkit/build-angular:dev-server",
56 | "options": {
57 | "browserTarget": "nav-app:build"
58 | },
59 | "configurations": {
60 | "production": {
61 | "browserTarget": "nav-app:build:production"
62 | }
63 | }
64 | },
65 | "extract-i18n": {
66 | "builder": "@angular-devkit/build-angular:extract-i18n",
67 | "options": {
68 | "browserTarget": "nav-app:build"
69 | }
70 | },
71 | "test": {
72 | "builder": "@angular-devkit/build-angular:karma",
73 | "options": {
74 | "main": "src/test.ts",
75 | "karmaConfig": "./karma.conf.js",
76 | "polyfills": "src/polyfills.ts",
77 | "tsConfig": "src/tsconfig.spec.json",
78 | "scripts": [
79 | "node_modules/file-saver/dist/FileSaver.js",
80 | "node_modules/mathjs/dist/math.js",
81 | "node_modules/tinycolor2/tinycolor.js",
82 | "node_modules/d3/dist/d3.js",
83 | "node_modules/tinygradient/tinygradient.js"
84 | ],
85 | "styles": [
86 | "src/styles.scss"
87 | ],
88 | "assets": [
89 | "src/assets",
90 | "src/favicon.ico"
91 | ]
92 | }
93 | },
94 | "lint": {
95 | "builder": "@angular-devkit/build-angular:tslint",
96 | "options": {
97 | "tsConfig": [
98 | "src/tsconfig.app.json",
99 | "src/tsconfig.spec.json"
100 | ],
101 | "exclude": [
102 | "**/node_modules/**"
103 | ]
104 | }
105 | }
106 | }
107 | },
108 | "nav-app-e2e": {
109 | "root": "e2e",
110 | "sourceRoot": "e2e",
111 | "projectType": "application",
112 | "architect": {
113 | "e2e": {
114 | "builder": "@angular-devkit/build-angular:protractor",
115 | "options": {
116 | "protractorConfig": "./protractor.conf.js",
117 | "devServerTarget": "nav-app:serve"
118 | }
119 | },
120 | "lint": {
121 | "builder": "@angular-devkit/build-angular:tslint",
122 | "options": {
123 | "tsConfig": [
124 | "e2e/tsconfig.e2e.json"
125 | ],
126 | "exclude": [
127 | "**/node_modules/**"
128 | ]
129 | }
130 | }
131 | }
132 | }
133 | },
134 | "defaultProject": "nav-app",
135 | "schematics": {
136 | "@schematics/angular:component": {
137 | "prefix": "app",
138 | "styleext": "scss"
139 | },
140 | "@schematics/angular:directive": {
141 | "prefix": "app"
142 | }
143 | }
144 | }
--------------------------------------------------------------------------------
/layers/data/samples/ATTACKcon/Red_Pins.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Red Pins",
3 | "version": "2.1",
4 | "domain": "mitre-enterprise",
5 | "description": "ATT&CKcon Matrix Question: What’s the least likely\u000b ATT&CK technique to\u000b be seen in the wild?",
6 | "filters": {
7 | "stages": [
8 | "act"
9 | ],
10 | "platforms": [
11 | "windows",
12 | "linux",
13 | "mac"
14 | ]
15 | },
16 | "sorting": 0,
17 | "viewMode": 0,
18 | "hideDisabled": false,
19 | "techniques": [
20 | {
21 | "techniqueID": "T1155",
22 | "tactic": "execution",
23 | "score": 2,
24 | "color": "",
25 | "comment": "",
26 | "enabled": true
27 | },
28 | {
29 | "techniqueID": "T1155",
30 | "tactic": "lateral-movement",
31 | "score": 2,
32 | "color": "",
33 | "comment": "",
34 | "enabled": true
35 | },
36 | {
37 | "techniqueID": "T1067",
38 | "tactic": "persistence",
39 | "score": 2,
40 | "color": "",
41 | "comment": "",
42 | "enabled": true
43 | },
44 | {
45 | "techniqueID": "T1109",
46 | "tactic": "defense-evasion",
47 | "score": 1,
48 | "color": "",
49 | "comment": "",
50 | "enabled": true
51 | },
52 | {
53 | "techniqueID": "T1109",
54 | "tactic": "persistence",
55 | "score": 1,
56 | "color": "",
57 | "comment": "",
58 | "enabled": true
59 | },
60 | {
61 | "techniqueID": "T1024",
62 | "tactic": "command-and-control",
63 | "score": 1,
64 | "color": "",
65 | "comment": "",
66 | "enabled": true
67 | },
68 | {
69 | "techniqueID": "T1140",
70 | "tactic": "defense-evasion",
71 | "score": 1,
72 | "color": "",
73 | "comment": "",
74 | "enabled": true
75 | },
76 | {
77 | "techniqueID": "T1052",
78 | "tactic": "exfiltration",
79 | "score": 3,
80 | "color": "",
81 | "comment": "",
82 | "enabled": true
83 | },
84 | {
85 | "techniqueID": "T1200",
86 | "tactic": "initial-access",
87 | "score": 4,
88 | "color": "",
89 | "comment": "",
90 | "enabled": true
91 | },
92 | {
93 | "techniqueID": "T1062",
94 | "tactic": "persistence",
95 | "score": 2,
96 | "color": "",
97 | "comment": "",
98 | "enabled": true
99 | },
100 | {
101 | "techniqueID": "T1215",
102 | "tactic": "persistence",
103 | "score": 1,
104 | "color": "",
105 | "comment": "",
106 | "enabled": true
107 | },
108 | {
109 | "techniqueID": "T1079",
110 | "tactic": "command-and-control",
111 | "score": 1,
112 | "color": "",
113 | "comment": "",
114 | "enabled": true
115 | },
116 | {
117 | "techniqueID": "T1205",
118 | "tactic": "defense-evasion",
119 | "score": 8,
120 | "color": "",
121 | "comment": "",
122 | "enabled": true
123 | },
124 | {
125 | "techniqueID": "T1205",
126 | "tactic": "persistence",
127 | "score": 8,
128 | "color": "",
129 | "comment": "",
130 | "enabled": true
131 | },
132 | {
133 | "techniqueID": "T1205",
134 | "tactic": "command-and-control",
135 | "score": 8,
136 | "color": "",
137 | "comment": "",
138 | "enabled": true
139 | },
140 | {
141 | "techniqueID": "T1145",
142 | "tactic": "credential-access",
143 | "score": 1,
144 | "color": "",
145 | "comment": "",
146 | "enabled": true
147 | },
148 | {
149 | "techniqueID": "T1091",
150 | "tactic": "lateral-movement",
151 | "score": 2,
152 | "color": "",
153 | "comment": "",
154 | "enabled": true
155 | },
156 | {
157 | "techniqueID": "T1091",
158 | "tactic": "initial-access",
159 | "score": 2,
160 | "color": "",
161 | "comment": "",
162 | "enabled": true
163 | },
164 | {
165 | "techniqueID": "T1029",
166 | "tactic": "exfiltration",
167 | "score": 1,
168 | "color": "",
169 | "comment": "",
170 | "enabled": true
171 | },
172 | {
173 | "techniqueID": "T1113",
174 | "tactic": "collection",
175 | "score": 1,
176 | "color": "",
177 | "comment": "",
178 | "enabled": true
179 | },
180 | {
181 | "techniqueID": "T1218",
182 | "tactic": "defense-evasion",
183 | "score": 1,
184 | "color": "",
185 | "comment": "",
186 | "enabled": true
187 | },
188 | {
189 | "techniqueID": "T1218",
190 | "tactic": "execution",
191 | "score": 1,
192 | "color": "",
193 | "comment": "",
194 | "enabled": true
195 | },
196 | {
197 | "techniqueID": "T1195",
198 | "tactic": "initial-access",
199 | "score": 3,
200 | "color": "",
201 | "comment": "",
202 | "enabled": true
203 | },
204 | {
205 | "techniqueID": "T1099",
206 | "tactic": "defense-evasion",
207 | "score": 1,
208 | "color": "",
209 | "comment": "",
210 | "enabled": true
211 | }
212 | ],
213 | "gradient": {
214 | "colors": [
215 | "#ebaaaa",
216 | "#c60505"
217 | ],
218 | "minValue": 1,
219 | "maxValue": 8
220 | },
221 | "legendItems": [],
222 | "showTacticRowBackground": true,
223 | "tacticRowBackground": "#205b8f",
224 | "selectTechniquesAcrossTactics": true
225 | }
--------------------------------------------------------------------------------
/layers/LAYERFORMATv1.md:
--------------------------------------------------------------------------------
1 | # ATT&CKTM Navigator Layer File Format Definition
2 | This document describes **Version 1** of the MITRE ATT&CK Navigator Layer file format. The ATT&CK Navigator stores layers as JSON, therefore this document defines the JSON properties in a layer file.
3 |
4 | ## Property Table
5 |
6 | | Name | Type | Required? | Default Value (if not present) | Description |
7 | | :------------- | :------------- | :------------- | :------------- | :------------- |
8 | | version | String | Yes | n/a | Must be "1.0" |
9 | | name | String | Yes | n/a | The name of the layer |
10 | | description | String | No | "" | A free-form text field that describes the contents or intent of the layer |
11 | | domain | String | Yes | n/a | Technology domain that this layer represents. Valid values are: "mitre-enterprise" or "mitre-mobile" |
12 | | filters |Filter object | No | | See Filter object definition below
13 | | sorting | Number | No | 0 | Specifies the ordering of the techniques within each tactic category as follows:
**0**: sort ascending alphabetically by technique name
**1**: sort descending alphabetically by technique name
**2**: sort ascending by technique score
**3**: sort descending by technique score |
14 | | viewFullTable | Boolean | No | true | Specifies the view mode for the layer as follows:
**true**: display the full table with tactic and technique names
**false**: display compact table with abbreviated tactic and technique names |
15 | | hideDisabled | Boolean | No | false | Specifies whether techniques that have been disabled are still displayed (greyed-out) or omitted from the view as follows:
**true**: omit techniques marked as disabled from the view
**false**: include disabled techniques in the view but display as greyed-out |
16 | | techniques | Array of Technique objects | No | | See definition of Technique object below |
17 | | gradient | Gradient object | No | Red to Green, minValue=0, maxValue=100 | See definition of Gradient object below |
18 |
19 | ## Filter Object Properties
20 |
21 | | Name | Type | Required? | Default Value (if not present) | Description |
22 | | :------------- | :------------- | :------------- | :------------- | :------------- |
23 | | stages | Array of String | No | ["act"] | Specifies the logical stages of the attack lifecycle to display. Valid choices are: "prepare" and "act". Array must contain at least one of these values. |
24 | | platforms | Array of String | No | All platforms defined within domain | Specifies the platforms within the technology domain – only those techniques tagged with these platforms are to be displayed. Valid values are as follows:
**domain=mitre-enterprise**: "windows", "linux", "mac"
**domain=mitre-mobile**: "android", "ios" |
25 |
26 | ## Technique Object properties
27 |
28 | | Name | Type | Required? | Default Value (if not present) | Description |
29 | | :------------- | :------------- | :------------- | :------------- | :------------- |
30 | | techniqueID | String | Yes | n/a | Unique identifier of the ATT&CK technique, e.g. "T####" |
31 | | comment | String | No | "" | Free-text field |
32 | | enabled | Boolean | No | true | Specifies if the technique is considered enabled or disabled in this layer |
33 | | score | Number | No | (unscored) | Optional numeric score assigned to this technique in the layer. If omitted, the technique is considered to be "unscored" meaning that it will not be assigned a color from the gradient by the Navigator. |
34 | | color | String | No | "" | Explicit color value assigned to the technique in this layer. Note that explicitly defined color overrides any color implied by the score – the Navigator will display the technique using the explicitly defined color. |
35 |
36 | ## Gradient Object properties
37 | | Name | Type | Required? | Default Value (if not present) | Description |
38 | | :------------- | :------------- | :------------- | :------------- | :------------- |
39 | | colors | Array of String | Yes | n/a | Specifies the hexadecimal RGB color values that constitute the color spectrum in use. The array must contain at least two (2) values, corresponding to the minValue and maxValue scores. |
40 | | minValue | Number | Yes | n/a | Lower bound score of the gradient |
41 | | maxValue | Number | Yes | n/a | Upper bound score of the gradient. *Note: maxValue must be > minValue* |
42 |
43 | ## Example
44 | The following example illustrates the layer file format:
45 | ```json
46 | {
47 | "version": "1.0",
48 | "name": "example",
49 | "description": "hello, world",
50 | "domain": "mitre-enterprise",
51 | "filters": {
52 | "stages": ["act"],
53 | "platforms": ["windows"],
54 | },
55 | "sorting": 2,
56 | "techniques": [
57 | {
58 | "techniqueID": "T1156",
59 | "enabled": false,
60 | "comment": "disabled technique with a comment"
61 | },
62 | {
63 | "techniqueID": "T1103",
64 | "score": 50
65 | },
66 | {
67 | "color": "#FF00FF",
68 | "techniqueID": "T1015",
69 | },
70 | ]
71 | }
72 | ```
73 |
--------------------------------------------------------------------------------
/layers/LAYERFORMATv1_1.md:
--------------------------------------------------------------------------------
1 | # ATT&CKTM Navigator Layer File Format Definition
2 | This document describes **Version 1.1** of the MITRE ATT&CK Navigator Layer file format. The ATT&CK Navigator stores layers as JSON, therefore this document defines the JSON properties in a layer file.
3 |
4 | ## Property Table
5 |
6 | | Name | Type | Required? | Default Value (if not present) | Description |
7 | | :------------- | :------------- | :------------- | :------------- | :------------- |
8 | | version | String | Yes | n/a | Must be "1.1" |
9 | | name | String | Yes | n/a | The name of the layer |
10 | | description | String | No | "" | A free-form text field that describes the contents or intent of the layer |
11 | | domain | String | Yes | n/a | Technology domain that this layer represents. Valid values are: "mitre-enterprise" or "mitre-mobile" |
12 | | filters |Filter object | No | | See Filter object definition below
13 | | sorting | Number | No | 0 | Specifies the ordering of the techniques within each tactic category as follows:
**0**: sort ascending alphabetically by technique name
**1**: sort descending alphabetically by technique name
**2**: sort ascending by technique score
**3**: sort descending by technique score |
14 | | viewMode | Number | No | 0 | Specifies the view mode for the layer as follows:
**0**: display the full table with tactic and technique names
**1**: display compact table with abbreviated tactic and technique names
**2**: display mini table with no text with the exception of tooltips |
15 | | hideDisabled | Boolean | No | false | Specifies whether techniques that have been disabled are still displayed (greyed-out) or omitted from the view as follows:
**true**: omit techniques marked as disabled from the view
**false**: include disabled techniques in the view but display as greyed-out |
16 | | techniques | Array of Technique objects | No | | See definition of Technique object below |
17 | | gradient | Gradient object | No | Red to Green, minValue=0, maxValue=100 | See definition of Gradient object below |
18 |
19 | ## Filter Object Properties
20 |
21 | | Name | Type | Required? | Default Value (if not present) | Description |
22 | | :------------- | :------------- | :------------- | :------------- | :------------- |
23 | | stages | Array of String | No | ["act"] | Specifies the logical stages of the attack lifecycle to display. Valid choices are: "prepare" and "act". Array must contain at least one of these values. |
24 | | platforms | Array of String | No | All platforms defined within domain | Specifies the platforms within the technology domain – only those techniques tagged with these platforms are to be displayed. Valid values are as follows:
**domain=mitre-enterprise**: "windows", "linux", "mac"
**domain=mitre-mobile**: "android", "ios" |
25 |
26 | ## Technique Object properties
27 |
28 | | Name | Type | Required? | Default Value (if not present) | Description |
29 | | :------------- | :------------- | :------------- | :------------- | :------------- |
30 | | techniqueID | String | Yes | n/a | Unique identifier of the ATT&CK technique, e.g. "T####" |
31 | | comment | String | No | "" | Free-text field |
32 | | enabled | Boolean | No | true | Specifies if the technique is considered enabled or disabled in this layer |
33 | | score | Number | No | (unscored) | Optional numeric score assigned to this technique in the layer. If omitted, the technique is considered to be "unscored" meaning that it will not be assigned a color from the gradient by the Navigator. |
34 | | color | String | No | "" | Explicit color value assigned to the technique in this layer. Note that explicitly defined color overrides any color implied by the score – the Navigator will display the technique using the explicitly defined color. |
35 |
36 | ## Gradient Object properties
37 | | Name | Type | Required? | Default Value (if not present) | Description |
38 | | :------------- | :------------- | :------------- | :------------- | :------------- |
39 | | colors | Array of String | Yes | n/a | Specifies the hexadecimal RGB color values that constitute the color spectrum in use. The array must contain at least two (2) values, corresponding to the minValue and maxValue scores. |
40 | | minValue | Number | Yes | n/a | Lower bound score of the gradient |
41 | | maxValue | Number | Yes | n/a | Upper bound score of the gradient. *Note: maxValue must be > minValue* |
42 |
43 | ## Example
44 | The following example illustrates the layer file format:
45 | ```json
46 | {
47 | "version": "1.1",
48 | "name": "example",
49 | "description": "hello, world",
50 | "domain": "mitre-enterprise",
51 | "filters": {
52 | "stages": ["act"],
53 | "platforms": ["windows"],
54 | },
55 | "sorting": 2,
56 | "techniques": [
57 | {
58 | "techniqueID": "T1156",
59 | "enabled": false,
60 | "comment": "disabled technique with a comment"
61 | },
62 | {
63 | "techniqueID": "T1103",
64 | "score": 50
65 | },
66 | {
67 | "color": "#FF00FF",
68 | "techniqueID": "T1015",
69 | },
70 | ]
71 | }
72 | ```
73 |
--------------------------------------------------------------------------------
/nav-app/src/styles.scss:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | @import "~@angular/material/prebuilt-themes/indigo-pink.css";
3 | @import "colors.scss";
4 | body {
5 | padding: 0 15px 15px 15px;
6 | margin-top: 0;
7 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
8 | }
9 |
10 | .noselect {
11 | -webkit-touch-callout: none; /* iOS Safari */
12 | -webkit-user-select: none; /* Safari */
13 | -khtml-user-select: none; /* Konqueror HTML */
14 | -moz-user-select: none; /* Firefox */
15 | -ms-user-select: none; /* Internet Explorer/Edge */
16 | user-select: none; /* Non-prefixed version, currently
17 | supported by Chrome and Opera */
18 | }
19 |
20 |
21 | // ___ ___ _ _ _____ ___ ___ _ ___
22 | // / __/ _ \| \| |_ _| _ \/ _ \| | / __|
23 | // | (_| (_) | .` | | | | / (_) | |__\__ \
24 | // \___\___/|_|\_| |_| |_|_\\___/|____|___/
25 |
26 | // $inputFontSize: 10pt;
27 | // panel with controls
28 | .controlsContainer {
29 | background-color: $panel-dark;
30 | // width: 100%;
31 | text-align: right;
32 | // padding: 0 3px;
33 | // display: flex;
34 | display: block;
35 | ul { margin: 0; }
36 | // justify-content: space-between;
37 | // font: 400 12px system-ui;
38 |
39 | .control-sections>li {
40 | list-style: none;
41 | display: inline-block;
42 | // &:not(:last-child){
43 | border-left: 1px solid darken($panel-dark, 8%);
44 | padding: 0 5px 0 5px;
45 | position: relative;
46 |
47 | // text-align: center;
48 | // label for a section of controls, e.g layer controls or technique controls
49 | .section-label {
50 | font-size: 8pt;
51 | // height: 8px;
52 | top: -13px;
53 | position: absolute;
54 | // border: 1px 1px 0 1px solid black;
55 | border-color: white;
56 | border-style: solid;
57 | border-width: 1px 1px 0 1px;
58 | // width:50%;
59 | // left: 25%;
60 | padding: 0 5px;
61 | background-color: $panel-dark;
62 | border-radius: 2px 2px 0 0;
63 | text-align: center;
64 | color: $tab-text-color;
65 | cursor: default;
66 | user-select: none;
67 | white-space: nowrap;
68 | // bottom: 10px;
69 | }
70 |
71 | .control-row-item {
72 |
73 | display: inline-block;
74 | position: relative;
75 | height: 34px;
76 |
77 | .control-row-button {
78 | border-radius: 3px;
79 | padding: 5px;
80 | height: 24px;
81 | cursor: pointer;
82 | &:hover { background-color: darken($panel-dark, 5%); }
83 | &.dropdown::after {
84 | font-size: 5pt;
85 | content: "▼";
86 | }
87 | }
88 |
89 |
90 | // dropdown controls container
91 | .dropdown-container {
92 | &.left { right: 0 }
93 | border: 1px solid black;
94 | background-color: white;
95 | box-shadow: 10px 10px 5px rgba(0, 0, 0, 0.5);
96 | position: absolute;
97 | z-index: 100; //draw on top of other controls
98 | width: max-content;
99 |
100 | &.inputfield {
101 | width: 150px;
102 | padding: 0px 10px;
103 | mat-form-field {
104 | width: 100%;
105 | &:first-child {
106 | padding-top:5px;
107 | }
108 | }
109 | }
110 | }
111 |
112 | }
113 | }
114 | }
115 |
116 | //////////////////////
117 | // Checkbox Styling //
118 | //////////////////////
119 |
120 | .checkbox-custom {
121 | opacity: 0;
122 | position: absolute;
123 | }
124 |
125 | .checkbox-custom, .checkbox-custom-label {
126 | display: inline-block;
127 | vertical-align: middle;
128 | margin: 5px;
129 | cursor: pointer;
130 | }
131 |
132 | .checkbox-custom-label {
133 | position: relative;
134 | &.disabled {
135 | color: rgba(0,0,0,0.46);
136 | }
137 | }
138 |
139 | .checkbox-custom + .checkbox-custom-label:before {
140 | content: '';
141 | background: #fff;
142 | border: 3px solid $panel-dark;
143 | display: inline-block;
144 | vertical-align: middle;
145 | width: 10px;
146 | height: 10px;
147 | padding: 2px;
148 | margin-right: 5px;
149 | text-align: center;
150 | }
151 |
152 | .checkbox-custom:checked + .checkbox-custom-label:before {
153 | background: $cell-highlight-color;
154 | box-shadow: inset 0px 0px 0px 1px $cell-highlight-color;
155 | }
156 | .checkbox-custom:checked:disabled + .checkbox-custom-label:before {
157 | background: desaturate($cell-highlight-color, 100%);
158 | box-shadow: inset 0px 0px 0px 1px desaturate($cell-highlight-color, 100%);
159 |
160 | }
161 |
--------------------------------------------------------------------------------
/layers/data/samples/ATTACKcon/Gold_Pins.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Gold Pins",
3 | "version": "2.1",
4 | "domain": "mitre-enterprise",
5 | "description": "ATT&CKcon Matrix Question: What techniques keep you up at night?",
6 | "filters": {
7 | "stages": [
8 | "act"
9 | ],
10 | "platforms": [
11 | "windows",
12 | "linux",
13 | "mac"
14 | ]
15 | },
16 | "sorting": 0,
17 | "viewMode": 0,
18 | "hideDisabled": false,
19 | "techniques": [
20 | {
21 | "techniqueID": "T1190",
22 | "tactic": "initial-access",
23 | "score": 3,
24 | "color": "",
25 | "comment": "",
26 | "enabled": true
27 | },
28 | {
29 | "techniqueID": "T1086",
30 | "tactic": "execution",
31 | "score": 1,
32 | "color": "",
33 | "comment": "",
34 | "enabled": true
35 | },
36 | {
37 | "techniqueID": "T1071",
38 | "tactic": "command-and-control",
39 | "score": 1,
40 | "color": "",
41 | "comment": "",
42 | "enabled": true
43 | },
44 | {
45 | "techniqueID": "T1078",
46 | "tactic": "defense-evasion",
47 | "score": 3,
48 | "color": "",
49 | "comment": "",
50 | "enabled": true
51 | },
52 | {
53 | "techniqueID": "T1078",
54 | "tactic": "persistence",
55 | "score": 3,
56 | "color": "",
57 | "comment": "",
58 | "enabled": true
59 | },
60 | {
61 | "techniqueID": "T1078",
62 | "tactic": "privilege-escalation",
63 | "score": 3,
64 | "color": "",
65 | "comment": "",
66 | "enabled": true
67 | },
68 | {
69 | "techniqueID": "T1078",
70 | "tactic": "initial-access",
71 | "score": 3,
72 | "color": "",
73 | "comment": "",
74 | "enabled": true
75 | },
76 | {
77 | "techniqueID": "T1155",
78 | "tactic": "execution",
79 | "score": 1,
80 | "color": "",
81 | "comment": "",
82 | "enabled": true
83 | },
84 | {
85 | "techniqueID": "T1155",
86 | "tactic": "lateral-movement",
87 | "score": 1,
88 | "color": "",
89 | "comment": "",
90 | "enabled": true
91 | },
92 | {
93 | "techniqueID": "T1094",
94 | "tactic": "command-and-control",
95 | "score": 1,
96 | "color": "",
97 | "comment": "",
98 | "enabled": true
99 | },
100 | {
101 | "techniqueID": "T1001",
102 | "tactic": "command-and-control",
103 | "score": 1,
104 | "color": "",
105 | "comment": "",
106 | "enabled": true
107 | },
108 | {
109 | "techniqueID": "T1041",
110 | "tactic": "exfiltration",
111 | "score": 1,
112 | "color": "",
113 | "comment": "",
114 | "enabled": true
115 | },
116 | {
117 | "techniqueID": "T1052",
118 | "tactic": "exfiltration",
119 | "score": 1,
120 | "color": "",
121 | "comment": "",
122 | "enabled": true
123 | },
124 | {
125 | "techniqueID": "T1200",
126 | "tactic": "initial-access",
127 | "score": 1,
128 | "color": "",
129 | "comment": "",
130 | "enabled": true
131 | },
132 | {
133 | "techniqueID": "T1170",
134 | "tactic": "defense-evasion",
135 | "score": 1,
136 | "color": "",
137 | "comment": "",
138 | "enabled": true
139 | },
140 | {
141 | "techniqueID": "T1170",
142 | "tactic": "execution",
143 | "score": 1,
144 | "color": "",
145 | "comment": "",
146 | "enabled": true
147 | },
148 | {
149 | "techniqueID": "T1205",
150 | "tactic": "defense-evasion",
151 | "score": 1,
152 | "color": "",
153 | "comment": "",
154 | "enabled": true
155 | },
156 | {
157 | "techniqueID": "T1205",
158 | "tactic": "persistence",
159 | "score": 1,
160 | "color": "",
161 | "comment": "",
162 | "enabled": true
163 | },
164 | {
165 | "techniqueID": "T1205",
166 | "tactic": "command-and-control",
167 | "score": 1,
168 | "color": "",
169 | "comment": "",
170 | "enabled": true
171 | },
172 | {
173 | "techniqueID": "T1180",
174 | "tactic": "persistence",
175 | "score": 1,
176 | "color": "",
177 | "comment": "",
178 | "enabled": true
179 | },
180 | {
181 | "techniqueID": "T1193",
182 | "tactic": "initial-access",
183 | "score": 1,
184 | "color": "",
185 | "comment": "",
186 | "enabled": true
187 | },
188 | {
189 | "techniqueID": "T1195",
190 | "tactic": "initial-access",
191 | "score": 2,
192 | "color": "",
193 | "comment": "",
194 | "enabled": true
195 | },
196 | {
197 | "techniqueID": "T1072",
198 | "tactic": "execution",
199 | "score": 1,
200 | "color": "",
201 | "comment": "",
202 | "enabled": true
203 | },
204 | {
205 | "techniqueID": "T1072",
206 | "tactic": "lateral-movement",
207 | "score": 1,
208 | "color": "",
209 | "comment": "",
210 | "enabled": true
211 | },
212 | {
213 | "techniqueID": "T1199",
214 | "tactic": "initial-access",
215 | "score": 2,
216 | "color": "",
217 | "comment": "",
218 | "enabled": true
219 | },
220 | {
221 | "techniqueID": "T1204",
222 | "tactic": "execution",
223 | "score": 1,
224 | "color": "",
225 | "comment": "",
226 | "enabled": true
227 | },
228 | {
229 | "techniqueID": "T1077",
230 | "tactic": "lateral-movement",
231 | "score": 2,
232 | "color": "",
233 | "comment": "",
234 | "enabled": true
235 | }
236 | ],
237 | "gradient": {
238 | "colors": [
239 | "#f7ffb0",
240 | "#ffd700"
241 | ],
242 | "minValue": 1,
243 | "maxValue": 5
244 | },
245 | "legendItems": [],
246 | "showTacticRowBackground": true,
247 | "tacticRowBackground": "#205b8f",
248 | "selectTechniquesAcrossTactics": true
249 | }
250 |
--------------------------------------------------------------------------------
/layers/LAYERFORMATv1_2.md:
--------------------------------------------------------------------------------
1 | # ATT&CKTM Navigator Layer File Format Definition
2 | This document describes **Version 1.2** of the MITRE ATT&CK Navigator Layer file format. The ATT&CK Navigator stores layers as JSON, therefore this document defines the JSON properties in a layer file.
3 |
4 | ## Property Table
5 |
6 | | Name | Type | Required? | Default Value (if not present) | Description |
7 | | :------------- | :------------- | :------------- | :------------- | :------------- |
8 | | version | String | Yes | n/a | Must be "1.2" |
9 | | name | String | Yes | n/a | The name of the layer |
10 | | description | String | No | "" | A free-form text field that describes the contents or intent of the layer |
11 | | domain | String | Yes | n/a | Technology domain that this layer represents. Valid values are: "mitre-enterprise" or "mitre-mobile" |
12 | | filters |Filter object | No | | See Filter object definition below
13 | | sorting | Number | No | 0 | Specifies the ordering of the techniques within each tactic category as follows:
**0**: sort ascending alphabetically by technique name
**1**: sort descending alphabetically by technique name
**2**: sort ascending by technique score
**3**: sort descending by technique score |
14 | | viewMode | Number | No | 0 | Specifies the view mode for the layer as follows:
**0**: display the full table with tactic and technique names
**1**: display compact table with abbreviated tactic and technique names
**2**: display mini table with no text with the exception of tooltips |
15 | | hideDisabled | Boolean | No | false | Specifies whether techniques that have been disabled are still displayed (greyed-out) or omitted from the view as follows:
**true**: omit techniques marked as disabled from the view
**false**: include disabled techniques in the view but display as greyed-out |
16 | | techniques | Array of Technique objects | No | | See definition of Technique object below |
17 | | gradient | Gradient object | No | Red to Green, minValue=0, maxValue=100 | See definition of Gradient object below |
18 | | legendItems | Array of LegendItem objects | no | | See definition of LegendItem object below |
19 |
20 | ## Filter Object Properties
21 |
22 | | Name | Type | Required? | Default Value (if not present) | Description |
23 | | :------------- | :------------- | :------------- | :------------- | :------------- |
24 | | stages | Array of String | No | ["act"] | Specifies the logical stages of the attack lifecycle to display. Valid choices are: "prepare" and "act". Array must contain at least one of these values |
25 | | platforms | Array of String | No | All platforms defined within domain | Specifies the platforms within the technology domain – only those techniques tagged with these platforms are to be displayed. Valid values are as follows:
**domain=mitre-enterprise**: "windows", "linux", "mac"
**domain=mitre-mobile**: "android", "ios" |
26 |
27 | ## Technique Object properties
28 |
29 | | Name | Type | Required? | Default Value (if not present) | Description |
30 | | :------------- | :------------- | :------------- | :------------- | :------------- |
31 | | techniqueID | String | Yes | n/a | Unique identifier of the ATT&CK technique, e.g. "T####" |
32 | | comment | String | No | "" | Free-text field |
33 | | enabled | Boolean | No | true | Specifies if the technique is considered enabled or disabled in this layer |
34 | | score | Number | No | (unscored) | Optional numeric score assigned to this technique in the layer. If omitted, the technique is considered to be "unscored" meaning that it will not be assigned a color from the gradient by the Navigator |
35 | | color | String | No | "" | Explicit color value assigned to the technique in this layer. Note that explicitly defined color overrides any color implied by the score – the Navigator will display the technique using the explicitly defined color |
36 |
37 | ## Gradient Object properties
38 | | Name | Type | Required? | Default Value (if not present) | Description |
39 | | :------------- | :------------- | :------------- | :------------- | :------------- |
40 | | colors | Array of String | Yes | n/a | Specifies the hexadecimal RGB color values that constitute the color spectrum in use. The array must contain at least two (2) values, corresponding to the minValue and maxValue scores. |
41 | | minValue | Number | Yes | n/a | Lower bound score of the gradient |
42 | | maxValue | Number | Yes | n/a | Upper bound score of the gradient. *Note: maxValue must be > minValue* |
43 |
44 | ## LegendItem Object properties
45 | | Name | Type | Required? | Default Value (if not present) | Description |
46 | | :------------- | :------------- | :------------- | :------------- | :------------- |
47 | | label | String | Yes | n/a | The name of the legend item |
48 | | color | String | Yes | n/a | The color of the legend item |
49 |
50 |
51 | ## Example
52 | The following example illustrates the layer file format:
53 | ```json
54 | {
55 | "version": "1.2",
56 | "name": "example",
57 | "description": "hello, world",
58 | "domain": "mitre-enterprise",
59 | "filters": {
60 | "stages": ["act"],
61 | "platforms": ["windows"],
62 | },
63 | "sorting": 2,
64 | "techniques": [
65 | {
66 | "techniqueID": "T1156",
67 | "enabled": false,
68 | "comment": "disabled technique with a comment"
69 | },
70 | {
71 | "techniqueID": "T1103",
72 | "score": 50
73 | },
74 | {
75 | "color": "#FF00FF",
76 | "techniqueID": "T1015",
77 | },
78 | ],
79 | "legendItems": [
80 | {
81 | "label": "Legend Item Label",
82 | "color": "#FF00FF"
83 | }
84 | ]
85 | }
86 | ```
87 |
--------------------------------------------------------------------------------
/layers/data/update_layers/October_2018_Updates_Mobile.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "October 2018 Updates Mobile",
3 | "version": "2.1",
4 | "domain": "mitre-mobile",
5 | "description": "",
6 | "filters": {
7 | "stages": [
8 | "act"
9 | ],
10 | "platforms": [
11 | "android",
12 | "ios"
13 | ]
14 | },
15 | "sorting": 0,
16 | "viewMode": 0,
17 | "hideDisabled": false,
18 | "techniques": [
19 | {
20 | "techniqueID": "T1475",
21 | "tactic": "initial-access",
22 | "color": "#a1d99b",
23 | "comment": "created to consolidate several techniques from old tactic",
24 | "enabled": true
25 | },
26 | {
27 | "techniqueID": "T1476",
28 | "tactic": "initial-access",
29 | "color": "#a1d99b",
30 | "comment": "created to consolidate several techniques from old tactic",
31 | "enabled": true
32 | },
33 | {
34 | "techniqueID": "T1466",
35 | "tactic": "network-effects",
36 | "color": "#fcf26b",
37 | "comment": "moved into new tactics from the Network-Based Effects Matrix",
38 | "enabled": true
39 | },
40 | {
41 | "techniqueID": "T1456",
42 | "tactic": "initial-access",
43 | "color": "#fcf26b",
44 | "comment": "renamed from Malicious Web Content and moved to Initial Access",
45 | "enabled": true
46 | },
47 | {
48 | "techniqueID": "T1439",
49 | "tactic": "network-effects",
50 | "color": "#fcf26b",
51 | "comment": "moved into new tactics from the Network-Based Effects Matrix",
52 | "enabled": true
53 | },
54 | {
55 | "techniqueID": "T1449",
56 | "tactic": "network-effects",
57 | "color": "#fcf26b",
58 | "comment": "moved into new tactics from the Network-Based Effects Matrix",
59 | "enabled": true
60 | },
61 | {
62 | "techniqueID": "T1450",
63 | "tactic": "network-effects",
64 | "color": "#fcf26b",
65 | "comment": "moved into new tactics from the Network-Based Effects Matrix",
66 | "enabled": true
67 | },
68 | {
69 | "techniqueID": "T1458",
70 | "tactic": "initial-access",
71 | "color": "#fcf26b",
72 | "comment": "moved to Initial Access",
73 | "enabled": true
74 | },
75 | {
76 | "techniqueID": "T1477",
77 | "tactic": "initial-access",
78 | "color": "#fcf26b",
79 | "comment": "changed scope, content, or tactics",
80 | "enabled": true
81 | },
82 | {
83 | "techniqueID": "T1478",
84 | "tactic": "defense-evasion",
85 | "color": "#a1d99b",
86 | "comment": "new technique",
87 | "enabled": true
88 | },
89 | {
90 | "techniqueID": "T1478",
91 | "tactic": "initial-access",
92 | "color": "#a1d99b",
93 | "comment": "new technique",
94 | "enabled": true
95 | },
96 | {
97 | "techniqueID": "T1464",
98 | "tactic": "network-effects",
99 | "color": "#fcf26b",
100 | "comment": "moved into new tactics from the Network-Based Effects Matrix",
101 | "enabled": true
102 | },
103 | {
104 | "techniqueID": "T1461",
105 | "tactic": "initial-access",
106 | "color": "#fcf26b",
107 | "comment": "moved to Initial Access",
108 | "enabled": true
109 | },
110 | {
111 | "techniqueID": "T1463",
112 | "tactic": "network-effects",
113 | "color": "#fcf26b",
114 | "comment": "moved into new tactics from the Network-Based Effects Matrix",
115 | "enabled": true
116 | },
117 | {
118 | "techniqueID": "T1470",
119 | "tactic": "remote-service-effects",
120 | "color": "#fcf26b",
121 | "comment": "moved into new tactics from the Network-Based Effects Matrix",
122 | "enabled": true
123 | },
124 | {
125 | "techniqueID": "T1468",
126 | "tactic": "remote-service-effects",
127 | "color": "#fcf26b",
128 | "comment": "moved into new tactics from the Network-Based Effects Matrix",
129 | "enabled": true
130 | },
131 | {
132 | "techniqueID": "T1469",
133 | "tactic": "remote-service-effects",
134 | "color": "#fcf26b",
135 | "comment": "moved into new tactics from the Network-Based Effects Matrix",
136 | "enabled": true
137 | },
138 | {
139 | "techniqueID": "T1444",
140 | "tactic": "initial-access",
141 | "color": "#fcf26b",
142 | "comment": "moved to Initial Access",
143 | "enabled": true
144 | },
145 | {
146 | "techniqueID": "T1467",
147 | "tactic": "network-effects",
148 | "color": "#fcf26b",
149 | "comment": "moved into new tactics from the Network-Based Effects Matrix",
150 | "enabled": true
151 | },
152 | {
153 | "techniqueID": "T1465",
154 | "tactic": "network-effects",
155 | "color": "#fcf26b",
156 | "comment": "moved into new tactics from the Network-Based Effects Matrix",
157 | "enabled": true
158 | },
159 | {
160 | "techniqueID": "T1451",
161 | "tactic": "network-effects",
162 | "color": "#fcf26b",
163 | "comment": "moved into new tactics from the Network-Based Effects Matrix",
164 | "enabled": true
165 | },
166 | {
167 | "techniqueID": "T1474",
168 | "tactic": "initial-access",
169 | "color": "#a1d99b",
170 | "comment": "created to consolidate several techniques in the old tactic",
171 | "enabled": true
172 | },
173 | {
174 | "techniqueID": "T1411",
175 | "tactic": "credential-access",
176 | "color": "#fcf26b",
177 | "comment": "changed scope, content, or tactics",
178 | "enabled": true
179 | }
180 | ],
181 | "gradient": {
182 | "colors": [
183 | "#ff6666",
184 | "#ffe766",
185 | "#8ec843"
186 | ],
187 | "minValue": 0,
188 | "maxValue": 100
189 | },
190 | "legendItems": [
191 | {
192 | "color": "#a1d99b",
193 | "label": "new technique"
194 | },
195 | {
196 | "color": "#fcf26b",
197 | "label": "changed scope, content, or tactics"
198 | }
199 | ],
200 | "showTacticRowBackground": true,
201 | "tacticRowBackground": "#205b8f",
202 | "selectTechniquesAcrossTactics": true
203 | }
--------------------------------------------------------------------------------
/layers/LAYERFORMATv1_3.md:
--------------------------------------------------------------------------------
1 | # ATT&CKTM Navigator Layer File Format Definition
2 | This document describes **Version 1.3** of the MITRE ATT&CK Navigator Layer file format. The ATT&CK Navigator stores layers as JSON, therefore this document defines the JSON properties in a layer file.
3 |
4 | ## Property Table
5 |
6 | | Name | Type | Required? | Default Value (if not present) | Description |
7 | | :------------- | :------------- | :------------- | :------------- | :------------- |
8 | | version | String | Yes | n/a | Must be "1.3" |
9 | | name | String | Yes | n/a | The name of the layer |
10 | | description | String | No | "" | A free-form text field that describes the contents or intent of the layer |
11 | | domain | String | Yes | n/a | Technology domain that this layer represents. Valid values are: "mitre-enterprise" or "mitre-mobile" |
12 | | filters |Filter object | No | | See Filter object definition below
13 | | sorting | Number | No | 0 | Specifies the ordering of the techniques within each tactic category as follows:
**0**: sort ascending alphabetically by technique name
**1**: sort descending alphabetically by technique name
**2**: sort ascending by technique score
**3**: sort descending by technique score |
14 | | viewMode | Number | No | 0 | Specifies the view mode for the layer as follows:
**0**: display the full table with tactic and technique names
**1**: display compact table with abbreviated tactic and technique names
**2**: display mini table with no text with the exception of tooltips |
15 | | hideDisabled | Boolean | No | false | Specifies whether techniques that have been disabled are still displayed (greyed-out) or omitted from the view as follows:
**true**: omit techniques marked as disabled from the view
**false**: include disabled techniques in the view but display as greyed-out |
16 | | techniques | Array of Technique objects | No | | See definition of Technique object below |
17 | | gradient | Gradient object | No | Red to Green, minValue=0, maxValue=100 | See definition of Gradient object below |
18 | | legendItems | Array of LegendItem objects | no | | See definition of LegendItem object below |
19 | | showTacticRowBackground | boolean | no | false | If true, the tactic row background color will be the value of the _tacticRowBackground_ field |
20 | | tacticRowBackground | string | no | "#dddddd" | The tactic row background color |
21 |
22 |
23 | ## Filter Object Properties
24 |
25 | | Name | Type | Required? | Default Value (if not present) | Description |
26 | | :------------- | :------------- | :------------- | :------------- | :------------- |
27 | | stages | Array of String | No | ["act"] | Specifies the logical stages of the attack lifecycle to display. Valid choices are: "prepare" and "act". Array must contain at least one of these values |
28 | | platforms | Array of String | No | All platforms defined within domain | Specifies the platforms within the technology domain – only those techniques tagged with these platforms are to be displayed. Valid values are as follows:
**domain=mitre-enterprise**: "windows", "linux", "mac"
**domain=mitre-mobile**: "android", "ios" |
29 |
30 | ## Technique Object properties
31 |
32 | | Name | Type | Required? | Default Value (if not present) | Description |
33 | | :------------- | :------------- | :------------- | :------------- | :------------- |
34 | | techniqueID | String | Yes | n/a | Unique identifier of the ATT&CK technique, e.g. "T####" |
35 | | comment | String | No | "" | Free-text field |
36 | | enabled | Boolean | No | true | Specifies if the technique is considered enabled or disabled in this layer |
37 | | score | Number | No | (unscored) | Optional numeric score assigned to this technique in the layer. If omitted, the technique is considered to be "unscored" meaning that it will not be assigned a color from the gradient by the Navigator |
38 | | color | String | No | "" | Explicit color value assigned to the technique in this layer. Note that explicitly defined color overrides any color implied by the score – the Navigator will display the technique using the explicitly defined color |
39 |
40 | ## Gradient Object properties
41 | | Name | Type | Required? | Default Value (if not present) | Description |
42 | | :------------- | :------------- | :------------- | :------------- | :------------- |
43 | | colors | Array of String | Yes | n/a | Specifies the hexadecimal RGB color values that constitute the color spectrum in use. The array must contain at least two (2) values, corresponding to the minValue and maxValue scores |
44 | | minValue | Number | Yes | n/a | Lower bound score of the gradient |
45 | | maxValue | Number | Yes | n/a | Upper bound score of the gradient. *Note: maxValue must be > minValue* |
46 |
47 | ## LegendItem Object properties
48 | | Name | Type | Required? | Default Value (if not present) | Description |
49 | | :------------- | :------------- | :------------- | :------------- | :------------- |
50 | | label | String | Yes | n/a | The name of the legend item |
51 | | color | String | Yes | n/a | The color of the legend item |
52 |
53 |
54 | ## Example
55 | The following example illustrates the layer file format:
56 | ```json
57 | {
58 | "version": "1.3",
59 | "name": "example",
60 | "description": "hello, world",
61 | "domain": "mitre-enterprise",
62 | "filters": {
63 | "stages": ["act"],
64 | "platforms": ["windows"],
65 | },
66 | "sorting": 2,
67 | "techniques": [
68 | {
69 | "techniqueID": "T1156",
70 | "enabled": false,
71 | "comment": "disabled technique with a comment"
72 | },
73 | {
74 | "techniqueID": "T1103",
75 | "score": 50
76 | },
77 | {
78 | "color": "#FF00FF",
79 | "techniqueID": "T1015",
80 | },
81 | ],
82 | "legendItems": [
83 | {
84 | "label": "Legend Item Label",
85 | "color": "#FF00FF"
86 | }
87 | ],
88 | "showTacticRowBackground": true,
89 | "tacticRowBackground": "#205b8f"
90 | }
91 | ```
92 |
--------------------------------------------------------------------------------
/layers/data/samples/ATTACKcon/Blue_Pins.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Blue Pins",
3 | "version": "2.1",
4 | "domain": "mitre-enterprise",
5 | "description": "\nATT&CKcon Matrix Question: With your ATT&CK-mapped detections, which ones generate the most false positives?",
6 | "filters": {
7 | "stages": [
8 | "act"
9 | ],
10 | "platforms": [
11 | "windows",
12 | "linux",
13 | "mac"
14 | ]
15 | },
16 | "sorting": 0,
17 | "viewMode": 0,
18 | "hideDisabled": false,
19 | "techniques": [
20 | {
21 | "techniqueID": "T1156",
22 | "tactic": "persistence",
23 | "score": 1,
24 | "color": "",
25 | "comment": "",
26 | "enabled": true
27 | },
28 | {
29 | "techniqueID": "T1059",
30 | "tactic": "execution",
31 | "score": 2,
32 | "color": "",
33 | "comment": "",
34 | "enabled": true
35 | },
36 | {
37 | "techniqueID": "T1043",
38 | "tactic": "command-and-control",
39 | "score": 1,
40 | "color": "",
41 | "comment": "",
42 | "enabled": true
43 | },
44 | {
45 | "techniqueID": "T1002",
46 | "tactic": "exfiltration",
47 | "score": 2,
48 | "color": "",
49 | "comment": "",
50 | "enabled": true
51 | },
52 | {
53 | "techniqueID": "T1132",
54 | "tactic": "command-and-control",
55 | "score": 1,
56 | "color": "",
57 | "comment": "",
58 | "enabled": true
59 | },
60 | {
61 | "techniqueID": "T1172",
62 | "tactic": "command-and-control",
63 | "score": 1,
64 | "color": "",
65 | "comment": "",
66 | "enabled": true
67 | },
68 | {
69 | "techniqueID": "T1190",
70 | "tactic": "initial-access",
71 | "score": 1,
72 | "color": "",
73 | "comment": "",
74 | "enabled": true
75 | },
76 | {
77 | "techniqueID": "T1107",
78 | "tactic": "defense-evasion",
79 | "score": 1,
80 | "color": "",
81 | "comment": "",
82 | "enabled": true
83 | },
84 | {
85 | "techniqueID": "T1083",
86 | "tactic": "discovery",
87 | "score": 1,
88 | "color": "",
89 | "comment": "",
90 | "enabled": true
91 | },
92 | {
93 | "techniqueID": "T1054",
94 | "tactic": "defense-evasion",
95 | "score": 1,
96 | "color": "",
97 | "comment": "",
98 | "enabled": true
99 | },
100 | {
101 | "techniqueID": "T1177",
102 | "tactic": "execution",
103 | "score": 2,
104 | "color": "",
105 | "comment": "",
106 | "enabled": true
107 | },
108 | {
109 | "techniqueID": "T1177",
110 | "tactic": "persistence",
111 | "score": 2,
112 | "color": "",
113 | "comment": "",
114 | "enabled": true
115 | },
116 | {
117 | "techniqueID": "T1112",
118 | "tactic": "defense-evasion",
119 | "score": 1,
120 | "color": "",
121 | "comment": "",
122 | "enabled": true
123 | },
124 | {
125 | "techniqueID": "T1050",
126 | "tactic": "persistence",
127 | "score": 2,
128 | "color": "",
129 | "comment": "",
130 | "enabled": true
131 | },
132 | {
133 | "techniqueID": "T1050",
134 | "tactic": "privilege-escalation",
135 | "score": 2,
136 | "color": "",
137 | "comment": "",
138 | "enabled": true
139 | },
140 | {
141 | "techniqueID": "T1086",
142 | "tactic": "execution",
143 | "score": 7,
144 | "color": "",
145 | "comment": "",
146 | "enabled": true
147 | },
148 | {
149 | "techniqueID": "T1060",
150 | "tactic": "persistence",
151 | "score": 2,
152 | "color": "",
153 | "comment": "",
154 | "enabled": true
155 | },
156 | {
157 | "techniqueID": "T1053",
158 | "tactic": "execution",
159 | "score": 1,
160 | "color": "",
161 | "comment": "",
162 | "enabled": true
163 | },
164 | {
165 | "techniqueID": "T1053",
166 | "tactic": "persistence",
167 | "score": 1,
168 | "color": "",
169 | "comment": "",
170 | "enabled": true
171 | },
172 | {
173 | "techniqueID": "T1053",
174 | "tactic": "privilege-escalation",
175 | "score": 1,
176 | "color": "",
177 | "comment": "",
178 | "enabled": true
179 | },
180 | {
181 | "techniqueID": "T1064",
182 | "tactic": "defense-evasion",
183 | "score": 1,
184 | "color": "",
185 | "comment": "",
186 | "enabled": true
187 | },
188 | {
189 | "techniqueID": "T1064",
190 | "tactic": "execution",
191 | "score": 1,
192 | "color": "",
193 | "comment": "",
194 | "enabled": true
195 | },
196 | {
197 | "techniqueID": "T1071",
198 | "tactic": "command-and-control",
199 | "score": 1,
200 | "color": "",
201 | "comment": "",
202 | "enabled": true
203 | },
204 | {
205 | "techniqueID": "T1078",
206 | "tactic": "defense-evasion",
207 | "score": 6,
208 | "color": "",
209 | "comment": "",
210 | "enabled": true
211 | },
212 | {
213 | "techniqueID": "T1078",
214 | "tactic": "persistence",
215 | "score": 6,
216 | "color": "",
217 | "comment": "",
218 | "enabled": true
219 | },
220 | {
221 | "techniqueID": "T1078",
222 | "tactic": "privilege-escalation",
223 | "score": 6,
224 | "color": "",
225 | "comment": "",
226 | "enabled": true
227 | },
228 | {
229 | "techniqueID": "T1078",
230 | "tactic": "initial-access",
231 | "score": 6,
232 | "color": "",
233 | "comment": "",
234 | "enabled": true
235 | },
236 | {
237 | "techniqueID": "T1102",
238 | "tactic": "command-and-control",
239 | "score": 2,
240 | "color": "",
241 | "comment": "",
242 | "enabled": true
243 | },
244 | {
245 | "techniqueID": "T1102",
246 | "tactic": "defense-evasion",
247 | "score": 2,
248 | "color": "",
249 | "comment": "",
250 | "enabled": true
251 | },
252 | {
253 | "techniqueID": "T1047",
254 | "tactic": "execution",
255 | "score": 2,
256 | "color": "",
257 | "comment": "",
258 | "enabled": true
259 | },
260 | {
261 | "techniqueID": "T1028",
262 | "tactic": "execution",
263 | "score": 1,
264 | "color": "",
265 | "comment": "",
266 | "enabled": true
267 | },
268 | {
269 | "techniqueID": "T1028",
270 | "tactic": "lateral-movement",
271 | "score": 1,
272 | "color": "",
273 | "comment": "",
274 | "enabled": true
275 | }
276 | ],
277 | "gradient": {
278 | "colors": [
279 | "#c0d6ed",
280 | "#042e5a"
281 | ],
282 | "minValue": 1,
283 | "maxValue": 8
284 | },
285 | "legendItems": [],
286 | "showTacticRowBackground": true,
287 | "tacticRowBackground": "#205b8f",
288 | "selectTechniquesAcrossTactics": true
289 | }
--------------------------------------------------------------------------------
/layers/data/update_layers/October_2018_Updates_Enterprise.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "October 2018 Updates Enterprise",
3 | "version": "2.1",
4 | "domain": "mitre-enterprise",
5 | "description": "",
6 | "filters": {
7 | "stages": [
8 | "act"
9 | ],
10 | "platforms": [
11 | "windows",
12 | "linux",
13 | "mac"
14 | ]
15 | },
16 | "sorting": 0,
17 | "viewMode": 0,
18 | "hideDisabled": false,
19 | "techniques": [
20 | {
21 | "techniqueID": "T1009",
22 | "tactic": "defense-evasion",
23 | "color": "#fcf26b",
24 | "comment": "Changed scope, content, or tactics",
25 | "enabled": true
26 | },
27 | {
28 | "techniqueID": "T1042",
29 | "tactic": "persistence",
30 | "color": "#fcf26b",
31 | "comment": "Changed scope, content, or tactics",
32 | "enabled": true
33 | },
34 | {
35 | "techniqueID": "T1109",
36 | "tactic": "defense-evasion",
37 | "color": "#fcf26b",
38 | "comment": "Changed scope, content, or tactics",
39 | "enabled": true
40 | },
41 | {
42 | "techniqueID": "T1109",
43 | "tactic": "persistence",
44 | "color": "#fcf26b",
45 | "comment": "Changed scope, content, or tactics",
46 | "enabled": true
47 | },
48 | {
49 | "techniqueID": "T1181",
50 | "tactic": "privilege-escalation",
51 | "color": "#fcf26b",
52 | "comment": "Changed scope, content, or tactics",
53 | "enabled": true
54 | },
55 | {
56 | "techniqueID": "T1181",
57 | "tactic": "defense-evasion",
58 | "color": "#fcf26b",
59 | "comment": "Changed scope, content, or tactics",
60 | "enabled": true
61 | },
62 | {
63 | "techniqueID": "T1222",
64 | "tactic": "defense-evasion",
65 | "color": "#a1d99b",
66 | "comment": "new technique",
67 | "enabled": true
68 | },
69 | {
70 | "techniqueID": "T1223",
71 | "tactic": "defense-evasion",
72 | "color": "#a1d99b",
73 | "comment": "new technique",
74 | "enabled": true
75 | },
76 | {
77 | "techniqueID": "T1223",
78 | "tactic": "execution",
79 | "color": "#a1d99b",
80 | "comment": "new technique",
81 | "enabled": true
82 | },
83 | {
84 | "techniqueID": "T1061",
85 | "tactic": "execution",
86 | "color": "#fcf26b",
87 | "comment": "Changed scope, content, or tactics",
88 | "enabled": true
89 | },
90 | {
91 | "techniqueID": "T1183",
92 | "tactic": "privilege-escalation",
93 | "color": "#fcf26b",
94 | "comment": "Changed scope, content, or tactics",
95 | "enabled": true
96 | },
97 | {
98 | "techniqueID": "T1183",
99 | "tactic": "persistence",
100 | "color": "#fcf26b",
101 | "comment": "Changed scope, content, or tactics",
102 | "enabled": true
103 | },
104 | {
105 | "techniqueID": "T1183",
106 | "tactic": "defense-evasion",
107 | "color": "#fcf26b",
108 | "comment": "Changed scope, content, or tactics",
109 | "enabled": true
110 | },
111 | {
112 | "techniqueID": "T1054",
113 | "tactic": "defense-evasion",
114 | "color": "#fcf26b",
115 | "comment": "Changed scope, content, or tactics",
116 | "enabled": true
117 | },
118 | {
119 | "techniqueID": "T1070",
120 | "tactic": "defense-evasion",
121 | "color": "#fcf26b",
122 | "comment": "Changed scope, content, or tactics",
123 | "enabled": true
124 | },
125 | {
126 | "techniqueID": "T1112",
127 | "tactic": "defense-evasion",
128 | "color": "#fcf26b",
129 | "comment": "Changed scope, content, or tactics",
130 | "enabled": true
131 | },
132 | {
133 | "techniqueID": "T1096",
134 | "tactic": "defense-evasion",
135 | "color": "#fcf26b",
136 | "comment": "Changed scope, content, or tactics",
137 | "enabled": true
138 | },
139 | {
140 | "techniqueID": "T1034",
141 | "tactic": "persistence",
142 | "color": "#fcf26b",
143 | "comment": "Changed scope, content, or tactics",
144 | "enabled": true
145 | },
146 | {
147 | "techniqueID": "T1034",
148 | "tactic": "privilege-escalation",
149 | "color": "#fcf26b",
150 | "comment": "Changed scope, content, or tactics",
151 | "enabled": true
152 | },
153 | {
154 | "techniqueID": "T1205",
155 | "tactic": "command-and-control",
156 | "color": "#fcf26b",
157 | "comment": "Changed scope, content, or tactics",
158 | "enabled": true
159 | },
160 | {
161 | "techniqueID": "T1205",
162 | "tactic": "defense-evasion",
163 | "color": "#fcf26b",
164 | "comment": "Changed scope, content, or tactics",
165 | "enabled": true
166 | },
167 | {
168 | "techniqueID": "T1205",
169 | "tactic": "persistence",
170 | "color": "#fcf26b",
171 | "comment": "Changed scope, content, or tactics",
172 | "enabled": true
173 | },
174 | {
175 | "techniqueID": "T1055",
176 | "tactic": "defense-evasion",
177 | "color": "#fcf26b",
178 | "comment": "Changed scope, content, or tactics",
179 | "enabled": true
180 | },
181 | {
182 | "techniqueID": "T1055",
183 | "tactic": "privilege-escalation",
184 | "color": "#fcf26b",
185 | "comment": "Changed scope, content, or tactics",
186 | "enabled": true
187 | },
188 | {
189 | "techniqueID": "T1060",
190 | "tactic": "persistence",
191 | "color": "#fcf26b",
192 | "comment": "Changed scope, content, or tactics",
193 | "enabled": true
194 | },
195 | {
196 | "techniqueID": "T1178",
197 | "tactic": "privilege-escalation",
198 | "color": "#fcf26b",
199 | "comment": "Changed scope, content, or tactics",
200 | "enabled": true
201 | },
202 | {
203 | "techniqueID": "T1051",
204 | "tactic": "lateral-movement",
205 | "color": "#fcf26b",
206 | "comment": "Changed scope, content, or tactics",
207 | "enabled": true
208 | },
209 | {
210 | "techniqueID": "T1221",
211 | "tactic": "defense-evasion",
212 | "color": "#a1d99b",
213 | "comment": "new technique",
214 | "enabled": true
215 | },
216 | {
217 | "techniqueID": "T1111",
218 | "tactic": "credential-access",
219 | "color": "#fcf26b",
220 | "comment": "Changed scope, content, or tactics",
221 | "enabled": true
222 | },
223 | {
224 | "techniqueID": "T1220",
225 | "tactic": "defense-evasion",
226 | "color": "#a1d99b",
227 | "comment": "new technique",
228 | "enabled": true
229 | },
230 | {
231 | "techniqueID": "T1220",
232 | "tactic": "execution",
233 | "color": "#a1d99b",
234 | "comment": "new technique",
235 | "enabled": true
236 | }
237 | ],
238 | "gradient": {
239 | "colors": [
240 | "#ff6666",
241 | "#ffe766",
242 | "#8ec843"
243 | ],
244 | "minValue": 0,
245 | "maxValue": 100
246 | },
247 | "legendItems": [
248 | {
249 | "color": "#a1d99b",
250 | "label": "new techniques"
251 | },
252 | {
253 | "color": "#fcf26b",
254 | "label": "changed scope, content, or tactics"
255 | }
256 | ],
257 | "showTacticRowBackground": true,
258 | "tacticRowBackground": "#205b8f",
259 | "selectTechniquesAcrossTactics": true
260 | }
261 |
--------------------------------------------------------------------------------
/layers/LAYERFORMATv2.md:
--------------------------------------------------------------------------------
1 | # ATT&CKTM Navigator Layer File Format Definition
2 | This document describes **Version 2.0** of the MITRE ATT&CK Navigator Layer file format. The ATT&CK Navigator stores layers as JSON, therefore this document defines the JSON properties in a layer file.
3 |
4 | ## Property Table
5 |
6 | | Name | Type | Required? | Default Value (if not present) | Description |
7 | | :------------- | :------------- | :------------- | :------------- | :------------- |
8 | | version | String | Yes | n/a | Must be "2.0" |
9 | | name | String | Yes | n/a | The name of the layer |
10 | | description | String | No | "" | A free-form text field that describes the contents or intent of the layer |
11 | | domain | String | Yes | n/a | Technology domain that this layer represents. Valid values are: "mitre-enterprise" or "mitre-mobile" |
12 | | filters |Filter object | No | | See Filter object definition below
13 | | sorting | Number | No | 0 | Specifies the ordering of the techniques within each tactic category as follows:
**0**: sort ascending alphabetically by technique name
**1**: sort descending alphabetically by technique name
**2**: sort ascending by technique score
**3**: sort descending by technique score |
14 | | viewMode | Number | No | 0 | Specifies the view mode for the layer as follows:
**0**: display the full table with tactic and technique names
**1**: display compact table with abbreviated tactic and technique names
**2**: display mini table with no text with the exception of tooltips |
15 | | hideDisabled | Boolean | No | false | Specifies whether techniques that have been disabled are still displayed (greyed-out) or omitted from the view as follows:
**true**: omit techniques marked as disabled from the view
**false**: include disabled techniques in the view but display as greyed-out |
16 | | techniques | Array of Technique objects | No | | See definition of Technique object below |
17 | | gradient | Gradient object | No | Red to Green, minValue=0, maxValue=100 | See definition of Gradient object below |
18 | | legendItems | Array of LegendItem objects | no | | See definition of LegendItem object below |
19 | | showTacticRowBackground | boolean | no | false | If true, the tactic row background color will be the value of the _tacticRowBackground_ field |
20 | | tacticRowBackground | string | no | "#dddddd" | The tactic row background color |
21 | | selectTechniquesAcrossTactics | boolean | no | true | If true, selecting a technique also selects all instances with the same technique ID |
22 |
23 |
24 | ## Filter Object Properties
25 |
26 | | Name | Type | Required? | Default Value (if not present) | Description |
27 | | :------------- | :------------- | :------------- | :------------- | :------------- |
28 | | stages | Array of String | No | ["act"] | Specifies the logical stages of the attack lifecycle to display. Valid choices are: "prepare" and "act". Array must contain at least one of these values |
29 | | platforms | Array of String | No | All platforms defined within domain | Specifies the platforms within the technology domain – only those techniques tagged with these platforms are to be displayed. Valid values are as follows:
**domain=mitre-enterprise**: "windows", "linux", "mac"
**domain=mitre-mobile**: "android", "ios" |
30 |
31 | ## Technique Object properties
32 |
33 | | Name | Type | Required? | Default Value (if not present) | Description |
34 | | :------------- | :------------- | :------------- | :------------- | :------------- |
35 | | techniqueID | String | Yes | n/a | Unique identifier of the ATT&CK technique, e.g. "T####" |
36 | | tactic | String | No | n/a | Unique identifier of the ATT&CK technique's tactic, e.g. "lateral-movement". If the field is not present, the annotations for the technique will appear under every tactic the technique belongs to |
37 | | comment | String | No | "" | Free-text field |
38 | | enabled | Boolean | No | true | Specifies if the technique is considered enabled or disabled in this layer |
39 | | score | Number | No | (unscored) | Optional numeric score assigned to this technique in the layer. If omitted, the technique is considered to be "unscored" meaning that it will not be assigned a color from the gradient by the Navigator |
40 | | color | String | No | "" | Explicit color value assigned to the technique in this layer. Note that explicitly defined color overrides any color implied by the score – the Navigator will display the technique using the explicitly defined color |
41 |
42 | ## Gradient Object properties
43 | | Name | Type | Required? | Default Value (if not present) | Description |
44 | | :------------- | :------------- | :------------- | :------------- | :------------- |
45 | | colors | Array of String | Yes | n/a | Specifies the hexadecimal RGB color values that constitute the color spectrum in use. The array must contain at least two (2) values, corresponding to the minValue and maxValue scores |
46 | | minValue | Number | Yes | n/a | Lower bound score of the gradient |
47 | | maxValue | Number | Yes | n/a | Upper bound score of the gradient. *Note: maxValue must be > minValue* |
48 |
49 | ## LegendItem Object properties
50 | | Name | Type | Required? | Default Value (if not present) | Description |
51 | | :------------- | :------------- | :------------- | :------------- | :------------- |
52 | | label | String | Yes | n/a | The name of the legend item |
53 | | color | String | Yes | n/a | The color of the legend item |
54 |
55 |
56 | ## Example
57 | The following example illustrates the layer file format:
58 | ```json
59 | {
60 | "name": "example layer",
61 | "version": "2.0",
62 | "domain": "mitre-enterprise",
63 | "description": "hello, world",
64 | "filters": {
65 | "stages": [
66 | "act"
67 | ],
68 | "platforms": [
69 | "windows",
70 | "mac"
71 | ]
72 | },
73 | "sorting": 2,
74 | "viewMode": 0,
75 | "hideDisabled": false,
76 | "techniques": [
77 | {
78 | "techniqueID": "T1155",
79 | "tactic": "execution",
80 | "color": "#fd8d3c",
81 | "comment": "This is a comment for technique T1155 only under the Execution tactic."
82 | },
83 | {
84 | "techniqueID": "T1155",
85 | "tactic": "lateral-movement",
86 | "score": 75
87 | },
88 | {
89 | "techniqueID": "T1010",
90 | "tactic": "discovery",
91 | "enabled": false
92 | }
93 | ],
94 | "gradient": {
95 | "colors": [
96 | "#ff6666",
97 | "#ffe766",
98 | "#8ec843"
99 | ],
100 | "minValue": 0,
101 | "maxValue": 100
102 | },
103 | "legendItems": [
104 | {
105 | "label": "Legend Item Label",
106 | "color": "#FF00FF"
107 | }
108 | ],
109 | "showTacticRowBackground": true,
110 | "tacticRowBackground": "#dddddd",
111 | "selectTechniquesAcrossTactics": false
112 | }
113 | ```
114 |
--------------------------------------------------------------------------------
/nav-app/src/app/tabs/tabs.component.scss:
--------------------------------------------------------------------------------
1 | @import "../../colors.scss";
2 |
3 | .tabs {
4 | padding-left: 0;
5 | margin-bottom: 0;
6 | list-style: none;
7 | // border-bottom: 1px solid #ddd; //horizontal line border
8 | user-select: none;
9 | margin-top: 0;
10 |
11 | &>li {
12 | bottom: 0;
13 | position: relative;
14 | display: block;
15 | float: left;
16 | margin-bottom: 0;
17 | cursor: pointer;
18 | height: 23px;
19 |
20 | a { //non-datatable tab names
21 | font-family: 'Roboto Mono', monospace;
22 | font-size: 14px;
23 | text-decoration: none;
24 | color: black;
25 | }
26 |
27 | input[type=text] { //datatable tab name edit field
28 | font-family: 'Roboto Mono', monospace;
29 | font-size: 14px;
30 | border: none;
31 | background: none;
32 | &:disabled {} //when the tab isn't active
33 | &:not(:disabled) { //when the tab is active
34 | &:focus { //when the input is selected (editing)
35 | background: $panel-light;
36 | }
37 | }
38 |
39 | }
40 |
41 |
42 | position: relative;
43 | display: block;
44 | padding: 10px 15px;
45 |
46 | margin-right: 2px;
47 | border: 1px solid transparent;
48 | border-radius: 4px 4px 0 0;
49 |
50 | // add new tab button
51 | &.addTab {
52 | font-size: 12pt;
53 | cursor: pointer;
54 | color: darken($panel-dark, 20%);
55 | &:hover {
56 | color: black;
57 | }
58 | }
59 |
60 | &:hover, &:focus { //when the mouse is over a non-selected tab
61 | &:not(.active) {
62 | text-decoration: none;
63 | &:not(.addTab) { //add tab should not behave like other tabs
64 | border-color: $panel-dark $panel-dark $panel-light $panel-dark;//black border bottom when hovered
65 | background-color: $panel-light;
66 | }
67 | }
68 | }
69 |
70 |
71 | //tab number that shows up when tab is highlighted
72 | &>.tabEnumerator {
73 | position: absolute;
74 | top: -10px;
75 | right: 5px;
76 | padding: 2px 4px;
77 | background: rgb(255,255,0);
78 | border-radius: 5px;
79 | }
80 |
81 | &.active {
82 | color: $tab-text-color;//text color
83 | cursor: default; //cursor behavior
84 | background-color: $panel-dark;
85 | border: 1px solid transparent; //override border highlighting on hover
86 | }
87 |
88 |
89 | }
90 |
91 | &:before {
92 | display: table;
93 | content: " ";
94 | }
95 | &:after {
96 | display: table;
97 | clear: both;
98 | content: " ";
99 | }
100 | }
101 |
102 | // close tab button
103 | .tab-close {
104 | margin-left: 10px;
105 | color: gray;
106 | text-align: right;
107 | cursor: pointer;
108 | &:hover {
109 | color: black
110 | }
111 | }
112 |
113 | .newTab {
114 | // text-align: center;
115 | padding: 5% 20%;
116 | }
117 |
118 | .border {
119 | border: 1px solid $panel-dark;
120 | }
121 |
122 | // button {
123 | // padding: 5px;
124 | // margin: 5px;
125 | // width: 300px;
126 | // // border: 1px solid black;
127 | // background-color: $panel-light;
128 | // border-radius: 0px;
129 | // &:hover {
130 | // background-color: $panel-dark;
131 | // }
132 | // }
133 |
134 | // .layerOperationsPanel {
135 | // // width: 50%;
136 | // // border: 1px solid #ddd;
137 | // margin: 0 auto;
138 | // table {
139 | // border-top: 1px solid #ddd;
140 | // margin: 0 auto;
141 | // border-collapse: collapse;
142 | // td.rowName {
143 | // text-align: right;
144 | // border-right: 1px solid #ddd;
145 | // }
146 | // td {
147 | // padding: 5px;
148 | // }
149 | // }
150 | // }
151 |
152 | .layerOpTable {
153 | td {
154 | padding: 5px;
155 | }
156 | }
157 |
158 | .headers-align .mat-expansion-panel-header-title,
159 | .headers-align .mat-expansion-panel-header-description {
160 | flex-basis: 0;
161 | }
162 |
163 | .headers-align .mat-expansion-panel-header-description {
164 | justify-content: space-between;
165 | align-items: center;
166 | }
167 |
168 | input[type=file]{
169 | padding: 5px;
170 | margin: 5px;
171 | width: 300px;
172 | // border: 1px solid black;
173 | background-color: $panel-light;
174 | border-radius: 0px;
175 | &:hover {
176 | background-color: $panel-dark;
177 | }
178 | }
179 |
180 |
181 | //button on new tab page
182 | .helpButtonContainer {
183 | // border: 1px solid black;
184 | text-align: center;
185 | margin-top: 20px;
186 | }
187 | .help {
188 | padding: 10px;
189 | }
190 |
191 | .header {
192 | text-align: right;
193 | div { display: inline-block; cursor: pointer; }
194 | .logo {
195 | // position: absolute;
196 | // top: 0;
197 | text-align: right;
198 | a {
199 | text-decoration: none;
200 | color: rgb(176, 26, 26);
201 | font-weight:500;
202 | }
203 | margin-right: 40px;
204 | padding: 5px;
205 | height: 2ex;
206 |
207 | }
208 |
209 | .helpButton {
210 | position: fixed;
211 | top: 0;
212 | right: 0;
213 | background: white;
214 | &:hover { background: $panel-light; }
215 | border-style: solid;
216 | border-color: $panel-dark;
217 | border-width: 0 0 1px 1px;
218 | border-radius: 0 0 0 50%;
219 | text-align: center;
220 | width: 2ex;
221 | height: 2ex;
222 | padding: 5px;
223 | }
224 | }
225 |
226 |
227 | .inputTable {
228 | width: 100%;
229 | border-collapse: collapse;
230 | tr {
231 | &.featureRow:hover {
232 | background: darken(white, 5%)
233 | }
234 | transition: ease 0.2s;
235 |
236 | width: 100%;
237 | // background: darken(white, 5%);
238 | margin-top: 5px;
239 | border-radius: 5px;
240 |
241 | td {
242 | text-align: left;
243 | width: 1%;
244 | padding: 5px;
245 | &.featureRow-button {
246 | img {vertical-align: middle; margin-bottom: 2px;}
247 | }
248 | &.subfeature {
249 | &:first-child {
250 | border-left: 1px solid $panel-dark;
251 | }
252 | &.last {
253 | border-bottom: 1px solid $panel-dark;
254 | }
255 | }
256 | }
257 | }
258 | }
259 |
260 | #layerlinkfield {
261 | color: rgba(0,0,0,.42);
262 | /deep/.mat-form-field-underline {
263 | background: none;
264 | background-image: linear-gradient(to right,rgba(0,0,0,.42) 0,rgba(0,0,0,.42) 33%,transparent 0);
265 | background-size: 4px 1px;
266 | background-repeat: repeat-x;
267 | }
268 | #layerLink {
269 | cursor: pointer;
270 | }
271 | }
272 |
--------------------------------------------------------------------------------
/nav-app/src/app/config.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { DataService, Technique } from './data.service'; //import the DataService component so we can use it
3 |
4 | @Injectable()
5 | export class ConfigService {
6 | public comment_color = "yellow";
7 | private features = new Map();
8 | private featureGroups = new Map();
9 | private featureStructure: object[];
10 | constructor(private dataService: DataService) {
11 | let self = this;
12 | dataService.getConfig().subscribe(function(config: any) {
13 | //parse feature preferences from config json
14 | config["features"].forEach(function(featureObject: any) {
15 | self.setFeature_object(featureObject);
16 | })
17 | //override json preferences with preferences from URL fragment
18 | self.getAllFragments().forEach(function(value: string, key: string) {
19 | let valueBool = (value == 'true');
20 | if (self.isFeature(key) || self.isFeatureGroup(key)) {
21 | // console.log("setting feature", key, valueBool)
22 | self.setFeature(key, valueBool);
23 | }
24 | // else {
25 | // console.log(key, "is not a feature")
26 | // }
27 | })
28 | self.featureStructure = config["features"]
29 | self.comment_color = config["comment_color"]
30 | })
31 | }
32 |
33 | public getFeatureList(): object[] {
34 | if (!this.featureStructure) return []
35 | return this.featureStructure;
36 | }
37 |
38 | public getFeature(featureName: string): boolean {
39 | return this.features.get(featureName);
40 | }
41 |
42 | /**
43 | * Return true if any/all features in the group are enabled
44 | * @param featureGroup feature group name
45 | * @param type 'any' or 'all' for logical or/and
46 | * @return true iffany/all are enabled, false otherwise
47 | */
48 | public getFeatureGroup(featureGroup: string, type?: string): boolean {
49 | if (!this.featureGroups.has(featureGroup)) return true;
50 |
51 | let subFeatures = this.featureGroups.get(featureGroup)
52 | let count = this.getFeatureGroupCount(featureGroup);
53 | return type == "any" ? count > 0 : count === subFeatures.length;
54 | }
55 |
56 | /**
57 | * Return the number of enabled features in the group
58 | * @param featureGroup feature group name
59 | * @return the number of enabled features in the group, or -1 if
60 | * the group does not exist
61 | */
62 | public getFeatureGroupCount(featureGroup: string): number {
63 | if (!this.featureGroups.has(featureGroup)) return -1;
64 | let count = 0
65 | let subFeatures = this.featureGroups.get(featureGroup)
66 | for (let i = 0; i < subFeatures.length; i++) {
67 | if (this.getFeature(subFeatures[i])) count += 1
68 | }
69 | return count;
70 | }
71 |
72 | /**
73 | * Recursively search an object for boolean properties, set these as features
74 | * Take a key:value pair of an object. If the value is a boolean, set the
75 | * feature[key] to value. Otherwise recursively walk value to find boolean
76 | * options.
77 | *
78 | * Additionally, if the given feature grouping (where value is an obj)
79 | * has been previously defined, boolean properties assigned to the grouping
80 | * name will apply to all subfeatures of the grouping.
81 | *
82 | * @param featureName string, the fieldname the value was found in
83 | * @param value boolean:object the value of the field. If a boolean,
84 | * sets feature[featureName] = value, otherwise walks recursively
85 | */
86 | public setFeature(featureName: string, value: any): string[] {
87 | let self = this
88 | // console.log(featureName, value);
89 |
90 | if (typeof(value) == "boolean") { //base case
91 | if (this.featureGroups.has(featureName)) { //feature group, assign to all subfeatures
92 | this.featureGroups.get(featureName).forEach(function(subFeatureName: string) {
93 | self.setFeature(subFeatureName, value);
94 | })
95 | } else { //single feature
96 | this.features.set(featureName, value);
97 | }
98 | return [featureName];
99 | }
100 |
101 | if (typeof(value) == "object") { //keep walking
102 | let subfeatures = [];
103 | Object.keys(value).forEach(function(fieldname: string) {
104 | subfeatures = Array.prototype.concat(subfeatures, self.setFeature(fieldname, value[fieldname]));
105 | })
106 | this.featureGroups.set(featureName, subfeatures);
107 | return subfeatures;
108 | }
109 | }
110 |
111 | /**
112 | * given a set of feature objects, set the enabledness of that object and all subobjects
113 | *
114 | * @param featureObject {name: string, enabled: boolean, subfeatures?: featureObject[] }
115 | * Of enabled is false and it has subfeatures, they will all be forced to be false too
116 | * @param override Set all subfeatures, and their subfeatures, values to
117 | * this value
118 | */
119 | public setFeature_object(featureObject: any, override=null):string[] {
120 | let self = this
121 |
122 | // base case
123 | if (!featureObject.hasOwnProperty("subfeatures")) {
124 |
125 | let enabled = override !== null? override : featureObject.enabled
126 | this.features.set(featureObject.name, enabled)
127 | return [featureObject.name]
128 | } else { //has subfeatures
129 | override = override ? override : !featureObject.enabled ? false : null;
130 | let subfeatures = [];
131 | featureObject.subfeatures.forEach(function(subfeature) {
132 | subfeatures = Array.prototype.concat(subfeatures, self.setFeature_object(subfeature, override))
133 | })
134 | this.featureGroups.set(featureObject.name, subfeatures)
135 | return subfeatures;
136 | }
137 |
138 |
139 | }
140 |
141 | /**
142 | * Return if the given string corresponds to a defined feature
143 | * @param featureName the name of the feature
144 | * @return true if the feature exists, false otherwise
145 | */
146 | public isFeature(featureName: string): boolean {
147 | return this.features.has(featureName)
148 | }
149 | /**
150 | * return if the given string corresponds to a defined feature group
151 | * @param featureGroupName the name of the feature group
152 | * @return true if it is a feature group, false otherwise
153 | */
154 | public isFeatureGroup(featureGroupName: string): boolean {
155 | return this.featureGroups.has(featureGroupName);
156 | }
157 |
158 | public getFeatureGroups(): string[] {
159 | let keys = [];
160 | this.featureGroups.forEach(function(value, key) { keys.push(key) })
161 | return keys;
162 | }
163 |
164 | public getFeatures(): string[] {
165 | let keys = [];
166 | this.features.forEach(function(value, key) { keys.push(key) })
167 | return keys;
168 | }
169 |
170 | /**
171 | * Get all url fragments
172 | * @param url optional, url to parse instead of window location href
173 | * @return all fragments as key-value pairs
174 | */
175 | getAllFragments(url?: string): Map {
176 | if (!url) url = window.location.href;
177 | let fragments = new Map();
178 | let regex = /[#&](\w+)=(\w+)/g
179 |
180 | // let results = url.match(regex)
181 | var match;
182 | while (match = regex.exec(url)) {
183 | fragments.set(match[1], match[2])
184 | }
185 |
186 | return fragments;
187 | }
188 |
189 | }
190 |
--------------------------------------------------------------------------------
/layers/LAYERFORMATv2_1.md:
--------------------------------------------------------------------------------
1 | # ATT&CKTM Navigator Layer File Format Definition
2 | This document describes **Version 2.1** of the MITRE ATT&CK Navigator Layer file format. The ATT&CK Navigator stores layers as JSON, therefore this document defines the JSON properties in a layer file.
3 |
4 | ## Property Table
5 |
6 | | Name | Type | Required? | Default Value (if not present) | Description |
7 | | :------------- | :------------- | :------------- | :------------- | :------------- |
8 | | version | String | Yes | n/a | Must be "2.1" |
9 | | name | String | Yes | n/a | The name of the layer |
10 | | description | String | No | "" | A free-form text field that describes the contents or intent of the layer |
11 | | domain | String | Yes | n/a | Technology domain that this layer represents. Valid values are: "mitre-enterprise" or "mitre-mobile" |
12 | | filters |Filter object | No | | See Filter object definition below
13 | | sorting | Number | No | 0 | Specifies the ordering of the techniques within each tactic category as follows:
**0**: sort ascending alphabetically by technique name
**1**: sort descending alphabetically by technique name
**2**: sort ascending by technique score
**3**: sort descending by technique score |
14 | | viewMode | Number | No | 0 | Specifies the view mode for the layer as follows:
**0**: display the full table with tactic and technique names
**1**: display compact table with abbreviated tactic and technique names
**2**: display mini table with no text with the exception of tooltips |
15 | | hideDisabled | Boolean | No | false | Specifies whether techniques that have been disabled are still displayed (greyed-out) or omitted from the view as follows:
**true**: omit techniques marked as disabled from the view
**false**: include disabled techniques in the view but display as greyed-out |
16 | | techniques | Array of Technique objects | No | | See definition of Technique object below |
17 | | gradient | Gradient object | No | Red to Green, minValue=0, maxValue=100 | See definition of Gradient object below |
18 | | legendItems | Array of LegendItem objects | no | | See definition of LegendItem object below |
19 | | showTacticRowBackground | boolean | no | false | If true, the tactic row background color will be the value of the _tacticRowBackground_ field |
20 | | tacticRowBackground | string | no | "#dddddd" | The tactic row background color |
21 | | selectTechniquesAcrossTactics | boolean | no | true | If true, selecting a technique also selects all instances with the same technique ID |
22 | | metadata | Array of Metadata objects | No | | User defined metadata for this layer. See definition of Metadata object below |
23 |
24 |
25 | ## Filter Object Properties
26 |
27 | | Name | Type | Required? | Default Value (if not present) | Description |
28 | | :------------- | :------------- | :------------- | :------------- | :------------- |
29 | | stages | Array of String | No | ["act"] | Specifies the logical stages of the attack lifecycle to display. Valid choices are: "prepare" and "act". Array must contain at least one of these values |
30 | | platforms | Array of String | No | All platforms defined within domain | Specifies the platforms within the technology domain – only those techniques tagged with these platforms are to be displayed. Valid values are as follows:
**domain=mitre-enterprise**: "windows", "linux", "mac"
**domain=mitre-mobile**: "android", "ios" |
31 |
32 | ## Technique Object properties
33 |
34 | | Name | Type | Required? | Default Value (if not present) | Description |
35 | | :------------- | :------------- | :------------- | :------------- | :------------- |
36 | | techniqueID | String | Yes | n/a | Unique identifier of the ATT&CK technique, e.g. "T####" |
37 | | tactic | String | No | n/a | Unique identifier of the ATT&CK technique's tactic, e.g. "lateral-movement". If the field is not present, the annotations for the technique will appear under every tactic the technique belongs to |
38 | | comment | String | No | "" | Free-text field |
39 | | enabled | Boolean | No | true | Specifies if the technique is considered enabled or disabled in this layer |
40 | | score | Number | No | (unscored) | Optional numeric score assigned to this technique in the layer. If omitted, the technique is considered to be "unscored" meaning that it will not be assigned a color from the gradient by the Navigator |
41 | | color | String | No | "" | Explicit color value assigned to the technique in this layer. Note that explicitly defined color overrides any color implied by the score – the Navigator will display the technique using the explicitly defined color |
42 | | metadata | Array of Metadata objects | No | | User defined metadata for this technique. See definition of Metadata object below |
43 |
44 | ## Gradient Object properties
45 | | Name | Type | Required? | Default Value (if not present) | Description |
46 | | :------------- | :------------- | :------------- | :------------- | :------------- |
47 | | colors | Array of String | Yes | n/a | Specifies the hexadecimal RGB color values that constitute the color spectrum in use. The array must contain at least two (2) values, corresponding to the minValue and maxValue scores |
48 | | minValue | Number | Yes | n/a | Lower bound score of the gradient |
49 | | maxValue | Number | Yes | n/a | Upper bound score of the gradient. *Note: maxValue must be > minValue* |
50 |
51 | ## LegendItem Object properties
52 | | Name | Type | Required? | Default Value (if not present) | Description |
53 | | :------------- | :------------- | :------------- | :------------- | :------------- |
54 | | label | String | Yes | n/a | The name of the legend item |
55 | | color | String | Yes | n/a | The color of the legend item |
56 |
57 | ## Metadata Object properties
58 | | Name | Type | Required? | Default Value (if not present) | Description |
59 | | :------------- | :------------- | :------------- | :------------- | :------------- |
60 | | name | String | Yes | n/a | the name of the metadata |
61 | | value | String | Yes | n/a | The value of the metadata |
62 |
63 |
64 | ## Example
65 | The following example illustrates the layer file format:
66 | ```json
67 | {
68 | "name": "example layer",
69 | "version": "2.1",
70 | "domain": "mitre-enterprise",
71 | "description": "hello, world",
72 | "filters": {
73 | "stages": [
74 | "act"
75 | ],
76 | "platforms": [
77 | "windows",
78 | "mac"
79 | ]
80 | },
81 | "sorting": 2,
82 | "viewMode": 0,
83 | "hideDisabled": false,
84 | "techniques": [
85 | {
86 | "techniqueID": "T1155",
87 | "tactic": "execution",
88 | "color": "#fd8d3c",
89 | "comment": "This is a comment for technique T1155 only under the Execution tactic."
90 | },
91 | {
92 | "techniqueID": "T1017",
93 | "tactic": "lateral-movement",
94 | "score": 75
95 | },
96 | {
97 | "techniqueID": "T1010",
98 | "tactic": "discovery",
99 | "enabled": false
100 | },
101 | {
102 | "techniqueID": "T1189",
103 | "tactic": "initial-access",
104 | "metadata": [
105 | {
106 | "name": "T1189 metadata1",
107 | "value": "T1189 metadata1 value"
108 | },
109 | {
110 | "name": "T1189 metadata2",
111 | "value": "T1189 metadata2 value"
112 | }
113 | ]
114 | },
115 | ],
116 | "gradient": {
117 | "colors": [
118 | "#ff6666",
119 | "#ffe766",
120 | "#8ec843"
121 | ],
122 | "minValue": 0,
123 | "maxValue": 100
124 | },
125 | "legendItems": [
126 | {
127 | "label": "Legend Item Label",
128 | "color": "#FF00FF"
129 | }
130 | ],
131 | "showTacticRowBackground": true,
132 | "tacticRowBackground": "#dddddd",
133 | "selectTechniquesAcrossTactics": false,
134 | "metadata": [
135 | {
136 | "name": "layer metadata 1",
137 | "value": "layer metadata 1 value"
138 | },
139 | {
140 | "name": "layer metadata 2",
141 | "value": "layer metadata 2 value"
142 | }
143 | ]
144 | }
145 | ```
146 |
--------------------------------------------------------------------------------
/nav-app/src/app/data.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | // import { HttpClient } from '@angular/common/http'
3 | import { Http } from '@angular/http'
4 | import { Observable } from "rxjs/Rx"
5 | import { fromPromise } from 'rxjs/observable/fromPromise';
6 | import { TaxiiConnect, Server, Collections, Collection, Status } from './taxii2lib';
7 |
8 | @Injectable()
9 | export class DataService {
10 |
11 | constructor(private http: Http) {}
12 |
13 | // Observable for data in config.json
14 | private configData$: Observable