# 📊 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
