RelaySMB Server
The RelaySMB server is OctoPwn's NTLM relay variant aimed at SMB targets. It runs a set of front-end listeners (SMB, HTTP, HTTPS, HTTP-proxy by default), waits for an inbound NTLM authentication, and on success forwards the in-flight NTLM exchange into a fresh SMB connection against one of the configured targets. Every successful relay spawns a real interactive SMB2 client session in the project — already authenticated, already attached to the new target — and (by default) immediately runs registry and DPAPI secrets dumps against the relayed host.
| Inbound listener (front) | Outbound target (back) |
|---|---|
smb, http, https, httpproxy, mssql |
SMB on targets |
The listener side is shared with the rest of the relay family
(RELAYLDAP, RELAYMSSQL,
RELAYESC8, RELAYNTLMREFLECTION) — the only thing
that changes between variants is what gets done with the relayed authentication on the
back-end. The full description of the listener-side parameters lives at the bottom of this
page; the sibling pages link back here for the deep dive.
How it works
- Bring up one or more listeners (SMB / HTTP / HTTPS / HTTP-proxy / MSSQL) on the agent host.
- A victim authenticates to one of those listeners — typically because they were coerced (PrinterBug, MS-EFSRPC, WebDAV, etc.) or because their name resolution was poisoned by the Spoofer server.
- The incoming NTLM challenge / response is not validated locally; it is shuttled into
a fresh outbound SMB connection (
aiosmb.SMBConnection) opened against the next target intargets. Targets are walked round-robin (itertools.cycle). - On the outbound side OctoPwn forces
nosign=True, so the relay only succeeds against targets where SMB signing is not enforced. - The captured Net-NTLM hash is added to the project's Credentials Hub with
source = RELAYED, deduplicated against existing entries. - A
SHARE_ENUM_ALLis issued as a liveness check — if listing shares works, the relay is considered successful. - A new SMB2 client session is created with
description = RELAYED, attached to the relayed connection viasetup_relay(). This session behaves like any other interactive SMB client — you get a fully featured SMB console, file browser, registry dumper, etc. - Auto-loot (default ON for both):
regdumptriggersregdump2against the relayed host (SAM / LSA / DCC / cached secrets), anddpapisecretstriggersdpapisecretsremoteregdump(DPAPI master keys harvested through the remote registry path). If the relayed account is a local administrator on the target, you walk away with offline-crackable secrets without a single extra command.
SMB-to-SMB only works when signing is not enforced
NTLM relay against SMB has the same fundamental constraint as ntlmrelayx: if the target
SMB server enforces signing, the relayed session is dropped during negotiation and you
will see list_shares fail in the relay-server console. Run smbsig
against your target list first to filter out enforced hosts.
Cross-protocol relay is restricted
NTLMv2 with the MIC present (modern Windows clients without CVE-2019-1040) cannot
be cross-protocol-relayed: SMB-in → SMB-out works, HTTP-in → SMB-out works for many
HTTP coercion paths but fails when the client adds a target binding. If a relay is
silently rejected at the auth-handshake stage, enable debug on the server and watch
for ntlm_data warnings.
Operational requirements
The relay listeners run inside the OctoPwn agent, not in the browser. That means the agent host has to satisfy a handful of constraints, and most "the server starts but no authentication ever lands" tickets boil down to one of these.
1. Privileged ports
Out of the box the listeners use:
| Listener | Default port | Privileged? |
|---|---|---|
| SMB | 445/TCP |
Yes (port < 1024) |
| HTTP | 80/TCP |
Yes |
| HTTPS | 443/TCP |
Yes |
| HTTP-proxy | 8080/TCP |
No |
| MSSQL | 1433/TCP |
No |
To bind any of the privileged ports the agent must be running as root/Administrator, or
on Linux the Python interpreter must hold CAP_NET_BIND_SERVICE
(setcap cap_net_bind_service=+ep <python-interpreter>).
You can move them to high ports with smbserverport / httpserverport / httpsserverport
(see "Listener-side parameters" below) — but moving the SMB port off 445 only works for
coercion paths that let you specify an explicit port (e.g. WebDAV via
\\host@8080\share\...). PrinterBug and similar protocols always come back to 445.
2. Conflicts with native services
Whichever ports the host already has bound, the relay cannot also bind:
- Windows: the Server service owns
445. Disabling it is intrusive and not always reversible without a reboot. In practice, the SMB listener is impractical on a Windows agent — use a Linux agent for relay work. - Linux: Samba's
smbdif installed;apache/nginx/lighttpdif a web server is running. Stop them before starting the relay. - macOS:
smbd(/usr/sbin/smbd), Apple's web stack, etc. Generally a poor agent host for relays.
When a listener fails to bind, the rest still come up — the relay session does not abort.
Watch the server console output at startup for ... server failed to start! Reason: ....
3. WASM / browser-only deployments
A pure-browser deployment with no native bridge cannot host these listeners — sockets are
not available. In WASM mode, the agent (wsnet) is doing the binding on its own host; the
project just steers it through the wsnet proxy. When platform.system() == 'Emscripten'
and connectproxy is unset, OctoPwn auto-fills it with proxy 0 so the outbound SMB
connection on the back-end also goes through the same agent.
4. The agent IP must be reachable from the victims
Whatever address the victims use to reach the relay (the IP they were coerced or poisoned
to) must be reachable on the right port. If you're behind NAT or a wsnet proxy, set
serverproxy / connectproxy to route both halves of the connection through the right
agent.
Relay-specific parameters
These are the parameters unique to RELAYSMB. The full list of the shared
listener-side parameters (servertypes, serverip, *serverport, serverproxy,
debug, ntlmallowguest, ntlmreflection) is at the bottom of this page.
Normal parameters
targets
Comma-separated list of SMB targets to relay to. Hostnames or IP addresses. Required. The list is walked round-robin: each new inbound auth is sent to the next entry.
regdump
Default: True. After a successful relay, automatically run regdump2 against the
relayed host. This dumps SAM, LSA, cached domain credentials and the machine account
secrets via the remote registry — same as
secretsdump.py -just-dc-user '*' <host> would on Linux, but using the relayed session
instead of a credential.
Set this to False if you only want the relayed shell and want to dump manually later
(e.g. you are worried about EDR noise or want the connection idle for further use).
dpapisecrets
Default: True. After a successful relay, automatically run
dpapisecretsremoteregdump against the relayed host — extract DPAPI master keys via the
remote registry path. Combined with regdump, this is what gives you offline-crackable
DPAPI loot from a single relayed admin auth.
Advanced parameters
connectproxy
Proxy ID to use for the outbound SMB connection to targets. This is independent of
serverproxy (which is the listener-side proxy). On WASM this is auto-set to 0 if
unset, so the outbound traffic also goes through the wsnet agent.
Listener-side parameters (shared)
Every relay variant shares this set of listener parameters. They configure what the agent listens on, not what it relays to.
Normal parameters
servertypes
List of front-end listeners to start. Default: smb,http,https,httpproxy. Valid entries:
| Value | Listener | Default port |
|---|---|---|
smb |
NTLM-relaying SMB server | 445/TCP |
http |
NTLM-relaying HTTP server | 80/TCP |
https |
NTLM-relaying HTTPS server (snake-oil cert) | 443/TCP |
httpproxy |
NTLM-relaying HTTP proxy | 8080/TCP |
mssql |
NTLM-relaying TDS server | 1433/TCP |
For SMB targeting, smb is essential and http / https are useful (PrinterBug,
WebDAV-coercion, browser-pop pop-ups, AutoDiscover, etc.). httpproxy matters if you
plan to advertise the agent via WPAD; mssql is irrelevant here and can be turned off
to avoid the port conflict if SQL Server runs on the agent host.
serverip
IP address to bind the listeners to. Default 0.0.0.0 (all interfaces). Set this to the
agent's actual interface IP if you have multiple NICs and want to avoid binding on the
wrong one.
Advanced parameters
smbserverport / httpserverport / httpsserverport / httpproxyserverport / mssqlserverport
Listening ports for each front-end protocol. Defaults: 445, 80, 443, 8080, 1433.
Useful when the standard port is already taken, or when you intentionally want to use a
high port from a coercion path that supports it (e.g. \\host@8080\... for WebDAV).
serverproxy
Proxy ID for the listener side. Tells the wsnet agent where to expose the listening
sockets — typically the same agent that the project is connected through. On WASM this
is auto-set to 0 if unset.
ntlmallowguest
Default: True. Allow inbound clients that authenticate as Guest. Most Windows hosts
silently fall back to Guest when the supplied credential is wrong; relaying a Guest
session is rarely useful but the credential is stored for visibility. Set to False
to hard-drop those.
ntlmreflection
Default: False. Allow the NTLM relay engine to accept relays where the auth target is
the same machine that initiated the connection (NTLM reflection). This is what
RELAYNTLMREFLECTION enables under the hood; on RELAYSMB, leaving it False matches
the historical safe default.
debug
Default: False. Enable verbose tracebacks and per-connection logging on the server
console. Indispensable when relays are silently rejected — turn this on first before
opening a support thread.
Commands
The standard ScannerConsoleBase commands apply (setparam, getparam, params,
info, serve, stop, historylist, …). The relay-specific entry point is:
serve
Start the listeners with the configured parameters. Equivalent to clicking Start on
the session window. Internally calls do_serve and creates one asyncio task per
listener plus one task that drains the auth-relay queue and calls handle_smb_relay
for each captured authentication.
stop
Stop all listener tasks and the relay-handler task. The interactive client sessions spawned by previous successful relays are not closed — they remain available in the project as normal SMB2 sessions you can keep using.
Typical workflow
- Pick the agent host carefully. Linux, ports
80/443/445/8080free, and same VLAN as your victims (or directly reachable from the coercion source). - Filter the target list. Run
smbsigagainst your intendedtargetsand keep only the hosts where signing is not enforced. - Start
RELAYSMBwithtargets=<filtered list>. Leaveregdump=Trueanddpapisecrets=Trueif you want auto-loot; set them toFalseif you want quiet relays for follow-up commands. - Drive authentication into the listener. Three common ways:
- Run
Spooferin spoof mode in a separate session — LLMNR / mDNS / NBT-NS poisoning will steer mistyped names to the agent. - Coerce a specific target with
coercefrom an SMB client session (PrinterBug, MS-EFSRPC, MS-DFSNM, …). - Coerce via a malicious file path (
\\agent\share\file.lnkin an emailed document, animgelement pointing at the agent, etc.). - Watch the relay console. A successful relay prints
SMB relay worked!and a new session ID. Switch to that session — you have a live SMB2 client on the relayed host. - Iterate. Adjust
targetsor restart with new ones; previous interactive sessions stay open.
Limitations & gotchas
- Signing-enforced targets are silently rejected. The first sign is
list_sharesfailing indebugmode. Pre-filter withsmbsig. - NTLMv2 + MIC + channel binding on modern, patched clients defeats most cross-protocol paths. SMB-in → SMB-out is fine; HTTP-in → SMB-out is fragile.
nosign=Trueis hard-coded on the outbound side. There is no way to negotiate signing on the relayed connection — the assumption is "signing is off".- Guest auth is allowed by default and floods the credential database with
Guest::DOMAIN:...:fullhash. Setntlmallowguest=Falsefor a tidier project. - The auto-loot pair (
regdump+dpapisecrets) is loud — full registry hive parsing and DPAPI master key extraction are visible to any half-decent EDR. Disable both for stealthier engagements. - Targets are walked round-robin. A single victim authentication relays to one target, not all of them. To hit every target you need either many victim authentications or a poisoning loop that keeps generating them.
- Listeners that fail to bind do not abort the session. Always re-read the server console at startup to confirm which listeners actually came up.