Skip to content

OPSEC Best Practices

Comprehensive operational security reference for Stentor operators. This guide covers detection surfaces for every major technique category, the garble obfuscation pipeline, the runtime opsec posture command, a decision matrix for technique selection by environment, and operational recommendations from pre-engagement through cleanup.

OPSEC is not optional

Every technique in Stentor's arsenal produces forensic artifacts. The question is never "will this be detectable?" but rather "what detects it, and is that detection present in this target environment?" Use this guide to make informed risk decisions throughout your engagement.


Detection Surface by Technique Category

Each technique category produces distinct forensic artifacts across different detection layers (endpoint telemetry, network monitoring, log analysis). The sections below map Stentor's capabilities to their detection surfaces with specific MITRE ATT&CK references and recommended mitigations.

Process Injection

Process Injection Detection Surface (10+ techniques in implant/internal/modules/inject/) | Technique | MITRE ATT&CK | Detection Vector | Severity | Mitigation | |-----------|--------------|-------------------|----------|------------| | CreateRemoteThread | T1055.001 | ETW kernel callbacks, Sysmon Event 8 (CreateRemoteThread), call stack analysis | **High** | Use QueueUserAPC or NtMapViewOfSection instead; combine with indirect syscalls | | QueueUserAPC | T1055.004 | ETW thread alertable wait monitoring, memory allocation patterns | **Medium** | Pair with module stomping for MEM_IMAGE backing | | NtMapViewOfSection | T1055.012 | Section object creation (Sysmon Event 9), cross-process mapping | **Medium** | Use indirect syscalls to avoid ntdll hook detection | | Early Bird APC | T1055.004 | Process creation in suspended state (Sysmon Event 1 + 8 correlation), APC queue inspection | **Medium** | Randomize target process; use PPID spoofing | | Thread Hijack | T1055.003 | GetThreadContext/SetThreadContext calls (ETW), instruction pointer modification | **High** | Combine with BeaconGate to route context APIs through syscalls | | Module Stomping | T1574.002 | DLL .text section modification (memory integrity), section hash mismatch | **Low** | Choose large, infrequently loaded DLLs (xpsservices.dll) | !!! warning "Primary injection risk" Memory allocation type is the strongest indicator. `MEM_PRIVATE` allocations with `PAGE_EXECUTE_READWRITE` are flagged by every modern EDR. Always enable module stomping (`MEM_IMAGE` backing) and disable `UseRWX` (use `RW` then `RX` transitions) to reduce this signal.

Credential Access

Credential Access Detection Surface (implant/internal/modules/creds/, kerberos/, dpapi/) | Technique | MITRE ATT&CK | Detection Vector | Severity | Mitigation | |-----------|--------------|-------------------|----------|------------| | SAM Dump (registry) | T1003.002 | Registry key access (HKLM\SAM), Sysmon Event 12/13 | **High** | Use in-memory parsing; avoid reg save to disk | | LSASS Access | T1003.001 | Process handle to lsass.exe (Sysmon Event 10), PPL protection bypass | **Critical** | Use minidump via comsvcs.dll or BOF; avoid direct OpenProcess on lsass | | Kerberoast | T1558.003 | Security Event 4769 (TGS requests for RC4 encryption), LDAP SPN queries | **High** | Request AES-encrypted tickets (etype 17/18); throttle requests over time | | DCSync | T1003.006 | Security Event 4662 (DS-Replication-Get-Changes-All), network replication traffic | **Critical** | Limit to specific accounts; run during replication windows | | DPAPI Masterkey | T1555.004 | DPAPI API calls, LSASS access for domain backup key | **Medium** | Use offline parsing where possible; avoid repeated masterkey requests | !!! danger "LSASS is the highest-risk target" Every EDR monitors LSASS access. Credential Credential Guard, PPL, and RunAsPPL make direct access impossible on hardened systems. Prefer Kerberoasting (offline cracking) or DPAPI (no LSASS touch) when possible. When LSASS access is required, use a BOF with indirect syscalls and BeaconGate enabled.

Lateral Movement

Lateral Movement Detection Surface (implant/internal/modules/lateral/) | Technique | MITRE ATT&CK | Detection Vector | Severity | Mitigation | |-----------|--------------|-------------------|----------|------------| | PsExec (service) | T1021.002 | Service creation Event 7045, Security Event 4624 type 3, named pipe | **High** | Use random service names; delete service after execution; avoid default pipe names | | WMI Exec | T1047 | WMI event logs (Microsoft-Windows-WMI-Activity), process creation under WmiPrvSE.exe | **Medium** | WMI is common in enterprise; blend with normal admin traffic | | WinRM | T1021.006 | Windows Remote Management logs, PowerShell remote session events (Event 4103/4104) | **Medium** | Use HTTPS transport; blend with existing remote management | | DCOM | T1021.003 | COM object instantiation, unusual parent-child process chains | **Low** | Varies by DCOM object; MMC20.Application and ShellBrowserWindow are well-known | | Pass-the-Hash | T1550.002 | NTLM authentication Event 4624 type 3 with LogonProcessName: NtLmSsp | **High** | Rotate between techniques; avoid repeated PtH to same target | | Pass-the-Ticket | T1550.003 | Kerberos authentication anomalies, ticket reuse from unexpected IPs | **Medium** | Use tickets from the correct user context; respect ticket lifetime | !!! warning "Authentication log correlation" Lateral movement generates authentication events (4624/4625) on both source and target. SOCs correlate these across systems. Vary techniques, space out movements, and prefer methods with lower log footprints (WMI, DCOM) over high-footprint ones (PsExec with service creation).

Persistence

Persistence Detection Surface (implant/internal/modules/persist/) | Technique | MITRE ATT&CK | Detection Vector | Severity | Mitigation | |-----------|--------------|-------------------|----------|------------| | Registry Run Keys | T1547.001 | Sysmon Events 12/13/14 (registry modification), autoruns enumeration | **High** | Use less-monitored keys (UserInitMprLogonScript); set during low-activity periods | | Scheduled Tasks | T1053.005 | Security Event 4698 (task created), Sysmon Event 1 (task host process) | **High** | Use XML task definitions with legitimate-looking names; set distant trigger times | | Service Creation | T1543.003 | Service Manager Event 7045, registry modification under HKLM\SYSTEM\CurrentControlSet\Services | **High** | Mimic legitimate service naming conventions; use svchost.exe shared services | | DLL Hijacking | T1574.001 | File creation events (Sysmon Event 11), DLL load from unusual paths | **Medium** | Target applications that load from writable directories; match DLL metadata | | COM Hijacking | T1546.015 | Registry modification in HKCU\Software\Classes\CLSID, InprocServer32 changes | **Low** | COM hijacking is difficult to detect without baseline; choose obscure CLSIDs | !!! tip "Persistence OPSEC hierarchy" COM hijacking is the stealthiest persistence mechanism (low detection, per-user, no admin required). Registry run keys and scheduled tasks are the most detected. Choose based on required privilege level and target monitoring capability.

Defense Evasion

Defense Evasion Detection Surface (implant/internal/modules/evasion/) | Technique | MITRE ATT&CK | Detection Vector | Severity | Mitigation | |-----------|--------------|-------------------|----------|------------| | AMSI Bypass (inline patch) | T1562.001 | Memory integrity scanning of amsi.dll, ETW AMSI provider events | **Medium** | Use hardware breakpoints (`hwbp amsi on`) instead of inline patches | | ETW Patching | T1562.006 | EtwEventWrite return value monitoring, ETW session gap detection | **Medium** | Use hardware breakpoints (`hwbp etw on`); patch selectively per provider | | Sleep Masking | T1497.003 | Periodic memory scanning during execution windows, timer pattern analysis | **Low** | Enable all three masks (text + heap + stack) for comprehensive coverage | | PPID Spoofing | T1134.004 | ETW kernel process events (EventHeader.ProcessId mismatch) | **Low** | Choose contextually appropriate parent processes | | Indirect Syscalls | T1106 | Stack frame analysis (ntdll call without matching export), ETW Threat-Intelligence | **Low** | Combine with BeaconGate for comprehensive API coverage | | EDR Unhooking | T1562.001 | Periodic hook integrity verification by EDR, KnownDlls section access | **Medium** | Use targeted unhooking (single function) rather than full DLL restoration | !!! info "Layered evasion" No single evasion technique is sufficient. Combine indirect syscalls + BeaconGate + sleep masking + HWBP + module stomping for comprehensive coverage. The `opsec` command scores your current posture and identifies gaps.

Discovery

Discovery Detection Surface (implant/internal/modules/discovery/) | Technique | MITRE ATT&CK | Detection Vector | Severity | Mitigation | |-----------|--------------|-------------------|----------|------------| | Network Scanning | T1046 | Network anomaly detection (port sweep patterns), firewall logs | **High** | Throttle scan rate; target specific ports; use ARP scanning on local subnet | | LDAP Enumeration | T1087.002 | LDAP query volume anomalies, unusual search base/filter patterns | **Medium** | Use targeted queries (specific OUs/groups); spread queries across time | | SPN Scanning | T1558.003 | Kerberos TGS requests with RC4 etype, unusual SPN query volume | **Medium** | Request AES tickets; limit scope to high-value SPNs | | Local System Discovery | T1082 | Process execution (systeminfo, ipconfig, etc.), WMI queries | **Low** | Use native API calls instead of spawning processes; prefer BOF execution | | Domain Trust Discovery | T1482 | LDAP queries for trustedDomain objects, nltest.exe execution | **Low** | Use LDAP directly instead of nltest; single query rather than enumeration | !!! tip "Discovery OPSEC" Discovery commands that spawn child processes (shell commands) are more detectable than those using native APIs or BOFs. Prefer inline execution over fork-and-run when possible. Use `execute-assembly` with compiled .NET tools rather than `shell` commands for AD enumeration.

Garble Obfuscation Pipeline

Garble is Stentor's build-time obfuscation tool for Go binaries. It strips, encrypts, or randomizes the forensic artifacts that make Go binaries identifiable and reversible. Understanding what garble fixes and what it cannot fix is essential for OPSEC planning.

Build Pipeline Flow

graph LR
    A[Payload Generation<br/>API / CNA Hook] --> B[garble<br/>-seed=random<br/>-literals -tiny]
    B --> C[ldflags<br/>-s -w -trimpath<br/>-buildid=]
    C --> D[Compiled Binary<br/>EXE / DLL]
    D --> E{Shellcode<br/>Wrapping?}
    E -->|Yes| F[Donut<br/>Position-independent<br/>shellcode]
    E -->|No| G[Final Binary<br/>Obfuscated EXE/DLL]
    F --> H[Final Payload<br/>PE headers stripped]

    style A fill:#6a1b9a,color:#fff
    style B fill:#4a148c,color:#fff
    style C fill:#311b92,color:#fff
    style D fill:#1a237e,color:#fff
    style F fill:#0d47a1,color:#fff
    style H fill:#01579b,color:#fff

What Garble Fixes

Artifact Risk Without Garble Garble Flag Status
Package paths (github.com/...) Full source repo path visible in strings -trimpath + garble FIXED
Function/symbol names All function names recoverable -seed=random FIXED -- names randomized per build
String literals (URLs, errors, config) C2 URLs, error messages readable -literals FIXED -- strings encrypted at compile time
Build ID metadata Links binary to build environment -buildid= (ldflags) FIXED -- stripped from binary
Binary size (panic/debug output) Panic strings, debug info bloat binary -tiny REDUCED -- ~15% smaller, panic output removed
Debug symbols Full DWARF debug info -s -w (ldflags) FIXED -- stripped by default

Known Unfixable Limitations

These are architectural requirements of the Go runtime. No obfuscation tool can remove them without breaking the binary.

Limitation Severity Why Unfixable Mitigation
pclntab magic bytes (0xFFFFFFF0/0xFFFFFFF1) HIGH Required by Go runtime for stack unwinding, GC, and panic recovery Donut shellcode wrapping strips PE headers entirely; sleep mask encrypts .text during sleep
Go-specific PE section characteristics MEDIUM Go linker produces distinctive .text/.data section layout and alignment Donut/shellcode loader eliminates PE structure; PE cloning (Rich header) reduces uniqueness
Go runtime goroutines (sysmon, GC) MEDIUM Background threads for garbage collection and system monitoring are always running Thread count filtering; sleep mask pauses GC during sleep
Type metadata for reflect/interfaces LOW Exported type names required for interface dispatch and reflection Set GOGARBLE to limit scope; avoid unnecessary exported types
.text readable during execution MEDIUM Go cannot execute from non-readable memory (no W^X execute-only) Sleep mask encrypts .text during sleep; only exposed during active execution
Go version in pclntab LOW pclntab structure version reveals Go version range (1.18+ vs 1.20+) Not practically exploitable beyond identifying Go version family
pclntab Deep Dive The `pclntab` (Program Counter Line Number Table) is the highest-risk unfixable artifact. It exists in every Go binary and contains: - **Magic bytes** that identify Go version family (0xFFFFFFF0 for Go 1.18+, 0xFFFFFFF1 for Go 1.20+) - **Function entry points** (names garbled but structure intact) - **Source file line number mappings** (paths stripped by -trimpath) - **Stack frame sizes** for unwinding Tools like GoReSym exploit this structure to recover function boundaries even from garbled binaries. The structure itself cannot be removed -- the Go runtime panics without it. **Impact:** Any binary containing pclntab magic bytes can be identified as Go regardless of all other obfuscation. Binary analysts can recover function boundaries (though not names) and reconstruct the program's call graph. **Best mitigation:** Wrap the garbled binary in Donut shellcode. Donut converts the binary to position-independent code, stripping PE headers and section characteristics entirely. The pclntab still exists in memory at runtime, but it is encrypted during sleep periods when sleep masking is enabled.

Build Modes

Mode Command Use Case Obfuscation Level
Development make build-implant Fast iteration, debugging Minimal (stripped symbols, -trimpath, -buildid=)
Production make build-implant-prod Engagement deployment Full (garble -seed=random -literals -tiny)
Relay payloads (obfuscated) Payload API with obfuscate: true Operator-generated payloads Full (same garble flags as production)
Relay payloads (no garble) Payload API with obfuscate: false Quick testing Minimal (-trimpath, -buildid= in ldflags)

Detection Tools

Tool Author Capability Effectiveness Against Garble
GoReSym Mandiant Recovers symbols via pclntab structure analysis High -- recovers function boundaries despite garble
GoStringUngarbler Google Defeats garble -literals via pattern matching Medium -- identifies and decrypts garble's string encryption
Ungarble Binary Ninja plugin CFG analysis to reverse garble obfuscation Medium -- control flow graph recovers semantic information
YARA rules (pclntab) Various Detects Go binaries via pclntab magic byte scan Always works -- architectural requirement, cannot be hidden
strings + grep Standard Searches for plaintext strings in binary Ineffective -- garble -literals encrypts all constants
PE-bear / CFF Explorer Various Analyzes PE structure and section characteristics Partial -- identifies Go-specific section layout

Operator Guidance

  • Garble is evasion, not invisibility. It makes static reverse engineering significantly harder but does not make a binary unanalyzable. A determined analyst with GoReSym can still recover function boundaries.

  • Go binaries ARE identifiable as Go. The pclntab magic bytes are an architectural requirement. No obfuscation can change this. If "not Go" is a hard requirement, use the C stager for initial access.

  • Wrap garbled implant in shellcode loader. Donut converts the garbled EXE to position-independent shellcode, stripping PE headers and section characteristics entirely.

  • Sleep mask protects at runtime. During sleep, the .text section is encrypted in memory, defeating memory scanning for Go patterns.

  • -seed=random means every build is unique. Each compilation produces a binary with different symbol names and string encryption keys, defeating signature-based AV detection.

  • EDR behavioral detection is orthogonal to garble. Garble only affects static analysis. Behavioral detections (API call sequences, network patterns, thread injection) are not affected by binary obfuscation.

  • C stager avoids Go signatures entirely. The MinGW C stager (~23KB) downloads and executes the full implant. It has no Go runtime, no pclntab, no goroutines. Use the C stager when initial access must not look like Go.


Runtime OPSEC Posture Command

The opsec command runs the OpsecModule (implant/internal/modules/opsec/opsec.go) and returns a scored posture report with 17 individual checks. Use it to audit a beacon's evasion configuration before executing sensitive operations.

Running the Command

Shell syntax:

opsec

API example:

curl -s -X POST https://stentor.app/api/v1/cockpit/shell \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "beacon_id": "BEACON_UUID",
    "command": "opsec"
  }'

Example Output

[*] OPSEC Posture Report
[*] Score: 71/100

[+] syscall_method: indirect -- APIs routed via ntdll gadgets
[+] sleep_mask: enabled -- .text encrypted during sleep
[+] heap_mask: enabled -- Heap records encrypted during sleep
[!] stack_mask: disabled -- Thread stack visible during sleep
[+] beacon_gate: enabled (25 APIs) -- Sensitive APIs through syscall shim
[!] module_stomp: disabled -- No module stomping (MEM_PRIVATE allocations)
[+] ppid_spoof: explorer.exe -- Child processes spoofed under explorer.exe
[+] spawnto: RuntimeBroker.exe (pool: 7) -- Context-aware rotation
[+] amsi_patched: enabled -- AmsiScanBuffer patched in fork-and-run
[!] etw_patched: disabled -- ETW active in fork-and-run processes
[+] tls_fingerprint: chrome_auto -- uTLS fingerprint spoofing active
[!] sleep_method: direct -- Standard sleep (no timer queue obfuscation)
[+] drip_load_inject: enabled -- Injection memory allocated in small chunks
[+] use_rwx: disabled -- W^X compliant (RW->RX transitions)
[!] udrl: disabled -- Standard reflective loading
[-] edr_hooks: 3 hooked -- Hooked: NtAllocateVirtualMemory, NtWriteVirtualMemory, NtCreateThreadEx -- run edr_unhook
[+] hwbp_status: 2/4 DR slots active -- AMSI/ETW bypass via hardware breakpoints

Recommendations:
  - Consider enabling stack masking for additional sleep protection
  - Configure module stomping DLL for MEM_IMAGE backing
  - Consider timer_queue sleep method for Ekko-style timer-based sleep
  - Consider enabling UDRL for custom reflective loading
  - Run edr_unhook to remove EDR userland hooks before injection/credential operations

Score Calculation

Each of the 17 checks scores based on its status:

Status Points Indicator Meaning
good 1.0 [+] Optimal OPSEC setting active
warn 0.5 [!] Acceptable but improvement available
bad 0.0 [-] Significant detection risk
info 0.0 [*] Informational (not scored against posture)

Formula: score = (sum of points / total checks) * 100

A score of 100 means all 17 checks are in the good state. Target a minimum score of 70 for standard engagements and 85+ for EDR-heavy environments.

All 17 Posture Checks

# Check Values Good Warn Bad Recommendation
1 syscall_method indirect, direct, none indirect direct none Enable indirect syscalls to bypass usermode hooks
2 sleep_mask enabled, disabled enabled -- disabled Encrypt beacon memory during sleep
3 heap_mask enabled, disabled enabled disabled -- Enable heap encryption for additional sleep protection
4 stack_mask enabled, disabled enabled disabled -- Enable stack encryption and spoofing
5 beacon_gate enabled (N APIs), disabled enabled -- disabled Route sensitive APIs through syscalls
6 module_stomp DLL name, disabled DLL configured disabled -- Use MEM_IMAGE backing via module stomping
7 ppid_spoof process name, disabled configured disabled -- Spoof child process parent PID
8 spawnto exe + pool info custom/pool -- rundll32.exe Change from default rundll32.exe
9 amsi_patched enabled, disabled enabled disabled -- Patch AMSI in fork-and-run processes
10 etw_patched enabled, disabled enabled disabled -- Patch ETW in fork-and-run processes
11 tls_fingerprint fingerprint name, default configured -- default Set uTLS fingerprint to avoid Go TLS detection
12 sleep_method timer_queue, direct timer_queue direct -- Use Ekko-style timer-based sleep
13 drip_load_inject enabled, disabled enabled disabled -- Allocate injection memory in small chunks
14 use_rwx disabled, enabled disabled (W^X) -- enabled (RWX) Disable RWX for W^X compliant allocations
15 udrl enabled, disabled enabled disabled -- Enable User-Defined Reflective Loader
16 edr_hooks none detected, N hooked none -- hooked Run edr_unhook before sensitive operations
17 hwbp_status N/4 DR slots, inactive active -- -- Enable HWBP for patchless AMSI/ETW bypass

Improving your score

Run opsec after initial check-in to identify gaps, then use the evasion commands to enable missing controls. A typical hardening sequence: syscall-method indirect then beacon_gate enable then sleep_config sleep_mask on then hwbp both on.


Decision Matrix: Technique Selection by Environment

Select evasion techniques based on the target environment's defensive posture. The matrix below maps each configurable setting to three environment profiles.

Technique Lab / No EDR Standard EDR EDR-Heavy / MDR
Syscall method none -- no evasion needed direct -- bypasses usermode hooks indirect -- ntdll trampoline, hardest to detect
Sleep masking Off -- fast iteration .text only -- basic memory protection .text + heap + stack -- comprehensive coverage
Sleep method direct -- reliable, debuggable direct -- stable for operations timer_queue -- avoids SleepEx monitoring
BeaconGate Disabled -- unnecessary overhead Enabled -- covers 25 critical APIs Enabled + mask_on_call -- encrypts memory per API call
PPID spoofing Disabled explorer.exe for user context Context-appropriate parent (svchost for SYSTEM, RuntimeBroker for user)
Module stomping Disabled xpsservices.dll -- MEM_IMAGE backing xpsservices.dll -- essential for memory scanning evasion
SpawnTo Default (rundll32.exe) RuntimeBroker.exe or dllhost.exe svchost.exe + argument spoofing + blockdlls
AMSI/ETW bypass Not needed Inline patch (amsi / etw commands) Hardware breakpoints (hwbp both on) -- no memory modification
Injection technique CreateRemoteThread -- simplest QueueUserAPC or NtMapViewOfSection Early Bird APC + module stomping + indirect syscalls
Fork-and-run process Any RuntimeBroker.exe with blockdlls Minimize fork-and-run; prefer BOF inline execution
C2 transport HTTP -- unencrypted, fast HTTPS with uTLS fingerprinting HTTPS + malleable profile + domain fronting
Garble obfuscation Off -- faster builds Full (-seed=random -literals -tiny) Full + Donut shellcode wrapping + C stager for initial access
TLS fingerprint Default Go TLS chrome_auto -- mimics Chrome chrome_auto -- essential to avoid Go TLS signatures
Drip-load injection Off -- unnecessary Enabled (10ms delay) Enabled (20ms+ delay) for cautious allocation
UseRWX Either -- no EDR watching Disabled (W^X: RW then RX) Disabled -- RWX pages are immediate red flags

Complete Evasion Profiles

Use these copy-paste profiles as starting points for each environment type.

Minimal configuration for fast iteration and testing.

sleep 5
syscall-method none

No evasion settings needed. Focus on functionality testing.

Moderate evasion for environments with CrowdStrike, SentinelOne, Defender for Endpoint, or similar.

sleep 60 25
syscall-method indirect
sleep_config sleep_mask on
sleep_config heap_mask on
beacon_gate enable
ppid explorer.exe
spawnto x64 %windir%\sysnative\RuntimeBroker.exe
blockdlls start
hwbp both on

Maximum evasion for heavily monitored environments with active SOC, memory scanning, and behavioral analytics.

sleep 300 40
syscall-method indirect
sleep_config sleep_mask on
sleep_config heap_mask on
sleep_config stack_spoof on
sleep_config stack_depth 0
sleep_config method timer_queue
beacon_gate enable
beacon_gate mask_on_call true
ppid explorer.exe
spawnto x64 %windir%\sysnative\dllhost.exe
blockdlls start
hwbp both on
argue net1.exe /enum /domain

Stability trade-off

Maximum evasion settings (stack masking, timer_queue sleep, mask-on-call) increase CPU overhead and may interact with the Go runtime in edge cases. Test thoroughly in a lab mirror of the target environment before deployment. Use opsec to verify the configuration is applied correctly.

Profile selection workflow

  1. Run reconnaissance to identify EDR products on target (use edr_query or manual enumeration)
  2. Select the appropriate profile from the matrix above
  3. Apply settings via the evasion commands after initial beacon check-in
  4. Run opsec to verify the configuration and check your posture score
  5. Adjust individual settings based on the posture report recommendations

Runtime Guardrails

Runtime guardrails enforce operational boundaries on beacon execution. Configure these at payload generation time to prevent beacons from running in unauthorized environments, after engagement deadlines, or outside operational windows.

Kill Date

The beacon checks the current date against the configured kill date on every poll cycle. After the kill date, the beacon executes CleanupArtifacts (removes scheduled tasks, registry keys, and self-deletes) then terminates.

kill_date: 2026-03-31

Always set a kill date

Every engagement payload should have a kill date. Forgotten beacons that check in after an engagement ends are a liability. Set the kill date to the engagement end date plus a buffer period (typically 7 days).

Working Hours

Restrict beacon activity to specific hours and days. Outside the configured window, the beacon calculates the time until the next working period and sleeps for that duration in a single obfuscated sleep call (not a rapid check-sleep loop).

working_hours: 08:00-18:00
working_days: Mon-Fri
timezone: America/New_York

Windows timezone mapping covers 16 common zones. The beacon resolves the Windows timezone name to UTC offset at startup.

Geofencing

Restrict execution to specific network environments. The beacon checks these constraints at startup and re-checks every 10 poll cycles.

Constraint Check Method Action on Mismatch
IP range Local adapter IPs vs CIDR list Exit + cleanup
Hostname os.Hostname() vs allowed list Exit + cleanup
Domain Backslash in username heuristic Exit + cleanup
Username Current user vs allowed list Exit + cleanup
{
  "geofence_ips": ["10.10.10.0/24", "192.168.1.0/24"],
  "geofence_hostnames": ["WS01", "WS02"],
  "geofence_domains": ["corp.local"],
  "geofence_usernames": ["labuser"]
}

DNS Canary Detection

Configure a DNS canary domain that the beacon resolves on startup. If the domain resolves (indicating the binary has been submitted to a sandbox that auto-resolves DNS), the beacon trips the canary endpoint and terminates.

dns_canary: canary.yourdomain.com

The canary trip endpoint is unauthenticated (accessible to the relay without a JWT token) so the beacon can report even before full C2 registration. The canary resolution uses net.Resolver (cross-platform, no build tags needed).

Pre-Task OPSEC Checks

When anti_analysis is enabled, the beacon runs environment checks before executing sensitive tasks:

  1. EDR detection -- 10 vendor process signatures (CrowdStrike, SentinelOne, Defender, Carbon Black, Cylance, ESET, Kaspersky, Sophos, Trend Micro, Symantec)
  2. Sandbox indicators -- Low CPU count, small RAM, recent OS install, known sandbox usernames
  3. Debugger detection -- IsDebuggerPresent, NtQueryInformationProcess(ProcessDebugPort)
  4. VM indicators -- Registry keys for VMware/VirtualBox/Hyper-V, known MAC prefixes

A 2+ indicator threshold is required to trigger (single indicator is ignored to reduce false positives). See Anti-Analysis for runtime configuration.

Cleanup on Exit

When a guardrail is tripped or kill date is reached, CleanupArtifacts performs:

  1. Removes 3 known scheduled task names used by persistence
  2. Cleans 3 registry key patterns used by persistence
  3. Self-deletes the beacon binary via a batch file (cmd /c del /q /f <path>)

Operational Recommendations

Pre-Engagement

Operational security starts before the first payload touches the target network.

Infrastructure Setup:

  • Domain categorization: Register domains 30+ days before engagement. Submit to categorization services (Bluecoat, McAfee, Palo Alto) for legitimate classification. Domains less than 7 days old are flagged by most web proxies.
  • TLS certificates: Use Let's Encrypt or purchase legitimate certificates. Self-signed certificates are flagged by SSL inspection appliances and generate browser warnings.
  • Redirectors: Place Apache/nginx redirectors between implant traffic and the teamserver. Configure redirect rules to filter analyst probing (user-agent, IP ranges, timing).
  • Malleable profiles: Use a malleable C2 profile that mimics legitimate traffic patterns (Microsoft 365, Slack, CDN). Test the profile against JA3/JA4 fingerprint databases.

Payload Testing:

  • Build with garble: Always use obfuscate: true for engagement payloads. Test detection rates against the target's AV/EDR in a mirrored environment.
  • Set guardrails: Configure IP, hostname, domain, or username guardrails to prevent execution on analyst sandboxes.
  • Set kill dates: Every engagement payload should have a kill date set to the engagement end date plus a buffer period.
  • Verify garble output: Run strings against the garbled binary to confirm no cleartext C2 URLs, error messages, or package paths remain.

Infrastructure checklist

Domain age > 30 days, valid TLS cert, redirector with filtering rules, malleable profile tested against JA3 databases, guardrails set, kill date configured. Missing any of these significantly increases detection risk during initial access.

Initial Access

The first payload execution is the highest-risk moment. An unknown binary running for the first time triggers the most aggressive scanning.

  • Use the C stager for Go-signature avoidance. The MinGW C stager (~23KB) has no Go runtime, no pclntab, no goroutines. It downloads and executes the full implant in memory. Use this when the initial dropper must not be identified as Go.
  • Select transport carefully. HTTPS with uTLS fingerprinting (chrome_auto) is the safest default. DNS C2 is useful for environments that block direct HTTPS but has lower bandwidth. SMB is for internal pivoting only (not initial access).
  • Use malleable profiles. A well-configured malleable profile makes C2 traffic appear as legitimate HTTPS to inspection appliances. Without it, default HTTP patterns are easily signatured.
  • Minimize initial footprint. Run opsec immediately after first check-in. Apply the appropriate evasion profile before executing any post-exploitation commands.

Post-Exploitation

Every command executed through the beacon generates artifacts. Minimize footprint by choosing execution methods carefully.

  • Prefer BOF over fork-and-run. Beacon Object Files execute inline in the beacon process -- no child process creation, no injection, no sacrificial process termination. Fork-and-run spawns a visible child process that EDR monitors.
  • Prefer inline-execute over execute-assembly. For .NET tools, inline execution avoids the CLR loading artifacts that process-level .NET profiling detects.
  • Manage sleep intervals. Interactive mode (sleep 0) generates continuous network traffic. Use sleep 5 for active operations and return to sleep 60+ when idle. Jitter prevents pattern detection.
  • Monitor event log generation. Every technique generates specific Windows events. Be aware of which events your current operation produces (see the detection surface tables above).

Fork-and-run is the loudest operation

Every fork-and-run operation creates a visible process chain: beacon spawns sacrificial process, injects code, captures output, terminates process. This generates Sysmon Events 1 (process create), 8 (CreateRemoteThread), 5 (process terminate), and potentially 10 (process access). Use BOFs or inline execution wherever possible.

Lateral Movement

Moving between systems generates authentication events that SOCs correlate across the environment.

  • Avoid repeating PtH to the same target. Pass-the-Hash to the same system from the same source generates a pattern that automated correlation detects. Vary source beacons and techniques.
  • Clean up services after PsExec. PsExec creates a service (Event 7045) that persists after execution. Delete the service immediately after use.
  • Be aware of timestamps. Lateral movement during off-hours (3:00 AM login from workstation) generates alerts. Match activity to expected business hours for the target account.
  • Prefer WMI or DCOM over PsExec. WMI execution and DCOM abuse generate fewer distinctive artifacts than service-based execution. WMI is especially good because WMI activity is common in enterprise environments.
  • Use token impersonation for legitimate context. Steal tokens from processes owned by users who would legitimately access the target system, then move laterally in that context.

Persistence and Long-Haul

Long-running operations require careful attention to beacon behavior patterns.

  • Sleep interval management. Long-haul beacons should use sleep intervals of 300+ seconds with 30-40% jitter. Low-and-slow check-in patterns are significantly harder to detect via network anomaly detection.
  • Transport rotation. If operating over multiple days, consider rotating between transports (HTTPS to DNS, or between different HTTPS endpoints) to avoid consistent pattern detection.
  • Beacon check-in patterns. Even with jitter, a beacon that checks in at perfectly regular intervals stands out. The combination of sleep + jitter creates natural variation, but be aware that extremely long engagements may show patterns in aggregate.
  • Persistence mechanism diversity. Do not rely on a single persistence mechanism. Use COM hijacking (stealthy, low detection) as primary and a scheduled task (reliable, high detection) as backup. Test persistence survival across reboots in the lab.
  • Credential refresh. Kerberos tickets and NTLM sessions expire. Plan for credential refresh intervals and have a procedure for re-obtaining access if persistence survives but cached credentials expire.

Cleanup

Engagement cleanup is an OPSEC obligation. Remove or document all artifacts left on target systems.

Event Log Awareness:

Each technique generates specific Windows events. Key events to be aware of:

Technique Events Generated Notes
Process injection Sysmon 1, 8, 10 CreateRemoteThread logged with source/target PIDs
Service creation Security 7045 Service name, binary path, account visible
Scheduled task Security 4698 Task XML definition logged
Registry modification Sysmon 12, 13, 14 Key path, old/new values logged
Authentication (lateral) Security 4624, 4625 Logon type, source IP, account name logged
Kerberos requests Security 4768, 4769 SPN, encryption type, ticket options logged
LSASS access Sysmon 10 Source process, granted access mask logged
PowerShell Event 4103, 4104 Full command-line and scriptblock logging

You cannot delete Security event logs without leaving a trace

Clearing the Security event log generates Event 1102 (Audit log was cleared). Selective deletion (evtdelete) still generates Event 1102/104 and leaves record ID gaps. The only way to avoid this is to not generate the event in the first place -- choose techniques with lower log footprints.

Artifact Removal:

  • Delete dropped files. Remove any executables, DLLs, or scripts placed on disk. Use timestomp to restore original timestamps on directories you accessed.
  • Remove persistence mechanisms. Delete registry keys, scheduled tasks, services, and COM hijack entries. Verify removal with a second check.
  • Clean up service artifacts. PsExec services, WMI subscriptions, and DCOM registrations should all be removed.
  • Use timestomp for file operations. The timestomp command (T1070.006) modifies file timestamps to match the surrounding files, reducing timeline analysis effectiveness. See file operations for details.
  • Document what cannot be removed. Some artifacts (event log entries, ETW traces, kernel-level audit records) cannot be removed post-execution. Document these in your engagement report so the client can reset baselines.

Context Menu Risk Indicators

The cockpit context menu displays a color-coded OPSEC risk dot next to every technique, giving operators an at-a-glance risk assessment before execution.

Color Risk Level What It Means
🟢 Low Passive enumeration, configuration reads, benign API calls. Generates minimal telemetry. Safe for initial reconnaissance.
🟡 Medium Active operations with moderate detection footprint. Fork-and-run, token manipulation, file operations, UAC bypass, LOLBins.
🔴 High Operations touching heavily monitored resources: LSASS, SAM, NTDS, process injection, credential dumping, PowerShell, destructive operations. Most EDRs flag these immediately.

Use risk indicators to plan your approach

Start an engagement with green (low-risk) enumeration techniques to map the environment before escalating to yellow and red techniques. This reduces the chance of early detection and gives you time to identify which defenses are active.

Risk levels are defined in the knowledge base YAML metadata (server/knowledge_base/techniques/) and served via the API -- they are not hardcoded in the UI and can be tuned per engagement.

See the Context Menu Guide for the full list of visual indicators including privilege badges and OS filtering.


Cross-References

  • Evasion Kits -- Build-time evasion options, custom kits (Artifact, Resource, UDRL, Sleep Mask), and the full evasion options reference table
  • Evasion Commands -- Runtime evasion command syntax, API examples, and recommended profiles for each command
  • Process Injection -- Injection technique details, supported methods, and per-technique OPSEC considerations
  • Credential Access -- Credential harvesting commands with OPSEC guidance per technique
  • Malleable Profiles -- Network-level OPSEC via traffic shaping, TLS fingerprint masking, and HTTP transformation