Skip to content

tomdu3/fishin-generator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

77 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Fishin' Generator ๐ŸŽฃ

Fishin' Generator

Fishin' Generator is a realistic phishing email simulator designed for corporate security awareness training. It allows security teams to generate and send safe, simulated phishing emails to employees, and tracks engagement (opens and clicks) to identify vulnerabilities in the human firewall.

Instead of just a technical exercise, this is positioned as a business solution. It demonstrates a deep understanding of social engineering - the number one attack vector for modern breaches - and provides actionable metrics for training.


๐Ÿ› ๏ธ Tech Stack & Architecture

  • Backend: Flask (Python) - Lightweight and perfect for serving the dashboard UI and handling fast API tracking endpoints.
  • Database: SQLite with Flask-SQLAlchemy (SQLAlchemy 2.0 API) - A robust, file-based relational database to store targets, templates, and tracking events.
  • Frontend: HTML + Jinja2 Templates, powered by HTMX for dynamic real-time updates without page reloads, and styled with Tailwind CSS (via CDN) for a clean, modern, and professional aesthetic.
  • Email Delivery: Standard Python smtplib + email.mime for generating and dispatching HTML emails, with a built-in "Dry Run" mode for safe local testing.

โœจ Core Features

1. Modern Dashboard

The simulator features a responsive, professional dashboard built with Tailwind CSS. Security teams can view high-level metrics (Total Campaigns, Total Targets) and see the real-time status of their tests.

2. Pre-Loaded Social Engineering Templates

The database comes seeded with 12 foundational phishing templates designed to mimic real-world attacks. These templates exploit specific emotional triggers:

  • Urgency/Fear: e.g., "Credential Reset Notification" or "MFA Fatigue Bypass".
  • Authority: e.g., "Executive Wire Transfer Request".
  • Curiosity/Familiarity: e.g., "HR Policy Document" or "Fake File Share".

Each template features a customized, context-aware Sender Display Name stored at the template level (e.g. "Barclays Bank Security", "Zoom Support", or "Human Resources"), which dynamically pairs with your sending infrastructure to simulate high-fidelity phishing headers.

3. Safe Educational Landing Page

If an employee falls for the simulation and clicks a malicious link, they are safely redirected to a local phished.html landing page. This page breaks the news gently and provides immediate, constructive feedback on how they could have spotted the phishing attempt (e.g., checking the sender domain, hovering over links).

4. Campaign Lifecycle Management (Active/Ended States)

Security teams can end campaigns to stop active phishing simulations when the testing window closes.

  • Suspended Tracking: When a campaign is "Ended", all subsequent clicks and opens from that campaign's emails are ignored, preventing late clicks from skewing active simulation metrics.
  • Reactivation & Email Resending: If needed, campaigns can be reactivated with a single click. This changes the status back to "Active" and triggers automatic email resending to all original targets with new tracking IDs, continuing the simulation.

๐Ÿ” Deep Dive: The Tracking Mechanism

The core logic of the project relies on tying specific actions back to a single user through a unique identifier. Here is exactly how the lifecycle of an event is tracked:

Phase 1: The "Sent" Event

When a campaign is launched, the Flask backend (app.py) iterates through the selected targets.

  1. It generates a unique UUID (tracking_id) for that specific target.
  2. It inserts a row into the TrackingEvent database table with event_type='Sent'.
  3. It passes this tracking_id to the mailer.py script.

Phase 2: The "Opened" Event (Pixel Tracking)

To know if a user opened the email, we use a tracking pixel:

  1. mailer.py appends an invisible HTML <img> tag to the bottom of the email: <img src="http://our-server/track/open/<tracking_id>.gif" width="1" height="1" style="display:none;" />
  2. When the employee's email client renders the HTML, it automatically makes an HTTP GET request to our server to download that image.
  3. Our server catches that request, looks up the tracking_id, logs an 'Opened' event in the database, and returns a transparent 1x1 pixel so the user sees nothing broken.

Phase 3: The "Clicked" Event (Link Rewriting)

To track if a user falls for the trap, we dynamically rewrite the links in the email:

  1. The templates use a placeholder {{ tracking_url }} for their call-to-action buttons.
  2. During email generation, Jinja replaces this with a custom URL: http://our-server/track/click/<tracking_id>.
  3. When the user clicks the "Reset Password" button, their browser navigates to our server.
  4. Our server catches the request, logs a 'Clicked' event using the tracking_id, and redirects the user to the educational training page.

(Note: The tracking_id column in the database is Indexed, rather than Unique, allowing us to store multiple events - Sent, Opened, Clicked - under the same ID for fast querying).


๐Ÿš€ How to Run

  1. Ensure you have uv installed.
  2. Install the dependencies:
    uv sync
  3. Set up your environment configuration (optional):
    • Copy the sample env file: cp .env.sample .env
    • Fill in your SMTP settings. If using Gmail, you will need to generate a 16-character App Password from your Google App Passwords account settings (2-Step Verification must be enabled first) and use it as SMTP_PASS without spaces.
  4. Run the Flask application:
    uv run app.py

  1. There are 2 ways to proceed:
  • Version 1 - Absolutely local with Dry Run

    Open your browser and navigate to http://localhost:5000.

Tip

Dry Run Mode: By default, if no SMTP credentials are provided via a .env file, the simulator will automatically run in "Dry Run" mode. Instead of actually sending emails, it will save the generated HTML email into a dry_run_emails/ folder and print the raw HTML to the terminal. You can simply double-click the saved .html file to view the email in your browser and test the clicking flow safely!


  • Version 2 - using serveo to have a real working demo

Note

For a temporary deployment we can use Serveo, a simple SSH-based tunneling service that exposes your local Flask app to the public internet without changing router settings or firewall rules. It creates a secure tunnel from your machine to a temporary public URL, so external users can reach http://localhost:5000 while the tunnel is active.

ssh -R 80:localhost:5000 serveo.net

After running the command a temporary public URL will be printed to your terminal (for example: https://randomsubdomain.serveo.net).

Note

For some reason, serveo.net may not work as expected, so I recommend using Cloudflared instead. Install it on your Linux machine first:

curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | gpg --dearmor | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared focal main' | sudo tee /etc/apt/sources.list.d/cloudflared.list
sudo apt-get update && sudo apt-get install cloudflared

or on Arch Linux:

sudo pacman -S cloudflared

Then run the following command:

cloudflared tunnel --url http://localhost:5000

Copy the generated URL and open it in a browser to access the dashboard remotely. It will be something like https://randomname.trycloudflare.com and it will work for 2 hours or until you close the terminal. The link will appear after the words Your quick Tunnel has been created! Visit it at (it may take some time to be reachable):

Use it as follows:

  • Copy the generated URL and open it in a browser to access the dashboard remotely.
  • Send a test campaign (or open a saved dry-run email) and ensure the tracking pixel and rewritten links use the serveo/cloudflared URL (e.g. https://randomsubdomain.serveo.net/track/open/<tracking_id>).
  • Click a tracked link from the email; the server will log the "Clicked" event and redirect to the educational landing page through the same public URL.
  • Remember the tunnel (and its URL) lasts only for the SSH session - closing the terminal ends the public link.

๐Ÿ—„๏ธ Database Schema

Entity-Relationship Diagram

erDiagram
    TARGET ||--o{ TRACKING_EVENT : "has many"
    TEMPLATE ||--o{ CAMPAIGN : "used in"
    CAMPAIGN ||--o{ TRACKING_EVENT : "generates"

    TARGET {
        int id PK
        string name
        string email
    }
    TEMPLATE {
        int id PK
        string name
        string sender_name
        string subject
        text body_html
    }
    CAMPAIGN {
        int id PK
        string name
        int template_id FK
        datetime created_at
        string status
    }
    TRACKING_EVENT {
        int id PK
        int campaign_id FK
        int target_id FK
        string tracking_id
        string event_type
        datetime timestamp
    }
Loading

Table Definitions

Target

Column Type Constraints
id Integer Primary Key
name String(100) Not Null
email String(120) Unique, Not Null

Template

Column Type Constraints
id Integer Primary Key
name String(100) Not Null
sender_name String(100) Nullable
subject String(200) Not Null
body_html Text Not Null

Campaign

Column Type Constraints
id Integer Primary Key
name String(100) Not Null
template_id Integer Foreign Key
created_at DateTime Not Null
status String(20) Not Null

TrackingEvent

Column Type Constraints
id Integer Primary Key
campaign_id Integer Foreign Key
target_id Integer Foreign Key
tracking_id String(36) Indexed
event_type String(20) Not Null
timestamp DateTime Not Null

๐Ÿ”ฎ Future Features

To transition this simulator from a local training exercise to a production-ready cloud service, the following roadmap features are planned:

  1. User Authentication & Authorization: Securing the administration dashboard behind a secure login flow using Flask-Login and cryptographically hashed passwords.
  2. Abuse Prevention Safeguards: Restricting outbound campaigns to verified recipient domains, and adding rate limiting to campaign creation to prevent spam abuse.
  3. Decoupled SMTP Settings: Migrating email credentials out of environment variables and into user settings, allowing administrators to utilize their own secure email infrastructure.

For a detailed step-by-step walkthrough on how to implement and deploy these updates, refer to the Deployment and Email Security Roadmap.

About

[ Flask | SQLite3 | HTMX | TailwindCSS ] Fishin generator is a phishing email simulator designed for corporate security awareness training.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors