โš”๏ธ CrimsonWare - Module Development Guide

Version: CW-DEV-2026.V1

Complete guide to creating custom modules for the CrimsonWare Security Intelligence Framework.

๐ŸŽฏ Introduction

CrimsonWare modules are self-contained Python classes that follow a specific structure. Each module handles its own UI, user input, and logic, and must provide a run() function that CrimsonWare can call.

๐Ÿ“ Module Locations

Modules are organized by category in the modules/ directory:

๐Ÿ“ Module File Structure

Every CrimsonWare module follows this pattern:

modules/category/your_module.py
#!/usr/bin/env python3
"""
CrimsonWare - Your Module Name
Brief description of what your module does
"""

import os
import sys
import time
import json
from datetime import datetime

# Rich imports for beautiful output
from rich.console import Console
from rich.table import Table
from rich.panel import Panel
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn
from rich.prompt import Prompt, Confirm
from rich import box
from rich.rule import Rule

console = Console()

class YourModule:
    """Main YourModule class"""
    
    def __init__(self):
        self.name = "Your Module Name"
        self.version = "1.0"
        
        # Your module's data and configuration
        self.some_data = {}
        self.output_dir = "your_module_output"
    
    def show_banner(self):
        """Show module banner"""
        banner = Panel(
            f"[bold bright_red]๐Ÿ”ง {self.name} v{self.version}[/bold bright_red]\n"
            "[yellow]Brief description of what your module does[/yellow]",
            border_style="bright_red",
            box=box.HEAVY,
            padding=(1, 2)
        )
        console.print(banner)
        console.print()
    
    def some_function(self, param):
        """Your module's core functionality"""
        # Implement your logic here
        pass
    
    def display_results(self, results):
        """Display results using rich tables"""
        table = Table(
            title="[bold bright_red]RESULTS[/bold bright_red]",
            box=box.HEAVY,
            border_style="bright_red",
            header_style="bold yellow"
        )
        
        table.add_column("Column 1", style="cyan")
        table.add_column("Column 2", style="white")
        
        # Add rows
        table.add_row("Value 1", "Value 2")
        
        console.print(table)
    
    def interactive_mode(self):
        """Run in interactive mode"""
        self.show_banner()
        
        while True:
            console.print()
            console.print(Rule("[bold yellow]YOUR MODULE MENU[/bold yellow]"))
            console.print()
            
            # Get user input
            user_input = Prompt.ask("[yellow]Enter something[/yellow]")
            
            if user_input.lower() in ['exit', 'quit', 'back']:
                break
            
            # Process input
            self.some_function(user_input)
            
            console.print()
            again = Prompt.ask(
                "[bright_black]Do another?[/bright_black]",
                choices=["y", "n"],
                default="y"
            )
            if again.lower() != 'y':
                break
    
    def run(self):
        """Main entry point for the module"""
        try:
            self.interactive_mode()
        except KeyboardInterrupt:
            console.print(f"\n[yellow]Interrupted by user[/yellow]")
        except Exception as e:
            console.print(f"[red]Error: {e}[/red]")
        finally:
            console.print(f"\n[cyan]Returning to main menu...[/cyan]")
            time.sleep(1)

# For direct testing
if __name__ == "__main__":
    module = YourModule()
    module.run()

# Define the run function that CrimsonWare expects
def run():
    """Function called by CrimsonWare"""
    module = YourModule()
    module.run()

โš ๏ธ CRITICAL REQUIREMENTS

๐Ÿšจ ABSOLUTELY REQUIRED

Your module MUST have a run() function at the bottom!

This is what CrimsonWare calls when a user selects your module:

def run():
"""Function called by CrimsonWare"""
module = YourModule()
module.run()

๐Ÿ“‹ Required Components

Component Required Purpose Example
class YourModule: YES Main class containing all functionality class UsernameTracker:
__init__(self) Recommended Initialize module properties self.name = "Module Name"
show_banner(self) Recommended Display module banner on startup Uses rich Panel with crimson theme
interactive_mode(self) Common pattern Handle user interaction loop Gets input, calls functions, handles exit
run(self) YES (class method) Main entry point for the class Calls interactive_mode() with error handling
def run(): (global) YES (CRITICAL) Function CrimsonWare actually calls Creates instance and calls instance.run()
if __name__ == "__main__": Recommended Allow direct testing Run module standalone for debugging

๐Ÿ“ Registering Your Module in CrimsonWare

To make your module appear in the CrimsonWare menus, you need to import it and add it to the module_mappings dictionary in crimsonware.py:

crimsonware.py (excerpt)
# In the imports section, add your module:
from modules.your_category import your_module

# In the CrimsonWare class __init__, find module_mappings:
self.module_mappings = {
    # ... existing mappings ...
    
    # Add your module with (category, tool_number): ("Module Name", module_object)
    # Category numbers: 1=OSINT, 2=RECON, 3=EXPLOIT, 4=FORENSICS, 5=ANALYSIS
    (1, 13): ("Your Module Name", your_module),  # OSINT category, tool #13
    
    # ... rest of mappings ...
}

๐Ÿ’ก Category Numbers

Choose a tool number that's not already used in that category.

๐Ÿ”ง Step-by-Step Module Creation

Step 1: Choose Your Category and Filename

# Navigate to the appropriate category
$ cd modules/osint/

# Create your module file (use lowercase with underscores)
$ touch my_awesome_tool.py

Step 2: Copy the Template

Use the template above and customize:

Step 3: Implement Your Core Logic

Look at the example modules for inspiration:

Step 4: Test Your Module Standalone

# Run directly to test
$ python3 modules/osint/my_awesome_tool.py

๐Ÿ“Š Common Patterns from Real Modules

1. The Interactive Loop Pattern

From username_tracker.py:

def interactive_mode(self):
    self.show_banner()
    
    while True:
        username = Prompt.ask("[yellow]Enter username to search[/yellow]")
        
        if username.lower() in ['exit', 'quit', 'back']:
            break
        
        self.search(username)
        
        again = Prompt.ask("[bright_black]Search another?[/bright_black]", choices=["y", "n"])

2. Progress Bars for Long Operations

From username_tracker.py:

with Progress(
    SpinnerColumn(),
    TextColumn("[progress.description]{task.description}"),
    BarColumn(),
    console=console
) as progress:
    task = progress.add_task("[bright_red]Searching...[/bright_red]", total=len(self.platforms))

3. Threading for Speed

From username_tracker.py:

with ThreadPoolExecutor(max_workers=10) as executor:
    future_to_platform = {
        executor.submit(self.check_username, platform, url, username): platform 
        for platform, url in self.platforms.items()
    }

4. Saving Results to JSON

From username_tracker.py:

def save_results(self, username, found, not_found):
    if not os.path.exists("results"):
        os.makedirs("results")
    
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    filename = f"results/username_username_timestamp.json"
    
    with open(filename, 'w') as f:
        json.dump(data, f, indent=4)

5. Beautiful Tables with Rich

From wifi_analyzer.py:

table = Table(
    title=f"[bold bright_red]WiFi Networks ({len(networks)})[/bold bright_red]",
    box=box.HEAVY,
    border_style="bright_red",
    header_style="bold yellow"
)

table.add_column("SSID", style="cyan")
table.add_column("BSSID", style="white")
table.add_column("Channel", style="green")
table.add_column("Signal", style="yellow")

๐ŸŽฏ Complete Working Example

Here's a minimal but complete module that demonstrates all required components:

modules/osint/ip_geolookup.py
#!/usr/bin/env python3
"""
CrimsonWare - IP Geolocation Lookup
Get geolocation data for an IP address
"""

import requests
import time
import json
from datetime import datetime

from rich.console import Console
from rich.table import Table
from rich.panel import Panel
from rich.prompt import Prompt
from rich import box
from rich.rule import Rule

console = Console()

class IPGeoLookup:
    """Main IP Geolocation class"""
    
    def __init__(self):
        self.name = "IP Geolocation Lookup"
        self.version = "1.0"
        self.api_url = "http://ip-api.com/json/"
    
    def show_banner(self):
        """Show module banner"""
        banner = Panel(
            f"[bold bright_red]๐ŸŒ {self.name} v{self.version}[/bold bright_red]\n"
            "[yellow]Get geolocation data for any IP address[/yellow]",
            border_style="bright_red",
            box=box.HEAVY,
            padding=(1, 2)
        )
        console.print(banner)
        console.print()
    
    def lookup(self, ip):
        """Look up IP geolocation"""
        console.print(f"\n[cyan]Looking up: [bold]{ip}[/bold][/cyan]")
        
        try:
            response = requests.get(self.api_url + ip, timeout=10)
            data = response.json()
            
            if data.get('status') == 'success':
                self.display_results(data)
                self.save_results(ip, data)
            else:
                console.print("[red]Invalid IP or API error[/red]")
                
        except Exception as e:
            console.print(f"[red]Error: {e}[/red]")
    
    def display_results(self, data):
        """Display geolocation results"""
        table = Table(
            title="[bold bright_red]GEOLOCATION RESULTS[/bold bright_red]",
            box=box.HEAVY,
            border_style="bright_red",
            header_style="bold yellow"
        )
        
        table.add_column("Field", style="cyan", width=15)
        table.add_column("Value", style="white", width=40)
        
        fields = [
            ("IP", "query"),
            ("Country", "country"),
            ("Region", "regionName"),
            ("City", "city"),
            ("ZIP", "zip"),
            ("Latitude", "lat"),
            ("Longitude", "lon"),
            ("ISP", "isp"),
            ("Organization", "org"),
            ("AS Number", "as"),
            ("Timezone", "timezone")
        ]
        
        for label, key in fields:
            if key in data and data[key]:
                table.add_row(label, str(data[key]))
        
        console.print(table)
    
    def save_results(self, ip, data):
        """Save results to JSON file"""
        import os
        
        if not os.path.exists("ip_lookups"):
            os.makedirs("ip_lookups")
        
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"ip_lookups/ip_timestamp.json"
        
        with open(filename, 'w') as f:
            json.dump(data, f, indent=2)
        
        console.print(f"\n[green]โœ“ Results saved to: {filename}[/green]")
    
    def interactive_mode(self):
        """Run in interactive mode"""
        self.show_banner()
        
        while True:
            console.print()
            console.print(Rule("[bold yellow]IP GEOLOCATION[/bold yellow]"))
            console.print()
            
            ip = Prompt.ask("[yellow]Enter IP address (or 'exit')[/yellow]")
            
            if ip.lower() in ['exit', 'quit', 'back']:
                break
            
            self.lookup(ip)
            
            console.print()
            again = Prompt.ask(
                "[bright_black]Look up another IP?[/bright_black]",
                choices=["y", "n"],
                default="y"
            )
            if again.lower() != 'y':
                break
    
    def run(self):
        """Main entry point for the module"""
        try:
            self.interactive_mode()
        except KeyboardInterrupt:
            console.print(f"\n[yellow]Interrupted by user[/yellow]")
        except Exception as e:
            console.print(f"[red]Error: {e}[/red]")
        finally:
            console.print(f"\n[cyan]Returning to main menu...[/cyan]")
            time.sleep(1)

# For direct testing
if __name__ == "__main__":
    module = IPGeoLookup()
    module.run()

# Define the run function that CrimsonWare expects
def run():
    """Function called by CrimsonWare"""
    module = IPGeoLookup()
    module.run()

๐Ÿงช Testing Your Module

Test Standalone:

crimsonware@dev:~
$ python3 modules/osint/ip_geolookup.py
โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
โ•‘ ๐ŸŒ IP Geolocation Lookup v1.0 โ•‘
โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
Enter IP address: 8.8.8.8

Test in CrimsonWare:

crimsonware@security:~
CrimsonWare> 1
โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
โ•‘ ๐Ÿ” OSINT TOOLS โ•‘
โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ
โ•‘ 13 โ”‚ IP Geolocation Lookup โ”‚ Ready โ•‘
โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

โœ… Best Practices

๐Ÿ“Œ DO:

โŒ DON'T:

๐Ÿ”ง Troubleshooting

Problem Solution
Module doesn't appear in menu Check that you added it to module_mappings in crimsonware.py and that the global run() function exists
"Module not found" error Verify the import path in crimsonware.py and that the file exists in the correct category folder
Module runs but has no output Check that you're using console.print() instead of print()
Rich formatting not working Ensure from rich.console import Console and console = Console() at the top of your file
Can't exit module Add exit condition in your interactive loop (check for 'exit', 'quit', 'back')

๐Ÿš€ Ready to Create?

You now have everything you need to create custom CrimsonWare modules:

Remember: The global run() function at the bottom is REQUIRED!

โ† Back to Wiki ๐Ÿ“š Main Documentation