Skip to content

Commit a285a23

Browse files
committed
Response Playbook filters
1 parent 0c70db0 commit a285a23

File tree

5 files changed

+304
-42
lines changed

5 files changed

+304
-42
lines changed

README.md

+131-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
| Data Needed | Fully supported |
99
| Enrichments | Fully supported |
1010
| Response Actions | Fully supported |
11-
| Response Playbooks | **NOT** supported |
11+
| Response Playbooks | Fully supported |
1212
| Detection Rules | Fully supported |
1313

1414

@@ -355,8 +355,6 @@ There are three types of filters - `exact match`, `contains` and `isnull`. Here
355355

356356
### JSON structure
357357

358-
> There are many fields defined which API will accept but in the backend, they are not considered in any way. Use `raw_rule` only!
359-
360358
```json
361359
{
362360
"references": ["https://www.lifewire.com/save-an-email-as-an-eml-file-in-gmail-1171956","https://eml.tooutlook.com/"],
@@ -402,9 +400,9 @@ workflow: |
402400
```python
403401
path_to_ra = "RA0001.yml"
404402
405-
with open(path_to_en, "r") as stream:
403+
with open(path_to_ra, "r") as stream:
406404
ra = [x for x in yaml.safe_load_all(stream)]
407-
data = {"raw_rule": ra}
405+
data = ra
408406
409407
r = requests.post(
410408
"http://127.0.0.1:8000/api/v1/atc/responseaction/",
@@ -431,6 +429,134 @@ There are two types of filters - `exact match` and `contains`. Here is the list
431429
* `author_exact`
432430
* `linked_ra_exact`
433431

432+
# Response Playbook
433+
434+
### JSON structure
435+
436+
437+
```json
438+
{
439+
"author": "@atc_project",
440+
"containment": ["RA_0006_containment_block_domain_on_email",
441+
"RA_0028_containment_block_threat_on_network_level"],
442+
"creation_date": "31.01.2019",
443+
"description": "Response playbook for Phishing Email case. \n",
444+
"eradication": ["RA_0010_eradication_delete_malicious_emails",
445+
"RA_0011_eradication_revoke_compromised_credentials",
446+
"RA_0012_eradication_report_phishing_attack_to_external_companies"],
447+
"identification": ["RA_0001_identification_get_original_email",
448+
"RA_0002_identification_extract_observables_from_email",
449+
"RA_0003_identification_make_sure_email_is_a_phising",
450+
"RA_0004_identification_analyse_obtained_indicators_of_compromise",
451+
"RA_0005_identification_find_all_phising_attack_victims",
452+
"RA_0040_identification_put_on_monitoring_compromised_accounts"],
453+
"lessons_learned": ["RA_0013_lessons_learned_develop_incident_report",
454+
"RA_0014_lessons_learned_conduct_lessons_learned_exercise"],
455+
"linked_rp": ["RP_0002_generic_post_exploitation"],
456+
"pap": "WHITE",
457+
"severity": "M",
458+
"tags": ["attack.initial_access", "attack.t1193", "attack.t1192", "phishing"],
459+
"title": "RP_0001_phishing_email",
460+
"tlp": "AMBER",
461+
"workflow": "1. Execute Response Actions step by step. Some of them directly connected, which means you will not be able to move forward not finishing previous step\n2. Start executing containment and eradication stages concurrently with next identification steps, as soon as you will receive infomration about malicious hosts\n3. If phishing led to code execution or remote access to victim host, immediately start executing Generic Post Exploitation Incident Response Playbook\n4. Save all timestamps of implemented actions in Incident Report draft on the fly, it will save a lot of time\n"
462+
}
463+
```
464+
465+
### ATC Detection Rule yaml file
466+
467+
```yaml
468+
title: RP_0001_phishing_email
469+
description: >
470+
Response playbook for Phishing Email case.
471+
tags:
472+
- attack.initial_access
473+
- attack.t1193
474+
- attack.t1192
475+
- phishing
476+
severity: M
477+
tlp: AMBER
478+
pap: WHITE
479+
author: '@atc_project'
480+
creation_date: 31.01.2019
481+
linked_rp:
482+
- RP_0002_generic_post_exploitation
483+
identification:
484+
- RA_0001_identification_get_original_email
485+
- RA_0002_identification_extract_observables_from_email
486+
- RA_0003_identification_make_sure_email_is_a_phising
487+
- RA_0004_identification_analyse_obtained_indicators_of_compromise
488+
- RA_0005_identification_find_all_phising_attack_victims
489+
- RA_0040_identification_put_on_monitoring_compromised_accounts
490+
containment:
491+
- RA_0006_containment_block_domain_on_email
492+
- RA_0028_containment_block_threat_on_network_level
493+
eradication:
494+
- RA_0010_eradication_delete_malicious_emails
495+
- RA_0011_eradication_revoke_compromised_credentials
496+
- RA_0012_eradication_report_phishing_attack_to_external_companies
497+
lessons_learned:
498+
- RA_0013_lessons_learned_develop_incident_report
499+
- RA_0014_lessons_learned_conduct_lessons_learned_exercise
500+
workflow: |
501+
1. Execute Response Actions step by step. Some of them directly connected, which means you will not be able to move forward not finishing previous step
502+
2. Start executing containment and eradication stages concurrently with next identification steps, as soon as you will receive infomration about malicious hosts
503+
3. If phishing led to code execution or remote access to victim host, immediately start executing Generic Post Exploitation Incident Response Playbook
504+
4. Save all timestamps of implemented actions in Incident Report draft on the fly, it will save a lot of time
505+
506+
```
507+
508+
### Python snippet for inserting data
509+
510+
> Remember that you have to put detection rule as `raw_rule`!
511+
512+
```python
513+
path_to_rp = "RP_0001.yml"
514+
515+
with open(path_to_rp, "r") as stream:
516+
rp = [x for x in yaml.safe_load_all(stream)]
517+
data = rp
518+
519+
r = requests.post(
520+
"http://127.0.0.1:8000/api/v1/atc/responseplaybook/",
521+
json=data
522+
)
523+
```
524+
525+
### Filters
526+
527+
There are two types of filters - `exact match` and `contains`. Here is the list of valid filters:
528+
529+
#### Contains
530+
531+
* `title_contains`
532+
* `description_contains`
533+
* `severity_contains`
534+
* `tags_contains`
535+
* `author_contains`
536+
* `linked_rp_contains`
537+
* `identification_contains`
538+
* `containment_contains`
539+
* `eradication_contains`
540+
* `recovery_contains`
541+
* `lessons_learned_contains`
542+
543+
#### Exact
544+
545+
* `tlp_exact`
546+
* `pap_exact`
547+
* `title_exact`
548+
* `description_exact`
549+
* `severity_exact`
550+
* `tags_exact`
551+
* `author_exact`
552+
* `linked_rp_exact`
553+
* `identification_exact`
554+
* `containment_exact`
555+
* `eradication_exact`
556+
* `recovery_exact`
557+
* `lessons_learned_exact`
558+
559+
434560
---
435561

436562
# Docker
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Generated by Django 2.2.7 on 2020-04-13 00:04
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('atc', '0016_auto_20200412_2353'),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name='responseplaybook',
15+
name='pap',
16+
field=models.CharField(choices=[('WHITE', 'White'), ('Green', 'Green'), ('Amber', 'Amber'), ('Red', 'Red')], max_length=5, verbose_name='PAP'),
17+
),
18+
migrations.AlterField(
19+
model_name='responseplaybook',
20+
name='severity',
21+
field=models.CharField(choices=[('L', 'Low'), ('M', 'Medium'), ('H', 'High')], max_length=6, verbose_name='Severity'),
22+
),
23+
migrations.AlterField(
24+
model_name='responseplaybook',
25+
name='tlp',
26+
field=models.CharField(choices=[('WHITE', 'White'), ('Green', 'Green'), ('Amber', 'Amber'), ('Red', 'Red')], max_length=5, verbose_name='TLP'),
27+
),
28+
]

atc/models.py

+15-15
Original file line numberDiff line numberDiff line change
@@ -413,34 +413,34 @@ class Meta:
413413
]
414414

415415
severity = models.CharField(
416-
max_length=1,
416+
max_length=6,
417417
choices=SEVERITY_CHOIES,
418418
verbose_name="Severity"
419419
)
420420

421-
TLP_CHOIES = [
422-
('W', 'White'),
423-
('G', 'Green'),
424-
('A', 'Amber'),
425-
('R', 'Red'),
421+
TLP_CHOICES = [
422+
('WHITE', 'White'),
423+
('Green', 'Green'),
424+
('Amber', 'Amber'),
425+
('Red', 'Red'),
426426
]
427427

428428
tlp = models.CharField(
429-
max_length=1,
430-
choices=TLP_CHOIES,
429+
max_length=5,
430+
choices=TLP_CHOICES,
431431
verbose_name="TLP"
432432
)
433433

434-
PAP_CHOIES = [
435-
('W', 'White'),
436-
('G', 'Green'),
437-
('A', 'Amber'),
438-
('R', 'Red'),
434+
PAP_CHOICES = [
435+
('WHITE', 'White'),
436+
('Green', 'Green'),
437+
('Amber', 'Amber'),
438+
('Red', 'Red'),
439439
]
440440

441441
pap = models.CharField(
442-
max_length=1,
443-
choices=PAP_CHOIES,
442+
max_length=5,
443+
choices=PAP_CHOICES,
444444
verbose_name="PAP"
445445
)
446446

atc/serializers.py

+7-22
Original file line numberDiff line numberDiff line change
@@ -838,14 +838,7 @@ def to_internal_value(self, data):
838838
class PAPTLPCharField(serializers.CharField):
839839

840840
def to_representation(self, value):
841-
CHOICES = {
842-
'W': 'WHITE',
843-
'G': 'GREEN',
844-
'A': 'AMBER',
845-
'R': 'RED',
846-
}
847-
848-
return CHOICES.get(value)
841+
return value
849842

850843

851844
class ResponsePlaybookSerializer(serializers.ModelSerializer):
@@ -940,22 +933,14 @@ def create(self, validated_data, instance=None):
940933
rplaybook.title = validated_data.get("title")
941934
rplaybook.description = validated_data.get("description")
942935

943-
if len(validated_data.get("severity")) >= 1 \
944-
and validated_data.get(
945-
"severity")[:1].upper() in ['L', 'M', 'H']:
946-
rplaybook.severity = validated_data.get(
947-
"severity")[:1].upper()
948-
949-
if len(validated_data.get("tlp")) >= 1 \
950-
and validated_data.get(
951-
"tlp")[:1].upper() in ['A', 'G', 'R', 'W']:
936+
if validated_data.get("severity"):
937+
rplaybook.severity = validated_data.get("severity")
952938

953-
rplaybook.tlp = validated_data.get("tlp")[:1].upper()
939+
if validated_data.get("tlp"):
940+
rplaybook.tlp = validated_data.get("tlp")
954941

955-
if len(validated_data.get("pap")) >= 1 \
956-
and validated_data.get(
957-
"pap")[:1].upper() in ['A', 'G', 'R', 'W']:
958-
rplaybook.pap = validated_data.get("pap")[:1].upper()
942+
if validated_data.get("pap"):
943+
rplaybook.pap = validated_data.get("pap")
959944

960945
rplaybook.author = validated_data.get("author")
961946
rplaybook.workflow = validated_data.get("workflow")

0 commit comments

Comments
 (0)