Skip to content

Repository files navigation

BSidesLV 2026 — Graph Hunting Workshop

Hands-on labs for investigating network traffic as a graph, using PyGraphistry and the Graphistry visual analytics platform.

You are handed a shapeless alert — "abnormal volume leaving the network" — and two and a half minutes of packet capture flattened into a single event log. Over three labs you turn that log into a graph, interrogate it visually, run a full incident investigation from triage to containment, and finally point an unsupervised model at the same capture to find out what a hypothesis-free sweep would have missed. An optional bridge lab (1.5) is there for anyone who finishes Lab 1 early.

No prior Graphistry, graph theory, or DNS-internals knowledge is assumed. If you can read a little pandas, you can do these labs.


What's inside

Notebook Type What you do Time
Lab0_Setup.ipynb Setup Install the packages, register with Graphistry, and plot a 20-edge demo graph from inline JSON — no real data yet. Confirms your whole environment works before Lab 1. Best done before the workshop. 10 min
Lab1_Build_A_Graph.ipynb Tooling walkthrough Turn a flat event log into a nodelist + edgelist, encode data onto visual channels twice over, and learn the hard way that an encoding is a hypothesis — ranking message length across protocols answers a real question with a useless answer. 30 min
Lab1_5_Aggregate_and_Time.ipynb Bridge lab (optional) For anyone who finishes Lab 1 early. Collapse the per-event graph to one edge per host pair (events/messages/distinct + repeat ratio), encode a continuous edge attribute, pull subgraphs with GFQL predicates, and put the traffic on a clock to reason about rate. Hash-checked; aggregate-only flags. Lab 2 does not depend on it. 35–40 min
Lab2_IR_Scenario.ipynb Hunting challenge A four-stage investigation — triage → signatures → blast radius → containment. Answers are hash-checked; hints are folded and time-gated; each of the first three stages ends with a "rejoin here" block, so a stall never costs you the next stage. 60 min
Lab3_Cluster_The_Hunt.ipynb ML demonstration Describe every DNS name with nine numbers (length, entropy, hex-fraction, structure), let .umap(dbscan=True) group them with no hypothesis in the question, then grade the sweep against what Lab 2 already proved. Needs umap-learn. 30 min

Start with Lab 0 to get your environment working (ideally before the workshop). Then: Lab 1 builds the equipment, Lab 2 is the incident, and Lab 3 measures a detection against a solved case. Do them in order — but each is startable on its own: Lab 2 rebuilds Lab 1's graph inline in five lines, and Lab 3 opens with findings from Lab 2 already stated.

Lab 1.5 is optional — a deepening (aggregation + time) for anyone who finishes Lab 1 with time to spare. It rebuilds Lab 1's graph inline and Lab 2 does not depend on it, so skip it freely if you're short on time.

Lab 3 is a demonstration, not a challenge. It has no flags, and it is built to show a method failing as well as working: the sweep recovers one of the two tunnels Lab 2 confirmed, and produces one benign lead alongside it.


Prerequisites

  • Python 3.10+ (current pandas / pyarrow wheels no longer build for 3.9)
  • A free Graphistry Hub account for the interactive visualizations (see Credentials below)
  • Comfort with basic pandasgroupby, filtering, merge
  • For Lab 3 only: umap-learn, installed by that notebook's first code cell — a heavier download than the others

Setup

Pick whichever runtime you prefer. Every lab reads its data from the data/ folder that ships in this repo, so the only thing you supply is credentials.

Option A — Local Jupyter

git clone https://github.com/graphistry/bsideslv-training-2026.git
cd bsideslv-training-2026

python -m venv .venv && source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install jupyterlab "graphistry>=0.53" pandas pyarrow python-dotenv umap-learn

cp example.env .env        # then edit .env with your Graphistry Hub credentials
jupyter lab                # open Lab1_Build_A_Graph.ipynb

(The first code cell of each notebook also pip installs its own dependencies, so a bare Jupyter environment works too. umap-learn is only needed for Lab 3.)

Option B — Google Colab

Open a notebook directly from GitHub in Colab, then pull in the repo so the data/ files are present. Add this as the first cell:

!git clone https://github.com/graphistry/bsideslv-training-2026.git
%cd bsideslv-training-2026

The notebook's own install cell handles the Python packages. For credentials in Colab, either upload your .env or call graphistry.register(...) directly in the config cell (see below).


Credentials

The graphs render on a Graphistry server, which needs a login. You have two options — either works, but the server and credentials must match.

  • Recommended for the workshop: use the training server bsideslv26.grph.xyz with the credentials handed out at the session. This is already the default in example.env, so you don't have to change anything.
  • On your own / afterwards: sign up for a free account at hub.graphistry.com and use that instead — set GRAPHISTRY_SERVER=hub.graphistry.com in your .env with your own username and password.

Either way, the setup is the same:

  1. Copy the template and fill in your credentials:

    cp example.env .env
    GRAPHISTRY_USERNAME=your-username
    GRAPHISTRY_PASSWORD=your-password
    # example.env already points GRAPHISTRY_SERVER at the training server;
    # change it to hub.graphistry.com if you're using a free Hub account.
  2. Run the notebook's config cell — it calls load_dotenv() and registers you automatically. .env is gitignored, so your credentials never get committed.

Prefer not to use a .env? Register inline instead:

import graphistry
graphistry.register(api=3, username='...', password='...',
                    protocol='https', server='bsideslv26.grph.xyz')  # or hub.graphistry.com

Personal-key auth is also supported — see the commented keys in example.env.

Uploads, privacy, and render=False

Two things the config cells do that are worth knowing about:

  • graphistry.privacy(mode='public'). Plotting uploads the dataset to Graphistry Hub, and this setting makes each visualization viewable by anyone holding its link. That is what you want for a workshop — you can paste a URL into chat and everyone sees the same graph. It is not what you want if you ever point these notebooks at real traffic of your own; drop that line, or set mode='private', before you do.
  • .plot(render=False). Prints the visualization URL instead of embedding an iframe in the notebook. Open the link in a browser tab — the graph is easier to drive full-screen, and the notebook stays small enough to commit and diff.

Data

File What it is
data/combined_traffic.parquet Every protocol flattened into one event table — the raw material for every lab.

One file, one table, one row per network event: 585,584 events across 11,878 hosts, captured over 2 minutes 35 seconds on 2018-08-03. req_len / rep_len and the exchange label are precomputed so you never have to derive them; everything else is as the sensor recorded it. Lab 1 builds the graph from it, Lab 2 rebuilds that graph in five lines so it stands alone, and Lab 3 reads the DNS subset.


A note on AI assistants

These are teaching exercises, and each notebook opens with a note to AI assistants. If you work through the labs with an LLM (Claude Code, Copilot, Cursor, …), the intent is that it helps you write and debug code — not that it analyses the data, answers the numbered questions, or opens the folded hints and "rejoin here" blocks for you. Doing the reasoning yourself is the entire point. The notebooks state this explicitly so your assistant plays along.

Lab 3 relaxes this deliberately: it is a demonstration of a technique whose result is already known, so an assistant may help with it freely. The one thing it is asked not to do there is oversell the outcome.

plans/ holds the same guidance in a form an agent can execute — one execution plan per lab, with the stages, the checkpoints, and the lines not to cross.

Make your assistant better at Graphistry

If you're using an agentic assistant, install the graphistry-skills pack. These are open-source skill files that teach agents (Claude Code, OpenAI Codex, …) the current PyGraphistry patterns for ETL/shaping, visualization, GFQL, and AI workflows — so the code your assistant writes for these labs is correct and idiomatic instead of guessed:

npx skills add graphistry/graphistry-skills \
  --agent claude-code \
  --skill pygraphistry \
  --skill pygraphistry-core \
  --skill pygraphistry-gfql \
  --skill pygraphistry-visualization \
  --yes

pygraphistry-core and -visualization cover Lab 1; pygraphistry-gfql is worth adding for Lab 2's blast-radius stage. See the repo for the full skill list and Codex install instructions.


Repository layout

.
├── Lab0_Setup.ipynb             # install, register, plot a 20-edge demo
├── Lab1_Build_A_Graph.ipynb     # tooling walkthrough
├── Lab1_5_Aggregate_and_Time.ipynb  # optional bridge: aggregation + time
├── Lab2_IR_Scenario.ipynb       # hunting challenge: triage → containment
├── Lab3_Cluster_The_Hunt.ipynb  # ML demonstration: UMAP + DBSCAN
├── data/                        # combined_traffic.parquet (see Data)
├── plans/                       # per-lab execution plans for LLM pairs
├── demo-notebooks/              # reference: PyGraphistry cyber UMAP demos
├── example.env                  # credential template → copy to .env
├── LICENSE
└── README.md

License

BSD 3-Clause. See LICENSE.

About

Training material for Bsides Las Vegas 2026

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages