Skip to content

Commit

Permalink
#1766 WIP: Add a section to manage attack pattern catalogs
Browse files Browse the repository at this point in the history
  • Loading branch information
nadouani committed Jan 29, 2021
1 parent b7109f1 commit 839a7e1
Show file tree
Hide file tree
Showing 10 changed files with 525 additions and 6 deletions.
2 changes: 2 additions & 0 deletions frontend/app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@
<script src="scripts/controllers/admin/AdminCustomFieldsCtrl.js"></script>
<script src="scripts/controllers/admin/AdminObservablesCtrl.js"></script>
<script src="scripts/controllers/admin/AdminUiSettingsCtrl.js"></script>
<script src="scripts/controllers/admin/attack/AttackPatternListCtrl.js"></script>
<script src="scripts/controllers/admin/organisation/case-template/AdminCaseTemplateImportCtrl.js"></script>
<script src="scripts/controllers/admin/organisation/case-template/AdminCaseTemplateTasksCtrl.js"></script>
<script src="scripts/controllers/admin/organisation/OrgDetailsCtrl.js"></script>
Expand Down Expand Up @@ -284,6 +285,7 @@
<script src="scripts/services/api/AlertingSrv.js"></script>
<script src="scripts/services/api/AnalyzerSrv.js"></script>
<script src="scripts/services/api/AnalyzerTemplateSrv.js"></script>
<script src="scripts/services/api/AttackPatternSrv.js"></script>
<script src="scripts/services/api/AuditSrv.js"></script>
<script src="scripts/services/api/AuthenticationSrv.js"></script>
<script src="scripts/services/api/CaseSrv.js"></script>
Expand Down
15 changes: 15 additions & 0 deletions frontend/app/scripts/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,21 @@ angular.module('thehive', [
permissions: ['manageTaxonomy']
}
})
.state('app.administration.attackPatterns', {
url: '/attack-patterns',
templateUrl: 'views/partials/admin/attack/list.html',
controller: 'AttackPatternListCtrl',
controllerAs: '$vm',
title: 'ATT&CK patterns administration',
resolve: {
appConfig: function(VersionSrv) {
return VersionSrv.get();
}
}
// guard: {
// permissions: ['manageTaxonomy']
// }
})
.state('app.administration.organisations', {
url: '/organisations',
templateUrl: 'views/partials/admin/organisation/list.html',
Expand Down
159 changes: 159 additions & 0 deletions frontend/app/scripts/controllers/admin/attack/AttackPatternListCtrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
(function() {
'use strict';

angular.module('theHiveControllers')
.controller('AttackPatternListCtrl', AttackPatternListCtrl)
.controller('AttackPatternDialogCtrl', AttackPatternDialogCtrl)
.controller('AttackPatternImportCtrl', AttackPatternImportCtrl);

function AttackPatternListCtrl($scope, $uibModal, PaginatedQuerySrv, FilteringSrv, AttackPatternSrv, NotificationSrv, ModalSrv, appConfig) {
var self = this;

this.appConfig = appConfig;

self.load = function() {
this.loading = true;

this.list = new PaginatedQuerySrv({
name: 'attack-patterns',
root: undefined,
objectType: 'pattern',
version: 'v1',
scope: $scope,
sort: self.filtering.context.sort,
loadAll: false,
pageSize: self.filtering.context.pageSize,
filter: this.filtering.buildQuery(),
baseFilter: {
_field: 'patternType',
_value:'attack-pattern'
},
operations: [
{'_name': 'listPattern'}
],
extraData: ['enabled'],
onUpdate: function() {
self.loading = false;
}
});
};

self.show = function(patternId) {
$uibModal.open({
animation: true,
templateUrl: 'views/partials/admin/attack/view.html',
controller: 'AttackPatternDialogCtrl',
controllerAs: '$modal',
size: 'max',
resolve: {
pattern: function() {
return AttackPatternSrv.get(patternId);
}
}
});
};


self.import = function () {
var modalInstance = $uibModal.open({
animation: true,
templateUrl: 'views/partials/admin/attack/import.html',
controller: 'AttackPatternImportCtrl',
controllerAs: '$vm',
size: 'lg',
resolve: {
appConfig: self.appConfig
}
});

modalInstance.result
.then(function() {
self.load();
})
.catch(function(err){
if(err && !_.isString(err)) {
NotificationSrv.error('Pattern import', err.data, err.status);
}
});
};

this.toggleFilters = function () {
this.filtering.toggleFilters();
};

this.filter = function () {
self.filtering.filter().then(this.applyFilters);
};

this.clearFilters = function () {
this.filtering.clearFilters()
.then(self.search);
};

this.removeFilter = function (index) {
self.filtering.removeFilter(index)
.then(self.search);
};

this.search = function () {
self.load();
self.filtering.storeContext();
};
this.addFilterValue = function (field, value) {
this.filtering.addFilterValue(field, value);
this.search();
};

self.$onInit = function() {
self.filtering = new FilteringSrv('pattern', 'attack-pattern.list', {
version: 'v1',
defaults: {
showFilters: true,
showStats: false,
pageSize: 15,
sort: ['+name']
},
defaultFilter: []
});

self.filtering.initContext('list')
.then(function() {
self.load();

$scope.$watch('$vm.list.pageSize', function (newValue) {
self.filtering.setPageSize(newValue);
});
});
};
}

function AttackPatternDialogCtrl($uibModalInstance, AttackPatternSrv, NotificationSrv, pattern) {
this.pattern = pattern;

this.ok = function () {
$uibModalInstance.close();
};

this.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
}

function AttackPatternImportCtrl($uibModalInstance, AttackPatternSrv, NotificationSrv, appConfig) {
this.appConfig = appConfig;
this.formData = {};

this.ok = function () {
AttackPatternSrv.import(this.formData)
.then(function() {
$uibModalInstance.close();
}, function(response) {
NotificationSrv.error('AttackPatternImportCtrl', response.data, response.status);
});
};

this.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
}
})();
52 changes: 52 additions & 0 deletions frontend/app/scripts/services/api/AttackPatternSrv.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@

(function() {
'use strict';
angular.module('theHiveServices')
.service('AttackPatternSrv', function($http, QuerySrv) {
var baseUrl = './api/v1/pattern';

this.list = function() {
return QuerySrv.call('v1', [
{ _name: 'listPattern' }
], {
name:'list-attack-patterns'
});
};

this.get = function(id) {
return $http.get(baseUrl + '/' + id)
.then(function(response){
return response.data;
});
};

this.import = function(post) {
var postData = {
file: post.attachment
};

return $http({
method: 'POST',
url: baseUrl + '/import/attack',
headers: {
'Content-Type': undefined
},
transformRequest: function (data) {
var formData = new FormData(),
copy = angular.copy(data, {});

angular.forEach(data, function (value, key) {
if (Object.getPrototypeOf(value) instanceof Blob || Object.getPrototypeOf(value) instanceof File) {
formData.append(key, value);
delete copy[key];
}
});

return formData;
},
data: postData
});
};
});

})();
19 changes: 13 additions & 6 deletions frontend/app/views/components/header.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,6 @@
<span class="hpad5">Case custom fields</span>
</a>
</li>
<li if-permission="manageTaxonomy">
<a ui-sref="app.administration.taxonomies">
<i class="fa fa-tags"></i>
<span class="hpad5">Taxonomies</span>
</a>
</li>
<li if-permission="manageObservableTemplate">
<a ui-sref="app.administration.observables">
<i class="glyphicon glyphicon-pushpin"></i>
Expand All @@ -116,6 +110,19 @@
<span class="hpad5">Analyzer templates</span>
</a>
</li>
<li class="divider"></li>
<li if-permission="manageTaxonomy">
<a ui-sref="app.administration.taxonomies">
<i class="fa fa-tags"></i>
<span class="hpad5">Taxonomies</span>
</a>
</li>
<li>
<a ui-sref="app.administration.attackPatterns">
<i class="fa fa-tags"></i>
<span class="hpad5">ATT&CK Patterns</span>
</a>
</li>
<!-- <li>
<a ui-sref="app.administration.ui-settings">
<i class="fa fa-cogs"></i>
Expand Down
22 changes: 22 additions & 0 deletions frontend/app/views/partials/admin/attack/import.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<form class="" name="form" ng-submit="$vm.ok()">
<div class="modal-header bg-primary">
<h3 class="modal-title">Import MITRE ATT&CK patterns</h3>
</div>
<div class="modal-body">

<div class="filter-panel mb-s">
<h4>Download the official MITRE ATT&CK library</h4>
<p>You can download the latest archive of the official MITRE ATT&CK patterns <a target="_blank" href="https://raw.githubusercontent.com/mitre/cti/master/enterprise-attack/enterprise-attack.json?version=TheHive-{{$vm.appConfig.versions.TheHive}}">from here</a></p>
</div>

<div class="form-group">
<label class="control-label">MITRE ATT&CK patterns</label>
<input type="hidden" name="attachment" ng-model="$vm.formData.attachment.status" required>
<div file-chooser="" filemodel="$vm.formData.attachment"></div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default pull-left" type="button" ng-click="$vm.cancel()">Cancel</button>
<button class="btn btn-primary pull-right" type="submit" ng-disabled="form.$invalid">Yes, Import it</button>
</div>
</form>
Loading

0 comments on commit 839a7e1

Please sign in to comment.