Cybertek-Detection-Scripts/lolrmm/project.md

491 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Project: Syncro LOLRMM Detector
## Summary
A **single self-contained PowerShell script** that runs on a recurring interval inside **Syncro RMM** and detects **unauthorized living-off-the-land remote management (LOLRMM)** activity on Windows endpoints.
The detector dynamically pulls the current LOLRMM catalog, inspects the local system for suspicious artifacts across the currently enabled RMM-focused detection layers, compares findings against an internal allowlist, and creates a **Syncro RMM alert** when non-approved remote management tools are detected.
This project gives Cybertek a lightweight, scalable endpoint detection layer for **unexpected remote access and RMM tooling**, especially for customers that may not have full Defender for Endpoint / SIEM coverage everywhere.
---
## Business Problem
Attackers increasingly use legitimate remote administration tools instead of obviously malicious malware.
Examples include:
- AnyDesk
- RustDesk
- TeamViewer
- ConnectWise ScreenConnect
- LogMeIn / GoToAssist
- Level.io
- RAdmin
- Other tools cataloged by LOLRMM
These tools are often:
- digitally signed
- encrypted over the network
- operationally normal-looking
- portable or easy to stage in user-writable paths
Because of that, they can bypass shallow antivirus-based detections and blend into normal IT activity.
The true detection goal is **not** "detect every remote tool."
The true detection goal is:
> Detect remote management infrastructure that is **not approved** for that customer or device.
---
## Project Goals
### Primary Goals
1. Pull LOLRMM data dynamically from the published API at runtime.
2. Detect likely unauthorized RMM artifacts on Windows endpoints across focused LOLRMM-backed detection layers.
3. Generate a Syncro RMM alert automatically when a detection occurs.
4. Keep everything contained in one PowerShell script that can be scheduled through Syncro.
5. Support allowlisting so approved tools do not generate noisy alerts.
6. Protect the integrity of the local feed cache against tampering.
7. Classify detections as NEW or RECURRING to support noise management.
### Secondary Goals
1. Write useful context into the alert body so technicians can triage quickly.
2. Optionally write scan results into Syncro Asset Custom Fields.
3. Optionally auto-close the open alert category when subsequent scans are clean.
4. Use a local cache so detection still works if the LOLRMM feed is temporarily unavailable.
5. Detect renamed RMM binaries through PE version resource metadata.
6. Flag detections running from user-writable paths as elevated risk.
7. Keep detections anchored to explicit LOLRMM tool matches rather than broad software inventory heuristics.
### Non-Goals
1. Full historical network telemetry.
2. Kernel-level or ETW-based monitoring.
3. Automated containment by default.
4. Per-customer centralized allowlist management (deferred to future phase).
5. File artifact checks from LOLRMM `Artifacts.Disk` (filesystem scans are too expensive for recurring execution).
6. Broad persistence hunting outside clear RMM identification scope.
---
## Why This Matters
Unauthorized RMM activity is often one of the earliest visible signs of interactive attacker behavior.
Threat actors commonly install or launch remote management tools to:
- keep persistence after initial access
- move laterally
- provide operator access to other team members
- re-enter the environment later
- stage for extortion or ransomware operations
That makes LOLRMM detection a strong **early-warning control**.
---
## Architecture
### Execution Model
- **Language:** PowerShell 5.1+
- **Runtime:** Syncro Windows script runner
- **Schedule:** Recurring via Syncro policy or asset schedule
- **Run Context:** SYSTEM
- **Alert Method:** `Rmm-Alert`
### Data Source
- LOLRMM API JSON feed:
- `https://lolrmm.io/api/rmm_tools.json`
### Local Storage
| Path | Purpose |
|------|---------|
| `C:\ProgramData\Cybertek\LOLRMM\rmm_tools_cache.json` | Cached LOLRMM feed |
| `C:\ProgramData\Cybertek\LOLRMM\rmm_tools_cache.json.sha256` | SHA-256 hash of cached feed for integrity verification |
| `C:\ProgramData\Cybertek\LOLRMM\last_detections.json` | Prior detection state for NEW vs RECURRING classification |
| `C:\ProgramData\Cybertek\LOLRMM\last_scan_report.txt` | Full untruncated detection report from most recent scan |
The script prefers the live feed but falls back to cached data if the download fails and the cache is within the configured age limit. The cache directory ACL is hardened on first run to restrict write access to SYSTEM and Administrators only.
---
## Detection Layers
The current script is intentionally scoped to **RMM identification only**. It favors layers that can be tied back to explicit LOLRMM indicators and avoids broader persistence/inventory checks that created noise during testing.
### 1. Running Process Detection
Look for current processes whose names, executable paths, or **PE version resource metadata** match LOLRMM-derived indicators.
Indicator sources:
- `Details.PEMetadata.Filename`
- `Details.PEMetadata.OriginalFileName`
- `Details.PEMetadata.InternalName`
- `Details.InstallationPaths`
**Matching strategy:**
- Process filename and stem are matched using **exact equality** against the indicator set.
- Full executable paths are matched using **path-aware substring** — the indicator must contain a path separator (`\` or `/`) to qualify, preventing short filename stems from spuriously matching unrelated Windows processes.
- PE version metadata (`ProductName`, `FileDescription`) uses **exact equality** against LOLRMM PE metadata values rather than broad substring matching.
PE version info is read directly from the binary using `FileVersionInfo`. This catches **renamed binaries** where the filename has been changed but the embedded version resource was not stripped.
Detections from user-writable paths (`%TEMP%`, `%APPDATA%`, `Downloads`, `Desktop`, `C:\Users\*`) are flagged with a `*** USER-WRITABLE PATH ***` marker in the alert body.
### 2. Service Detection
Inspect Windows services for service names, display names, and binary paths matching LOLRMM indicators.
**Matching strategy:** Service name and display name use exact equality matching. Binary path uses path-aware substring matching (same rules as process path above).
This detects installed RMM agents even when they are not actively being used.
### 3. Live Network Detection
Inspect **current established TCP connections** using `Get-NetTCPConnection`, then:
- map connections to owning process IDs
- look up the process path
- optionally perform reverse DNS lookup on the remote IP
- compare the resolved hostname to LOLRMM domains when reverse DNS is enabled
**Current default:** reverse DNS is **disabled** to avoid long endpoint-specific timeouts. The layer still evaluates the owning process name and path against LOLRMM indicators.
**Caveat:** This layer is point-in-time only. It can detect active sessions but will miss short-lived connections that start and stop between script runs. The other layers cover persistence regardless of active session state.
### 4. Scheduled Task Detection
Inspect Windows scheduled tasks for action executable paths, arguments, and task names that match LOLRMM indicators.
**Matching strategy:** Task name and executable filename/stem use exact equality matching. Executable full path and arguments use path-aware substring matching.
Microsoft built-in task paths (`\Microsoft\Windows\`, `\Microsoft\Office\`, etc.) are excluded to reduce noise. This layer is configurable via `ExcludedTaskPaths`.
### 5. Registry Artifact Detection
Perform targeted registry key existence checks using artifact paths from LOLRMM's `Artifacts.Registry` catalog data.
Only HKLM keys are checked. One detection per LOLRMM tool name is generated to avoid duplicate alerts.
This layer is lightweight — it performs only the specific key lookups listed in the catalog, not a broad registry scan.
### Disabled by Default
The following layers exist in code or earlier design work but are **disabled by default** in the current script to keep output tightly aligned to RMM detection and reduce false positives:
- Installed software detection
- Startup entry detection
These may be revisited later as separate scripts or narrower optional modules.
---
## Data Integrity
### Feed Validation
After downloading the live feed, the script validates that the parsed JSON contains at least `MinFeedEntryCount` entries (default: 50) before trusting or caching it. This prevents a truncated, empty, or spoofed response from being cached and silently degrading detection.
### Cache Integrity
The SHA-256 hash of the cached feed is stored in a companion `.sha256` file. On each cache load, the hash is recomputed and compared. A mismatch aborts the script with an error alert rather than silently operating on tampered data.
### Cache Directory ACL
On first run, the script removes inherited permissions from `C:\ProgramData\Cybertek\LOLRMM\` and grants Full Control exclusively to SYSTEM and the Administrators group. This prevents a low-privilege process from modifying the cached feed or state files.
---
## Alerting Strategy
### Alert Category
- `unauthorized_rmm_detected`
### Alert Contents
The alert body includes:
- host/computer name
- scan timestamp
- feed source (live or cache)
- total detection count with NEW / RECURRING breakdown
- per-detection: layer, NEW/RECURRING status, matched LOLRMM tool name
- process name, PID, executable path
- PE version metadata (ProductName, CompanyName) when available
- user-writable path warning when applicable
- publisher/signature info
- service state and start mode
- scheduled task path and executable
- registry artifact key path
- remote IP, port, and reverse-DNS hostname for network matches when reverse DNS is enabled
- matched-on reason for each detection
### NEW vs RECURRING Classification
Detection state is persisted between runs in `last_detections.json`. Each detection is classified as:
- **NEW** — not seen on the previous scan
- **RECURRING** — seen on one or more prior scans
Both are included in alerts by default. Setting `SuppressRecurringDetections = $true` limits alerts to new findings only, which significantly reduces noise on endpoints with a known persistent tool under investigation.
### Dedupe Behavior
Syncro de-dupes by alert category per asset, so the script consistently uses the same alert category for this detector.
### Optional Cleanup
When a subsequent scan is clean, the script closes the alert category automatically if `CloseAlertWhenClean = $true` (the default).
---
## Allowlist Design
The allowlist is what makes this operationally useful rather than noisy.
### Allowlist Dimensions
- **Approved domains** — suppress network matches to these domains
- **Approved process names** — suppress process/service/task matches by name
- **Approved path patterns** — suppress matches from these path patterns (wildcard)
- **Approved publishers** — suppress matches where the Authenticode CN field matches
Publisher matching extracts the `CN=` field from the full Authenticode subject string for a tighter comparison, rather than a loose substring match against the entire subject.
### Current Defaults
- Splashtop (process names, path pattern, publisher)
- Syncro (name, path pattern, domain)
### Future Improvement
Move allowlists out of the script and into one of:
- Syncro script variables
- customer-specific custom fields
- hosted JSON config
- internal API
---
## Feature Flags
All major detection layers and behaviors are independently toggleable in `$Config`:
| Flag | Default | Purpose |
|------|---------|---------|
| `EnableScheduledTaskDetection` | `$true` | Scheduled task layer |
| `EnableInstalledSoftwareDetection` | `$false` | Uninstall-registry software inventory layer |
| `EnableStartupEntryDetection` | `$false` | Run/RunOnce startup layer |
| `EnableRegistryArtifacts` | `$true` | Registry artifact layer |
| `EnablePEVersionCheck` | `$true` | Renamed binary detection via PE metadata |
| `SuppressRecurringDetections` | `$false` | Only alert on NEW detections |
| `HardenCacheDirectoryAcl` | `$true` | Restrict cache directory permissions |
| `CloseAlertWhenClean` | `$true` | Auto-close alert on clean scan |
| `SetAssetFields` | `$false` | Write results to Syncro Asset Custom Fields |
| `ResolveReverseDns` | `$false` | Reverse DNS for network connections |
| `ResolveReverseDnsPrivateIPs` | `$false` | Also resolve private/RFC1918 IPs |
---
## Script Outputs
### Success / Clean
- exit code `0`
- no unauthorized matches
- state file updated
- optionally closes prior alert category
### Detection Found
- exit code `0` (Syncro handles alerting via `Rmm-Alert`; non-zero exit is not needed)
- creates/updates Syncro RMM alert with full triage context
- writes full untruncated report to `C:\ProgramData\Cybertek\LOLRMM\last_scan_report.txt` for technician review
- alert body is truncated at `MaxAlertBodyLength` characters with a note pointing to the report file
- persists detection state for NEW/RECURRING tracking
- optionally writes asset fields and activity log entry
### Script Error
- exit code `2`
- creates `unauthorized_rmm_detector_error` alert category
---
## Deployment Plan
### Phase 1: Internal Validation
1. Import script into Syncro.
2. Run manually on internal lab/test endpoints.
3. Validate:
- LOLRMM feed download and validation
- cache fallback and integrity check
- cache directory ACL hardening
- process matches (name, path, PE version info)
- service matches
- scheduled task matches
- registry artifact matches
- network matches
- NEW vs RECURRING classification across consecutive runs
- alert creation and body content
- alert closing behavior on clean scan
4. Intentionally launch a known non-approved tool in a test environment and verify detection across all applicable layers.
5. Rename a known RMM binary and verify PE version info detection fires.
### Phase 2: Controlled Pilot
1. Deploy to Cybertek-managed internal endpoints.
2. Schedule every 3060 minutes.
3. Review noise and false positives.
4. Expand allowlist as needed.
5. Evaluate whether `SuppressRecurringDetections` should be enabled for steady-state operation.
### Phase 3: High-Risk Customer Rollout
1. Roll out to compliance-sensitive and higher-risk customers.
2. Consider 15-minute interval only if script runtime remains consistently low.
3. Pair alerts with automated remediation or ticketing later if desired.
---
## Scheduling Guidance
Recommended first-pass schedule:
- **High-risk endpoints:** every 1530 minutes
- **Most managed workstations:** every 3060 minutes
- **Lower-risk / resource-sensitive endpoints:** hourly
The script is designed to remain lightweight. The most expensive operations (process enumeration, PE version reads, scheduled task enumeration) complete in seconds on typical endpoints.
---
## Known Limitations
1. **Network checks are not historical.**
- They only see established sockets at scan time.
2. **Reverse DNS is disabled by default.**
- It caused endpoint-specific timeouts during testing.
- It can be re-enabled later if domain-level enrichment is worth the runtime cost in a given environment.
3. **Community-driven catalog data can be incomplete.**
- Some LOLRMM tools have richer metadata than others.
4. **PE version info can be stripped or spoofed.**
- Sophisticated attackers can clear or alter the version resource block.
- This is an additional detection layer, not a guarantee.
5. **Registry artifacts only cover HKLM when running as SYSTEM.**
6. **Scheduled task exclusions are path-based.**
- A malicious task placed under `\Microsoft\Windows\` would be skipped. This is an accepted trade-off for noise reduction.
7. **Signature trust is contextual.**
- Signed software can still be abused. Publisher allowlisting is a convenience, not a security control.
8. **Exact name matching may miss obfuscated RMM filenames.**
- If an attacker renames an RMM binary to something not in the LOLRMM catalog's filename indicators, the process/service name layers will not match. The PE version metadata secondary check partially compensates for this.
9. **The detector is only as precise as the LOLRMM catalog.**
- The script now tries to report only matches that map back to an explicit LOLRMM tool.
- If the upstream catalog is broad or incomplete, detections will inherit those limitations.
---
## Future Enhancements
### Detection Enhancements
1. File artifact checks from LOLRMM `Artifacts.Disk` (low priority — expensive on large disks).
2. Enumerate loaded user registry hives (`HKU:\`) for HKCU registry artifact checks.
3. WMI subscription persistence detection.
4. Correlate detections across layers for a simple confidence score.
5. Detect processes with no window title / hidden windows as an additional risk signal.
### Response Enhancements
1. Auto-create Syncro ticket on high-confidence or NEW detections.
2. Auto-run remediation script on specific tools.
3. Kill specific unauthorized processes.
4. Notify a Teams/webhook channel.
### Management Enhancements
1. Centralize allowlists outside the script (Syncro script variables, hosted JSON, or internal API).
2. Build customer-specific policy profiles.
3. Write summary status into Syncro Asset Custom Fields for saved searches and reporting.
4. Add a dashboard/reporting layer for all LOLRMM detections across the customer base.
### Variant Roadmap
Two script variants are planned:
1. **MIT / Cybertek-managed clients**
- Assumes no non-approved RMM tools should exist.
- May take automated remediation steps after high-confidence detection.
- Will require a separate remediation map per tool rather than a generic uninstall workflow.
2. **Public / general client version**
- Will remain detection-first.
- Should prompt the user to acknowledge the detected remote access tool and optionally request Cybertek review / ticket submission.
- This interactive workflow is planned for a future iteration and is not part of the current script.
---
## Success Criteria
This project is successful when:
1. The script runs repeatedly inside Syncro without manual intervention.
2. The LOLRMM feed is pulled dynamically or loaded from a verified cache.
3. Unauthorized RMM tools generate actionable Syncro alerts across the enabled RMM-focused detection layers.
4. Renamed RMM binaries are caught via PE version metadata.
5. Approved tooling does not generate frequent false positives.
6. Technicians can triage directly from alert content without opening the endpoint first.
7. Recurring detections are distinguishable from new ones in the alert body.
---
## Files
### `lolrmm_syncro_detector.ps1`
Production-ready PowerShell detector for Syncro. Focused LOLRMM-backed detection across processes, services, network connections, scheduled tasks, and registry artifacts; feed integrity validation; cache ACL hardening; PE version metadata checks; user-writable path flagging; NEW/RECURRING state tracking; full report file output; and conservative exact/path-aware matching tuned to reduce false positives.
### `mock_syncro_module.psm1`
Local testing stub that implements `Rmm-Alert`, `Close-Rmm-Alert`, `Log-Activity`, and `Set-Asset-Field` as console-printing mock functions. Allows local test runs without a live Syncro connection.
### `test_local.ps1`
Local test runner. Sets `$env:SyncroModule` to the mock module path and launches the detector in a child process so `exit` calls do not close the test session.
### `project.md`
This planning and design file.
---
## Suggested Immediate Next Steps
1. Import the script into Syncro as a PowerShell script.
2. Test manually on an internal workstation — verify feed download, cache write, and ACL hardening.
3. Install a known non-approved RMM tool in a lab environment.
4. Verify detections fire across process, service, scheduled task, network, and registry artifact layers.
5. Rename the tool binary and verify PE version info detection catches it.
6. Run the script a second time and verify the detection is classified as RECURRING.
7. Uninstall the tool and verify the third run is clean and the alert closes.
8. Tune the allowlist before broad deployment.
9. Decide whether `SuppressRecurringDetections = $true` fits the operational workflow.