This commit is contained in:
Itay Mizeretz 2018-05-23 18:06:30 +03:00
parent c91aee3129
commit d831769d1f
3 changed files with 74 additions and 11 deletions

View File

@ -241,9 +241,14 @@ SCHEMA = {
"default": [
],
"description":
"List of IP/subnet groups. Each group should consist of subnets that aren't supposed"
" to be accessible to one another. If the monkey is in one subnet it'll scan the other"
" subnets in the same group."
"You can use this feature to test for network segmentation, by proving lists of"
" IP/subnet groups that should not be accessible to each other. Each input group"
" consists of subnets that should not be accessible to each other. If the Monkey"
" is inside of one of the subnets it will attempt to connect to machines in the"
" other subnet."
" Example, by providing input 192.168.1.0/24, 192.168.2.0/24, 192.168.3.1-192.168.3.10,"
" a Monkey with the IP address 192.168.2.5 will try to access machines inside"
" 192.168.1.0/24 or 192.168.3.1-192.168.3.10."
}
}
}

View File

@ -1,4 +1,5 @@
import itertools
import functools
import ipaddress
from enum import Enum
@ -329,11 +330,52 @@ class ReportService:
return ip_address
return None
@staticmethod
def get_cross_segment_issues_of_single_machine(source_subnet_range, target_subnet_range):
"""
Gets list of cross segment issues of a single machine. Meaning a machine has an interface for each of the
subnets.
:param source_subnet_range: The subnet range which shouldn't be able to access target_subnet.
:param target_subnet_range: The subnet range which shouldn't be accessible from source_subnet.
:return:
"""
cross_segment_issues = []
for monkey in mongo.db.monkey.find({}, {'ip_addresses': 1, 'hostname': 1}):
ip_in_src = None
ip_in_dst = None
for ip_addr in monkey['ip_addresses']:
if source_subnet_range.is_in_range(unicode(ip_addr)):
ip_in_src = ip_addr
break
# No point searching the dst subnet if there are no IPs in src subnet.
if not ip_in_src:
continue
for ip_addr in monkey['ip_addresses']:
if target_subnet_range.is_in_range(unicode(ip_addr)):
ip_in_dst = ip_addr
break
if ip_in_dst:
cross_segment_issues.append(
{
'source': ip_in_src,
'hostname': monkey['hostname'],
'target': ip_in_dst,
'services': None,
'is_self': True
})
return cross_segment_issues
@staticmethod
def get_cross_segment_issues_per_subnet_pair(scans, source_subnet, target_subnet):
"""
Gets list of cross segment issues from source_subnet to target_subnet.
:param scans: List of all scan telemetry entries. Must have monkey_guid, ip_addr and services.
This should be a PyMongo cursor object.
:param source_subnet: The subnet which shouldn't be able to access target_subnet.
:param target_subnet: The subnet which shouldn't be accessible from source_subnet.
:return:
@ -345,6 +387,7 @@ class ReportService:
cross_segment_issues = []
scans.rewind() # If we iterated over scans already we need to rewind.
for scan in scans:
target_ip = scan['data']['machine']['ip_addr']
if target_subnet_range.is_in_range(unicode(target_ip)):
@ -359,16 +402,19 @@ class ReportService:
'source': cross_segment_ip,
'hostname': monkey['hostname'],
'target': target_ip,
'services': scan['data']['machine']['services']
'services': scan['data']['machine']['services'],
'is_self': False
})
return cross_segment_issues
return cross_segment_issues + ReportService.get_cross_segment_issues_of_single_machine(
source_subnet_range, target_subnet_range)
@staticmethod
def get_cross_segment_issues_per_subnet_group(scans, subnet_group):
"""
Gets list of cross segment issues within given subnet_group.
:param scans: List of all scan telemetry entries. Must have monkey_guid, ip_addr and services.
This should be a PyMongo cursor object.
:param subnet_group: List of subnets which shouldn't be accessible from each other.
:return: Cross segment issues regarding the subnets in the group.
"""
@ -405,8 +451,15 @@ class ReportService:
@staticmethod
def get_issues():
issues = ReportService.get_exploits() + ReportService.get_tunnels() \
+ ReportService.get_island_cross_segment_issues() + ReportService.get_azure_issues()
ISSUE_GENERATORS = [
ReportService.get_exploits,
ReportService.get_tunnels,
ReportService.get_island_cross_segment_issues,
ReportService.get_azure_issues
]
issues = functools.reduce(lambda acc, issue_gen: acc + issue_gen(), ISSUE_GENERATORS, [])
issues_dict = {}
for issue in issues:
machine = issue['machine']

View File

@ -456,10 +456,15 @@ class ReportPageComponent extends AuthComponent {
<CollapsibleWellComponent>
<ul>
{crossSegmentIssue['issues'].map(x =>
<li>
{'IP ' + x['source'] + ' (' + x['hostname'] + ') connected to IP ' + x['target']
+ ' using the services: ' + Object.keys(x['services']).join(', ')}
</li>
x['is_self'] ?
<li>
{'Machine ' + x['hostname'] + ' has both ips: ' + x['source'] + ' and ' + x['target']}
</li>
:
<li>
{'IP ' + x['source'] + ' (' + x['hostname'] + ') connected to IP ' + x['target']
+ ' using the services: ' + Object.keys(x['services']).join(', ')}
</li>
)}
</ul>
</CollapsibleWellComponent>