January 18, 2021

Adversary Resilience Via Least Privilege Networking – Part 2

Sagie Dulce
VP Research

In part 1 of this blog, we introduced tools and methodology to help organizations constantly measure and improve their network’s resilience, in large part by mitigating privilege escalation paths discovered by BloodHound via network access.

In this blog, we will dive deeper into how network access can be integrated into BloodHound’s database and how the different tools can be used to better measure resilience.

How to Integrate Network Access into the BloodHound Database

The BloodHound Neo4j graph database is made up of nodes and edges. Nodes are entities inside a domain, such as a computer, group, user, etc., while edges describe the relationship between these nodes. For example, a computer and a user can have an edge between them “HasSession”, which means that user is logged on to that computer; or a user may have an edge “MemberOf”, which means they are part of a group.

To represent the “hidden” network dimension, we have to add an additional type of edge. We called this new edge “Open” to describe when network access exists from one entity to another, such as “Open” from computer A to B. It indicates the direction of the access, so computer A has network access to computer B, but computer B doesn’t have access to computer A. For simplicity sake, we ignored specific ports, based on the assumption that an “Open” edge means there is a significant port open between these hosts that could enable lateral movement, such as SMB, RDP, Powershell Remoting, etc.

Setting Up a Demo Dataset

To demonstrate and test our least privilege networking stance, we set up a demo lab, which simply consisted of a database in Neo4j. To create this database we used our DB Creator (based on SpecterOps DB Creator) which creates “Open” edges between random nodes in the database. We used the setavgcon parameter, which controls the average number of computers each computer can access, to describe the “restrictiveness” of the network. For example, a network with 5% average access, means that each computer in the network has access, on average, to 5% of the other computers in the network.

Collecting Network Access Information

To get the best results and to truly minimize network permissions for resilience requires complete visibility into existing network access. This information may already be available somewhere in the environment, but more likely it will need to be collected. Tools such as TrustMeternmap and CornerShot, can help provide this visibility. ShotHound can also be used to follow the paths in BloodHound, which can then be validated with CornerShot.

Once this information is collected, there is still some effort required to integrate this information into BloodHound’s database. It’s not very complicated, as a simple python script, or even a simple Cypher query, can do the job. The important part is to add “Open” edges between nodes with network access.

Finding Practical Paths

In part 1 of this blog series, we discussed how practical paths differ from logical ones. Mainly, practical paths are logical paths that are usable from a network point of view. This means it is open and can be used to get from point A to point B. All practical paths are logical, but not all logical paths are practical because network permissions may be restricted/blocked at some point along the route.

To discover if a logical path is practical, we generated the following Cypher query to find all the shortest paths to a domain admin and filters out impractical paths that are not supported by the network:

MATCH p=allShortestPaths((n)-[:MemberOf|HasSession|AdminTo*1..]->(m:Group {name:”DOMAIN ADMINS@TESTLAB.LOCAL”})) WHERE NOT n=m
WITH nodes(p) as nds,p
MATCH (src:Computer)-[:Open]->(trgt:Computer)
MATCH (c:Computer)
WHERE src IN nds AND trgt IN nds AND c IN nds
WITH p,nds,c,src,trgt,reduce(ix = -1, i IN RANGE(0,SIZE(nds)-1) | CASE nds[i] WHEN src THEN i ELSE ix END ) AS srcix, reduce(ix = -1, i IN RANGE(0,SIZE(nds)-1) | CASE nds[i] WHEN trgt THEN i ELSE ix END ) AS trgtix
WHERE trgtix > srcix
WITH p,size(collect(DISTINCT c)) AS total_hosts, size(collect(DISTINCT trgt)) AS total_targets
WHERE total_hosts = total_targets + 1

This query, along with several other queries, can be found in our custom_queries json file. The file can be copied and pasted to any local Bloodhound deployment and used to uncover only practical paths.

Measuring Practical Paths for Network Resilience

As we described in the first blog of this series, a very basic implementation of a least privilege network can dramatically reduce the number of practical paths available. The fewer practical paths, the more resilient the network.

The following Cypher query measures the percentage of practical paths to a domain admin as a measure of resilience. This query can be easily modified to calculate resilience against any other objective.

MATCH z=allShortestPaths((n)-[:MemberOf|HasSession|AdminTo1..]->(m:Group {name:”DOMAIN ADMINS@TESTLAB.LOCAL”})) WHERE NOT n=m
WITH count(z) as total_paths
MATCH p=allShortestPaths((n)-[:MemberOf|HasSession|AdminTo
1..]->(m:Group {name:”DOMAIN ADMINS@TESTLAB.LOCAL”})) WHERE NOT n=m
WITH nodes(p) as nds,p,total_paths
MATCH (src:Computer)-[:Open]->(trgt:Computer)
MATCH (c:Computer)
WHERE src IN nds AND trgt IN nds AND c IN nds
WITH total_paths,p,nds,c,src,trgt,reduce(ix = -1, i IN RANGE(0,SIZE(nds)-1) | CASE nds[i] WHEN src THEN i ELSE ix END ) AS srcix, reduce(ix = -1, i IN RANGE(0,SIZE(nds)-1) | CASE nds[i] WHEN trgt THEN i ELSE ix END ) AS trgtix
WHERE trgtix > srcix
WITH total_paths,p,size(collect(DISTINCT c)) AS total_hosts, size(collect(DISTINCT trgt)) AS total_targets
WHERE total_hosts = total_targets + 1
WITH count(p) AS practical_paths,total_paths
RETURN total_paths AS all_paths,practical_paths ,100 * practical_paths/total_paths AS path_resilience

We ran this query against several simulated databases, each with a different average access percentage. The detailed results are plotted below:

Is 0% Practical Paths Enough?

Even if we hit 0% on path resilience, it does not mean that there are no paths to the domain admin, it only means that all paths that were discovered were impractical. There could be other paths, longer ones, that are still practical. Even in medium-sized networks, the complexity associated with finding additional, longer, practical paths is computationally hard, which also makes it non trivial for attackers to find.

Having said that, attackers only need one good path to take over a network. A worm-like infection, such as ransomware, that tries to connect to every possible host in the network will eventually stumble upon a path(s) that can get them where they need to go. For that reason, it is also important to measure the network’s resilience against ransomware-like infections.

Resilience With Ransomulator

When an infection starts to spread in the network, for example a worm or ransomware, we can think of it as waves of compromise. The first wave is when the first host is compromised. The second wave is all the hosts that are compromised from that initial host. The third wave is all the hosts that are compromised from any hosts in the previous waves, and so on. The sooner a wave is blocked, the more its impact is limited, and the more resilient the network.

Calculating all possible infection waves is not always feasible when looking at all the logical paths. For that reason we developed Ransomulator.

Ransomulator can help discover infection paths so we can start to mitigate them. Ransomulator should be executed against BloodHound’s database, assuming the network information discussed earlier is already integrated into it. Once running, it will output the sizes of infection waves for each host. The following example shows how ransomulator evaluates all infection waves in a simulated dataset. This data can be exported for better analysis and plotted:

Armed with this information, the security team can follow these paths and apply mitigations to improve the resiliency of the network.

Summary and Next Steps

The lower the average access percentage, the less the impact an attack can on the environment. There are a number of tools and capabilities we’ve laid out to help security teams understand, measure and improve the resilience of their network to minimize attack impacts and damage.

We suggest you start to download and use some of these tools to help you establish and maintain the level of resilience you are looking for in your environment.

For any questions, please don’t hesistate to contact us at

Subscribe for
new posts

Request Demo