Replaced Conclusive with Failed, and Positive with Passed

This commit is contained in:
Shay Nehmad 2019-08-28 11:59:33 +03:00
parent 04005b14d7
commit dfebf5e841
22 changed files with 153 additions and 178 deletions

View File

@ -16,11 +16,11 @@ DATA = u"Data"
PILLARS = (DATA, PEOPLE, NETWORKS, DEVICES, WORKLOADS, VISIBILITY_ANALYTICS, AUTOMATION_ORCHESTRATION) PILLARS = (DATA, PEOPLE, NETWORKS, DEVICES, WORKLOADS, VISIBILITY_ANALYTICS, AUTOMATION_ORCHESTRATION)
STATUS_UNEXECUTED = u"Unexecuted" STATUS_UNEXECUTED = u"Unexecuted"
STATUS_POSITIVE = u"Positive" STATUS_PASSED = u"Passed"
STATUS_INCONCLUSIVE = u"Inconclusive" STATUS_INCONCLUSIVE = u"Inconclusive"
STATUS_CONCLUSIVE = u"Conclusive" STATUS_FAILED = u"Failed"
# Don't change order! The statuses are ordered by importance/severity. # Don't change order! The statuses are ordered by importance/severity.
ORDERED_TEST_STATUSES = [STATUS_CONCLUSIVE, STATUS_INCONCLUSIVE, STATUS_POSITIVE, STATUS_UNEXECUTED] ORDERED_TEST_STATUSES = [STATUS_FAILED, STATUS_INCONCLUSIVE, STATUS_PASSED, STATUS_UNEXECUTED]
TEST_DATA_ENDPOINT_ELASTIC = u"unencrypted_data_endpoint_elastic" TEST_DATA_ENDPOINT_ELASTIC = u"unencrypted_data_endpoint_elastic"
TEST_DATA_ENDPOINT_HTTP = u"unencrypted_data_endpoint_http" TEST_DATA_ENDPOINT_HTTP = u"unencrypted_data_endpoint_http"
@ -61,12 +61,12 @@ TESTS_MAP = {
TEST_SEGMENTATION: { TEST_SEGMENTATION: {
TEST_EXPLANATION_KEY: u"The Monkey tried to scan and find machines that it can communicate with from the machine it's running on, that belong to different network segments.", TEST_EXPLANATION_KEY: u"The Monkey tried to scan and find machines that it can communicate with from the machine it's running on, that belong to different network segments.",
FINDING_EXPLANATION_BY_STATUS_KEY: { FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_CONCLUSIVE: "Monkey performed cross-segment communication. Check firewall rules and logs.", STATUS_FAILED: "Monkey performed cross-segment communication. Check firewall rules and logs.",
STATUS_POSITIVE: "Monkey couldn't perform cross-segment communication. If relevant, check firewall logs." STATUS_PASSED: "Monkey couldn't perform cross-segment communication. If relevant, check firewall logs."
}, },
RECOMMENDATION_KEY: RECOMMENDATION_SEGMENTATION, RECOMMENDATION_KEY: RECOMMENDATION_SEGMENTATION,
PILLARS_KEY: [NETWORKS], PILLARS_KEY: [NETWORKS],
POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_POSITIVE, STATUS_CONCLUSIVE] POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_PASSED, STATUS_FAILED]
}, },
TEST_MALICIOUS_ACTIVITY_TIMELINE: { TEST_MALICIOUS_ACTIVITY_TIMELINE: {
TEST_EXPLANATION_KEY: u"The Monkeys in the network performed malicious-looking actions, like scanning and attempting exploitation.", TEST_EXPLANATION_KEY: u"The Monkeys in the network performed malicious-looking actions, like scanning and attempting exploitation.",
@ -80,22 +80,22 @@ TESTS_MAP = {
TEST_ENDPOINT_SECURITY_EXISTS: { TEST_ENDPOINT_SECURITY_EXISTS: {
TEST_EXPLANATION_KEY: u"The Monkey checked if there is an active process of an endpoint security software.", TEST_EXPLANATION_KEY: u"The Monkey checked if there is an active process of an endpoint security software.",
FINDING_EXPLANATION_BY_STATUS_KEY: { FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_CONCLUSIVE: "Monkey didn't find ANY active endpoint security processes. Install and activate anti-virus software on endpoints.", STATUS_FAILED: "Monkey didn't find ANY active endpoint security processes. Install and activate anti-virus software on endpoints.",
STATUS_POSITIVE: "Monkey found active endpoint security processes. Check their logs to see if Monkey was a security concern." STATUS_PASSED: "Monkey found active endpoint security processes. Check their logs to see if Monkey was a security concern."
}, },
RECOMMENDATION_KEY: RECOMMENDATION_ENDPOINT_SECURITY, RECOMMENDATION_KEY: RECOMMENDATION_ENDPOINT_SECURITY,
PILLARS_KEY: [DEVICES], PILLARS_KEY: [DEVICES],
POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_CONCLUSIVE, STATUS_POSITIVE] POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_FAILED, STATUS_PASSED]
}, },
TEST_MACHINE_EXPLOITED: { TEST_MACHINE_EXPLOITED: {
TEST_EXPLANATION_KEY: u"The Monkey tries to exploit machines in order to breach them and propagate in the network.", TEST_EXPLANATION_KEY: u"The Monkey tries to exploit machines in order to breach them and propagate in the network.",
FINDING_EXPLANATION_BY_STATUS_KEY: { FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_CONCLUSIVE: "Monkey successfully exploited endpoints. Check IDS/IPS logs to see activity recognized and see which endpoints were compromised.", STATUS_FAILED: "Monkey successfully exploited endpoints. Check IDS/IPS logs to see activity recognized and see which endpoints were compromised.",
STATUS_POSITIVE: "Monkey didn't manage to exploit an endpoint." STATUS_PASSED: "Monkey didn't manage to exploit an endpoint."
}, },
RECOMMENDATION_KEY: RECOMMENDATION_ENDPOINT_SECURITY, RECOMMENDATION_KEY: RECOMMENDATION_ENDPOINT_SECURITY,
PILLARS_KEY: [DEVICES], PILLARS_KEY: [DEVICES],
POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_CONCLUSIVE, STATUS_INCONCLUSIVE] POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_FAILED, STATUS_INCONCLUSIVE]
}, },
TEST_SCHEDULED_EXECUTION: { TEST_SCHEDULED_EXECUTION: {
TEST_EXPLANATION_KEY: "The Monkey was executed in a scheduled manner.", TEST_EXPLANATION_KEY: "The Monkey was executed in a scheduled manner.",
@ -109,22 +109,22 @@ TESTS_MAP = {
TEST_DATA_ENDPOINT_ELASTIC: { TEST_DATA_ENDPOINT_ELASTIC: {
TEST_EXPLANATION_KEY: u"The Monkey scanned for unencrypted access to ElasticSearch instances.", TEST_EXPLANATION_KEY: u"The Monkey scanned for unencrypted access to ElasticSearch instances.",
FINDING_EXPLANATION_BY_STATUS_KEY: { FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_CONCLUSIVE: "Monkey accessed ElasticSearch instances. Limit access to data by encrypting it in in-transit.", STATUS_FAILED: "Monkey accessed ElasticSearch instances. Limit access to data by encrypting it in in-transit.",
STATUS_POSITIVE: "Monkey didn't find open ElasticSearch instances. If you have such instances, look for alerts that indicate attempts to access them." STATUS_PASSED: "Monkey didn't find open ElasticSearch instances. If you have such instances, look for alerts that indicate attempts to access them."
}, },
RECOMMENDATION_KEY: RECOMMENDATION_DATA_TRANSIT, RECOMMENDATION_KEY: RECOMMENDATION_DATA_TRANSIT,
PILLARS_KEY: [DATA], PILLARS_KEY: [DATA],
POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_CONCLUSIVE, STATUS_POSITIVE] POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_FAILED, STATUS_PASSED]
}, },
TEST_DATA_ENDPOINT_HTTP: { TEST_DATA_ENDPOINT_HTTP: {
TEST_EXPLANATION_KEY: u"The Monkey scanned for unencrypted access to HTTP servers.", TEST_EXPLANATION_KEY: u"The Monkey scanned for unencrypted access to HTTP servers.",
FINDING_EXPLANATION_BY_STATUS_KEY: { FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_CONCLUSIVE: "Monkey accessed HTTP servers. Limit access to data by encrypting it in in-transit.", STATUS_FAILED: "Monkey accessed HTTP servers. Limit access to data by encrypting it in in-transit.",
STATUS_POSITIVE: "Monkey didn't find open HTTP servers. If you have such servers, look for alerts that indicate attempts to access them." STATUS_PASSED: "Monkey didn't find open HTTP servers. If you have such servers, look for alerts that indicate attempts to access them."
}, },
RECOMMENDATION_KEY: RECOMMENDATION_DATA_TRANSIT, RECOMMENDATION_KEY: RECOMMENDATION_DATA_TRANSIT,
PILLARS_KEY: [DATA], PILLARS_KEY: [DATA],
POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_CONCLUSIVE, STATUS_POSITIVE] POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_FAILED, STATUS_PASSED]
}, },
} }

View File

@ -16,12 +16,13 @@ class Finding(Document):
This model represents a Zero-Trust finding: A result of a test the monkey/island might perform to see if a This model represents a Zero-Trust finding: A result of a test the monkey/island might perform to see if a
specific recommendation of zero trust is upheld or broken. specific recommendation of zero trust is upheld or broken.
Findings might be Findings might have the following statuses:
Negative Failed
Conclusive, meaning that we are sure that something is wrong (example: segmentation issue). Meaning that we are sure that something is wrong (example: segmentation issue).
Inconclusive, meaning that we need the user to check something himself (example: 2FA logs, AV missing). Inconclusive
Positive Meaning that we need the user to check something himself (example: 2FA logs, AV missing).
Conclusive, meaning that we are sure that something is correct (example: Monkey failed exploiting). Passed
Meaning that we are sure that something is correct (example: Monkey failed exploiting).
This class has 2 main section: This class has 2 main section:
* The schema section defines the DB fields in the document. This is the data of the object. * The schema section defines the DB fields in the document. This is the data of the object.

View File

@ -1,30 +1,34 @@
from mongoengine import StringField from mongoengine import StringField
from common.data.zero_trust_consts import TEST_SEGMENTATION, STATUS_CONCLUSIVE, STATUS_POSITIVE from common.data.zero_trust_consts import TEST_SEGMENTATION, STATUS_FAILED, STATUS_PASSED
from monkey_island.cc.models.zero_trust.finding import Finding from monkey_island.cc.models.zero_trust.finding import Finding
def need_to_overwrite_status(saved_status, new_status): def need_to_overwrite_status(saved_status, new_status):
return (saved_status == STATUS_POSITIVE) and (new_status == STATUS_CONCLUSIVE) return (saved_status == STATUS_PASSED) and (new_status == STATUS_FAILED)
class SegmentationFinding(Finding): class SegmentationFinding(Finding):
"""
trying to add conclusive:
If the finding doesn't exist at all: create conclusive
else:
if positive, turn to conclusive
add event
trying to add positive:
If the finding doesn't exist at all: create positive
else: add event
"""
first_subnet = StringField() first_subnet = StringField()
second_subnet = StringField() second_subnet = StringField()
@staticmethod @staticmethod
def create_or_add_to_existing_finding(subnets, status, segmentation_event): def create_or_add_to_existing_finding(subnets, status, segmentation_event):
"""
If you're trying to add a Failed finding:
If the finding doesn't exist at all: create failed
else:
if pass, turn to fail
add event
If you're trying to add a Passed finding:
If the finding doesn't exist at all: create Passed
else: add event
:param subnets: the 2 subnets of this finding.
:param status: STATUS_PASSED or STATUS_FAILED
:param segmentation_event: The specific event
"""
assert len(subnets) == 2 assert len(subnets) == 2
# Sort them so A -> B and B -> A segmentation findings will be the same one. # Sort them so A -> B and B -> A segmentation findings will be the same one.

View File

@ -19,7 +19,7 @@ class TestFinding(IslandTestCase):
self.clean_finding_db() self.clean_finding_db()
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
_ = Finding.save_finding(test="bla bla", status=STATUS_CONCLUSIVE, events=[]) _ = Finding.save_finding(test="bla bla", status=STATUS_FAILED, events=[])
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
_ = Finding.save_finding(test=TEST_SEGMENTATION, status="bla bla", events=[]) _ = Finding.save_finding(test=TEST_SEGMENTATION, status="bla bla", events=[])
@ -32,7 +32,7 @@ class TestFinding(IslandTestCase):
event_example = Event.create_event( event_example = Event.create_event(
title="Event Title", message="event message", event_type=EVENT_TYPE_MONKEY_NETWORK) title="Event Title", message="event message", event_type=EVENT_TYPE_MONKEY_NETWORK)
Finding.save_finding(test=TEST_SEGMENTATION, status=STATUS_CONCLUSIVE, events=[event_example]) Finding.save_finding(test=TEST_SEGMENTATION, status=STATUS_FAILED, events=[event_example])
self.assertEquals(len(Finding.objects(test=TEST_SEGMENTATION)), 1) self.assertEquals(len(Finding.objects(test=TEST_SEGMENTATION)), 1)
self.assertEquals(len(Finding.objects(status=STATUS_CONCLUSIVE)), 1) self.assertEquals(len(Finding.objects(status=STATUS_FAILED)), 1)

View File

@ -1,4 +1,4 @@
from common.data.zero_trust_consts import STATUS_CONCLUSIVE, EVENT_TYPE_MONKEY_NETWORK from common.data.zero_trust_consts import STATUS_FAILED, EVENT_TYPE_MONKEY_NETWORK
from monkey_island.cc.models.zero_trust.event import Event from monkey_island.cc.models.zero_trust.event import Event
from monkey_island.cc.testing.IslandTestCase import IslandTestCase from monkey_island.cc.testing.IslandTestCase import IslandTestCase
from monkey_island.cc.models.zero_trust.segmentation_finding import SegmentationFinding from monkey_island.cc.models.zero_trust.segmentation_finding import SegmentationFinding
@ -16,7 +16,7 @@ class TestSegmentationFinding(IslandTestCase):
SegmentationFinding.create_or_add_to_existing_finding( SegmentationFinding.create_or_add_to_existing_finding(
subnets=[first_segment, second_segment], subnets=[first_segment, second_segment],
status=STATUS_CONCLUSIVE, status=STATUS_FAILED,
segmentation_event=event segmentation_event=event
) )
@ -26,7 +26,7 @@ class TestSegmentationFinding(IslandTestCase):
SegmentationFinding.create_or_add_to_existing_finding( SegmentationFinding.create_or_add_to_existing_finding(
# !!! REVERSE ORDER # !!! REVERSE ORDER
subnets=[second_segment, first_segment], subnets=[second_segment, first_segment],
status=STATUS_CONCLUSIVE, status=STATUS_FAILED,
segmentation_event=event segmentation_event=event
) )
@ -36,7 +36,7 @@ class TestSegmentationFinding(IslandTestCase):
SegmentationFinding.create_or_add_to_existing_finding( SegmentationFinding.create_or_add_to_existing_finding(
# !!! REVERSE ORDER # !!! REVERSE ORDER
subnets=[first_segment, third_segment], subnets=[first_segment, third_segment],
status=STATUS_CONCLUSIVE, status=STATUS_FAILED,
segmentation_event=event segmentation_event=event
) )
@ -45,7 +45,7 @@ class TestSegmentationFinding(IslandTestCase):
SegmentationFinding.create_or_add_to_existing_finding( SegmentationFinding.create_or_add_to_existing_finding(
# !!! REVERSE ORDER # !!! REVERSE ORDER
subnets=[second_segment, third_segment], subnets=[second_segment, third_segment],
status=STATUS_CONCLUSIVE, status=STATUS_FAILED,
segmentation_event=event segmentation_event=event
) )

View File

@ -1,4 +1,4 @@
{ {
"server_config": "testing", "server_config": "standard",
"deployment": "develop" "deployment": "develop"
} }

View File

@ -7,9 +7,9 @@ from monkey_island.cc.testing.IslandTestCase import IslandTestCase
def save_example_findings(): def save_example_findings():
# arrange # arrange
Finding.save_finding(TEST_ENDPOINT_SECURITY_EXISTS, STATUS_POSITIVE, []) # devices positive = 1 Finding.save_finding(TEST_ENDPOINT_SECURITY_EXISTS, STATUS_PASSED, []) # devices passed = 1
Finding.save_finding(TEST_ENDPOINT_SECURITY_EXISTS, STATUS_POSITIVE, []) # devices positive = 2 Finding.save_finding(TEST_ENDPOINT_SECURITY_EXISTS, STATUS_PASSED, []) # devices passed = 2
Finding.save_finding(TEST_ENDPOINT_SECURITY_EXISTS, STATUS_CONCLUSIVE, []) # devices conclusive = 1 Finding.save_finding(TEST_ENDPOINT_SECURITY_EXISTS, STATUS_FAILED, []) # devices failed = 1
# devices unexecuted = 1 # devices unexecuted = 1
# people inconclusive = 1 # people inconclusive = 1
# networks inconclusive = 1 # networks inconclusive = 1
@ -17,22 +17,22 @@ def save_example_findings():
# people inconclusive = 2 # people inconclusive = 2
# networks inconclusive = 2 # networks inconclusive = 2
Finding.save_finding(TEST_SCHEDULED_EXECUTION, STATUS_INCONCLUSIVE, []) Finding.save_finding(TEST_SCHEDULED_EXECUTION, STATUS_INCONCLUSIVE, [])
# data conclusive 1 # data failed 1
Finding.save_finding(TEST_DATA_ENDPOINT_HTTP, STATUS_CONCLUSIVE, []) Finding.save_finding(TEST_DATA_ENDPOINT_HTTP, STATUS_FAILED, [])
# data conclusive 2 # data failed 2
Finding.save_finding(TEST_DATA_ENDPOINT_HTTP, STATUS_CONCLUSIVE, []) Finding.save_finding(TEST_DATA_ENDPOINT_HTTP, STATUS_FAILED, [])
# data conclusive 3 # data failed 3
Finding.save_finding(TEST_DATA_ENDPOINT_HTTP, STATUS_CONCLUSIVE, []) Finding.save_finding(TEST_DATA_ENDPOINT_HTTP, STATUS_FAILED, [])
# data conclusive 4 # data failed 4
Finding.save_finding(TEST_DATA_ENDPOINT_HTTP, STATUS_CONCLUSIVE, []) Finding.save_finding(TEST_DATA_ENDPOINT_HTTP, STATUS_FAILED, [])
# data conclusive 5 # data failed 5
Finding.save_finding(TEST_DATA_ENDPOINT_HTTP, STATUS_CONCLUSIVE, []) Finding.save_finding(TEST_DATA_ENDPOINT_HTTP, STATUS_FAILED, [])
# data inconclusive 1 # data inconclusive 1
Finding.save_finding(TEST_DATA_ENDPOINT_HTTP, STATUS_INCONCLUSIVE, []) Finding.save_finding(TEST_DATA_ENDPOINT_HTTP, STATUS_INCONCLUSIVE, [])
# data inconclusive 2 # data inconclusive 2
Finding.save_finding(TEST_DATA_ENDPOINT_HTTP, STATUS_INCONCLUSIVE, []) Finding.save_finding(TEST_DATA_ENDPOINT_HTTP, STATUS_INCONCLUSIVE, [])
# data positive 1 # data passed 1
Finding.save_finding(TEST_DATA_ENDPOINT_HTTP, STATUS_POSITIVE, []) Finding.save_finding(TEST_DATA_ENDPOINT_HTTP, STATUS_PASSED, [])
class TestZeroTrustService(IslandTestCase): class TestZeroTrustService(IslandTestCase):
@ -44,52 +44,52 @@ class TestZeroTrustService(IslandTestCase):
expected = [ expected = [
{ {
"Conclusive": 5, STATUS_FAILED: 5,
"Inconclusive": 2, STATUS_INCONCLUSIVE: 2,
"Positive": 1, STATUS_PASSED: 1,
"Unexecuted": 1, STATUS_UNEXECUTED: 1,
"pillar": "Data" "pillar": "Data"
}, },
{ {
"Conclusive": 0, STATUS_FAILED: 0,
"Inconclusive": 2, STATUS_INCONCLUSIVE: 2,
"Positive": 0, STATUS_PASSED: 0,
"Unexecuted": 0, STATUS_UNEXECUTED: 0,
"pillar": "People" "pillar": "People"
}, },
{ {
"Conclusive": 0, STATUS_FAILED: 0,
"Inconclusive": 2, STATUS_INCONCLUSIVE: 2,
"Positive": 0, STATUS_PASSED: 0,
"Unexecuted": 2, STATUS_UNEXECUTED: 2,
"pillar": "Networks" "pillar": "Networks"
}, },
{ {
"Conclusive": 1, STATUS_FAILED: 1,
"Inconclusive": 0, STATUS_INCONCLUSIVE: 0,
"Positive": 2, STATUS_PASSED: 2,
"Unexecuted": 1, STATUS_UNEXECUTED: 1,
"pillar": "Devices" "pillar": "Devices"
}, },
{ {
"Conclusive": 0, STATUS_FAILED: 0,
"Inconclusive": 0, STATUS_INCONCLUSIVE: 0,
"Positive": 0, STATUS_PASSED: 0,
"Unexecuted": 0, STATUS_UNEXECUTED: 0,
"pillar": "Workloads" "pillar": "Workloads"
}, },
{ {
"Conclusive": 0, STATUS_FAILED: 0,
"Inconclusive": 0, STATUS_INCONCLUSIVE: 0,
"Positive": 0, STATUS_PASSED: 0,
"Unexecuted": 1, STATUS_UNEXECUTED: 1,
"pillar": "Visibility & Analytics" "pillar": "Visibility & Analytics"
}, },
{ {
"Conclusive": 0, STATUS_FAILED: 0,
"Inconclusive": 0, STATUS_INCONCLUSIVE: 0,
"Positive": 0, STATUS_PASSED: 0,
"Unexecuted": 0, STATUS_UNEXECUTED: 0,
"pillar": "Automation & Orchestration" "pillar": "Automation & Orchestration"
} }
] ]
@ -109,14 +109,14 @@ class TestZeroTrustService(IslandTestCase):
DATA: [ DATA: [
{ {
"recommendation": RECOMMENDATIONS[RECOMMENDATION_DATA_TRANSIT], "recommendation": RECOMMENDATIONS[RECOMMENDATION_DATA_TRANSIT],
"status": STATUS_CONCLUSIVE, "status": STATUS_FAILED,
"tests": [ "tests": [
{ {
"status": STATUS_UNEXECUTED, "status": STATUS_UNEXECUTED,
"test": TESTS_MAP[TEST_DATA_ENDPOINT_ELASTIC][TEST_EXPLANATION_KEY] "test": TESTS_MAP[TEST_DATA_ENDPOINT_ELASTIC][TEST_EXPLANATION_KEY]
}, },
{ {
"status": STATUS_CONCLUSIVE, "status": STATUS_FAILED,
"test": TESTS_MAP[TEST_DATA_ENDPOINT_HTTP][TEST_EXPLANATION_KEY] "test": TESTS_MAP[TEST_DATA_ENDPOINT_HTTP][TEST_EXPLANATION_KEY]
} }
] ]
@ -125,10 +125,10 @@ class TestZeroTrustService(IslandTestCase):
DEVICES: [ DEVICES: [
{ {
"recommendation": RECOMMENDATIONS[RECOMMENDATION_ENDPOINT_SECURITY], "recommendation": RECOMMENDATIONS[RECOMMENDATION_ENDPOINT_SECURITY],
"status": STATUS_CONCLUSIVE, "status": STATUS_FAILED,
"tests": [ "tests": [
{ {
"status": STATUS_CONCLUSIVE, "status": STATUS_FAILED,
"test": TESTS_MAP[TEST_ENDPOINT_SECURITY_EXISTS][TEST_EXPLANATION_KEY] "test": TESTS_MAP[TEST_ENDPOINT_SECURITY_EXISTS][TEST_EXPLANATION_KEY]
}, },
{ {
@ -221,12 +221,12 @@ class TestZeroTrustService(IslandTestCase):
expected = { expected = {
AUTOMATION_ORCHESTRATION: STATUS_UNEXECUTED, AUTOMATION_ORCHESTRATION: STATUS_UNEXECUTED,
DEVICES: STATUS_CONCLUSIVE, DEVICES: STATUS_FAILED,
NETWORKS: STATUS_INCONCLUSIVE, NETWORKS: STATUS_INCONCLUSIVE,
PEOPLE: STATUS_INCONCLUSIVE, PEOPLE: STATUS_INCONCLUSIVE,
VISIBILITY_ANALYTICS: STATUS_UNEXECUTED, VISIBILITY_ANALYTICS: STATUS_UNEXECUTED,
WORKLOADS: STATUS_UNEXECUTED, WORKLOADS: STATUS_UNEXECUTED,
DATA: STATUS_CONCLUSIVE DATA: STATUS_FAILED
} }
self.assertEquals(ZeroTrustService.get_pillars_to_statuses(), expected) self.assertEquals(ZeroTrustService.get_pillars_to_statuses(), expected)

View File

@ -16,9 +16,9 @@ class ZeroTrustService(object):
all_findings = Finding.objects() all_findings = Finding.objects()
pillar_grade = { pillar_grade = {
"pillar": pillar, "pillar": pillar,
STATUS_CONCLUSIVE: 0, STATUS_FAILED: 0,
STATUS_INCONCLUSIVE: 0, STATUS_INCONCLUSIVE: 0,
STATUS_POSITIVE: 0, STATUS_PASSED: 0,
STATUS_UNEXECUTED: 0 STATUS_UNEXECUTED: 0
} }
@ -123,9 +123,9 @@ class ZeroTrustService(object):
@staticmethod @staticmethod
def get_statuses_to_pillars(): def get_statuses_to_pillars():
results = { results = {
STATUS_CONCLUSIVE: [], STATUS_FAILED: [],
STATUS_INCONCLUSIVE: [], STATUS_INCONCLUSIVE: [],
STATUS_POSITIVE: [], STATUS_PASSED: [],
STATUS_UNEXECUTED: [] STATUS_UNEXECUTED: []
} }
for pillar in PILLARS: for pillar in PILLARS:

View File

@ -1,6 +1,6 @@
from monkey_island.cc.services.node import NodeService from monkey_island.cc.services.node import NodeService
from monkey_island.cc.services.telemetry.zero_trust_tests.segmentation import \ from monkey_island.cc.services.telemetry.zero_trust_tests.segmentation import \
test_positive_findings_for_unreached_segments test_passed_findings_for_unreached_segments
def process_state_telemetry(telemetry_json): def process_state_telemetry(telemetry_json):
@ -12,4 +12,4 @@ def process_state_telemetry(telemetry_json):
NodeService.set_monkey_dead(monkey, False) NodeService.set_monkey_dead(monkey, False)
if telemetry_json['data']['done']: if telemetry_json['data']['done']:
test_positive_findings_for_unreached_segments(telemetry_json) test_passed_findings_for_unreached_segments(telemetry_json)

View File

@ -1,7 +1,7 @@
import json import json
from common.data.zero_trust_consts import EVENT_TYPE_MONKEY_LOCAL, EVENT_TYPE_ISLAND, \ from common.data.zero_trust_consts import EVENT_TYPE_MONKEY_LOCAL, EVENT_TYPE_ISLAND, \
STATUS_POSITIVE, STATUS_CONCLUSIVE, TEST_ENDPOINT_SECURITY_EXISTS STATUS_PASSED, STATUS_FAILED, TEST_ENDPOINT_SECURITY_EXISTS
from monkey_island.cc.models import Monkey from monkey_island.cc.models import Monkey
from monkey_island.cc.models.zero_trust.event import Event from monkey_island.cc.models.zero_trust.event import Event
from monkey_island.cc.models.zero_trust.finding import Finding from monkey_island.cc.models.zero_trust.finding import Finding
@ -28,9 +28,9 @@ def test_antivirus_existence(telemetry_json):
)) ))
if len(av_processes) > 0: if len(av_processes) > 0:
test_status = STATUS_POSITIVE test_status = STATUS_PASSED
else: else:
test_status = STATUS_CONCLUSIVE test_status = STATUS_FAILED
Finding.save_finding(test=TEST_ENDPOINT_SECURITY_EXISTS, status=test_status, events=events) Finding.save_finding(test=TEST_ENDPOINT_SECURITY_EXISTS, status=test_status, events=events)

View File

@ -11,8 +11,8 @@ HTTP_SERVERS_SERVICES_NAMES = ['tcp-80']
def test_open_data_endpoints(telemetry_json): def test_open_data_endpoints(telemetry_json):
services = telemetry_json["data"]["machine"]["services"] services = telemetry_json["data"]["machine"]["services"]
current_monkey = Monkey.get_single_monkey_by_guid(telemetry_json['monkey_guid']) current_monkey = Monkey.get_single_monkey_by_guid(telemetry_json['monkey_guid'])
found_http_server_status = STATUS_POSITIVE found_http_server_status = STATUS_PASSED
found_elastic_search_server = STATUS_POSITIVE found_elastic_search_server = STATUS_PASSED
events = [ events = [
Event.create_event( Event.create_event(
@ -32,7 +32,7 @@ def test_open_data_endpoints(telemetry_json):
event_type=EVENT_TYPE_ISLAND event_type=EVENT_TYPE_ISLAND
)) ))
if service_name in HTTP_SERVERS_SERVICES_NAMES: if service_name in HTTP_SERVERS_SERVICES_NAMES:
found_http_server_status = STATUS_CONCLUSIVE found_http_server_status = STATUS_FAILED
events.append(Event.create_event( events.append(Event.create_event(
title="Scan telemetry analysis", title="Scan telemetry analysis",
message="Service {} on {} recognized as an open data endpoint! Service details: {}".format( message="Service {} on {} recognized as an open data endpoint! Service details: {}".format(
@ -43,7 +43,7 @@ def test_open_data_endpoints(telemetry_json):
event_type=EVENT_TYPE_ISLAND event_type=EVENT_TYPE_ISLAND
)) ))
if service_name in 'elastic-search-9200': if service_name in 'elastic-search-9200':
found_elastic_search_server = STATUS_CONCLUSIVE found_elastic_search_server = STATUS_FAILED
events.append(Event.create_event( events.append(Event.create_event(
title="Scan telemetry analysis", title="Scan telemetry analysis",
message="Service {} on {} recognized as an open data endpoint! Service details: {}".format( message="Service {} on {} recognized as an open data endpoint! Service details: {}".format(

View File

@ -18,7 +18,7 @@ def test_machine_exploited(telemetry_json):
) )
] ]
status = STATUS_POSITIVE status = STATUS_PASSED
if telemetry_json['data']['result']: if telemetry_json['data']['result']:
events.append( events.append(
@ -31,7 +31,7 @@ def test_machine_exploited(telemetry_json):
event_type=EVENT_TYPE_MONKEY_NETWORK, event_type=EVENT_TYPE_MONKEY_NETWORK,
timestamp=telemetry_json['timestamp']) timestamp=telemetry_json['timestamp'])
) )
status = STATUS_CONCLUSIVE status = STATUS_FAILED
Finding.save_finding( Finding.save_finding(
test=TEST_MACHINE_EXPLOITED, test=TEST_MACHINE_EXPLOITED,

View File

@ -1,7 +1,7 @@
import itertools import itertools
from six import text_type from six import text_type
from common.data.zero_trust_consts import STATUS_CONCLUSIVE, EVENT_TYPE_MONKEY_NETWORK, STATUS_POSITIVE, \ from common.data.zero_trust_consts import STATUS_FAILED, EVENT_TYPE_MONKEY_NETWORK, STATUS_PASSED, \
EVENT_TYPE_ISLAND EVENT_TYPE_ISLAND
from common.network.network_range import NetworkRange from common.network.network_range import NetworkRange
from common.network.segmentation_utils import get_ip_in_src_and_not_in_dst, get_ip_if_in_subnet from common.network.segmentation_utils import get_ip_in_src_and_not_in_dst, get_ip_if_in_subnet
@ -45,7 +45,7 @@ def test_segmentation_violation(scan_telemetry_json):
event = get_segmentation_violation_event(current_monkey, source_subnet, target_ip, target_subnet) event = get_segmentation_violation_event(current_monkey, source_subnet, target_ip, target_subnet)
SegmentationFinding.create_or_add_to_existing_finding( SegmentationFinding.create_or_add_to_existing_finding(
subnets=[source_subnet, target_subnet], subnets=[source_subnet, target_subnet],
status=STATUS_CONCLUSIVE, status=STATUS_FAILED,
segmentation_event=event segmentation_event=event
) )
@ -64,7 +64,7 @@ def get_segmentation_violation_event(current_monkey, source_subnet, target_ip, t
) )
def test_positive_findings_for_unreached_segments(state_telemetry_json): def test_passed_findings_for_unreached_segments(state_telemetry_json):
flat_all_subnets = [item for sublist in get_config_network_segments_as_subnet_groups() for item in sublist] flat_all_subnets = [item for sublist in get_config_network_segments_as_subnet_groups() for item in sublist]
current_monkey = Monkey.get_single_monkey_by_guid(state_telemetry_json['monkey_guid']) current_monkey = Monkey.get_single_monkey_by_guid(state_telemetry_json['monkey_guid'])
create_or_add_findings_for_all_pairs(flat_all_subnets, current_monkey) create_or_add_findings_for_all_pairs(flat_all_subnets, current_monkey)
@ -87,7 +87,7 @@ def create_or_add_findings_for_all_pairs(all_subnets, current_monkey):
for subnet_pair in all_subnets_pairs_for_this_monkey: for subnet_pair in all_subnets_pairs_for_this_monkey:
SegmentationFinding.create_or_add_to_existing_finding( SegmentationFinding.create_or_add_to_existing_finding(
subnets=list(subnet_pair), subnets=list(subnet_pair),
status=STATUS_POSITIVE, status=STATUS_PASSED,
segmentation_event=Event.create_event( segmentation_event=Event.create_event(
"Segmentation test done", "Segmentation test done",
message="Monkey on {hostname} is done attempting cross-segment communications from `{src_seg}` " message="Monkey on {hostname} is done attempting cross-segment communications from `{src_seg}` "

View File

@ -1,6 +1,6 @@
import uuid import uuid
from common.data.zero_trust_consts import TEST_SEGMENTATION, STATUS_POSITIVE, STATUS_CONCLUSIVE, \ from common.data.zero_trust_consts import TEST_SEGMENTATION, STATUS_PASSED, STATUS_FAILED, \
EVENT_TYPE_MONKEY_NETWORK EVENT_TYPE_MONKEY_NETWORK
from monkey_island.cc.models import Monkey from monkey_island.cc.models import Monkey
from monkey_island.cc.models.zero_trust.event import Event from monkey_island.cc.models.zero_trust.event import Event
@ -32,20 +32,15 @@ class TestSegmentationTests(IslandTestCase):
create_or_add_findings_for_all_pairs(all_subnets, monkey) create_or_add_findings_for_all_pairs(all_subnets, monkey)
# There are 2 subnets in which the monkey is NOT # There are 2 subnets in which the monkey is NOT
self.assertEquals(len(Finding.objects(test=TEST_SEGMENTATION, status=STATUS_POSITIVE)), 2) self.assertEquals(len(Finding.objects(test=TEST_SEGMENTATION, status=STATUS_PASSED)), 2)
# This is a monkey from 2nd subnet communicated with 1st subnet. # This is a monkey from 2nd subnet communicated with 1st subnet.
SegmentationFinding.create_or_add_to_existing_finding( SegmentationFinding.create_or_add_to_existing_finding(
[FIRST_SUBNET, SECOND_SUBNET], [FIRST_SUBNET, SECOND_SUBNET],
STATUS_CONCLUSIVE, STATUS_FAILED,
Event.create_event(title="sdf", message="asd", event_type=EVENT_TYPE_MONKEY_NETWORK) Event.create_event(title="sdf", message="asd", event_type=EVENT_TYPE_MONKEY_NETWORK)
) )
print("Printing all segmentation findings") self.assertEquals(len(Finding.objects(test=TEST_SEGMENTATION, status=STATUS_PASSED)), 1)
all_findings = Finding.objects(test=TEST_SEGMENTATION) self.assertEquals(len(Finding.objects(test=TEST_SEGMENTATION, status=STATUS_FAILED)), 1)
for f in all_findings:
print(f.to_json())
self.assertEquals(len(Finding.objects(test=TEST_SEGMENTATION, status=STATUS_POSITIVE)), 1)
self.assertEquals(len(Finding.objects(test=TEST_SEGMENTATION, status=STATUS_CONCLUSIVE)), 1)
self.assertEquals(len(Finding.objects(test=TEST_SEGMENTATION)), 2) self.assertEquals(len(Finding.objects(test=TEST_SEGMENTATION)), 2)

View File

@ -12,6 +12,7 @@ import StatusesToPillarsSummary from "../report-components/zerotrust/StatusesToP
import PrintReportButton from "../report-components/common/PrintReportButton"; import PrintReportButton from "../report-components/common/PrintReportButton";
import {extractExecutionStatusFromServerResponse} from "../report-components/common/ExecutionStatus"; import {extractExecutionStatusFromServerResponse} from "../report-components/common/ExecutionStatus";
import ZeroTrustReportLegend from "../report-components/zerotrust/ReportLegend"; import ZeroTrustReportLegend from "../report-components/zerotrust/ReportLegend";
import {ZeroTrustStatuses} from "../report-components/zerotrust/ZeroTrustPillars";
class ZeroTrustReportPageComponent extends AuthComponent { class ZeroTrustReportPageComponent extends AuthComponent {
@ -179,14 +180,6 @@ class ZeroTrustReportPageComponent extends AuthComponent {
}); });
}); });
} }
anyIssuesFound() {
const severe = function(finding) {
return (finding.status === "Conclusive" || finding.status === "Inconclusive");
};
return this.state.findings.some(severe);
}
} }
export default ZeroTrustReportPageComponent; export default ZeroTrustReportPageComponent;

View File

@ -1,27 +1,11 @@
import React, {Component} from "react"; import React, {Component} from "react";
import PillarLabel from "./PillarLabel";
import * as PropTypes from "prop-types"; import * as PropTypes from "prop-types";
import ResponsiveVennDiagram from "./venn-components/ResponsiveVennDiagram"; import ResponsiveVennDiagram from "./venn-components/ResponsiveVennDiagram";
const columns = [
{
Header: 'Pillar Grading',
columns: [
{ Header: 'Pillar', id: 'Pillar', accessor: x => {
return (<PillarLabel pillar={x.pillar.name} status={x.pillar.status} />);
}},
{ Header: 'Conclusive', accessor: 'Conclusive'},
{ Header: 'Inconclusive', accessor: 'Inconclusive'},
{ Header: 'Unexecuted', accessor: 'Unexecuted'},
{ Header: 'Positive', accessor: 'Positive'},
]
}
];
class PillarOverview extends Component { class PillarOverview extends Component {
render() { render() {
return (<div id={this.constructor.name}> return (<div id={this.constructor.name}>
<ResponsiveVennDiagram pillarsGrades={this.props.grades} /> <ResponsiveVennDiagram pillarsGrades={this.props.grades}/>
</div>); </div>);
} }
} }

View File

@ -4,6 +4,7 @@ import AuthComponent from "../../AuthComponent";
import 'styles/ZeroTrustPillars.css' import 'styles/ZeroTrustPillars.css'
import StatusLabel from "./StatusLabel"; import StatusLabel from "./StatusLabel";
import * as PropTypes from "prop-types"; import * as PropTypes from "prop-types";
import {ZeroTrustStatuses} from "./ZeroTrustPillars";
const columns = [ const columns = [
@ -30,17 +31,12 @@ const columns = [
class TestsStatus extends AuthComponent { class TestsStatus extends AuthComponent {
render() { render() {
const positiveStatus = "Positive";
const conclusiveStatus = "Conclusive";
const inconclusiveStatus = "Inconclusive";
const unexecutedStatus = "Unexecuted";
return ( return (
<Fragment> <Fragment>
{this.getFilteredTestsByStatusIfAny(conclusiveStatus)} {this.getFilteredTestsByStatusIfAny(ZeroTrustStatuses.failed)}
{this.getFilteredTestsByStatusIfAny(inconclusiveStatus)} {this.getFilteredTestsByStatusIfAny(ZeroTrustStatuses.inconclusive)}
{this.getFilteredTestsByStatusIfAny(positiveStatus)} {this.getFilteredTestsByStatusIfAny(ZeroTrustStatuses.passed)}
{this.getFilteredTestsByStatusIfAny(unexecutedStatus)} {this.getFilteredTestsByStatusIfAny(ZeroTrustStatuses.unexecuted)}
</Fragment> </Fragment>
); );
} }

View File

@ -38,7 +38,7 @@ class ZeroTrustReportLegend extends Component {
<ul style={{listStyle: "none"}}> <ul style={{listStyle: "none"}}>
<li> <li>
<div style={{display: "inline-block"}}> <div style={{display: "inline-block"}}>
<StatusLabel showText={true} status={ZeroTrustStatuses.conclusive}/> <StatusLabel showText={true} status={ZeroTrustStatuses.failed}/>
</div> </div>
{"\t"}The test failed; the monkeys found something wrong. {"\t"}The test failed; the monkeys found something wrong.
</li> </li>
@ -50,7 +50,7 @@ class ZeroTrustReportLegend extends Component {
</li> </li>
<li> <li>
<div style={{display: "inline-block"}}> <div style={{display: "inline-block"}}>
<StatusLabel showText={true} status={ZeroTrustStatuses.positive}/> <StatusLabel showText={true} status={ZeroTrustStatuses.passed}/>
</div> </div>
{"\t"}This status means the test passed 🙂 {"\t"}This status means the test passed 🙂
</li> </li>

View File

@ -2,16 +2,16 @@ import React, {Component} from "react";
import * as PropTypes from "prop-types"; import * as PropTypes from "prop-types";
const statusToIcon = { const statusToIcon = {
"Positive": "fa-check", "Passed": "fa-check",
"Inconclusive": "fa-exclamation-triangle", "Inconclusive": "fa-exclamation-triangle",
"Conclusive": "fa-bomb", "Failed": "fa-bomb",
"Unexecuted": "fa-question", "Unexecuted": "fa-question",
}; };
export const statusToLabelType = { export const statusToLabelType = {
"Positive": "label-success", "Passed": "label-success",
"Inconclusive": "label-warning", "Inconclusive": "label-warning",
"Conclusive": "label-danger", "Failed": "label-danger",
"Unexecuted": "label-default", "Unexecuted": "label-default",
}; };

View File

@ -2,14 +2,15 @@ import React, {Component, Fragment} from "react";
import PillarLabel from "./PillarLabel"; import PillarLabel from "./PillarLabel";
import StatusLabel from "./StatusLabel"; import StatusLabel from "./StatusLabel";
import * as PropTypes from "prop-types"; import * as PropTypes from "prop-types";
import {ZeroTrustStatuses} from "./ZeroTrustPillars";
export default class StatusesToPillarsSummary extends Component { export default class StatusesToPillarsSummary extends Component {
render() { render() {
return (<div id="piilar-summary"> return (<div id="piilar-summary">
{this.getStatusSummary("Conclusive")} {this.getStatusSummary(ZeroTrustStatuses.failed)}
{this.getStatusSummary("Inconclusive")} {this.getStatusSummary(ZeroTrustStatuses.inconclusive)}
{this.getStatusSummary("Positive")} {this.getStatusSummary(ZeroTrustStatuses.passed)}
{this.getStatusSummary("Unexecuted")} {this.getStatusSummary(ZeroTrustStatuses.unexecuted)}
</div>); </div>);
} }

View File

@ -9,9 +9,9 @@ export const ZeroTrustPillars = {
}; };
export const ZeroTrustStatuses = { export const ZeroTrustStatuses = {
conclusive: "Conclusive", failed: "Failed",
inconclusive: "Inconclusive", inconclusive: "Inconclusive",
positive: "Positive", passed: "Passed",
unexecuted: "Unexecuted" unexecuted: "Unexecuted"
}; };

View File

@ -4,6 +4,7 @@ import CircularNode from './CircularNode'
import ArcNode from './ArcNode' import ArcNode from './ArcNode'
import {TypographicUtilities} from './Utility.js' import {TypographicUtilities} from './Utility.js'
import './VennDiagram.css' import './VennDiagram.css'
import {ZeroTrustStatuses} from "../ZeroTrustPillars";
class VennDiagram extends React.Component { class VennDiagram extends React.Component {
constructor(props_) { constructor(props_) {
@ -14,7 +15,7 @@ class VennDiagram extends React.Component {
this.width = this.height = 512; this.width = this.height = 512;
this.prefix = 'vennDiagram'; this.prefix = 'vennDiagram';
this.suffices = ['', '|tests are|conclusive', '|tests were|inconclusive', '|tests|performed']; this.suffices = ['', '|tests are|failed', '|tests were|inconclusive', '|tests|performed'];
this.fontStyles = [{size: Math.max(9, this.width / 32), color: 'white'}, { this.fontStyles = [{size: Math.max(9, this.width / 32), color: 'white'}, {
size: Math.max(6, this.width / 52), size: Math.max(6, this.width / 52),
color: 'black' color: 'black'
@ -65,23 +66,23 @@ class VennDiagram extends React.Component {
this.rules = [ this.rules = [
{ {
id: 'Rule #1', status: 'Unexecuted', hex: '#777777', f: function (d_) { id: 'Rule #1', status: ZeroTrustStatuses.unexecuted, hex: '#777777', f: function (d_) {
return d_['Conclusive'] + d_['Inconclusive'] + d_['Positive'] === 0; return d_[ZeroTrustStatuses.failed] + d_[ZeroTrustStatuses.inconclusive] + d_[ZeroTrustStatuses.passed] === 0;
} }
}, },
{ {
id: 'Rule #2', status: 'Conclusive', hex: '#D9534F', f: function (d_) { id: 'Rule #2', status: ZeroTrustStatuses.failed, hex: '#D9534F', f: function (d_) {
return d_['Conclusive'] > 0; return d_[ZeroTrustStatuses.failed] > 0;
} }
}, },
{ {
id: 'Rule #3', status: 'Inconclusive', hex: '#F0AD4E', f: function (d_) { id: 'Rule #3', status: 'Inconclusive', hex: '#F0AD4E', f: function (d_) {
return d_['Conclusive'] === 0 && d_['Inconclusive'] > 0; return d_[ZeroTrustStatuses.failed] === 0 && d_['Inconclusive'] > 0;
} }
}, },
{ {
id: 'Rule #4', status: 'Positive', hex: '#5CB85C', f: function (d_) { id: 'Rule #4', status: ZeroTrustStatuses.passed, hex: '#5CB85C', f: function (d_) {
return d_['Positive'] + d_['Unexecuted'] >= 2 && d_['Positive'] * d_['Unexecuted'] > 0; return d_[ZeroTrustStatuses.passed] + d_[ZeroTrustStatuses.unexecuted] >= 2 && d_[ZeroTrustStatuses.passed] * d_[ZeroTrustStatuses.unexecuted] > 0;
} }
} }