logger container ready

This commit is contained in:
marcos.luna
2025-11-17 16:32:41 +01:00
parent 2fe9fa8254
commit a3986b7497
9 changed files with 1109 additions and 1 deletions
+7
View File
@@ -34,6 +34,13 @@ ENV MYTHIC_SERVER_PORT="17443"
ENV MYTHIC_SERVER_USERNAME="mythic_admin"
ENV MYTHIC_SERVER_PASSWORD="mythic_password"
# --- Variables de entorno para Syslog Logging Container (opcional) ---
# El logger lee la configuración desde logger/syslog.conf (recomendado)
# También puede leer desde variables de entorno si están configuradas
ENV SYSLOG_SERVER=""
ENV SYSLOG_PORT="514"
ENV SYSLOG_FACILITY="16"
# --- Copia tu código de translator ---
# This COPY ensures local changes are included when USE_BUILD_CONTEXT=true
WORKDIR /Mythic/
+376
View File
@@ -0,0 +1,376 @@
# 📊 Cazalla Logging Container
Complete logging system for the Cazalla agent that records all Mythic events and sends them to a central syslog server.
## 📋 Description
This logging container follows the official Mythic pattern for logging containers. It automatically subscribes to all Mythic events and logs them to:
1. **Local files**: One file per day at `/tmp/cazalla_mythic_YYYY-MM-DD.log` (inside the container)
2. **Central syslog**: Sends all events to a configured rsyslog server (RFC 3164)
**Advantages:**
- ✅ Does not modify the agent (avoids detections)
- ✅ Follows the official Mythic pattern
- ✅ Runs on the server, not on the target
- ✅ Logs ALL events automatically
- ✅ Simple configuration via configuration file
- ✅ No log rotation (one file per day, all files are kept)
## 🏗️ Architecture
```
┌─────────────┐
│ Mythic │
│ Events │
└──────┬──────┘
┌─────────────────┐
│ CazallaLogger │
│ (Logging │
│ Container) │
└──────┬──────────┘
├──► Local file (/tmp/cazalla_mythic_YYYY-MM-DD.log)
└──► Syslog Server (rsyslog) ──► /var/log/cazalla.log
```
## ⚙️ Configuration
### Method 1: Configuration File (Recommended)
The logger reads configuration from a file inside the container. **You don't need to modify docker-compose.yml**.
1. **Edit the configuration file:**
```bash
nano Payload_Type/cazalla/logger/syslog.conf
```
2. **Configure your values:**
```bash
# Syslog server IP or hostname (leave empty to disable syslog)
# Use the host IP (10.8.20.50) or 172.17.0.1 (docker0 bridge) to reach rsyslog on the host
SYSLOG_SERVER=10.8.20.50
# Syslog server port (default: 514)
SYSLOG_PORT=514
# Syslog facility code (0-23, default: 16 = LOCAL0)
SYSLOG_FACILITY=16
```
3. **Rebuild and restart the container:**
```bash
cd /opt/mythic
sudo ./mythic-cli build cazalla
sudo ./mythic-cli restart cazalla
```
### Method 2: Environment Variables (Alternative)
If you prefer to use environment variables, you can configure them in Mythic's `.env` file and manually add them to `docker-compose.yml`. However, **Method 1 is simpler**.
### Configuring rsyslog on the Host
If you want to receive logs on the Debian host where Mythic runs:
1. **Install rsyslog** (if not installed):
```bash
sudo apt-get update && sudo apt-get install -y rsyslog
```
2. **Enable UDP reception** in `/etc/rsyslog.conf`:
```bash
sudo sed -i 's/#module(load="imudp")/module(load="imudp")/' /etc/rsyslog.conf
sudo sed -i 's/#input(type="imudp" port="514")/input(type="imudp" port="514")/' /etc/rsyslog.conf
```
3. **Create rule for Cazalla** in `/etc/rsyslog.d/50-cazalla.conf`:
```bash
sudo bash -c 'cat > /etc/rsyslog.d/50-cazalla.conf << EOF
# Logs from Cazalla Mythic agent
# Filter by facility LOCAL0 (16)
if \$syslogfacility-text == "local0" then /var/log/cazalla.log
& stop
EOF
'
```
4. **Restart rsyslog:**
```bash
sudo systemctl restart rsyslog
```
5. **Verify it's listening:**
```bash
sudo netstat -ulnp | grep 514
# You should see: UNCONN ... 0.0.0.0:514 ... rsyslogd
```
## 📊 Events Logged
The logger subscribes to **ALL** Mythic events:
| Event | Description | Example |
|--------|-------------|---------|
| `CALLBACK` | Agent connects/checkin | New callback from target |
| `TASK` | Task created/updated | Command executed (`shell`, `ls`, etc.) |
| `RESPONSE` | Agent response | Command output |
| `CREDENTIAL` | Credential captured | Username/password extracted |
| `KEYLOG` | Keystrokes captured | Keylogger data |
| `FILE` | File uploaded/downloaded | File upload/download |
| `ARTIFACT` | Artifact generated | IOC detected (process created, etc.) |
| `PAYLOAD` | Payload created | New payload generated |
## 📝 Log Format
### Local File
Logs are saved in structured JSON format:
```json
{
"event_type": "TASK",
"timestamp": "2025-11-17T15:18:23.117715674Z",
"operation_id": 1,
"operation_name": "Operation Chimera",
"username": "mythic_admin",
"action": "new_task",
"server_name": "mythic",
"data": {
"id": 18,
"command_name": "shell",
"params": "{\"command\":\"whoami\"}",
"status": "success",
...
}
}
```
### Syslog
Messages are sent to syslog in RFC 3164 format with complete JSON:
```
<134>Nov 17 15:18:23 cazalla cazalla: {"event_type": "TASK", "timestamp": "...", ...}
```
- **Priority**: Calculated based on facility (16 = LOCAL0) + severity
- **Severity**: INFO (6) for most, WARNING (4) for artifacts
- **Tag**: `cazalla`
- **Message**: Complete JSON of the event
## 🔍 Verification
### Verify Logger is Active
```bash
# View container logs
sudo docker logs cazalla | grep -i "syslog\|Logger initialized"
# You should see:
# INFO:cazalla_logger:Syslog client initialized: 10.8.20.50:514 (facility=16)
# INFO:cazalla_logger:Logger initialized: cazalla_logger
```
### Verify Local Logs (inside container)
```bash
# View today's log file
sudo docker exec cazalla cat /tmp/cazalla_mythic_$(date +%Y-%m-%d).log | tail -20
# Or view all log files
sudo docker exec cazalla ls -lh /tmp/cazalla_mythic_*.log
```
### Verify Logs in Syslog (host)
```bash
# View logs in real-time
sudo tail -f /var/log/cazalla.log
# View recent events
sudo tail -50 /var/log/cazalla.log
# Count events by type
sudo tail -1000 /var/log/cazalla.log | grep -o '"event_type": "[^"]*"' | sort | uniq -c
```
### Verify Events are Being Sent
```bash
# View events in container logs
sudo docker logs cazalla | grep -E "(TASK|RESPONSE|CALLBACK)" | tail -10
# View events in syslog
sudo tail -20 /var/log/cazalla.log | grep -E "(TASK|RESPONSE|CALLBACK)"
```
## 🛠️ Troubleshooting
### Logger Not Initializing
**Symptom:** You don't see "Logger initialized" in container logs.
**Solution:**
1. Verify the logger is imported in `main.py`:
```bash
grep -A 5 "from logger" Payload_Type/cazalla/main.py
```
2. Check container logs:
```bash
sudo docker logs cazalla | grep -i "error\|warning\|logger"
```
### Syslog Not Initializing
**Symptom:** You see "Syslog not configured" in logs.
**Solution:**
1. Verify the configuration file exists:
```bash
sudo docker exec cazalla cat /Mythic/logger/syslog.conf
```
2. Verify `SYSLOG_SERVER` has a value (not empty):
```bash
sudo docker exec cazalla cat /Mythic/logger/syslog.conf | grep SYSLOG_SERVER
```
3. Rebuild the container if you just edited the file:
```bash
cd /opt/mythic
sudo ./mythic-cli build cazalla
sudo ./mythic-cli restart cazalla
```
### Messages Not Reaching Syslog
**Symptom:** Logger initializes but you don't see messages in `/var/log/cazalla.log`.
**Solution:**
1. Verify rsyslog is listening:
```bash
sudo netstat -ulnp | grep 514
```
2. Verify connectivity from container:
```bash
# Get host IP (docker0 bridge or real IP)
IP_HOST=$(ip addr show docker0 | grep "inet " | awk '{print $2}' | cut -d/ -f1)
echo "Host IP: $IP_HOST"
# Test from container
sudo docker exec cazalla python3 -c "
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto(b'test', ('$IP_HOST', 514))
print('Message sent')
"
# Verify it arrived
sleep 1 && sudo tail -1 /var/log/cazalla.log
```
3. Verify rsyslog configuration:
```bash
sudo cat /etc/rsyslog.d/50-cazalla.conf
sudo systemctl status rsyslog
```
4. Verify firewall:
```bash
sudo iptables -L -n | grep 514
```
### Logs Are Empty or Incomplete
**Symptom:** Logs have empty fields (`"operation_id": null`, `"username": ""`).
**Solution:**
This is normal for some events. The logger extracts all available information from the `LoggingMessage` object. If some fields are empty, it's because Mythic doesn't provide them for that specific event.
### Configuration File Not Copied to Container
**Symptom:** The `syslog.conf` file doesn't exist in the container.
**Solution:**
1. Verify the file exists locally:
```bash
ls -la Payload_Type/cazalla/logger/syslog.conf
```
2. Verify `CAZALLA_USE_BUILD_CONTEXT="true"` in `/opt/mythic/.env`:
```bash
grep CAZALLA_USE_BUILD_CONTEXT /opt/mythic/.env
```
3. Rebuild the container:
```bash
cd /opt/mythic
sudo ./mythic-cli build cazalla
```
## 📚 Syslog Facility Codes
| Code | Facility | Description |
|--------|----------|-------------|
| 0 | KERN | Kernel messages |
| 1 | USER | User-level messages |
| 2 | MAIL | Mail system |
| 3 | DAEMON | System daemons |
| 4 | AUTH | Security/authorization |
| 5 | SYSLOG | Messages generated by syslogd |
| 6 | LPR | Line printer subsystem |
| 7 | NEWS | Network news subsystem |
| 8 | UUCP | UUCP subsystem |
| 9 | CRON | Clock daemon |
| 10 | AUTHPRIV | Security/authorization (private) |
| 11 | FTP | FTP daemon |
| **16-23** | **LOCAL0-7** | **Reserved for local use (recommended)** |
**Recommendation:** Use `16` (LOCAL0) for custom application logs.
## 🔧 Code Structure
```
Payload_Type/cazalla/logger/
├── __init__.py # Exports cazalla_logger
├── logger.py # CazallaLogger class + SyslogClient
├── syslog.conf # Syslog configuration
└── README.md # This documentation
```
### Main Classes
- **`CazallaLogger`**: Inherits from `mythic_container.LoggingBase.Log`
- Automatically registers with Mythic
- Implements `new_*` methods for each event type
- Formats messages as JSON
- Sends to local file and syslog
- **`SyslogClient`**: UDP client for syslog (RFC 3164)
- Formats messages according to RFC 3164
- Maps events to syslog severities
- Handles errors silently
## 📖 References
- [Mythic Logging Container Documentation](https://docs.mythic-c2.net/customizing/3.-consuming-containers/logging)
- [RFC 3164 - The BSD syslog Protocol](https://tools.ietf.org/html/rfc3164)
- [Mythic Example Containers](https://github.com/MythicMeta/ExampleContainers)
## 📝 Important Notes
1. **You don't need to modify docker-compose.yml** - Everything is configured from `syslog.conf`
2. **The file is copied to the container** when built, so after editing it you need to rebuild
3. **Logs are saved locally** even if syslog is configured
4. **One file per day** - No rotation, all files are kept
5. **Environment variables take precedence** over the configuration file if both are configured
---
**Developed by:** Kaseya OFSTeam
+6
View File
@@ -0,0 +1,6 @@
# Logger package for Cazalla Mythic agent
from .logger import cazalla_logger
# Export logger instance so it can be imported
__all__ = ['cazalla_logger']
+350
View File
@@ -0,0 +1,350 @@
"""
Logging Container for Cazalla Mythic Agent
This container subscribes to Mythic events following the official Python logging container pattern.
Based on: https://docs.mythic-c2.net/customizing/3.-consuming-containers/logging
Example: https://github.com/MythicMeta/ExampleContainers/tree/main/Payload_Type/python_services/my_logger
First implementation: Uses built-in Mythic logger (stdout/file)
Future: Will add syslog forwarding
"""
from mythic_container.LoggingBase import *
import logging
import json
import sys
import os
import socket
from datetime import datetime
class CazallaLogger(Log):
"""
Logging container for Cazalla agent
Follows the official Python logging container pattern
"""
LogToFilePath = "/tmp" # Path for file logging (empty = stdout only)
LogLevel = logging.INFO
LogMaxSizeInMB = 0 # 0 = no rotation, keep everything
LogMaxBackups = 0 # No backups needed (one file per day)
name = "cazalla_logger"
description = "Cazalla logging container - logs ALL Mythic events to daily files and syslog"
def __init__(self):
"""Initialize the logger"""
# Set up Python logging
self.mylogger = logging.getLogger('cazalla_logger')
self.mylogger.setLevel(self.LogLevel)
# Clear any existing handlers to avoid duplicates
self.mylogger.handlers.clear()
# Always add stdout handler
stdout_handler = logging.StreamHandler()
stdout_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
stdout_handler.setFormatter(stdout_formatter)
self.mylogger.addHandler(stdout_handler)
# Configure file logging - one file per day (no rotation)
if self.LogToFilePath:
from pathlib import Path
log_dir = Path(self.LogToFilePath)
log_dir.mkdir(parents=True, exist_ok=True)
# Create filename with current date: cazalla_mythic_YYYY-MM-DD.log
today = datetime.now().strftime("%Y-%m-%d")
log_file = log_dir / f'cazalla_mythic_{today}.log'
# Use FileHandler (no rotation) - one file per day
file_handler = logging.FileHandler(log_file, mode='a', encoding='utf-8')
file_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(file_formatter)
self.mylogger.addHandler(file_handler)
self.log_file_path = str(log_file)
else:
self.log_file_path = "stdout only"
# Initialize syslog client if configured
# Try to read from config file first, then fall back to environment variables
self.syslog_client = None
syslog_server, syslog_port, syslog_facility = self._load_syslog_config()
if syslog_server:
try:
self.syslog_client = SyslogClient(syslog_server, syslog_port, syslog_facility)
self.mylogger.info(f"Syslog client initialized: {syslog_server}:{syslog_port} (facility={syslog_facility})")
except Exception as e:
self.mylogger.warning(f"Failed to initialize syslog client: {e}")
else:
self.mylogger.info("Syslog not configured (edit logger/syslog.conf or set SYSLOG_SERVER env var to enable)")
# Log initialization
self.mylogger.info(f"Logger initialized: {self.name}")
self.mylogger.info(f"Log file: {self.log_file_path}")
self.mylogger.info(f"Log level: {logging.getLevelName(self.LogLevel)}")
self.mylogger.info("Subscribed to ALL events: callbacks, tasks, responses, credentials, keylogs, files, artifacts, payloads")
self.mylogger.info("Logging mode: ONE FILE PER DAY (no rotation, no deletion)")
def _load_syslog_config(self):
"""
Load syslog configuration from config file or environment variables
Priority: 1) Config file, 2) Environment variables, 3) Defaults
Returns: (server, port, facility)
"""
# Try to read from config file first
# Try multiple possible paths
possible_paths = [
'/Mythic/logger/syslog.conf', # Absolute path in container
os.path.join(os.path.dirname(__file__), 'syslog.conf') if '__file__' in globals() else None,
]
# Remove None values
possible_paths = [p for p in possible_paths if p]
config_file = None
for path in possible_paths:
if os.path.exists(path):
config_file = path
break
# If no config file found, use first path as default
if not config_file and possible_paths:
config_file = possible_paths[0]
syslog_server = ""
syslog_port = 514
syslog_facility = 16
# Read from config file if it exists
if config_file and os.path.exists(config_file):
try:
with open(config_file, 'r') as f:
for line in f:
line = line.strip()
# Skip comments and empty lines
if not line or line.startswith('#'):
continue
# Parse key=value pairs
if '=' in line:
key, value = line.split('=', 1)
key = key.strip()
value = value.strip()
if key == 'SYSLOG_SERVER' and value: # Only set if value is not empty
syslog_server = value
elif key == 'SYSLOG_PORT':
try:
syslog_port = int(value)
except ValueError:
pass
elif key == 'SYSLOG_FACILITY':
try:
syslog_facility = int(value)
except ValueError:
pass
except Exception as e:
# Can't use self.mylogger here as it might not be initialized yet
print(f"Warning: Error reading syslog config file {config_file}: {e}", file=sys.stderr)
# Override with environment variables if set (env vars take precedence)
# Only override if env var is not empty
env_syslog_server = os.getenv("SYSLOG_SERVER", "")
if env_syslog_server: # Only override if env var is set and not empty
syslog_server = env_syslog_server
if os.getenv("SYSLOG_PORT"):
try:
syslog_port = int(os.getenv("SYSLOG_PORT"))
except ValueError:
pass
if os.getenv("SYSLOG_FACILITY"):
try:
syslog_facility = int(os.getenv("SYSLOG_FACILITY"))
except ValueError:
pass
return syslog_server, syslog_port, syslog_facility
def _format_log_message(self, event_type: str, msg: LoggingMessage) -> str:
"""Format log message with all available information"""
try:
# Extract information from LoggingMessage (fields are capitalized)
operation_id = getattr(msg, 'OperationID', None)
operation_name = getattr(msg, 'OperationName', None)
username = getattr(msg, 'OperatorUsername', None)
timestamp = getattr(msg, 'Timestamp', None)
action = getattr(msg, 'Action', None)
data = getattr(msg, 'Data', {})
server_name = getattr(msg, 'ServerName', None)
# Try to_json() method if available (some versions of LoggingMessage have it)
try:
if hasattr(msg, 'to_json'):
msg_dict = msg.to_json()
# Override with to_json data if available
operation_id = msg_dict.get('operation_id') or operation_id
operation_name = msg_dict.get('operation_name') or operation_name
username = msg_dict.get('username') or username
timestamp = msg_dict.get('timestamp') or timestamp
action = msg_dict.get('action') or action
data = msg_dict.get('data', data)
server_name = msg_dict.get('server_name') or server_name
except:
pass
# Format timestamp
if timestamp:
if isinstance(timestamp, str):
formatted_timestamp = timestamp
else:
formatted_timestamp = timestamp.isoformat() if hasattr(timestamp, 'isoformat') else str(timestamp)
else:
formatted_timestamp = datetime.now().isoformat()
# Format as structured JSON for easy parsing
log_data = {
"event_type": event_type,
"timestamp": formatted_timestamp,
"operation_id": operation_id,
"operation_name": operation_name,
"username": username,
"action": action,
"server_name": server_name,
"data": data if data else {}
}
return json.dumps(log_data, default=str, ensure_ascii=False)
except Exception as e:
# Fallback: try to convert message to string/dict
try:
if hasattr(msg, 'to_json'):
return json.dumps({"event_type": event_type, "raw_message": msg.to_json()}, default=str)
else:
return json.dumps({"event_type": event_type, "raw_message": str(msg)}, default=str)
except:
return f'{{"event_type": "{event_type}", "error": "Failed to format message: {e}", "raw": "{str(msg)}"}}'
async def new_callback(self, msg: LoggingMessage) -> None:
"""Handle new callback events - agent checkin"""
log_msg = self._format_log_message("CALLBACK", msg)
self.mylogger.info(log_msg)
# Send to syslog if configured
if self.syslog_client:
self.syslog_client.send_syslog("new_callback", log_msg)
async def new_task(self, msg: LoggingMessage) -> None:
"""Handle new task events - command execution"""
log_msg = self._format_log_message("TASK", msg)
self.mylogger.info(log_msg)
# Send to syslog if configured
if self.syslog_client:
self.syslog_client.send_syslog("new_task", log_msg)
async def new_response(self, msg: LoggingMessage) -> None:
"""Handle new response events - command output"""
log_msg = self._format_log_message("RESPONSE", msg)
self.mylogger.info(log_msg)
# Send to syslog if configured
if self.syslog_client:
self.syslog_client.send_syslog("new_response", log_msg)
async def new_credential(self, msg: LoggingMessage) -> None:
"""Handle new credential events - captured credentials"""
log_msg = self._format_log_message("CREDENTIAL", msg)
self.mylogger.info(log_msg)
# Send to syslog if configured
if self.syslog_client:
self.syslog_client.send_syslog("new_credential", log_msg)
async def new_keylog(self, msg: LoggingMessage) -> None:
"""Handle new keylog events - captured keystrokes"""
log_msg = self._format_log_message("KEYLOG", msg)
self.mylogger.info(log_msg)
# Send to syslog if configured
if self.syslog_client:
self.syslog_client.send_syslog("new_keylog", log_msg)
async def new_file(self, msg: LoggingMessage) -> None:
"""Handle new file events - file uploads/downloads"""
log_msg = self._format_log_message("FILE", msg)
self.mylogger.info(log_msg)
# Send to syslog if configured
if self.syslog_client:
self.syslog_client.send_syslog("new_file", log_msg)
async def new_artifact(self, msg: LoggingMessage) -> None:
"""Handle new artifact events - IOCs and artifacts"""
log_msg = self._format_log_message("ARTIFACT", msg)
self.mylogger.warning(log_msg) # Warning level for artifacts
# Send to syslog if configured
if self.syslog_client:
self.syslog_client.send_syslog("new_artifact", log_msg)
async def new_payload(self, msg: LoggingMessage) -> None:
"""Handle new payload events - payload creation"""
log_msg = self._format_log_message("PAYLOAD", msg)
self.mylogger.info(log_msg)
# Send to syslog if configured
if self.syslog_client:
self.syslog_client.send_syslog("new_payload", log_msg)
class SyslogClient:
"""UDP syslog client following RFC 3164 for rsyslog integration"""
def __init__(self, server: str, port: int = 514, facility: int = 16):
self.server = server
self.port = port
self.facility = facility
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.hostname = socket.gethostname()
self.tag = "cazalla"
def _get_timestamp(self) -> str:
"""Get current timestamp in RFC 3164 format (Mmm dd HH:MM:SS)"""
now = datetime.now()
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
return f"{months[now.month-1]} {now.day:2d} {now.hour:02d}:{now.minute:02d}:{now.second:02d}"
def _format_syslog_message(self, severity: int, message: str) -> bytes:
"""
Format syslog message according to RFC 3164
Format: <PRI>TIMESTAMP HOSTNAME TAG: MESSAGE
"""
priority = (self.facility * 8) + severity
timestamp = self._get_timestamp()
formatted = f"<{priority}>{timestamp} {self.hostname} {self.tag}: {message}"
return formatted.encode('utf-8')
def send_syslog(self, event_type: str, json_message: str):
"""
Send message to syslog server
Args:
event_type: Type of event (CALLBACK, TASK, etc.)
json_message: JSON formatted message to send
"""
try:
# Map event types to syslog severity
severity_map = {
"CALLBACK": 6, # INFO
"TASK": 6, # INFO
"RESPONSE": 6, # INFO
"CREDENTIAL": 6, # INFO
"KEYLOG": 6, # INFO
"FILE": 6, # INFO
"ARTIFACT": 4, # WARNING
"PAYLOAD": 6, # INFO
}
severity = severity_map.get(event_type, 6) # Default to INFO
# Format and send syslog message
syslog_msg = self._format_syslog_message(severity, json_message)
self.socket.sendto(syslog_msg, (self.server, self.port))
except Exception as e:
# Don't fail if syslog send fails, just log it
print(f"[SYSLOG] Error sending message: {e}", flush=True)
# Register the logger - Mythic will automatically detect and register it
# The class name and inheritance from Log is what makes it work
cazalla_logger = CazallaLogger()
+14
View File
@@ -0,0 +1,14 @@
# Syslog Configuration for Cazalla Logging Container
# Edit this file with your syslog server details
# After editing, restart the container: sudo ./mythic-cli restart cazalla
# Syslog server IP or hostname (leave empty to disable syslog)
# Use the host IP (10.8.20.50) or 172.17.0.1 (docker0 bridge) to reach rsyslog on the host
SYSLOG_SERVER=10.8.20.50
# Syslog server port (default: 514)
SYSLOG_PORT=514
# Syslog facility code (0-23, default: 16 = LOCAL0)
SYSLOG_FACILITY=16
+16 -1
View File
@@ -4,8 +4,23 @@ import asyncio
import cazalla
#import websocket.mythic.c2_functions.websocket
from translator.translator import *
#from my_logger import logger
# Import logging container - following official Python pattern
# The logger is automatically registered when the class is instantiated
try:
from logger import cazalla_logger # Import logging container
print("[MAIN] ✓ Logging container imported and registered")
except Exception as e:
print(f"[MAIN] WARNING: Could not import logging container: {e}")
print("[MAIN] Container will continue without logging functionality")
import traceback
traceback.print_exc()
#from basic_command_augment import *
#from basic_eventer.my_eventing import *
# Start Mythic services
# Note: In Go, basic_logger uses MythicServiceLogger service
# In Python, the logging registration happens during import above
# If logging needs a separate service, we may need to register it here
mythic_container.mythic_service.start_and_run_forever()