NullSec CppSentry

February 27, 2026 · View on GitHub

Network Packet Sentinel written in C++20

Version Language License

Part of the NullSec offensive security toolkit
Twitter: x.com/AnonAntics
Portal: bad-antics.github.io

Overview

CppSentry is a high-performance network packet analyzer that detects malicious traffic patterns, C2 communications, and data exfiltration attempts. Built with modern C++20 features for type safety, performance, and expressive code.

C++20 Features Showcased

  • std::optional: Nullable rule results
  • std::variant: Type-safe unions
  • Lambda Expressions: Rule matchers
  • Structured Bindings: Clean destructuring
  • Concepts/Constraints: Type requirements
  • std::string_view: Zero-copy strings
  • Smart Pointers: RAII memory management
  • STL Algorithms: Functional operations

Detection Rules

Rule IDNameRiskMITREDescription
NET-001Port ScanMEDIUMT1046SYN scan detection
C2-001C2 PortHIGHT1071Known C2 ports
EXFIL-001Large TransferHIGHT1048Data exfiltration
TUN-001ICMP TunnelHIGHT1095ICMP tunneling
DNS-001DNS ExfilCRITICALT1048.003DNS exfiltration
SMB-001SMB ActivityMEDIUMT1021.002Lateral movement
RDP-001RDP ConnectionLOWT1021.001Remote desktop

Installation

# Clone
git clone https://github.com/bad-antics/nullsec-cppsentry.git
cd nullsec-cppsentry

# Build (requires C++20 compiler)
g++ -std=c++20 -O3 -o cppsentry cppsentry.cpp

# Or with CMake
mkdir build && cd build
cmake ..
make

Usage

# Run demo mode
./cppsentry

# Monitor interface
./cppsentry -i eth0

# Verbose output
./cppsentry -v -i eth0

# Custom rules
./cppsentry -r custom_rules.json -i eth0

Options

USAGE:
    cppsentry [OPTIONS] <INTERFACE>

OPTIONS:
    -h, --help       Show help
    -i, --interface  Network interface to monitor
    -r, --rules      Custom rules file
    -v, --verbose    Verbose output

Sample Output

╔══════════════════════════════════════════════════════════════════╗
║           NullSec CppSentry - Network Packet Sentinel            ║
╚══════════════════════════════════════════════════════════════════╝

[Demo Mode]

Analyzing network traffic for threats...

  [CRITICAL] DNS Exfiltration
    Rule:        DNS-001
    Source:      10.0.0.100:54000
    Destination: 8.8.8.8:53
    Protocol:    UDP
    Size:        512 bytes
    MITRE:       T1048.003

  [HIGH] Suspicious C2 Port
    Rule:        C2-001
    Source:      10.0.0.50:49152
    Destination: 185.220.101.1:4444
    Protocol:    TCP
    Size:        256 bytes
    MITRE:       T1071

  [HIGH] Large Data Transfer
    Rule:        EXFIL-001
    Source:      192.168.1.200:55555
    Destination: 203.0.113.50:443
    Protocol:    TCP
    Size:        500000 bytes
    MITRE:       T1048

  [MEDIUM] Port Scan Detected
    Rule:        NET-001
    Source:      45.33.32.156:12345
    Destination: 10.0.0.5:22
    Protocol:    TCP
    Size:        64 bytes
    MITRE:       T1046

═══════════════════════════════════════════

  Summary:
    Packets Analyzed: 11
    Alerts Generated: 9
    Critical:         1
    High:             4
    Medium:           3
    Low:              1

Code Highlights

std::optional for Nullable Results

struct Rule {
    std::string id;
    std::string name;
    std::function<std::optional<RiskLevel>(const Packet&)> matcher;
    std::string mitre;
};

// Rule returns optional - no match = nullopt
rules_.push_back({
    "NET-001",
    "Port Scan Detected",
    [](const Packet& pkt) -> std::optional<RiskLevel> {
        if (pkt.flags & 0x02 && !(pkt.flags & 0x10)) {
            return RiskLevel::Medium;
        }
        return std::nullopt;
    },
    "T1046"
});

Lambda-based Rule Matchers

[](const Packet& pkt) -> std::optional<RiskLevel> {
    static const std::vector<uint16_t> c2_ports = {4444, 5555, 6666, 31337};
    if (std::find(c2_ports.begin(), c2_ports.end(), pkt.dest_port) != c2_ports.end()) {
        return RiskLevel::High;
    }
    return std::nullopt;
}

STL Algorithms

// Count alerts by risk level
auto countByRisk = [&alerts](RiskLevel risk) {
    return std::count_if(alerts.begin(), alerts.end(),
        [risk](const Alert& a) { return a.risk == risk; });
};

// Sort alerts by severity
std::sort(alerts.begin(), alerts.end(),
    [](const Alert& a, const Alert& b) {
        return static_cast<int>(a.risk) < static_cast<int>(b.risk);
    });

Modern Enum Classes

enum class RiskLevel {
    Critical,
    High,
    Medium,
    Low,
    Info
};

std::string_view riskToString(RiskLevel risk) {
    switch (risk) {
        case RiskLevel::Critical: return "CRITICAL";
        case RiskLevel::High: return "HIGH";
        // ...
    }
}

Architecture

┌────────────────────────────────────────────────────────────────┐
│                   CppSentry Architecture                       │
├────────────────────────────────────────────────────────────────┤
│                                                                │
│    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐      │
│    │  Network    │───▶│   Packet    │───▶│   Packet    │      │
│    │  Interface  │    │   Capture   │    │   Queue     │      │
│    └─────────────┘    └─────────────┘    └──────┬──────┘      │
│                                                  │             │
│                                                  ▼             │
│    ┌──────────────────────────────────────────────────┐       │
│    │               Rule Engine                         │       │
│    │  ┌──────────┐ ┌──────────┐ ┌──────────┐         │       │
│    │  │ Port     │ │ Protocol │ │ Payload  │         │       │
│    │  │ Rules    │ │ Rules    │ │ Rules    │         │       │
│    │  └──────────┘ └──────────┘ └──────────┘         │       │
│    └────────────────────────┬─────────────────────────┘       │
│                             │                                  │
│                             ▼                                  │
│    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐      │
│    │   Match?    │───▶│   Alert     │───▶│   Output    │      │
│    │ optional<>  │    │   Vector    │    │   Handler   │      │
│    └─────────────┘    └─────────────┘    └─────────────┘      │
│                                                                │
└────────────────────────────────────────────────────────────────┘

Why C++20?

RequirementC++20 Advantage
PerformanceZero-overhead abstractions
Type SafetyConcepts, std::optional
ExpressivenessRanges, lambdas
Memory SafetySmart pointers, RAII
Packet ProcessingDirect memory access
Cross-platformUniversal support

License

MIT License - See LICENSE for details.