Press enter or click to view image in full size
What is Anglerphish? It’s a GoPhish fork that I’ve been working on for some time. For more details you can check the original article or the Github repo itself.
One of the newer features added to Anglerphish is MFA simulation. It’s worth noting that this is not a separate campaign type — instead, it is fully implemented through landing pages.
Important Disclaimer
This is not a red team tool. The goal of this feature is to simulate user behavior and measure how far a user will go before recognizing a phishing attempt. It is designed for security awareness and assessment purposes.
Currently, the MFA simulation relies on the SMS functionality built into Anglerphish, meaning only SMS-based MFA is supported, and it requires the target’s phone number.
This is not real-time MFA phishing like what tools such as Evilginx provide. In fact, a more advanced implementation would likely involve integrating Evilginx directly into Anglerphish.
Multi-Factor Authentication (MFA) is everywhere. Employees encounter it daily — logging into Microsoft 365, accessing company VPNs, and confirming bank transactions. Attackers are well aware of this. Modern phishing kits routinely include fake MFA prompts to capture one-time codes in real time.
If your security awareness program only tests whether users will give up their password, you’re leaving a significant gap.
Can users recognize a fake MFA prompt?
That’s exactly what Anglerphish helps you evaluate.
This guide walks through three approaches to adding MFA simulation to your phishing campaigns. All three approaches use the same backend logic — the difference lies only in how the MFA prompt is presented.
With that out of the way, let’s get into the important part.
Anglerphish uses its SMS functionality to deliver a simulated MFA code. It looks for the target’s phone number in two places (in order):
phone or Phone , allowing you to capture the target’s phone number during form submission.If neither is available, MFA is silently skipped and the campaign proceeds normally. No errors, no broken pages.
Here’s the flow when MFA is enabled:
Target visits phishing link
│
▼
Landing page loads (GET) → "Clicked Link" event recorded
│
▼
Target submits credentials (POST) → "Submitted Data" event recorded
│
▼
Anglerphish generates a random code (e.g., 847291)
│
▼
Code is sent via SMS → "MFA Code Sent" event recorded
│
▼
MFA verification page is shown to target
│
▼
Target enters the code
├── Correct → "MFA Code Verified" event → Redirect to final URL
└── Wrong → "MFA Code Failed" event → Show error, try againAll of these events appear in your campaign results timeline, so you get full visibility into how far each target went.
The way MFA is presented depends on a couple of simple settings. Anglerphish offers 3 approaches, controlled by two settings:
Is MFA enabled?
└── YES → Should Anglerphish show its own MFA page?
├── TRUE → Is custom HTML provided?
│ ├── NO ──── → APPROACH 1: Default built-in template
│ └── YES ──── → APPROACH 2: Your customized template
└── FALSE ──────── → APPROACH 3: You handle it with JavaScriptLet’s walk through each approach in detail.
Best for: Quick tests, proof-of-concept, when you don’t care about branding the MFA page.
What happens: After the target submits credentials, Anglerphish replaces the entire page with a clean, generic “Verification Required” page. No coding needed.
6Numeric5. Don’t click “Customize” — leave the template empty
6. Save the page
That’s it. When a target submits credentials, they’ll see this:
Press enter or click to view image in full size
Best for: Matching the MFA page to a specific brand, while still letting Anglerphish handle the heavy lifting.
What happens: Same as Approach 1, but instead of the generic page, Anglerphish shows your custom HTML. You control the look — Anglerphish controls the logic.
6. Edit the HTML (the default template is pre-loaded as a starting point)
7. Click “Preview” tab to see how it looks
8. Click “Apply” to save your customization
When a target submits credentials, they’ll see the customized page:
Important! Your custom MFA page must follow these rules or it won’t work:
method="POST"mfa_codeaction should be empty (action="") so it posts back to AnglerphishThe bare minimum:
<!-- ✅ This works -->
<form method="POST" action="">
<input type="text" name="mfa_code">
<button type="submit">Verify</button>
</form>That’s it. Everything around it — the <html>, <head>, CSS, images, logos, text — is entirely optional decoration. As long as those 3 rules are followed, the MFA verification will work.
<!-- ❌ This breaks — wrong field name -->
<form method="POST" action="">
<input type="text" name="verification_code">
<button type="submit">Verify</button>
</form>Best for: Seamless single-page experiences, advanced multi-step wizards, when you want the MFA prompt to appear within your landing page (not replace it).
Join Medium for free to get updates from this writer.
What happens: After credential submission, Anglerphish re-renders your original landing page but injects hidden flags. Your JavaScript detects these flags and transforms the page to show the MFA input.
#login visible, #mfa hidden)window.mfaPending=true injected#login, shows #mfa → target sees the code inputwindow.mfaError="Invalid code" → script shows errorBelow is a minimal example of the required page code (no CSS):
<html>
<body> <!-- 1. Login form -->
<div id="login">
<form method="POST" action="">
<input name="username" placeholder="Email">
<input name="password" type="password" placeholder="Password">
<button type="submit">Sign In</button>
</form>
</div>
<!-- 2. MFA form (hidden by default) -->
<div id="mfa" style="display:none">
<p>Enter the code sent to your phone</p>
<form method="POST" action="">
<input name="mfa_code" placeholder="Code">
<button type="submit">Verify</button>
</form>
<p id="err" style="color:red"></p>
</div>
<!-- 3. Check Anglerphish flags -->
<script>
document.addEventListener('DOMContentLoaded', function() {
if (window.mfaPending) {
document.getElementById('login').style.display = 'none';
document.getElementById('mfa').style.display = 'block';
}
if (window.mfaError) {
document.getElementById('login').style.display = 'none';
document.getElementById('mfa').style.display = 'block';
document.getElementById('err').textContent = window.mfaError;
}
});
</script>
</body>
</html>
Note, the same 3 rules apply for the MFA form as shown in Approach 2.
The page code has three sections:
The MFA form is hidden by default.
After the user submits credentials, Anglerphish re-serves the same page but adds a hidden signal.
The signal or flag is injected just before </body> of the page as shown below:
<script>window.mfaPending=true;</script>The script checks for that signal — if it’s there, it hides the login form and shows the MFA form instead.
If the user enters a wrong code, Anglerphish adds a different signal and the script also displays the error message:
<script>window.mfaError=”Invalid code”;</script>Think of it as a simple “div switcher” — it decides which form the user sees based on where they are in the MFA flow.
All the code is simply added, into the Landing Page editor.
Press enter or click to view image in full size
Anglerphish gives you flexibility to match your MFA simulation to your assessment goals:
The key insight is that all three approaches share the same backend engine — the same code generation, SMS delivery, verification logic, and event tracking. The only difference is how the MFA prompt is presented to the target.
Start with Approach 1 to understand the workflow, then move to Approaches 2 or 3 as you need more realism.