Class InteractshClient

Namespace
Kuestenlogik.Bowire.Oast
Assembly
Kuestenlogik.Bowire.Oast.dll

An IOastClient speaking the interactsh wire protocol, so --oast-server points at any compatible instance — Küstenlogik's, a self-hosted one, or a third party's. No third-party dependency: HttpClient plus BCL crypto only.

public sealed class InteractshClient : IOastClient, IAsyncDisposable
Inheritance
InteractshClient
Implements
Inherited Members

Remarks

The exchange, per the reference implementation:

  1. Generate an RSA keypair. POST /register with {PublicKey (base64 of the PEM), SecretKey (uuid), CorrelationID}.
  2. Plant <correlationId><nonce>.<domain> hosts in probes — 20 + 13 characters by default, the length the server slices on.
  3. GET /poll?id=&secret= returns aes_key (the AES key, RSA-OAEP/SHA-256 wrapped to our public key) and data (each item AES-CTR encrypted, IV = the first 16 bytes). extra / tld_data arrive as plaintext JSON.

The server never learns the AES key's plaintext from us and we never send the private key — the point of the RSA wrap is that a shared/hosted instance cannot read interactions belonging to other sessions.

Constructors

InteractshClient(string, string?, HttpMessageHandler?)

Create a client for the interaction server at serverUrl (e.g. https://oast.example.com). Pass token to authenticate against a gated instance (one started with bowire oast serve --token); it is sent verbatim as the Authorization header, matching the interactsh convention. Pass httpHandler to drive the exchange in tests without a live server.

public InteractshClient(string serverUrl, string? token = null, HttpMessageHandler? httpHandler = null)

Parameters

serverUrl string
token string
httpHandler HttpMessageHandler

Properties

ServerDomain

The interaction-server domain callbacks are addressed under (e.g. oast.example.com). Surfaced so findings can name where the evidence was collected.

public string ServerDomain { get; }

Property Value

string

Methods

Allocate()

Reserve a fresh callback host for one probe. Cheap + local after the session is registered — allocation does not round-trip per call.

public OastAllocation Allocate()

Returns

OastAllocation

DisposeAsync()

public ValueTask DisposeAsync()

Returns

ValueTask

PollAsync(CancellationToken)

Fetch the interactions the server has recorded for this session since the last poll. Returns only new ones; correlate them to a probe via FullId / UniqueId.

public Task<IReadOnlyList<OastInteraction>> PollAsync(CancellationToken ct = default)

Parameters

ct CancellationToken

Returns

Task<IReadOnlyList<OastInteraction>>

RegisterAsync(CancellationToken)

Register this session's public key with the server. Called once, lazily, by the first PollAsync(CancellationToken); exposed so a caller can fail fast (e.g. a bad --oast-server URL) before running a whole scan.

public Task RegisterAsync(CancellationToken ct = default)

Parameters

ct CancellationToken

Returns

Task