Squatter Payload Provider
Squatter is Hovel's first core payload provider. It is a lab and
demonstration payload system for authorized environments. The provider is a
normal Hovel payload_provider module that speaks JSON-RPC over
stdio; the Windows payload binary is opaque payload code produced by that
provider. The current provider metadata reports Windows x86 with a Windows 7
compatibility floor. The Windows C payload keeps XP SP3 as a low-level lab
support floor in its headers, but Hovel should not claim XP compatibility
until provider metadata and tests do.
Hovel must not learn Squatter's implant wire protocol, command grammar, PE internals, or Windows API strategy. Hovel learns step contracts, payload identity, compatibility, lifecycle requirements, artifacts, transport endpoints, payload instances, cleanup handles, and session refs from the provider over RPC. Hovel controls planning, confirmation, artifact recording, capability validation, and session brokering; the provider owns Squatter's transport and wire semantics.
Settled Decisions
- Squatter is a payload capability, not a native Hovel execution path.
- The Squatter provider is a first-class
payload_providermodule with explicit chain steps. - The provider reports step contracts, configuration schema, prepare materialization, cleanup contracts, and output capabilities through JSON-RPC.
- Hovel discovers payload formats, transports, compatibility, and session strategy from live provider contracts, not static payload YAML.
- Final payload bytes are generated during execution after confirmation, then recorded as artifacts with hashes.
- Hovel materializes provider bytes to controlled workspace artifact paths and passes typed payload artifacts to installer steps.
- Payload generation and materialization are per target and per transport.
- A provider may return multiple artifacts for one target, but one artifact must be marked primary.
- Installed Squatter agents are tracked as durable Hovel installed payload records, separate from generated artifacts and live sessions.
- Squatter returns provider-owned reconnect and cleanup descriptors; Hovel validates and persists the installed payload record in SQLite.
- Exploit modules do not receive Squatter protocol details. They produce execution capabilities that Squatter install steps consume.
- Provider compatibility is checked from contracts and metadata where the current planning path exposes them; actual bytes are generated after confirmation.
- The provider is tagged
dangerousbecause Squatter supports file transfer, process execution, DLL loading, task listing, and sessions. - The provider offers an opt-in PKI-backed
squatter+tlsMesh stream. Hovel stamps the identity into the generated PE, Mesh carries ciphertext unchanged, and statically linked wolfSSL terminates TLS 1.3 inside the Windows payload.
Repository Shape
modules/
squatter/
README.md
BUILD.bazel
provider/
main.go
lp.go
mesh.go
stamp.go
generate_main.go
client/
cmd/
squatterctl/
smbadminctl/
shell/
smbpipe/
wire/
xfer/
tests/
windows/
BUILD.bazel
pe_inspect_test.py
source_contract_test.py
src/
squatter.c
base/
iocpserver/
modules/
nocrt/
runtime/
security/
sqlog/
wire/
The provider is written in Go using Hovel's Go SDK. The Windows payload is C
code built with a pinned MinGW cross toolchain. The current payload includes
the mux runtime, TCP bind, reverse TCP, SMB named-pipe support, interactive
shell transport, one-shot cmd.exe execution, typed Windows
collection commands, process control, file transfer, payload status, and
auditable self-cleanup. PE and source-contract tests protect the
no-import-table payload shape and the expected source layout.
Module Contract
A payload provider participates in the common module lifecycle and exposes
chain-step contracts through the generic step RPC methods:
step.describe, step.prepare,
step.execute, and step.cleanup. The provider dispatches
internally by step_id. Hovel never calls Squatter-specific private
methods for orchestration.
squatter.generate
squatter.install_smb
squatter.connect_smb
squatter.connect_tcp_bind
squatter.listen_tcp_callback
squatter.connect_tcp_callback
Only connector steps produce SessionRef. Listener steps keep
provider-owned live state for the chain run. Generate and install steps may
produce PayloadArtifact,
PayloadInstance, TransportEndpoint,
CleanupHandle, and explicit installed-payload descriptors, but they
do not open operator sessions.
Provider Configuration
Common options should use payload.* keys. Squatter-specific options
may use squatter.* keys when they are not portable across payload
providers.
payload.provider = squatter
payload.format = pe-exe
payload.transport = smb-named-pipe | tcp-bind | tcp-callback
payload.lhost = 10.10.14.3
payload.lport = 4444
payload.bind_port = 9100
payload.pipe = random-neutral
squatter.agent.max_chunk_size = 65536
payload.transport is required. The first Squatter provider supports
smb-named-pipe, tcp-bind, and
tcp-callback. SMB named-pipe mode requires an SMB
CredentialCapability and can be installed by the provider. TCP bind
mode requires an explicit installed-payload record or capability for a target
endpoint. TCP callback mode requires a listener step plus an explicit
installed-payload record or capability. If the agent has not connected back, the
installed payload remains installed with provider-owned callback
status in its reconnect metadata until a refresh or connection attempt proves it
unreachable.
Payload Metadata
Payload metadata is returned by the provider over RPC. Hovel uses it for planning, review, compatibility checks, artifact recording, and session orchestration.
{
"id": "squatter/windows/x86/windows-7/smb-named-pipe/pe-exe",
"name": "squatter",
"version": "0.1.0",
"kind": "pe",
"platform": "windows",
"os": "windows",
"arch": "x86",
"minOS": "windows-7",
"testedOS": ["windows-7"],
"formats": ["pe-exe", "pe"],
"tags": ["pe", "windows", "agent", "squatter"],
"capabilities": [
"host.info",
"file.get",
"file.put",
"file.stat",
"file.hash",
"registry.query",
"eventlog.query",
"drive.list",
"share.list",
"acl.stat",
"process.exec",
"process.exec.as_user",
"process.run",
"process.list",
"process.tasklist",
"process.kill",
"payload.status",
"payload.cleanup"
],
"transport": {
"kind": "smb-named-pipe",
"encrypted": false
},
"session": {
"kind": "agent",
"acquisition": "active-connect",
"requiresPreThrowListener": false,
"requiresPostThrowConnect": true,
"owner": "payload_provider"
}
}
DLL output is no longer advertised by the current provider command surface. DLL/rundll support would add export and loader semantics and should follow only after the PE EXE orchestration and typed command surface stay stable.
Transports
SMB named-pipe, TCP bind, and TCP callback comms are all required Squatter functionality. They differ in chain requirements and reconnect strategy, but the Squatter provider owns the actual LP-to-payload protocol in all modes.
SMB named-pipe mode uses credential-backed active connection:
- squatter.generate
- squatter.install_smb
- squatter.connect_smb
- provider-owned Hovel session
TCP bind mode uses target-side listening:
- squatter.generate
- explicit or external TCP-bind install record
- squatter.connect_tcp_bind
- provider-owned Hovel session
TCP callback mode uses a confirmed listener step:
- squatter.listen_tcp_callback
- squatter.generate
- explicit or external TCP-callback install record
- payload callback
- squatter.connect_tcp_callback
- provider-owned Hovel session
SMB mode uses a Windows named pipe exposed through SMB. The provider connects
to \\target\pipe\name using an explicit
CredentialCapability and exposes the resulting Squatter agent
session through Hovel's session abstraction. The exploit module does not own or
proxy that session.
The operator-side connector uses github.com/jfjallid/go-smb to
authenticate to IPC$, open the configured pipe, and run the same
Squatter mux protocol used by TCP transports over the resulting pipe handle.
The required configuration keys are target.host or
smb.host, payload.pipe, smb.username,
smb.password, optional smb.domain, and optional
smb.port.
The first SMB connector is SMB2/3 only because it is backed by
github.com/jfjallid/go-smb. Windows XP targets that only expose
SMBv1 should use tcp-bind or tcp-callback for the
representative MS17-010 chain unless a separate SMBv1 pipe connector is added.
TCP bind generation patches the payload to listen on
payload.bind_port on the target. The provider connects to
target.host:payload.bind_port after installation and emits an
active SessionRef when the TCP connection opens. TCP callback
generation patches the payload with payload.lhost and
payload.lport, starts a provider listener, and adopts the accepted
connection as the Squatter session. TCP install is intentionally record-driven
until the provider has a real remote-execution installer for those transports.
Mesh and PKI-Backed TLS
Squatter also implements Hovel's destination-scoped Mesh contract. The
provider reports one root node plus one stable child node for every surveyed
or dialed host/port, a read-only destination survey task, and two stream
protocols: squatter for a raw TCP-bind flow and
squatter+tls for a TLS 1.3 flow. Both become ordinary Hovel
SessionRef values, so the daemon's Mesh bridge can expose them
without learning the Squatter frame grammar.
Every endpoint node has a direct provider link and optional route. Routed stream creation validates the route shape and terminal node, then rejects any conflicting node id, destination host, or destination port. This keeps multiple live Squatter endpoints independently addressable and prevents a caller from using valid topology metadata to redirect a stream elsewhere.
Payload TLS is backed by the provider's strict
payload-tls-server standard stamp slot. That slot accepts only a
hovel.pki.bundle/v1 projection with private-key bytes,
the tls-server purpose and profile, the
payload consumer type, and the
portable-x509 compatibility target. Hovel resolves the selected
assignment into one private bundle containing the leaf, private key, chain,
trust anchors, validity, fingerprints, and key-establishment policy. The
provider rejects unknown fields and verifies certificate/key consistency,
ordered chain termination, EKU, validity, freshness, bundled CRLs, and exact
named-group policy before writing a versioned SQPKI001 manifest
into a configured TCP-bind PE.
The current payload requires the complete ordered portable classical set:
x25519, secp256r1, secp384r1, and
secp521r1. Subsets, reordered preferences, and other policies are
rejected rather than silently diverging from the compiled wolfSSL profile.
SHA-256 bindings cover both the canonical
bundle and the complete runtime manifest. Callback and named-pipe artifacts
are rejected by this stamp slot until their TLS roles have an end-to-end
implementation.
- TLS Mesh client
- Hovel Session carrying TLS ciphertext
- provider and Mesh byte pass-through
- payload wolfSSL terminates TLS 1.3
- Squatter frame mux
The certificate and PKCS#8 key are payload-owned: they are stamped into the PE rather than retained as provider runtime state or installed in a Windows certificate store. The no-CRT payload validates all lengths, counts, and digests before initializing statically linked wolfSSL. An unstamped payload retains plaintext TCP behavior, while a present but malformed or modified stamp fails startup closed and never falls back to plaintext. Named pipes remain protected at their existing SMB transport boundary. TCP accepts create a session immediately, while its TLS handshake runs on the session reader thread with bounded socket I/O, so a silent peer cannot monopolize the listener.
The pinned wolfSSL 5.9.2 profile uses the Windows NT 4.0 API surface and does not depend on Schannel, Secur32, Crypt32, CNG, or the Windows certificate store. This prevents TLS from raising Squatter's legacy API floor, although the complete provider continues to report Windows 7 until older releases are exercised in the automated matrix. Static wolfSSL distribution is subject to wolfSSL's GPLv3 or commercial licensing terms.
Prepared Target Footprint
Prepare is pure/local. It generates planned target-side identifiers, but it
does not build the final executable, contact the target, stage files, or start
services. The target review flow lets the operator edit prepared values before
confirmation and makes them immutable afterward; the current runtime can call
step.prepare, but generic pre-confirm editing and persistence are
still pending.
credential username: random neutral string
credential password: random high-entropy string
service name: random neutral string
service display: random neutral or configured string
staged filename: random neutral .exe by default
pipe name: random neutral string
collision strategy: fail after confirmation
Target-side names must not include Hovel, Squatter, run ids, or other tool-identifying strings. Evidence stores the complete mapping plainly, including plaintext created credentials, so the operator can remediate even if automated cleanup fails.
Session Ownership
Squatter sessions are provider-managed and Hovel-brokered. A live install is a
durable installed payload record; a session is an attachable view over that
target-side instance. Hovel sees a SessionRef with kind, transport,
state, installed payload id, and capabilities. The provider owns framing, task
IDs, file chunking, command/result mapping, retries, and transport details.
session kind agent
session owner payload_provider
transport squatter/smb-named-pipe, squatter/tcp-bind, or squatter/tcp-callback
capabilities host.info, file.get, file.put, file.stat, registry.query,
eventlog.query, process.exec, process.list, payload.cleanup
The provider may present a shell-like operator experience through Hovel's
session API, but the LP-to-payload protocol should be typed and robust. Hovel
should not treat a Squatter session as a raw cmd.exe terminal.
Operators can discover typed session actions with session commands
or session capabilities, then call them with
session call without touching the interactive byte stream.
Operators may detach from a live Squatter session and reconnect later when the
transport supports it. SMB named-pipe and TCP bind reconnect with an
active-connect strategy. TCP callback sessions attach to an accepted listener
connection; if no callback is present, the installed payload remains
installed or unreachable according to the provider's
explicit observation.
Installed Payload Tracking
Squatter install steps return an explicit installed-payload descriptor when the
target-side agent is staged and started. Hovel persists that descriptor as
workspace inventory with a short handle such as p1. The record
stores normalized fields for listing and filtering, plus Squatter-owned
reconnect and cleanup JSON with schema names and versions.
{
"provider": "squatter",
"payloadId": "squatter/windows/x86/xp-sp3/tcp-bind/pe-exe",
"payloadVersion": "0.1.0",
"target": "10.0.0.42",
"targetId": "t1",
"instanceKey": "stamp-or-agent-id-when-known",
"transport": "tcp-bind",
"endpoint": "10.0.0.42:9101",
"state": "installed",
"supportsReconnect": true,
"supportsMultipleSessions": false,
"reconnect": {
"providerId": "squatter",
"schema": "squatter.reconnect.tcp_bind",
"schemaVersion": "1",
"descriptor": { "host": "10.0.0.42", "port": 9101 }
}
}
payloads connect p1 passes the stored reconnect descriptor back to
Squatter through the provider connect_session operation. On success,
Hovel creates a normal session visible in session list and links it
to the installed payload. On failure, Hovel records the exact provider error and
marks the installed payload unreachable; it does not delete the
record.
payloads commands p1 and its payloads capabilities p1
alias ask the provider for the installed payload's typed action catalog.
payloads call p1 <command> invokes one provider-owned action
without opening an interactive session. The convenience commands
payloads getfile, payloads putfile, and
payloads cmd are compatibility shims over the same provider call
path. Command results can produce artifacts; Hovel materializes those artifacts
into the workspace and prints the artifact id and path instead of binary bytes.
payloads register-squatter <target> --host <host> --port <port>
is a development and lab helper for manually started TCP-bind Squatter
instances. It creates a normal installed-payload record with a provider-owned
reconnect descriptor, so the same payloads connect,
payloads commands, and payloads call paths can operate
it.
Squatter may support more than one reconnect endpoint for a deployed agent later. The v1 descriptor may contain one endpoint, but the storage and provider JSON should allow endpoint lists without changing the core installed-payload table.
Throw Planning
The target throw plan hash covers operator intent, the live step contract snapshot, and deterministic configuration: selected provider steps, selected transport, provider config, prepared target-side names, expected format, expected platform, compatibility facts, and whether listener or connector steps are required. The current source records reviewed intent, target IDs, module or step references, and configuration; full contract snapshots and prepared-value hashing remain pending.
The plan hash should not include final generated payload bytes, runtime session IDs, or observed connection handles. Those values are produced after confirmation and recorded as events and artifacts. Post-confirmation contract drift blocking is part of the target safety model and is not implemented yet.
Chain validation must enforce declared requirements. Validation should fail when a Squatter install step lacks a compatible payload artifact, when SMB mode lacks an SMB credential capability, or when a connector step lacks an installed payload instance and endpoint in an allowed state.
Throw Execution
Squatter steps produce capabilities, artifacts, evidence, and state transitions. Generation failures, listener bind failures, install failures, and connection failures are reported at the responsible step with exact evidence.
- for each target, query live step contracts
- prepare local names and transport config
- confirm snapshot
- generate final per-target payload artifacts
- materialize artifacts in workspace
- install payload with declared capabilities
- connect or listen for session when required
- keep provider alive while it owns active sessions
- cleanup target and provider-side state from cleanup handles
Hovel records generated payloads in the normal artifact list. Operators should see metadata such as name, kind, provider module, target, throw, SHA-256, size, and controlled workspace path. Hovel should not render binary bytes in ordinary terminal output.
If install succeeds but session connection fails, Squatter returns the
installed-payload descriptor plus a warning evidence record. Hovel persists the
installed payload and marks it unreachable. The CLI must print the
exact target, staged path, service name, pipe or port, plaintext SMB credential
when one was created, connection endpoint, exact error, active cleanup handles,
and the reconnect and cleanup commands.
Build Contract
Squatter now lives in the modules/ slice, outside the core
Hovel framework workspace. Use task modules:ci for the hermetic
module gate, task modules:wine-test for the host Wine boundary,
task modules:wine-docker-test for both real PE functional runs,
task modules:squatter:coverage for the 90% aggregate Go ratchet,
and task release:modules-package for installable archives. Keep
Squatter labels and host dependencies behind those Task contracts rather than
calling Bazel or Wine directly.
The Windows payload uses repo-local Bazel rules over a pinned MinGW archive:
url = "https://github.com/vibepwners/windows-toolchains/releases/download/v0.0.1/mingw-w64-gcc-15.2.0-ucrt-posix-dw2-i686-w64-mingw32-linux-x86_64.tar.xz"
sha256 = "<recorded checksum>"
The helper stays intentionally narrow so Squatter can build PE payloads without turning the repository into a general Windows C/C++ toolchain abstraction.
cc_binary(
name = "squatter.exe",
srcs = ["squatter.c"],
linkopts = [
"-nostdlib",
"-Wl,-e,_sq_nocrt_entry",
"-Wl,--subsystem,console",
],
)
windows_multiplatform(
name = "squatter_all",
binary = ":squatter.exe",
)
Defaults should encode the intended no-CRT/no-import posture:
-ffreestanding
-fno-stack-protector
-fno-asynchronous-unwind-tables
-nostdlib
-nodefaultlibs
-Wl,--entry,<entry>
PE inspection verifies the produced payload is i386, has the expected subsystem and entry point, embeds Hovel/Squatter markers, and has no unexpected import table or CRT dependency.
Windows Payload Contract
The Windows payload is not cross-platform code. The current payload is i386,
uses a no-CRT entry path, resolves Win32 APIs through the PEB, and keeps
Windows-specific headers centralized under base/win.h. The
provider reports conservative compatibility until broader Windows versions are
tested.
Provider-reported Squatter capabilities:
- Collect native host facts.
- Download, upload, stat, and hash files.
- Query registry values, recent event log records, logical drives, local shares, and file ACLs.
- Run processes, launch through an interactive user token when available, list processes, and kill processes by PID.
- Report payload status and request auditable payload cleanup.
The concrete provider-owned commands currently exposed through Hovel are:
wininfo
process.list
process.run
process.run_as_user
process.kill
payload.status
payload.cleanup
file.stat
registry.query
eventlog.query
drive.list
share.list
acl.stat
getfile
putfile
cmd
Safe collection commands are marked read-only in the provider catalog.
Process execution, process termination, file upload, and payload cleanup are
marked destructive. The payload also includes an echo module for
mux and functional tests, but that test module is not an operator command.
Current Implementation Status
The current source-backed Squatter path includes:
- Core capability schema names for
RemoteExecutionCapability,CredentialCapability,PayloadArtifact,PayloadInstance,TransportEndpoint,SessionRef, andCleanupHandle. - Generic step JSON-RPC dispatch through
step.describe,step.prepare,step.execute, andstep.cleanup. - Live contract planning that resolves enabled module steps to capability bindings or typed missing requirements. Full contract snapshot persistence and post-confirmation drift blocking remain future safety work.
- SMB install preparation for neutral service names, staged filenames, pipe names, endpoint config, and planned cleanup handles. Credential creation remains a separate module step.
- SMB named-pipe connect through explicit credentials, TCP bind connect, and TCP callback listener/connect paths that can emit
SessionRefcapability records. - Durable installed payload inventory with short handles, provider-owned reconnect descriptors, provider-owned cleanup descriptors, and Hovel-owned persistence.
- Provider-owned payload command surfaces for host facts, process list/run/kill, file get/put/stat/hash, registry query, event log query, drive/share listing, ACL stat, payload status, payload cleanup, and
cmd.exeexecution. - CLI and MCP typed command discovery and invocation through
payloads commands/payloads call,session commands/session call,hovel_payload_capabilities/hovel_payload_call, andhovel_session_capabilities/hovel_session_call. - Human-readable command tables with safe/write/destructive effect labels and pretty-printed JSON command output.
The Squatter path still avoids:
- MS17-010-specific Squatter protocol handling.
- Hidden helper-step insertion by the planner.
- Target-visible Hovel or Squatter ownership markers.
- Command-only Squatter staging as a fallback for the representative SMB chain.
- Silent credential redaction in normal operator CLI output.
The representative MS17-010 chain should require an upload-capable remote execution
path for SMB install. If the MS17-010 exploit cannot honestly produce an
upload_file sub-capability, Squatter SMB install must not pretend
it can use the MS17-010 exploit for staging. A separate command-only installer variant may be
designed later if it becomes operationally necessary.