Quickstart

Note

Please check VirusTotal Graph overview before start.

Basic usage

Start by importing the vt_graph_api module:

>>> import vt_graph_api

Creates a new graph (replace <apikey> with your actual VirusTotal API key):

>>> graph = vt_graph_api.VTGraph("<apikey>", name="My Graph", private=False)

Warning

Private graphs are only allowed for premium users.

Nodes

Nodes are the minimum unit of graph representation. There’s some basic node types, and we have also the opportunity to represent our own custom node types, so we can specify any type such as “actor” or “email”. The basic node types are the following:

  • file
  • domain
  • ip_address
  • url

The difference between basic nodes and custom nodes is that the first ones could be expanded using VirusTotal API.

Adding Node

Warning

Adding a file node with no sha256 hash, url node with raw URL instead of an VirusTotal URL identifier or unknown ID with fetch_vt_enterprise option, consumes API quota.

We can either add a basic node:

>>> graph.add_node("www.virustotal.com", "domain", label="mynode")

Or our own custom type:

>>> graph.add_node("badguy", "victim")")

We can also specify that we want to fetch information on VirusTotal, about the node we are adding by setting fetch_information to True:

>>> graph.add_node("www.virustotal.com", "domain", fetch_information=True)

You can improve the search using VirusTotal Intelligence by setting fetch_vt_enterprise to True.

Warning

fetch_vt_enterprise flag is only available for premium users.

If we want to add some nodes at the same time we can use add_nodes, this method receive a node list which is a list of dictionaries with the following structure:

node_list = [
    ...
    {
      "node_id" = "www.virustotal.com",
      "node_type" = "domain",
      "label" = "mynode",   # This attribute is optional.
      "attributes" = "",  # This attribute is optional.
      "x_position" = "", # This attribute is optional.
      "y_position" = ""  # This attribute is optional.
    },
    ...
]

>>> graph.add_nodes(node_list, fetch_information=True)

See also

For advanced usage, please check API Reference.

Warning

Setting fetch_information to True consumes API quota.

Deleting Node

graph.delete_node("www.virustotal.com")

This method will raise NodeNotFoundError if the given node id does not belong to the graph.

Note

This method also deletes every link which have relation with the deleted node.

Checking if node id belongs to graph

It is possible to check if graph has a node id using:

>>> graph.has_node("www.virustotal.com")
False

Expansions

An expansion is the action to get related nodes to a node.

See also

Please see VirusTotal documentation in order to check relationship types:

Expanding node by a given expansion

There is file node with the hash 7ed0707be56fe3a7f5f2eb1747fdb929bbb9879e6c22b6825da67be5e93b6bd2 and we want to know the domains that the file has contacted with, so we can use VirusTotal API to get the connected domains by expanding the file node using contacted_domains as expansion type.

>>> graph.expand("7ed0707be56fe3a7f5f2eb1747fdb929bbb9879e6c22b6825da67be5e93b6bd2", "contacted_domains")

This method adds to the graph the contacted domains returned by VirusTotal API.

Note

It is possible to specify the maximum number of nodes returned by the expansion, setting max_nodes_per_relationship parameter.

Warning

This call consumes API quota as much as max_nodes_per_relationship/max_nodes_per_query.

Note

max_nodes_per_query = 40, this is the maximum number of nodes that we can request to VirusTotal API per query.

See also

Please check API Reference for more information.

Expanding node one level

We can expand a node in all of his available expansions:

>>> graph.expand_one_level("7ed0707be56fe3a7f5f2eb1747fdb929bbb9879e6c22b6825da67be5e93b6bd2", max_nodes_per_relationship=10)

Warning

This call consumes API quota as much as the number of node’s expansions * max_nodes_per_relationship/max_nodes_per_query.

Expanding the whole graph

Alternatively we can expand the whole graph all the levels that we want:

>>> graph.expand_n_level(level=2)

Note

As the methods before, we can specify max_nodes_per_relationship and max_nodes to ensure that we will not take more nodes than necessary.

Warning

This call consumes API quota as much as the number of total expansion of each graph node * max_nodes_per_relationship/max_nodes_per_query.

See also

Please see API Reference for more information.

Save

Once our graph is finished we can save it in VirusTotal:

>>> graph.save_graph()

Note

At this point if the Graph is set public it will be searchable in VirusTotal UI.

Load

We can recover a VirusTotal Graph if we have his ID:

>>> vt_graph_api.VTGraph.load_graph("<graphid>", "<apikey>")

We can retrieve graphs that we are viewer, editor or owner.

Warning

We cannot modify and save the loaded graph if we have no editor permissions.

See also

Please see also clone_graph method.

Clone

>>> vt_graph_api.VTGraph.clone_graph("<graphid>", "<apikey>")

Warning

This method does not clone the original user/group viewers/editors. It is necessary to call save_graph() in order to save the cloned graph in VirusTotal.

See also

Please check API Reference for advanced usage.

Utilities

Check if someone is viewer

>>> vt_graph_api.is_viewer("<username>", "<graphid>", "<apikey>")
False

Check if someone is editor

>>> vt_graph_api.is_viewer("<username>", "<graphid>", "<apikey>")
False

Getting iframe

We can also get an iframe link in order to embed the graph in our website.

>>> vt_graph_api.get_iframe_code()
'<iframe src="https://www.virustotal.com/graph/embed/<<graph_id>>" width="800" height="600"></iframe>'

Getting API quota consumed

We can get how many API quota we have consumed since the script started

>>> graph.get_api_calls()
1257