Note: This blog post is an extract from the Graphs for Cybersecurity white paper by Dave Voutila, Gal Bello, Tara Jana, and Deb Cameron.
Cyberattacks had been on the rise for years, with nation state threat actors and foreign hacking collectives joining in, devoting more time and resources to attacks. To effectively mitigate cybersecurity risks, we need advanced data solutions that empower us to correlate and analyze connections at a real-world scale.
In the earlier blogs of the series, we discussed how attackers and defenders think in graphs, an overview of cyberthreats, and policies and strategies we can adopt to mitigate these threats.
In this part 3 and the last part of the series, we’ll show you how building a knowledge graph can support you at all stages of an attack – from before it begins to until it ends as well as for subsequent incident analysis.
Knowledge Graph as Digital Twin
A knowledge graph creates a digital twin of your environment, enabling you to represent all or part of your network data in a holistic view. This view is very useful for cybersecurity analysts to query and take action on. In addition, the knowledge graph can be analyzed by data scientists, who build models to detect malicious activities.
The task of automating and systematizing cybersecurity relies on processing the organization’s security data and bringing it into the graph. The digital footprint might include:
- Which systems connect to which systems
- Which systems are open to the Internet
- Users and the groups they belong to
- What permissions are given to members of the groups
- Your policies and the systems to which they are applied
- The systems that are most important to protect (the crown jewels)
Your graph may include events like:
- User access events
- Application resources usage
- Devices connected
- Service health
Creating a Graph of Network Infrastructure
Networks are graphs by nature, comprised of connections. Storing this information in a graph database enables actionable insight and analysis.
It is easier than you might think to create a graph of your network. For example, the major cloud providers offer metadata API services for describing the infrastructure that a customer has in place. This data can then be easily ingested into a graph database like Neo4j. For example, GCP offers the Cloud Asset Inventory; Azure has the Azure Resource Management API and Microsoft Graph API; AWS offers its AWS Organizations API.
Alternatively, some tools create a network graph for you, such as Cartography, an open source tool built on Neo4j and described in the appendix for this paper.
For on-premise platforms, you can investigate the system resources – in VMWare or HyperV, for example – using the vendor’s provided APIs.
Once the information is in the graph database, it is straightforward to run queries and visualize the network structure.
This simple Cypher query returns 200 nodes, as shown in the following screenshot.
MATCH (n) RETURN n LIMIT 200
With your network structure loaded into the graph, you can identify the crown jewels that need the most protection. Give special labels or properties to nodes for valuable resources. You can then easily query them and track dependencies. Add relationships that mark critical access paths (our sample graph includes relationships such as FIREWALL_INGRESS for example).
Adding Software Information to the Graph
If you are already using configuration management tools, you can use their APIs to ingest the versions and health reports of the software and operating systems they monitor. If you are not using configuration management tools, you can start with Nessus or Nmap, which can scan networks and devices and combine that information with software activity logs to provide information such as versions, libraries, ports they use, who is accessing them, and which resources they rely on. You then ingest this information into your graph.
Enriching the Graph With Threat Intelligence
MITRE, NIST, and others have created vulnerability databases that are used industry-wide. By ingesting this data into your graph, you can see where the vulnerabilities impact critical resources and reveal potential attack paths to those resources.
The ATT&CK-D3FEND matrices, developed by MITRE, are a freely available set of tactics and exploits that attackers have been known to use and a corresponding set of defensive measures used to counter them. Once you visualize your infrastructure as a graph, you can see the set of attack paths, including information from ATT&CK. You can then link to the defense tactics from D3FEND. GraphKer, an open source tool discussed in the appendix, simplifies the process of loading threat intelligence into Neo4j.
Visualizing Vulnerabilities and Attack Paths
Attack paths take the attackers’ perspective and show the path of potential multistage attacks along with the vulnerabilities used at each stage. This process goes beyond a static list of vulnerabilities and looks at how an attacker could use them.
An attack path analysis can identify different paths an attacker may take through your infrastructure to reach those assets. All the attack paths on a network together form an attack graph. Visualizing the paths as a graph is intuitive, especially with a graph data visualization tool such as Neo4j Bloom.
Assessment, Planning, and Preparation
A digital twin of your IT environment has tactical advantages. You can programmatically assess the impact of changes to your environment before implementing them.
Having an approval gate to check changes is critical to protecting the system. Depending on the rules you implement, you can automatically reject or roll back suspicious changes or raise tickets to review them manually.
Analyzing the Digital Twin Using Graph Algorithms
One approach to security is to find the types of vulnerabilities that affect the largest share of your infrastructure. Then, assessing the likelihood of these assets being breached will reveal where to focus resources to achieve a tremendous increase in security.
A more visionary approach looks at each node’s context in the network to decide on the most important nodes to focus on.
The Cypher examples in this section make some assumptions:
- You have created a graph of your IT infrastructure and classified some nodes as externally facing.
- You know the node IDs of your most valuable assets (your crown jewels).
- You have installed Neo4j Graph Data Science so you can run graph algorithms to analyze your graph as a whole.
In this Cypher example (available in the code repository for this white paper), we call a shortest path algorithm to discover the shortest path to a valuable resource called target node. We build a graph of all the paths from the Internet to a specific crown jewel and add a POSSIBLE_ATTACK relationship.
# build a graph of all shortest attack paths to a specific crown jewel MATCH (external:ExternalFacingNode) CALL gds.shortestPath.dijkstra.stream(“attackPathGraph”, { sourceNode: id(external), targetNode: targetId, path: true}) YIELD sourceNode,targetNode,nodeIds # create POSSIBLE_ATTACK relationships WITH nodeIds UNWIND apoc.coll.pairsMin(gds.util.asNodes(nodeIds)) AS pair WITH pair[0] AS toNode, pair[1] AS fromNode MERGE (toNode) <- [:POSSIBLE_ATTACK] - (fromNode)
We then get all the pairs of nodes in that attack graph and score them using the betweenness centrality algorithm. We then write those scores back to the database:
CALL gds.graph.create(‘centralityGraph’, ‘*’, { relType: { type: ‘*’, orientation: ‘UNDIRECTED’, properties: {} }}, {}); CALL gds.betweenness.stream(‘centralityGraph’, {}) YIELD nodeId, score WITH gds.util.asNode(nodeId), score AS betweenness RETURN n.name, betweenness ORDER BY betweenness DESC
Each node is returned with a score based on how many possible attack paths go through it.
Attaching a probability to each hop in the attack paths enables you to use the graph as a vulnerability tree and predict which attacks are the most likely to succeed.
A score combining the two numbers we have calculated – the node’s centrality and the likelihood of attacks being carried out – would be a powerful metric for prioritizing efforts.
Threat Intelligence and Prediction
Certain events increase the likelihood of attacks. For example, when a company is mentioned in the news, it is more likely to come onto attackers’ radar.
Similarly, as new vulnerabilities are disclosed, attackers will test them out. Suppose you have set up a system to ingest vulnerabilities from vulnerability databases automatically. Then, as described earlier, you can quickly build reports and create alerts about the potential impact on the crown jewels and take proactive security measures to mitigate those threats.
Detection
Unfortunately, it is impossible to guarantee complete security, so detecting breaches is critical if any measures to limit the attack are to be taken.
With your data loaded into a graph database, you can automatically run queries to flag specific patterns of events on the network.
You may detect suspicious actions by looking for unusual patterns. For example, you may want to monitor how many attempts an IP address has made to log into a system or systems or how many logins you are seeing from a country people do not normally log in from. A graph showing accounts and IPs logged into them would likely make it easy to identify such patterns.
You can uncover data leaks by monitoring access to files from unexpected accounts and IP addresses. For example, suppose a user rarely looks at files on the network but suddenly accesses many files using IP addresses or devices that they have not used before. Such events may indicate that an account has been compromised, and you can detect this automatically.
If you detect that your network is being scanned and analyzed, this can indicate the start of an attack. In addition, if you know which resources have been scanned, you know where the attack is most likely to hit and can take additional measures to protect or obfuscate that target.
If you pick up attack fingerprints that have been seen before, this may mean that a similar attack strategy is being followed – perhaps even by the same attacker.
Intrusion detection systems (IDS) monitor your network for signs of intrusion. Load IDS data into the graph to see whether an attack is in progress.
An unexplained network traffic surge may be the start of a DDoS attack.
Once you detect an attack in progress, you can use the graph to find out more about the attackers, including their IP addresses.
Correlating these signals, you can more easily detect attacks and mitigate any future attacks.
Investigation and Response
Once you find suspicious events, the top priority is to discover whether they are innocuous or represent an actual attack.
Suppose you can holistically view the suspicious events together on a graph. Then, you can find the commonalities between them and assess the scale of the attack and where it might be originating from on the network. Graphs further empower you to examine all of the contextual information around these events, such as the user accounts and devices involved.
Graph visualizations show the critical information that will be required to determine how to stop the attack – potentially by blocking user accounts or access from specific IP address ranges.
Cyberattacks are usually a chain of system compromises. If you were to model all the cyberattacks you see and their chains of compromises, that model would naturally take the form of a graph. When you are suffering a cyberattack, predicting the attackers’ next move is a case of matching the latest attack with a node on the graph and seeing which events most often came next.
With system dependencies modeled in the network graph, you can run a simple query to find out which other systems will be affected when one system is compromised or taken offline by a DDoS attack for example:
MATCH (compromisedSystem) <- [:DEPENDS_UPON*] - (system:System) RETURN system
Next, the security staff can alert the teams responsible for the systems under attack. To query for the teams maintaining the systems dependent on the compromised system, you may run a query like this one:
MATCH (compromisedSystem) <- [:DEPENDS_UPON*] - (system:System) <- [:SUPPORTED_BY] - (team:Team) RETURN team
Finding Compromised Systems After a Phishing Attack
A great strength of graph databases is the ability to explore connections deeply. For example, if we start with a phishing email, we can find all the emails that the user sent in that time, get the receiving accounts, and then get all the systems connected to see the possible extent of the phishing attack.
MATCH (phishingEmail) - [:WAS_SENT_TO] - (user:User) -[message:SENT_EMAIL_TO|SENT_SLACK_MESSAGE_TO|SENT_IM_TO*0..6] - (recipient) - [connection:CONNECTED_TO_SYSTEM] - (potentiallyCompromisedSystem: System) WHERE connection.date > phishingEmail.sentDate RETURN potentiallyCompromisedSystem
This query finds all potentially impacted entities that are connected to the compromised system by six hops or less.
Grouping Incidents Using Community Detection
Security incidents can be loaded into a graph database and grouped as communities using community detection algorithms like Louvain. There are many cases where alerts might be related.
They might indicate:
- The same attack such as a DDoS attack in progress
- The same event picked up by different detection mechanisms
- Multiple parts of one attack, like multiple hosts being probed by the same machine or phishing emails sent to several recipients
Given a graph database with a group of alerts, this Cypher code runs the Louvain graph algorithm to find communities.
CALL gds.graph.create({ ‘communities’, ‘Alert’, { relType: { type: ‘*’, orientation: ‘UNDIRECTED’, properties: {} } } }); CALL gds.louvain.write(‘communities’, { writeProperty: ‘communityId’} );
After running Louvain on the alerts, you can analyze the events further. We can create an AlertGroup object representing each community and link the alerts to their community using the communityId field that the algorithm populated:
MATCH (a:Alert) MERGE (a) -> [:IN_GROUP] -> (ag:AlertGroup {name: a.communityId}
The graph now has the same objects as if we had run the following Cypher:
MERGE (g1:AlertGroup {name: ‘1’}) MERGE (g2:AlertGroup {name: ‘2’}) MERGE (:Alert {name: ‘a’, communityId: 2, from: ‘evilcorp’}) – [:IN_GROUP] -> (g2) MERGE (:Alert {name: ‘b’, communityId: 2}) - [:IN_GROUP] -> (g2) MERGE (:Alert {name: ‘c’, communityId: 2}) - [:IN_GROUP] -> (g2) MERGE (:Alert {name: ‘d’, communityId: 2}) - [:IN_GROUP] -> (g2) MERGE (:Alert {name: ‘e’, communityId: 1, from: ‘nicecorp’}) - [:IN_GROUP] -> (g1)
Now we can use the information on the alerts to decide how much we trust the group as a whole, and write that information to the group:
MATCH (group:AlertGroup) - [:IN_GROUP] - (e:Alert {from: ‘nicecorp’}) SET group.trustworthy=’high’; MATCH (group:AlertGroup) - [:IN_GROUP] - (e:Alert {from: ‘evilcorp’}) SET group.trustworthy=’low’;
To view this information:
MATCH (a:Alert) - [] - (ag:AlertGroup ) WHERE ag.trustworthy IS NOT NULL RETURN a, ag
The complete code for this example (and all the examples in this paper) is available in its Github repository.
As we have seen, creating and analyzing a graph of your infrastructure – a digital twin – is one of the most effective measures you can take for improving your cybersecurity posture and managing the endless, dynamic complexity of cybersecurity vulnerabilities and threats.
Of course, when you create a digital twin of your infrastructure, you will find it serves many other purposes. Here are a few:
- Lending Tree sought to create a real-time view of its microservices and dependencies; soon they also used the tool to predict their monthly cloud usage
- Vanguard refactored their application from Java monoliths to microservices, mapping it all in Neo4j to improve software quality and enforce best practices
- The UK Department for Education uses Neo4j AuraDB to map and modernize its IT landscape, consolidating software licensing and paying for their subscription with their savings
Graphs eat complexity for breakfast, and there is no area more complex than the ever-morphing cybersecurity threats we face today.
Why Neo4j for Cybersecurity
The Neo4j Graph Data Platform offers a way to model, manage, and transform ever-changing cybersecurity landscapes.
The powerhouse at the core of the platform is the Neo4j Graph Database. Fully ACID compliant, Neo4j is a native graph database, optimized for storing data as a graph structure. Neo4j connects data as it is stored, enabling it to traverse connections orders of magnitude faster.
Neo4j provides security at the database level. Role-based access control empowers organizations to create rules about sensitive data and know that those rules will be applied across all applications and uses of Neo4j. Administrators declare role-based permissions at the schema level and all data is protected in accordance with those permissions.
Neo4j includes powerful developer tools to help you efficiently write, profile, and debug queries as well as visualize and explore your data. As we have seen, Cypher is simple and powerful, not to mention faster and far more compact than SQL. With the Neo4j GraphQL Library, you can generate Cypher from GraphQL, further empowering front-end developers. Connectors bring in streaming data from Kafka and Spark.
Neo4j Graph Data Science powers analysis and insights from graph datasets with billions of nodes. Neo4j Graph Data Science offers an enterprise-ready analytics workspace, more than 65 ready to run graph algorithms, and easy-to-use machine learning pipelines.
Neo4j Bloom enables novices and experts alike to visually investigate and explore their graph data from different perspectives. Rich graph visualizations drive understanding and alignment of technical and business staff, enabling rapid progress.
Storing your data in an enterprise-ready graph database like Neo4j empowers you to solve your most pressing problems and then expand your use case as needed. Answer any query in milliseconds, visualize your graph to see patterns, and use Neo4j Graph Data Science to identify anomalies and vulnerabilities proactively before attackers exploit them.
Get started right away with Neo4j or learn more about Neo4j for cybersecurity by attending a Connections event, or email us at cybersecurity@neotechnology.com.
Open Source Tools and Github Repository
Loading Infrastructure Into Neo4j
Here are two open source tools that enable you to load your infrastructure into Neo4j.
Cartography is an open source tool for auditing cloud infrastructure. It scans the public clouds, Kubernetes setups, Github accounts, Okta installations, and PagerDuty and puts the information into a graph in Neo4j. If you are looking for a simple starting point, Cartography may be a good tool to help you load your organization’s network into Neo4j.
Bloodhound is an auditing and examination solution that queries everything in your Active Directory domain and loads it into a Neo4j database. It includes prewritten queries to explore your domain and look for security weaknesses. For example, you can explore routes on your domain and find routes from nodes marked as compromised to the domain administrator nodes.
Loading Threat Intelligence Into Neo4j
The landscape of cybersecurity vulnerabilities, weaknesses, and attack patterns is continually evolving. MITRE and NIST both publish open data describing these items, and GraphKer is designed to make it easy to visualize and analyze this data.
GraphKer represents every public record of every CVE, CWE, CAPEC and CPE provided by MITRE and NIST and connects them using Neo4j.
This Python tool scrapes the MITRE and NIST websites and loads the data into Neo4j. The data is also regularly published as a Neo4j database backup file, which you can easily load into Neo4j. You can then quickly examine the data using an exploration tool like Neo4j Bloom or query it using Cypher.
You can link this data with the data in the graph you have describing your network. For example, you could link software running on your machines to the related vulnerability database entries, and update the data automatically so you can easily see the latest vulnerabilities and proactively apply relevant fixes.
Github Repository
If you would like to put the code in this blog to work, download it from the Github repository.