Visualizing Computer Networks

Using Dash Cytoscape to create interactive visuals based on real computer network data

Eamon O'Connor
The Startup

--

Photo by Alina Grubnyak on Unsplash

Background

I work in Cyber Security. And if I’m being really honest, it’s not very interesting. There are plenty of tools, open-source or proprietary, that can automate many of the tedious tasks within a security role, but I always find myself more fascinated by how the tool works than by how much it’s helping me.

Cyber Security, Incident Response, Digital Forensics…They’re all very destructive by nature. But I’m a creative. How can a creative add value to an intrinsically destructive field? And how can I make my job more interesting by mixing it with my interests?

By creating tools.

This post is a walkthrough of a personal project I completed, which is a small step towards the creation of my own tool.

The Project

Turning thousands of lines of pcap data into interactive network visualisations.

Complete code available on my github repository.

Image by Author

Too often an Incident Responder asks for a map of the network, only to discover it’s more than 2 years old and not much more than a ghost of the current network topology.

So we try to create the ‘ground truth’ of what the network actually looks like. Various tools can be used for this, netflow, nmap, tracert. This example will focus on network packet captures, but a bit of Python applied in the right doses could adapt this project to any network mapping command line tool output.

Wireshark is a great tool, but as the size of the packet capture increases, the performance drops as it tries to parse the potential hundreds of thousands of lines of traffic data.

So I began by exporting my pcap data to a csv. Which python loves.

Parsing Script

The script is on the repo. It’s not fancy. It was a quick and dirty creation to produce a quick result. Python is good for that. Which I love.

I managed to turn about 10,000 lines of this (data is publicly available and not licensed)

"No.","Time","Source","Destination","Protocol","Length","Info""1","0.000000","220.175.8.56","80.171.48.1","Messenger","488","NetrSendMessage request""2","300.930215","222.136.251.117","80.171.48.1","Messenger","488","NetrSendMessage request""3","300.931213","222.136.251.117","80.171.48.1","Messenger","488","NetrSendMessage request""4","860.029588","70.85.177.186","80.171.48.1","Messenger","521","NetrSendMessage request""5","860.030586","70.85.177.186","80.171.48.1","Messenger","521","NetrSendMessage request""6","919.623101","61.239.151.129","80.171.48.1","Messenger","843","NetrSendMessage request"+ ~10000 more lines

Into this (feel free to scroll past) The output isn’t too interesting…yet.

[{"data": {"id": "10.200.1.18", "label": "10.200.1.18"}},{"data": {"id": "10.50.1.54", "label": "10.50.1.54"}},{"data": {"id": "10.200.1.252", "label": "10.200.1.252"}},{"data": {"id": "10.200.1.162", "label": "10.200.1.162"}},{"data": {"id": "54.175.48.202", "label": "54.175.48.202"}},{"data": {"id": "10.200.1.184", "label": "10.200.1.184"}},{"data": {"id": "10.200.1.45", "label": "10.200.1.45"}},{"data": {"id": "10.200.1.51", "label": "10.200.1.51"}},{"data": {"id": "10.200.1.191", "label": "10.200.1.191"}},{"data": {"id": "10.200.1.231", "label": "10.200.1.231"}},{"data": {"id": "10.200.1.86", "label": "10.200.1.86"}},{"data": {"id": "10.200.1.178", "label": "10.200.1.178"}},{"data": {"id": "8.8.8.8", "label": "8.8.8.8"}},{"data": {"source": "10.200.1.18", "target": "10.50.1.54", "weight": 10901}},{"data": {"source": "10.50.1.54", "target": "10.200.1.18", "weight": 10794}},{"data": {"source": "10.200.1.18", "target": "10.200.1.252", "weight": 54}},{"data": {"source": "10.200.1.252", "target": "10.200.1.18", "weight": 86}},{"data": {"source": "10.200.1.162", "target": "10.200.1.18", "weight": 1040}},{"data": {"source": "10.200.1.18", "target": "10.200.1.162", "weight": 67}},{"data": {"source": "10.200.1.18", "target": "8.8.8.8", "weight": 11}},{"data": {"source": "10.200.1.18", "target": "54.175.48.202", "weight": 46}},{"data": {"source": "54.175.48.202", "target": "10.200.1.18", "weight": 29}},{"data": {"source": "10.200.1.18", "target": "10.200.1.184", "weight": 45}},{"data": {"source": "10.200.1.184", "target": "10.200.1.18", "weight": 70}},{"data": {"source": "10.200.1.45", "target": "10.200.1.18", "weight": 1636}},{"data": {"source": "10.200.1.18", "target": "10.200.1.45", "weight": 102}},{"data": {"source": "10.200.1.18", "target": "10.200.1.51", "weight": 55}},{"data": {"source": "10.200.1.51", "target": "10.200.1.18", "weight": 85}},{"data": {"source": "10.200.1.18", "target": "10.200.1.191", "weight": 14}},{"data": {"source": "10.200.1.191", "target": "10.200.1.18", "weight": 16}},{"data": {"source": "10.200.1.231", "target": "10.200.1.18", "weight": 979}},{"data": {"source": "10.200.1.86", "target": "10.200.1.18", "weight": 3}},{"data": {"source": "10.200.1.18", "target": "10.200.1.86", "weight": 2}},{"data": {"source": "10.200.1.18", "target": "10.200.1.178", "weight": 15}},{"data": {"source": "10.200.1.178", "target": "10.200.1.18", "weight": 12}},{"data": {"source": "10.200.1.18", "target": "10.200.1.231", "weight": 6}},{"data": {"source": "10.200.1.18", "target": "10.200.1.231", "weight": 6}}]

So we managed to turn over 10,000 lines of csv data into about 38 lines of json. The nifty thing about the script was that it created a weight attribute.

For example.

{"data": {"source": "10.200.1.162", "target": "10.200.1.18", "weight": 1040}}

See above how the weight is 1040? That means that the source connected to the target 1040 times. We don’t need to see every connection, just how many there were.

Dash

Dash was built by Plotly on top of Flask to integrate python data visualisations into web apps.

Cytoscape

According to https://js.cytoscape.org/, cytoscape.js is

[A]Graph theory (network) library for visualisation and analysis.

Dash-Cytoscape

“Dash Cytoscape is a graph visualization component for creating easily customizable, high-performance, interactive, and web-based networks. It extends and renders Cytoscape.js, and offers deep integration with Dash layouts and callbacks, enabling the creation of powerful networks in conjunction with the rich collection of Dash components, as well as established computational biology and network science libraries such as Biopython and networkX.”

— xhlulu and the Dash Team, https://dash.plotly.com/cytoscape

Building the app

I can’t take too much credit for this code, as the Plotly team made it so easy.

All you really need to do is copy the quickstart guide on the dash-cytoscape page, plug in your data, select your layout and run the app.

I added a json import to load my newly created json data.

import dashimport dash_cytoscape as cytoimport dash_html_components as htmlimport json

Create an instance for your app

app = dash.Dash(__name__)

Load your data

with open('net.json', 'r') as f:data = json.load(f)

Create your layout

app.layout = html.Div([cyto.Cytoscape(id='cytoscape-compound',layout={'name': 'breadthfirst','roots': '[id = "Web"]'},style={'width': '100%', 'height': '1000px'},stylesheet=[{'selector': 'node','style': {'content': 'data(label)'}},{'selector': '.segment','style': {'width': 5}},{'selector': '.joiner','style': {'line-style': 'dashed'}}],elements=data)])

Run the server when you run the file

if __name__ == '__main__':app.run_server(debug=True)

And the result!

Image by Author

You can head over to my repo for more detailed instructions on creating the code, cloning the repo and inserting your own data.

Thank you for reading. See you in the cloud.

Eamon

Twitter @ejooco

Github https://github.com/ejooco

--

--

Eamon O'Connor
The Startup

Creative Destruction | Web Dev | Data Science. I am a military veteran studying a Masters in Data Science, Strategy and Leadership.