Skip to content

Format reference

The .txt grammar for the implemented protocols on one page: every line, every field, every assert. Written to be read by a language model.

This page is the complete grammar for the protocols the runtime implements today. It is written so a language model can produce a correct file from this page alone. Nothing else is needed for the implemented set; the vocabulary is open and grows toward every protocol in the Identity list.

The file

  • A solution is a text file with a .txt extension.
  • Lines starting with # are comments and are ignored.
  • Blank lines separate sections. Two-space indentation marks a block.
  • A value is the rest of the line after name: ; surrounding quotes are stripped. Quotes are optional, and are only needed when a value contains # or leading or trailing spaces.
  • Field names are lowercase with underscores. There is no other syntax.

The header

Lines before the first step:

linemeaning
id: <name>required, names the attack, in vendor/product style
summary: <text>optional, one sentence about the attack
ref: <ref>optional, repeat the line for more, for example CVE-2014-0160
param: <name>optional, the HTTP input parameter name
vars:optional block, one name: value per line, starting values
oob:optional block, host: and port: lines; port: 0 picks a free one

The names flag_path, oob_host, and oob_port are reserved and cannot be declared.

A step

A step is a block. The first line is <identity> <step-name>. Indented lines below it are fields.

<identity> <step-name>
  <field>: <value>
  assert: <type> "<expect>"

The identity and the step name are always required. Step names are unique within the file.

Identity

The runtime implements eighteen protocols today, the ones that appear most often in real exploits. Use only these to produce a valid file; the vocabulary is open and grows toward every protocol in the Identity list:

identityrequired fieldsother fields
http, httpsencodingpayload, path, headers, capture
websocketsendrecv, recv_until, timeout, close, capture
tcp, tls, ssh, ftp, smtp, ldap, redis, mysql, postgresql, smb, telnetsendrecv, recv_until, timeout, close, capture
dns, snmpsendrecv, recv_until, timeout, close, capture
processcommandcwd
fileop, pathdata

http, https

encoding is one of query, form, json, raw-json, plain. payload is the value to send. path appends to the target URL. headers is a block, one name: value per line. The target is a base URL; https is the same exchange over TLS, and the http identity also covers both schemes.

The response an assert or capture sees is the full exchange: the status line and headers of every response in the redirect chain (so a redirect Location is assertable), then the final body.

websocket

send is the text payload, wrapped into a masked text frame with the length computed by the runtime. The hex "..." form does not apply here; the payload is sent as-is. recv is the most bytes to read. recv_until stops the read at a hex marker. timeout is seconds. close: true ends the session after the step. The connection stays open across steps.

tcp, tls, and the byte-family services

send is the bytes to send, written as hex; it may be empty when a step only reads. Instead of hand-computed hex you can write the payload as text: send: hex "HELO x\r\n" hex-encodes the quoted text, with the usual \r, \n, \t, \", \\ escapes plus \xHH for one arbitrary byte, so control characters stay visible. recv is the most bytes to read. recv_until stops the read at a hex marker. timeout is seconds. close: true ends the session after the step. The connection stays open across steps. tls sends and receives raw TLS record bytes, so a solution authors the handshake itself. Each service (ssh, ftp, smtp, ldap, redis, mysql, postgresql, smb, telnet) has a default port when the target omits one.

dns, snmp

dns and snmp speak raw datagrams over UDP; the fields are the byte-session fields above. The target is host:port; the default port is 53 for dns and 161 for snmp.

process

command is the command, words separated by spaces. cwd sets the working directory.

file

op is read or write. path is the file path. data is the bytes to write, required when op is write.

Capture

capture <var>: <regex> pulls a value out of the response for later steps. On http the regex runs over the full response text (status line, headers, and body); on tcp/tls/websocket over the received hex, and group 1 is hex-decoded. Later steps use {var}.

Set

set: is a block, one name: value per line. The values go to later steps. A later write on the same name wins. A step’s own set applies to later steps only.

Assert

assert: <type> "<expect>" is the pass or fail test on the response:

typeexpectpasses when
containsrequiredthe response contains the exact text
regexrequiredthe response matches the pattern
flagnonethe response contains a flag-shaped string such as FLAG{...}
oobrequiredthe target contacted the out-of-band listener
emptynonethe response is empty: the target never answered

An optional note: line explains what passing means.

Target

The target argument is shaped by the solution’s protocols: tcp, tls, and the byte-family services (including dns and snmp) take host:port, http, https, and websocket take a base URL, process and file ignore it.

Full example

id: openssl/heartbleed-mem-leak
summary: CVE-2014-0160 Heartbleed
ref: CVE-2014-0160

tls clienthello-heartbeat
  send: 1603030125010001210303...
  recv_until: 0e000000
  recv: 65536
  assert: contains "0e000000"
  meaning: server completes the handshake

tls malformed-heartbeat
  send: 1803030003014000
  recv: 70000
  assert: regex "18030[123]40"

Result

The runtime prints one line per step (name PASS|FAIL test) and a result line: verified when every test passes, not verified when one fails. Parse errors name the line number. The runtime never interprets: the file is what runs.

Write attacks down. Verify them.

Download the binary, point it at a target you own, and get a verified result. The corpus is open and the format is plain text.