Skip to content

ENG-8829 fix(network-ops): run relay/coercion tools as streaming listeners, not 30s force-kills - #177

Merged
thomasqbrady merged 1 commit into
mainfrom
eng-8829-krbrelayx-relay-listener
Oct 15, 2026
Merged

thomasqbrady merged 1 commit into
mainfrom
eng-8829-krbrelayx-relay-listener

Conversation

@thomasqbrady

Copy link
Copy Markdown
Contributor

Summary

krbrelayx_relay, certipy's relay action, and the standalone impacket_ntlmrelayx are long-running listeners, but they ran under execute()'s short blocking timeout: at the deadline the process group was force-killed and the call reported as a timeout failure. A relay could never stay up long enough to catch a relayed/coerced authentication.

This ports the async stdout-reader pattern (already used by impacket_ntlmrelay_attack) into a shared helper and wires the three listener tools to it.

What changed

  • New tools/_relay.py — stream_listener() streams a listener's stdout and:
    • returns early on a tool-specific success line (plus a short drain for follow-up loot like a cert/hash);
    • on no match, tells apart still listening at the deadline (returns captured output — catching nothing is a result, not an error) from a self-exit (non-zero raises a RuntimeError; a clean exit returns a note). This restores the failure signal execute() used to give on a crash;
    • caps retained output (1 MB) so a verbose relay can't blow up memory/context;
    • redacts credentials (-p, -hashes, --aeskey) from the command it logs.
  • krbrelayx_relay, certipy relay, standalone impacket_ntlmrelayx now stream via the helper with a per-call relay_timeout.
  • Coercion triggers left unchanged (krbrelayx_printer_bug, petitpotam, etc.) — documented as one-shot triggers, not listeners (the ticket described printer_bug as a listener; it isn't).
  • Success patterns were verified against the real krbrelayx/certipy source; this caught and removed a krbrelayx pattern that also matched the FAILED auth line.
  • network-ops bumped to 2.1.10.

Testing

  • Unit tests for routing, the success drain, SIGKILL escalation, crash-vs-timeout signalling, credential redaction, output cap, and the krbrelayx failed-auth case.
  • A real-subprocess test that spawns a process, lets it block past the timeout, and asserts the listener returns a note and is terminated (verifies the actual timeout + process-group kill path, not just mocks).
  • just validate passes; the ! checks are environment binaries not installed in CI.

Known limitation

The live Windows coercion end-to-end (a real target coerced → authenticates back → listener catches it) isn't exercised here — it needs a Windows host (print spooler / EFSRPC), which the Linux sandbox can't be. The design bounds the downside: a missed/early pattern degrades to "returns the full captured output at the timeout," never a lost or mislabeled result. A minor trailer-wording dedup was split out as a follow-up (ENG-8882).

…t 30s force-kills (ENG-8829)

krbrelayx_relay, certipy's relay action, and the standalone impacket_ntlmrelayx
are long-running listeners, but ran under execute()'s short blocking timeout:
the process group was force-killed at the deadline and the call reported as a
timeout failure, so a relay could never stay up long enough to catch a
relayed/coerced authentication.

Add a shared _relay.py that streams a listener's stdout and:
- returns early on a tool-specific success line (patterns verified against the
  real krbrelayx/certipy source);
- on no match, distinguishes still-listening-at-timeout (returns the captured
  output — catching nothing is a result, not an error) from a self-exit
  (non-zero raises, a clean exit returns a note);
- caps retained output so a verbose relay can't blow up memory/context;
- redacts credentials from the command it logs.

Wire the three listener tools to it with a per-call relay_timeout. Leave the
one-shot coercion triggers (printerbug, petitpotam, etc.) unchanged, documented
as triggers rather than listeners. Bump network-ops to 2.1.9 and add tests,
including a real-subprocess timeout/kill test.

@mkultraWasHere mkultraWasHere left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@thomasqbrady
thomasqbrady merged commit 0634606 into main Oct 15, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants