Module Architecture - kaotickj/NetSentinel GitHub Wiki

Module Architecture

NetSentinel follows a modular architecture to ensure each component is reusable, testable, and easy to extend. Modules are isolated by function and interact through a shared data structure passed at runtime.


Overview of Core Modules

netsentinel/
β”œβ”€β”€ core/
β”‚ β”œβ”€β”€ recon.py # Network scanning, host discovery
β”‚ β”œβ”€β”€ smb_enum.py # SMB share enumeration
β”‚ β”œβ”€β”€ kerberos_enum.py # SPN & AS-REP Kerberos recon
β”‚ └── init.py
β”œβ”€β”€ utils/
β”‚ β”œβ”€β”€ logger.py # Unified logging
β”‚ β”œβ”€β”€ config.py # Domain credentials (env or file)
β”‚ β”œβ”€β”€ ports.py # Common TCP ports list
β”‚ └── init.py
main.py # CLI entry point

---

Data Flow

Each module receives structured data (host records) from recon.py, and may enrich it with new keys (e.g., open ports, hostnames, shares). Output is passed down the pipeline and optionally written to a JSON file.

main.py β†’ recon.py β†’ [ smb_enum.py | kerberos_enum.py ] β†’ export


Logging Convention

All modules use the centralized Logger class in utils/logger.py. This provides:

  • Timestamped output
  • Colorized severity indicators (INFO, WARN, ERROR)
  • Optional debugging verbosity

Purpose of Each Module

Module Description
recon.py Performs network scanning and port enumeration
smb_enum.py Discovers anonymous SMB shares on live hosts
kerberos_enum.py Detects Kerberoastable SPNs and AS-REP vulnerabilities
config.py Loads domain credentials from environment or file
ports.py Supplies scan targets to recon.py
logger.py Provides consistent output handling

Creating New Modules

NetSentinel is designed to be easily extended by adding modules to the core/ directory. These modules should focus on a single responsibility (e.g., SNMP scan, HTTP banner grabbing) and follow a consistent structure.


1. Module Template

Create a new file in core/, e.g., snmp_enum.py:

from utils.logger import Logger

class SNMPEnumerator:
    def __init__(self, logger: Logger):
        self.logger = logger

    def enumerate(self, hosts: list):
        self.logger.info("Running SNMP scan...")
        for host in hosts:
            ip = host.get("ip")
            # SNMP logic here
            self.logger.debug(f"Queried {ip} via SNMP")

2. Register the Module in main.py

Import and call your module conditionally based on a new CLI argument:

from core.snmp_enum import SNMPEnumerator

if args.snmp_enum:
    snmp = SNMPEnumerator(logger)
    snmp.enumerate(results)

3. Add a CLI Flag

Add this to your argument parser:

parser.add_argument("--snmp-enum", action="store_true", help="Enumerate SNMP devices")

4. Guidelines

  • Accept a list of hosts from recon

  • Use the shared Logger for output

  • Return enriched results or modify the host data inline

  • Fail gracefully with try/except blocks

  • Don’t hard-code ports β€” use ports.py or inline where justified


Example Use Case

python3 main.py --target 10.0.0.0/24 --snmp-enum

This structure ensures consistent behavior across all modules.


Extending Recon Functions

The recon.py module performs initial host discovery and port scanning. It feeds structured output to all other modules. This document explains how to enhance its functionality with new enrichment methods or discovery logic.


Base Output Format

Each discovered host is returned as a dictionary:

{
  "ip": "10.0.0.5",
  "mac": "00:11:22:33:44:55",
  "hostname": "DC01",
  "ports": [445, 135]
}

This list is passed to modules like smb_enum and kerberos_enum.


Adding Enrichment Functions

To extend the recon process, add new methods to the NetworkScanner class in recon.py.

: OS Fingerprinting (via TTL)

def enrich_with_os_guessing(self):
    for host in self.live_hosts:
        ip = host["ip"]
        ttl = self.get_ttl(ip)
        host["os_guess"] = self.guess_os_from_ttl(ttl)

Call this function inside run() or through a new CLI argument.


Suggested Enrichments

Feature Output Field Method Name
TTL fingerprinting os_guess enrich_with_os_guessing()
NetBIOS hostnames netbios_name enrich_with_netbios()
Clock skew via ICMP clock_skew enrich_with_clock_skew()

#### Best Practices
  • Keep methods isolated and testable

  • Use .get("ip") defensively

  • Avoid blocking calls where possible

  • Append enrichment data, never overwrite core fields


Example Flow After Extension

scanner = NetworkScanner(...)
scanner.run()
scanner.enrich_with_os_guessing()

This improves data passed to all downstream modules.

⚠️ **GitHub.com Fallback** ⚠️