Detecting C2 Beaconing in VPC Flow Logs With Pythonic Periodicity Check

BY

Asante Babers

/

Apr 18, 2025

/

Detection Engineering

/

5 Min

Read

Detecting C2 Beaconing in VPC Flow Logs With Pythonic Periodicity Check

When I first started looking into detecting command-and-control (C2) beaconing activity in cloud environments, I kept running into the same roadblock: either the solutions were too heavy (machine learning models, expensive SIEM pipelines), or too narrow (static indicators, fragile regex). I wanted something practical, lightweight, and—most importantly—natively Python.

Recently, I read a fascinating blog post by Diego (@diegowritesa) on detecting C2 beacons using frequency analysis. That lit a fire under me. If periodicity is the fingerprint of a beacon, why not catch that rhythm in the flow logs?

🧠 What Are We Looking For?

In C2 communications, infected hosts "call home" to a malicious server on a fixed or jittered schedule. It might be every 30 seconds, or maybe it’s random-ish—45s, 47s, 49s—but it’s still periodic.

These "beacons" are subtle. They don’t transfer much data. They’re fast. And they’re easy to miss with traditional detection methods.

But here’s the key: even jittered beacons form patterns—and patterns can be caught with basic signal analysis techniques.

🛰️ Signal Analysis for Security: A Quick Primer

In signal processing, we often use Fast Fourier Transform (FFT) to detect periodicity in data. FFT takes a time-based signal (like a series of timestamps) and transforms it into the frequency domain, showing us which patterns (or "frequencies") are most dominant.

Sounds fancy, but it’s just math. And while FFT is great, it's overkill for Panther’s real-time Python engine, and we don’t have NumPy or SciPy here.

So instead, we approximate that idea using intervals between timestamps and check if they cluster tightly. It’s not FFT, but it’s a cousin—let’s call it the Pythonic Periodicity Check.

🧪 The Game Plan

Here’s the strategy we’ll use in our detection rule:

  1. Track connections per IP pair (source → destination).

  2. Cache timestamps of each connection using Panther’s caching helpers.

  3. Compute intervals between those timestamps.

  4. Check for consistent timing (low standard deviation, tight clustering).

  5. Fire an alert if it looks beacon-y.

🧑‍💻 Step-by-Step Code

Step 1: Import Caching Helpers


Step 2: Extract Fields from AWS.VPCFlow Schema


Step 3: Cache Timestamps Using Panther Helpers

cache_key = f"beacon:{src_ip}:{dst_ip}:{proto}"
timestamps = get_string_set(cache_key)

# Convert timestamps from string to float (seconds)
timestamps = [float(t) for t in timestamps]
timestamps.append(start_ts.timestamp())
timestamps = sorted(timestamps)[-30:]

We use a unique cache key per communication pair and store up to 30 timestamps. The helper add_to_string_set ensures that this cache behaves like a set. The TTL is handled internally by Panther, and defaults to 15 minutes unless configured otherwise.

Step 4: Calculate Intervals

if len(timestamps) < 5:
    return False

intervals = [t2 - t1 for t1, t2 in zip(timestamps, timestamps[1:]

This gives us a list like [59.8, 60.1, 59.7, 60.3], which we can analyze for consistency.

Step 5: Periodicity Check Without FFT


We say it’s periodic if:

  • Most intervals are within ±20% of the median.

  • Standard deviation is low (e.g. < 8s).

  • Interval falls within a common beacon window (20–180s).

Step 6: Trigger the Alert


Boom. If it walks like a beacon, talks like a beacon—we alert.

✅ Full Detection Code (Panther-Ready)

You can find the full detection code here.

🔍 Why This Works

  • It’s native. No dependencies beyond what Panther provides.

  • It’s explainable. Every part of the detection can be reasoned about.

  • It’s flexible. You can tune thresholds, add ports, correlate across services.

🎵 Conclusion

C2 beacons are like metronomes hiding in your traffic. They might be off-beat. They might be faint. But with just a bit of Python, caching, and creative thinking—you can catch them in the act.

Let the machines sing. We’ll be listening.

—Asante

©2023 Asante Babers

©2023 Asante Babers