NullSec CppSentry
February 27, 2026 · View on GitHub
Network Packet Sentinel written in C++20
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 ID | Name | Risk | MITRE | Description |
|---|---|---|---|---|
| NET-001 | Port Scan | MEDIUM | T1046 | SYN scan detection |
| C2-001 | C2 Port | HIGH | T1071 | Known C2 ports |
| EXFIL-001 | Large Transfer | HIGH | T1048 | Data exfiltration |
| TUN-001 | ICMP Tunnel | HIGH | T1095 | ICMP tunneling |
| DNS-001 | DNS Exfil | CRITICAL | T1048.003 | DNS exfiltration |
| SMB-001 | SMB Activity | MEDIUM | T1021.002 | Lateral movement |
| RDP-001 | RDP Connection | LOW | T1021.001 | Remote 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?
| Requirement | C++20 Advantage |
|---|---|
| Performance | Zero-overhead abstractions |
| Type Safety | Concepts, std::optional |
| Expressiveness | Ranges, lambdas |
| Memory Safety | Smart pointers, RAII |
| Packet Processing | Direct memory access |
| Cross-platform | Universal support |
License
MIT License - See LICENSE for details.
Related Tools
- nullsec-flowtrace - Flow analyzer (Haskell)
- nullsec-beaconhunt - Beacon detector (Elixir)
- nullsec-clusterguard - Distributed IDS (Erlang)