├── 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 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_file_upload_gray_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_done_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_file_download_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /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 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_filter_list_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_format_size_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_keyboard_arrow_up_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /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 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_keyboard_arrow_right_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /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 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_playlist_add_gray_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_remove_circle_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_view_large_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_view_list_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_view_list_grey_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_clear_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /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 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_clear_gray_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_close_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 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 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_insert_comment_gray_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_insert_chart_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_content_copy_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_description_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_insert_chart_gray_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_check_box_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_save_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_save_gray_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_view_medium_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 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 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /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 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_camera_alt_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_visibility_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_visibility_gray_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_lock_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /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 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /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 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_layers_clear_gray_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_lock_open_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_search_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /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 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_texture_gray_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 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 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /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 | 2 | 3 | 4 | 5 | 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 | 2 | 3 | 6 | # 7 | 8 | 9 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_sort_alphabetically_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | A 7 | 8 | 9 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_format_color_fill_gray_nobottom_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_format_color_fill_black_nobottom_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 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 | 2 | 3 | 6 | A 7 | Z 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_sort_numerically_ascending_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 1 7 | 2 8 | 9 | 10 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_sort_alphabetically_descending_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | Z 7 | A 8 | 9 | 10 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_palette_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_sort_numerically_descending_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 2 7 | 1 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /nav-app/src/assets/icons/ic_color_lens_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /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 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /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; 15 | 16 | // Observables for data 17 | private enterpriseData$: Observable; 18 | private mobileData$: Observable; 19 | 20 | // Order of tactics to be displayed in application 21 | private actTacticsOrder: String[] = []; 22 | private prepareTacticsOrder: String[] = []; 23 | private totalTacticsOrder: String[] = []; 24 | 25 | // URLs in case config file doesn't load properly 26 | private enterpriseAttackURL: string = "https://raw.githubusercontent.com/mitre/cti/master/enterprise-attack/enterprise-attack.json"; 27 | private pre_attack_URL: string = "https://raw.githubusercontent.com/mitre/cti/master/pre-attack/pre-attack.json"; 28 | private mobileDataURL: string = "https://raw.githubusercontent.com/mitre/cti/master/mobile-attack/mobile-attack.json"; 29 | 30 | private useTAXIIServer: boolean = false; 31 | private taxiiURL: string = ''; 32 | private taxiiCollections: String[] = []; 33 | 34 | setUpURLs(eAttackURL, preAttackURL, mURL, useTAXIIServer, taxiiURL, taxiiCollections){ 35 | this.enterpriseAttackURL = eAttackURL; 36 | this.pre_attack_URL = preAttackURL; 37 | this.mobileDataURL = mURL; 38 | this.useTAXIIServer = useTAXIIServer; 39 | this.taxiiURL = taxiiURL; 40 | this.taxiiCollections = taxiiCollections; 41 | } 42 | 43 | getConfig(refresh:boolean = false){ 44 | if (refresh || !this.configData$){ 45 | this.configData$ = this.http.get("./assets/config.json").map(res => res.json()) 46 | } 47 | return this.configData$; 48 | } 49 | 50 | getEnterpriseData(refresh: boolean = false, useTAXIIServer: boolean = false){ 51 | if (useTAXIIServer) { 52 | console.log("fetching data from TAXII server") 53 | let conn = new TaxiiConnect(this.taxiiURL, '', '', 5000); 54 | let enterpriseCollectionInfo: any = { 55 | 'id': this.taxiiCollections['enterprise_attack'], 56 | 'title': 'Enterprise ATT&CK', 57 | 'description': '', 58 | 'can_read': true, 59 | 'can_write': false, 60 | 'media_types': ['application/vnd.oasis.stix+json'] 61 | } 62 | const enterpriseCollection = new Collection(enterpriseCollectionInfo, this.taxiiURL + 'stix', conn); 63 | 64 | let preattackCollectionInfo: any = { 65 | 'id': this.taxiiCollections['pre_attack'], 66 | 'title': 'Pre-ATT&CK', 67 | 'description': '', 68 | 'can_read': true, 69 | 'can_write': false, 70 | 'media_types': ['application/vnd.oasis.stix+json'] 71 | } 72 | 73 | const preattackCollection = new Collection(preattackCollectionInfo, this.taxiiURL + 'stix', conn); 74 | 75 | this.enterpriseData$ = Observable.forkJoin( 76 | fromPromise(enterpriseCollection.getObjects('', undefined)), 77 | fromPromise(preattackCollection.getObjects('', undefined)) 78 | ) 79 | } 80 | else if (refresh || !this.enterpriseData$){ 81 | this.enterpriseData$ = Observable.forkJoin( 82 | this.http.get(this.enterpriseAttackURL).map(res => res.json()), 83 | this.http.get(this.pre_attack_URL).map(res => res.json()) 84 | ); 85 | } 86 | return this.enterpriseData$ //observable 87 | } 88 | 89 | getMobileData(refresh: boolean = false, useTAXIIServer: boolean = false){ 90 | //load from remote if not yet loaded or refresh=true 91 | if (useTAXIIServer) { 92 | console.log("fetching data from TAXII server") 93 | let conn = new TaxiiConnect(this.taxiiURL, '', '', 5000); 94 | let mobileCollectionInfo: any = { 95 | 'id': this.taxiiCollections['mobile_attack'], 96 | 'title': 'Mobile ATT&CK', 97 | 'description': '', 98 | 'can_read': true, 99 | 'can_write': false, 100 | 'media_types': ['application/vnd.oasis.stix+json'] 101 | } 102 | const mobileCollection = new Collection(mobileCollectionInfo, this.taxiiURL + 'stix', conn); 103 | 104 | let preattackCollectionInfo: any = { 105 | 'id': this.taxiiCollections['pre_attack'], 106 | 'title': 'Pre-ATT&CK', 107 | 'description': '', 108 | 'can_read': true, 109 | 'can_write': false, 110 | 'media_types': ['application/vnd.oasis.stix+json'] 111 | } 112 | 113 | const preattackCollection = new Collection(preattackCollectionInfo, this.taxiiURL + 'stix', conn); 114 | 115 | this.mobileData$ = Observable.forkJoin( 116 | fromPromise(mobileCollection.getObjects('', undefined)), 117 | fromPromise(preattackCollection.getObjects('', undefined)) 118 | ) 119 | } 120 | else if (refresh || !this.mobileData$){ 121 | this.mobileData$ = Observable.forkJoin( 122 | this.http.get(this.mobileDataURL).map(res => res.json()), 123 | this.http.get(this.pre_attack_URL).map(res => res.json()) 124 | ); 125 | } 126 | return this.mobileData$ //observable 127 | } 128 | 129 | setTacticOrder(retrievedTactics){ 130 | // this.totalTacticsOrder = retrievedTactics; 131 | for(var i = 0; i < retrievedTactics.length; i++){ 132 | var phase = retrievedTactics[i].phase; 133 | var tactic = retrievedTactics[i].tactic; 134 | if(phase.localeCompare("prepare") === 0){ 135 | this.prepareTacticsOrder.push(tactic); 136 | } else { 137 | this.actTacticsOrder.push(tactic); 138 | } 139 | this.totalTacticsOrder.push(tactic); 140 | } 141 | } 142 | 143 | /** 144 | * Convert a list of techniques to a list of tactics, each one containing the techniques of the tactic 145 | * @param {[object]} techniques the techniques to convert 146 | * @return {object} object with keys of each tactic and values of the techniques of those tactics 147 | */ 148 | techniquesToTactics(techniques: Technique[]) { 149 | if (techniques.length === 0) return [] 150 | var tactics = {}; 151 | techniques.forEach(function(technique) { 152 | var tt = technique.tactic; 153 | if (tactics[tt]) tactics[tt].push(technique) 154 | else tactics[tt] = [technique]; 155 | 156 | }); 157 | return tactics; 158 | } 159 | 160 | /** 161 | * Extract all tactic names from the list of techniques 162 | * @param {[object]} techniques the techniques to extract 163 | * @return {[string]} an array of all tactic names 164 | */ 165 | tacticNames(techniques: Technique[]) { 166 | if (techniques.length === 0) return [] 167 | var techniquesFinal: String[] = []; 168 | var seen = new Set(); 169 | techniques.forEach(function(technique) { 170 | var tt = technique.tactic; 171 | seen.add(tt); 172 | }); 173 | for(var i = 0; i < this.totalTacticsOrder.length; i++){ 174 | var tactic = this.totalTacticsOrder[i]; 175 | if(seen.has(tactic)){ 176 | techniquesFinal.push(tactic); 177 | } 178 | } 179 | return techniquesFinal; 180 | } 181 | } 182 | 183 | export class Technique { 184 | description: string; 185 | external_references_url: string; 186 | id: string; 187 | tactic: string; 188 | name: string; 189 | platforms: string[]; 190 | technique_id: string; 191 | technique_tactic_union_id: string; 192 | constructor(name: string, description: string, tactic: string, url: string, platforms: string[], id: string, tid: string) { 193 | this.name = name; this.description = description, this.tactic = tactic; 194 | this.id = id; this.platforms = platforms; this.external_references_url = url; 195 | this.technique_id = tid; 196 | this.technique_tactic_union_id = this.technique_id + "^" + this.tactic; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /layers/data/samples/ATTACKcon/Submitter_Responses.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Submitter Responses", 3 | "version": "2.1", 4 | "domain": "mitre-enterprise", 5 | "description": "Answers submitted to the ATT&CKcon CFP in response to \"What is your favorite technique?\"", 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": "T1015", 22 | "tactic": "persistence", 23 | "score": 1, 24 | "color": "", 25 | "comment": "", 26 | "enabled": true 27 | }, 28 | { 29 | "techniqueID": "T1015", 30 | "tactic": "privilege-escalation", 31 | "score": 1, 32 | "color": "", 33 | "comment": "", 34 | "enabled": true 35 | }, 36 | { 37 | "techniqueID": "T1098", 38 | "tactic": "credential-access", 39 | "score": 1, 40 | "color": "", 41 | "comment": "", 42 | "enabled": true 43 | }, 44 | { 45 | "techniqueID": "T1098", 46 | "tactic": "persistence", 47 | "score": 1, 48 | "color": "", 49 | "comment": "", 50 | "enabled": true 51 | }, 52 | { 53 | "techniqueID": "T1017", 54 | "tactic": "lateral-movement", 55 | "score": 1, 56 | "color": "", 57 | "comment": "", 58 | "enabled": true 59 | }, 60 | { 61 | "techniqueID": "T1067", 62 | "tactic": "persistence", 63 | "score": 1, 64 | "color": "", 65 | "comment": "", 66 | "enabled": true 67 | }, 68 | { 69 | "techniqueID": "T1110", 70 | "tactic": "credential-access", 71 | "score": 1, 72 | "color": "", 73 | "comment": "", 74 | "enabled": true 75 | }, 76 | { 77 | "techniqueID": "T1191", 78 | "tactic": "defense-evasion", 79 | "score": 1, 80 | "color": "", 81 | "comment": "", 82 | "enabled": true 83 | }, 84 | { 85 | "techniqueID": "T1191", 86 | "tactic": "execution", 87 | "score": 1, 88 | "color": "", 89 | "comment": "", 90 | "enabled": true 91 | }, 92 | { 93 | "techniqueID": "T1059", 94 | "tactic": "execution", 95 | "score": 1, 96 | "color": "", 97 | "comment": "", 98 | "enabled": true 99 | }, 100 | { 101 | "techniqueID": "T1043", 102 | "tactic": "command-and-control", 103 | "score": 2, 104 | "color": "", 105 | "comment": "", 106 | "enabled": true 107 | }, 108 | { 109 | "techniqueID": "T1122", 110 | "tactic": "defense-evasion", 111 | "score": 1, 112 | "color": "", 113 | "comment": "", 114 | "enabled": true 115 | }, 116 | { 117 | "techniqueID": "T1122", 118 | "tactic": "persistence", 119 | "score": 1, 120 | "color": "", 121 | "comment": "", 122 | "enabled": true 123 | }, 124 | { 125 | "techniqueID": "T1003", 126 | "tactic": "credential-access", 127 | "score": 7, 128 | "color": "", 129 | "comment": "", 130 | "enabled": true 131 | }, 132 | { 133 | "techniqueID": "T1094", 134 | "tactic": "command-and-control", 135 | "score": 1, 136 | "color": "", 137 | "comment": "", 138 | "enabled": true 139 | }, 140 | { 141 | "techniqueID": "T1073", 142 | "tactic": "defense-evasion", 143 | "score": 1, 144 | "color": "", 145 | "comment": "", 146 | "enabled": true 147 | }, 148 | { 149 | "techniqueID": "T1048", 150 | "tactic": "exfiltration", 151 | "score": 2, 152 | "color": "", 153 | "comment": "", 154 | "enabled": true 155 | }, 156 | { 157 | "techniqueID": "T1190", 158 | "tactic": "initial-access", 159 | "score": 2, 160 | "color": "", 161 | "comment": "", 162 | "enabled": true 163 | }, 164 | { 165 | "techniqueID": "T1179", 166 | "tactic": "persistence", 167 | "score": 3, 168 | "color": "", 169 | "comment": "", 170 | "enabled": true 171 | }, 172 | { 173 | "techniqueID": "T1179", 174 | "tactic": "privilege-escalation", 175 | "score": 3, 176 | "color": "", 177 | "comment": "", 178 | "enabled": true 179 | }, 180 | { 181 | "techniqueID": "T1179", 182 | "tactic": "credential-access", 183 | "score": 3, 184 | "color": "", 185 | "comment": "", 186 | "enabled": true 187 | }, 188 | { 189 | "techniqueID": "T1056", 190 | "tactic": "collection", 191 | "score": 1, 192 | "color": "", 193 | "comment": "", 194 | "enabled": true 195 | }, 196 | { 197 | "techniqueID": "T1056", 198 | "tactic": "credential-access", 199 | "score": 1, 200 | "color": "", 201 | "comment": "", 202 | "enabled": true 203 | }, 204 | { 205 | "techniqueID": "T1208", 206 | "tactic": "credential-access", 207 | "score": 3, 208 | "color": "", 209 | "comment": "", 210 | "enabled": true 211 | }, 212 | { 213 | "techniqueID": "T1036", 214 | "tactic": "defense-evasion", 215 | "score": 1, 216 | "color": "", 217 | "comment": "", 218 | "enabled": true 219 | }, 220 | { 221 | "techniqueID": "T1075", 222 | "tactic": "lateral-movement", 223 | "score": 1, 224 | "color": "", 225 | "comment": "", 226 | "enabled": true 227 | }, 228 | { 229 | "techniqueID": "T1013", 230 | "tactic": "persistence", 231 | "score": 1, 232 | "color": "", 233 | "comment": "", 234 | "enabled": true 235 | }, 236 | { 237 | "techniqueID": "T1013", 238 | "tactic": "privilege-escalation", 239 | "score": 1, 240 | "color": "", 241 | "comment": "", 242 | "enabled": true 243 | }, 244 | { 245 | "techniqueID": "T1086", 246 | "tactic": "execution", 247 | "score": 6, 248 | "color": "", 249 | "comment": "", 250 | "enabled": true 251 | }, 252 | { 253 | "techniqueID": "T1093", 254 | "tactic": "defense-evasion", 255 | "score": 1, 256 | "color": "", 257 | "comment": "", 258 | "enabled": true 259 | }, 260 | { 261 | "techniqueID": "T1055", 262 | "tactic": "defense-evasion", 263 | "score": 2, 264 | "color": "", 265 | "comment": "", 266 | "enabled": true 267 | }, 268 | { 269 | "techniqueID": "T1055", 270 | "tactic": "privilege-escalation", 271 | "score": 2, 272 | "color": "", 273 | "comment": "", 274 | "enabled": true 275 | }, 276 | { 277 | "techniqueID": "T1117", 278 | "tactic": "defense-evasion", 279 | "score": 3, 280 | "color": "", 281 | "comment": "", 282 | "enabled": true 283 | }, 284 | { 285 | "techniqueID": "T1117", 286 | "tactic": "execution", 287 | "score": 3, 288 | "color": "", 289 | "comment": "", 290 | "enabled": true 291 | }, 292 | { 293 | "techniqueID": "T1218", 294 | "tactic": "defense-evasion", 295 | "score": 1, 296 | "color": "", 297 | "comment": "", 298 | "enabled": true 299 | }, 300 | { 301 | "techniqueID": "T1218", 302 | "tactic": "execution", 303 | "score": 1, 304 | "color": "", 305 | "comment": "", 306 | "enabled": true 307 | }, 308 | { 309 | "techniqueID": "T1151", 310 | "tactic": "defense-evasion", 311 | "score": 2, 312 | "color": "", 313 | "comment": "", 314 | "enabled": true 315 | }, 316 | { 317 | "techniqueID": "T1151", 318 | "tactic": "execution", 319 | "score": 2, 320 | "color": "", 321 | "comment": "", 322 | "enabled": true 323 | }, 324 | { 325 | "techniqueID": "T1193", 326 | "tactic": "initial-access", 327 | "score": 1, 328 | "color": "", 329 | "comment": "", 330 | "enabled": true 331 | }, 332 | { 333 | "techniqueID": "T1206", 334 | "tactic": "privilege-escalation", 335 | "score": 2, 336 | "color": "", 337 | "comment": "", 338 | "enabled": true 339 | }, 340 | { 341 | "techniqueID": "T1209", 342 | "tactic": "persistence", 343 | "score": 1, 344 | "color": "", 345 | "comment": "", 346 | "enabled": true 347 | }, 348 | { 349 | "techniqueID": "T1199", 350 | "tactic": "initial-access", 351 | "score": 1, 352 | "color": "", 353 | "comment": "", 354 | "enabled": true 355 | }, 356 | { 357 | "techniqueID": "T1111", 358 | "tactic": "credential-access", 359 | "score": 1, 360 | "color": "", 361 | "comment": "", 362 | "enabled": true 363 | }, 364 | { 365 | "techniqueID": "T1077", 366 | "tactic": "lateral-movement", 367 | "score": 1, 368 | "color": "", 369 | "comment": "", 370 | "enabled": true 371 | }, 372 | { 373 | "techniqueID": "T1084", 374 | "tactic": "persistence", 375 | "score": 1, 376 | "color": "", 377 | "comment": "", 378 | "enabled": true 379 | }, 380 | { 381 | "techniqueID": "T1028", 382 | "tactic": "execution", 383 | "score": 1, 384 | "color": "", 385 | "comment": "", 386 | "enabled": true 387 | }, 388 | { 389 | "techniqueID": "T1028", 390 | "tactic": "lateral-movement", 391 | "score": 1, 392 | "color": "", 393 | "comment": "", 394 | "enabled": true 395 | } 396 | ], 397 | "gradient": { 398 | "colors": [ 399 | "#bedbf9", 400 | "#24282d" 401 | ], 402 | "minValue": 1, 403 | "maxValue": 7 404 | }, 405 | "legendItems": [ 406 | { 407 | "color": "#bedbf9", 408 | "label": "1" 409 | }, 410 | { 411 | "color": "#24282d", 412 | "label": "7" 413 | } 414 | ], 415 | "showTacticRowBackground": true, 416 | "tacticRowBackground": "#205b8f", 417 | "selectTechniquesAcrossTactics": true 418 | } -------------------------------------------------------------------------------- /layers/data/samples/Bear_APT.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "all techniques used by an APT group with phrase 'bear' in the group aliases", 3 | "version": "2.1", 4 | "name": "*Bear APTs", 5 | "domain": "mitre-enterprise", 6 | "techniques": [ 7 | { 8 | "color": "#ff6666", 9 | "comment": "used by Cozy Bear", 10 | "techniqueID": "T1045" 11 | }, 12 | { 13 | "color": "#ff6666", 14 | "comment": "used by Energetic Bear, Fancy Bear", 15 | "techniqueID": "T1107" 16 | }, 17 | { 18 | "color": "#ff6666", 19 | "comment": "used by Fancy Bear", 20 | "techniqueID": "T1074" 21 | }, 22 | { 23 | "color": "#ff6666", 24 | "comment": "used by Fancy Bear", 25 | "techniqueID": "T1134" 26 | }, 27 | { 28 | "color": "#ff6666", 29 | "comment": "used by Fancy Bear", 30 | "techniqueID": "T1122" 31 | }, 32 | { 33 | "color": "#ff6666", 34 | "comment": "used by Fancy Bear", 35 | "techniqueID": "T1001" 36 | }, 37 | { 38 | "color": "#ff6666", 39 | "comment": "used by Fancy Bear", 40 | "techniqueID": "T1068" 41 | }, 42 | { 43 | "color": "#ff6666", 44 | "comment": "used by Cozy Bear", 45 | "techniqueID": "T1088" 46 | }, 47 | { 48 | "color": "#ff6666", 49 | "comment": "used by WhiteBear", 50 | "techniqueID": "T1077" 51 | }, 52 | { 53 | "color": "#ff6666", 54 | "comment": "used by WhiteBear", 55 | "techniqueID": "T1018" 56 | }, 57 | { 58 | "color": "#ff6666", 59 | "comment": "used by Energetic Bear", 60 | "techniqueID": "T1076" 61 | }, 62 | { 63 | "color": "#ff6666", 64 | "comment": "used by Energetic Bear", 65 | "techniqueID": "T1133" 66 | }, 67 | { 68 | "color": "#ff6666", 69 | "comment": "used by Energetic Bear, Cozy Bear", 70 | "techniqueID": "T1086" 71 | }, 72 | { 73 | "color": "#ff6666", 74 | "comment": "used by Fancy Bear", 75 | "techniqueID": "T1099" 76 | }, 77 | { 78 | "color": "#ff6666", 79 | "comment": "used by Cozy Bear, Fancy Bear", 80 | "techniqueID": "T1075" 81 | }, 82 | { 83 | "color": "#ff6666", 84 | "comment": "used by Energetic Bear, Fancy Bear", 85 | "techniqueID": "T1105" 86 | }, 87 | { 88 | "color": "#ff6666", 89 | "comment": "used by Energetic Bear", 90 | "techniqueID": "T1114" 91 | }, 92 | { 93 | "color": "#ff6666", 94 | "comment": "used by Cozy Bear", 95 | "techniqueID": "T1015" 96 | }, 97 | { 98 | "color": "#ff6666", 99 | "comment": "used by WhiteBear, Fancy Bear", 100 | "techniqueID": "T1083" 101 | }, 102 | { 103 | "color": "#ff6666", 104 | "comment": "used by Fancy Bear", 105 | "techniqueID": "T1027" 106 | }, 107 | { 108 | "color": "#ff6666", 109 | "comment": "used by Cozy Bear", 110 | "techniqueID": "T1084" 111 | }, 112 | { 113 | "color": "#ff6666", 114 | "comment": "used by Energetic Bear", 115 | "techniqueID": "T1136" 116 | }, 117 | { 118 | "color": "#ff6666", 119 | "comment": "used by WhiteBear", 120 | "techniqueID": "T1012" 121 | }, 122 | { 123 | "color": "#ff6666", 124 | "comment": "used by Energetic Bear, Cozy Bear, Fancy Bear", 125 | "techniqueID": "T1070" 126 | }, 127 | { 128 | "color": "#ff6666", 129 | "comment": "used by Fancy Bear", 130 | "techniqueID": "T1040" 131 | }, 132 | { 133 | "color": "#ff6666", 134 | "comment": "used by Fancy Bear", 135 | "techniqueID": "T1081" 136 | }, 137 | { 138 | "color": "#ff6666", 139 | "comment": "used by Energetic Bear, Fancy Bear", 140 | "techniqueID": "T1003" 141 | }, 142 | { 143 | "color": "#ff6666", 144 | "comment": "used by Fancy Bear", 145 | "techniqueID": "T1137" 146 | }, 147 | { 148 | "color": "#ff6666", 149 | "comment": "used by Fancy Bear", 150 | "techniqueID": "T1090" 151 | }, 152 | { 153 | "color": "#ff6666", 154 | "comment": "used by Energetic Bear", 155 | "techniqueID": "T1187" 156 | }, 157 | { 158 | "color": "#ff6666", 159 | "comment": "used by Fancy Bear, WhiteBear", 160 | "techniqueID": "T1082" 161 | }, 162 | { 163 | "color": "#ff6666", 164 | "comment": "used by Fancy Bear", 165 | "techniqueID": "T1025" 166 | }, 167 | { 168 | "color": "#ff6666", 169 | "comment": "used by Energetic Bear, Cozy Bear", 170 | "techniqueID": "T1053" 171 | }, 172 | { 173 | "color": "#ff6666", 174 | "comment": "used by Fancy Bear", 175 | "techniqueID": "T1173" 176 | }, 177 | { 178 | "color": "#ff6666", 179 | "comment": "used by WhiteBear", 180 | "techniqueID": "T1124" 181 | }, 182 | { 183 | "color": "#ff6666", 184 | "comment": "used by Fancy Bear", 185 | "techniqueID": "T1067" 186 | }, 187 | { 188 | "color": "#ff6666", 189 | "comment": "used by Cozy Bear", 190 | "techniqueID": "T1060" 191 | }, 192 | { 193 | "color": "#ff6666", 194 | "comment": "used by Cozy Bear", 195 | "techniqueID": "T1172" 196 | }, 197 | { 198 | "color": "#ff6666", 199 | "comment": "used by Fancy Bear", 200 | "techniqueID": "T1091" 201 | }, 202 | { 203 | "color": "#ff6666", 204 | "comment": "used by Fancy Bear", 205 | "techniqueID": "T1033" 206 | }, 207 | { 208 | "color": "#ff6666", 209 | "comment": "used by Energetic Bear", 210 | "techniqueID": "T1036" 211 | }, 212 | { 213 | "color": "#ff6666", 214 | "comment": "used by WhiteBear", 215 | "techniqueID": "T1066" 216 | }, 217 | { 218 | "color": "#ff6666", 219 | "comment": "used by WhiteBear", 220 | "techniqueID": "T1007" 221 | }, 222 | { 223 | "color": "#ff6666", 224 | "comment": "used by Fancy Bear", 225 | "techniqueID": "T1078" 226 | }, 227 | { 228 | "color": "#ff6666", 229 | "comment": "used by Cozy Bear", 230 | "techniqueID": "T1188" 231 | }, 232 | { 233 | "color": "#ff6666", 234 | "comment": "used by Energetic Bear", 235 | "techniqueID": "T1135" 236 | }, 237 | { 238 | "color": "#ff6666", 239 | "comment": "used by Energetic Bear", 240 | "techniqueID": "T1043" 241 | }, 242 | { 243 | "color": "#ff6666", 244 | "comment": "used by Fancy Bear, Energetic Bear", 245 | "techniqueID": "T1113" 246 | }, 247 | { 248 | "color": "#ff6666", 249 | "comment": "used by Fancy Bear", 250 | "techniqueID": "T1085" 251 | }, 252 | { 253 | "color": "#ff6666", 254 | "comment": "used by Energetic Bear", 255 | "techniqueID": "T1100" 256 | }, 257 | { 258 | "color": "#ff6666", 259 | "comment": "used by Fancy Bear", 260 | "techniqueID": "T1120" 261 | }, 262 | { 263 | "color": "#ff6666", 264 | "comment": "used by Cozy Bear", 265 | "techniqueID": "T1047" 266 | }, 267 | { 268 | "color": "#ff6666", 269 | "comment": "used by Energetic Bear, Cozy Bear", 270 | "techniqueID": "T1064" 271 | }, 272 | { 273 | "color": "#ff6666", 274 | "comment": "used by Energetic Bear, WhiteBear", 275 | "techniqueID": "T1110" 276 | }, 277 | { 278 | "color": "#ff6666", 279 | "comment": "used by Fancy Bear", 280 | "techniqueID": "T1071" 281 | }, 282 | { 283 | "color": "#ff6666", 284 | "comment": "used by Fancy Bear", 285 | "techniqueID": "T1056" 286 | }, 287 | { 288 | "color": "#ff6666", 289 | "comment": "used by WhiteBear", 290 | "techniqueID": "T1016" 291 | }, 292 | { 293 | "color": "#ff6666", 294 | "comment": "used by WhiteBear, Fancy Bear", 295 | "techniqueID": "T1057" 296 | }, 297 | { 298 | "color": "#ff6666", 299 | "comment": "used by WhiteBear", 300 | "techniqueID": "T1049" 301 | } 302 | ], 303 | "legendItems": [ 304 | { 305 | "label": "has 'bear' in group aliases", 306 | "color": "#ff6666" 307 | } 308 | ] 309 | } 310 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------