How to configure out-of-band testing
Some vulnerabilities never tell you they worked. Blind SSRF, XXE, out-of-band SQL injection and blind XSS all produce the same response as a target that is not vulnerable at all. The only way to observe them is to make the target call a server you control, and then watch that server.
That server is the out-of-band (OAST) backend.
Why this is not simply “on”
Section titled “Why this is not simply “on””The out-of-band hostname is embedded in the payload. It is therefore your target (not the scanner) that makes the callback.
The template scanner’s own default is a set of public servers operated by its vendor. Left alone, that means a machine inside your network resolves and connects to a third-party host, disclosing that the machine exists, that it is reachable, and that it processes attacker-supplied input. A packet capture of the scanner would show none of it, because the scanner is not the thing making the call.
BattleTest never uses that default in any mode. The image overrides it. This page is about which backend you get instead.
The three modes
Section titled “The three modes”Set OAST_MODE in your deployment’s environment.
| Mode | Agent blind-vuln tools | Template-scanner OAST templates | DNS you must own |
|---|---|---|---|
catcher (default) |
Yes | No | Nothing, or one wildcard A record |
interactsh |
Yes | Yes | A whole domain, delegated |
off |
No: reported as unavailable | No | Nothing |
catcher: the default
Section titled “catcher: the default”The deployment ships a small, self-hosted callback catcher (oob-catcher). It is receive-only, has no egress of its own, and speaks a simple register-and-poll contract that BattleTest’s own agents use directly.
What it detects. Everything the agents probe for: blind SSRF, XXE, out-of-band SQL injection, blind XSS, DNS exfiltration (anywhere an agent constructs the payload itself).
What it does not. The template scanner (nuclei) does not speak this protocol and cannot be pointed at it. Its OAST template set stays excluded. Use self-hosted interactsh to enable nuclei OAST templates.
What it costs you. At most one DNS record:
- A single A record plus
OOB_PUBLIC_URLgives path-token correlation (https://oob.example.com/c/<id>). Enough for payloads that take a URL. - A wildcard A record (
*.oast.example.com→ the catcher) additionally catches payloads that take a bare hostname rather than a URL, which is the common shape for XXE and for DNS-only exfiltration. SetOOB_DOMAINto the wildcard’s base.
The address must be reachable by your targets. Check it from a host outside your network. An internal-only catcher observes nothing, and the run still looks clean.
interactsh: the full capability
Section titled “interactsh: the full capability”A self-hosted interactsh server, run by you. The template scanner is pointed at it with -iserver and -itoken, which restores its entire OAST template set.
Everything catcher does, plus the template scanner’s blind-vulnerability templates. It also captures SMTP and LDAP interactions, which the catcher does not.
off: no out-of-band testing
Section titled “off: no out-of-band testing”The template scanner runs with OAST disabled, and the agent’s out-of-band tools report themselves unavailable rather than returning an empty result that reads like a negative finding. The run emits a degradation notice naming the classes that went untested, and that notice is part of the signed export.
Choose this deliberately. Use it when your deployment cannot expose any callback surface.
What running interactsh actually requires
Section titled “What running interactsh actually requires”Concretely, four things:
1. A domain you can repoint. Not a subdomain: a registered domain whose nameserver records you can change at the registrar. In practice this is a domain bought for the purpose. Whatever else that domain was serving stops being served the moment you delegate it.
2. A host with a stable public IP, reachable from your targets on ports 53 (TCP and UDP), 80, 443, 25, 587 and 389.
3. Those ports free on that host. Port 80 and 443 rule out sharing with a reverse proxy; port 25 collides with BattleTest’s own test-mailbox catcher if you run one. In practice interactsh wants a machine of its own.
4. Ports that stay as they are. The port is implied by the payload the target receives (http://<id>.<domain> is port 80), so remapping on the host side breaks correlation silently, with no error to show for it.
Delegating the domain
Section titled “Delegating the domain”Create host (glue) records at your registrar
Add two hostnames on the domain, ns1 and ns2, both pointing at your server’s public IP address. Registrars call this “host records”, “glue records”, or “personal nameservers”; the wording varies, the operation does not.
Both may point at the same IP. Two records exist because most registrars require two nameservers.
Repoint the domain's nameservers
In the domain’s DNS settings, choose to use your own nameservers and enter ns1.YOUR-DOMAIN and ns2.YOUR-DOMAIN.
Delegation makes your interactsh server authoritative for the domain. DNS propagation can take up to 48 hours.
Configure the deployment
OAST_MODE=interactshOAST_INTERACTSH_DOMAIN=your-domain.exampleOAST_INTERACTSH_IP=203.0.113.10 # the server's PUBLIC IPOAST_INTERACTSH_TOKEN=<a long random string>OAST_INTERACTSH_URL=https://your-domain.exampleOAST_INTERACTSH_IP is not optional. Left unset, interactsh tries to discover its own address by fetching a public IP-echo service and by opening a socket toward one of its vendor’s hosts: two undeclared outbound calls at startup, and a hard exit when both fail. Worse, inside a container the address it would settle on is the container’s, so every DNS answer would point your targets at a private address and no callback would ever arrive.
OAST_INTERACTSH_TOKEN is not optional either. A server started without one accepts registration from anyone who finds it, which makes it an open relay running on your infrastructure under your domain. The service refuses to start without a token rather than defaulting to open.
Start it
docker compose -f docker-compose.prod.yml --profile interactsh up -d interactshThe service sits behind a compose profile so a deployment that has not done the delegation never starts a server that cannot work.
Verify a callback actually lands
From a host outside your network, not the deployment host:
dig +short test123.your-domain.example @ns1.your-domain.examplecurl -sv http://test123.your-domain.example/ 2>&1 | head -20The DNS query should resolve to your server’s public IP, and the HTTP request should reach it. If either fails, the delegation has not propagated or a firewall is in the way, and every blind-vulnerability result the deployment produces from here will be a false negative.
Air-gapped and internal-CA deployments
Section titled “Air-gapped and internal-CA deployments”interactsh obtains a TLS certificate through ACME by default, which reaches Let’s Encrypt. On a network that cannot, supply your own:
OAST_INTERACTSH_ARGS=-skip-acme -cert /tls/tls.crt -privkey /tls/tls.keyOAST_INTERACTSH_CERT_PATH=/etc/ssl/internal/oast-wildcard.crtOAST_INTERACTSH_KEY_PATH=/etc/ssl/internal/oast-wildcard.keyThe certificate must be a wildcard for the domain. Correlation hostnames are randomly generated subdomains, so a single-name certificate makes every HTTPS and SMTPS interaction fail its handshake, which looks identical to a target that never called back.
-skip-acme on its own, with no certificate supplied, disables TLS entirely. HTTP, DNS and SMTP interactions still work; HTTPS ones do not.
Storage is on disk (-disk) so a redeploy does not discard interactions a run is still polling for.
Network requirements
Section titled “Network requirements”Confirm these requirements before delegating the domain:
- The domain is single-purpose. Buy one for this. It serves no mail, no web presence, and nothing else depends on its DNS.
- Callback destination. Self-hosting keeps callback traffic on infrastructure you control.
- The server is receive-only. It answers DNS and accepts connections. It initiates nothing outbound once
OAST_INTERACTSH_IPis set. - Without delegation. The bundled catcher supports agent-driven tests. Nuclei OAST templates require interactsh. The report records which backend was used.
What a run tells you
Section titled “What a run tells you”If out-of-band testing is unavailable, the run emits a coverage notice before testing. The notice lists the vulnerability classes that will not be tested.
That notice is recorded inside the signed manifest content, so the caveat cannot be separated from the report it qualifies.