Video failed to load

How to Conduct a Phishing Simulation

1546 words
8 minutes
How to Conduct a Phishing Simulation
How to Conduct a Phishing Simulation

Translation Notice

This article was originally written in Chinese and translated into English with the assistance of AI. The translation has been reviewed and edited for clarity, accuracy, and readability. Please refer to the original source where necessary, especially for technical terms, commands, configuration details, and proper nouns.

With proper authorization, phishing simulations are an important way to assess an organization’s security awareness and defenses. This article covers a disciplined, safe, and controlled 2025 simulation, from information gathering and attack-surface analysis to simulated-page assessment, platform selection, and data collection.

Disclaimer#

This article is for lawful cybersecurity learning, research, and defensive improvement only. All operations, examples, and techniques may be used only in explicitly authorized environments, including personal assets, owned systems, laboratories, or systems covered by written authorization.

Never use any technique discussed here for unauthorized penetration testing, attacks, data theft, phishing, disruption of system stability, or any other illegal or non-compliant activity.

Users bear all legal liability, financial losses, and other consequences resulting from violating laws or exceeding the scope of authorization. The author and publishing platform assume no responsibility.

If you cannot confirm that the target environment is authorized, stop immediately.


Types of Phishing#

  1. Social phishing

Attackers contact employees through commonly used social platforms, such as messaging tools and social media, impersonate colleagues, partners, or other trusted identities, and persuade victims to click malicious links, visit spoofed pages, or download files containing malicious content. This type of phishing relies on trust, urgency, or promised benefits. It is difficult to notice and highly deceptive; victims often act without verifying the identity or content, leading to account compromise, endpoint infection, or further abuse of internal systems.

  1. Email phishing

Email phishing is one of the most common forms. Attackers send messages disguised as official notices, business correspondence, financial settlements, system alerts, or HR documents, directing recipients to click links or open attachments. These emails often closely imitate legitimate messages in sender address, templates, and wording. Some add time pressure, such as “urgent action required” or “your account will soon be disabled,” to lower vigilance. A mistaken action can expose credentials, leak sensitive information, or create endpoint risk.

How to Conduct a Phishing Simulation#

In security services, phishing simulations assess an organization’s defenses against social engineering. When a client cannot provide a complete user list or test sample, potential exposure can be assessed through information gathering and attack-surface analysis.

1. Information Gathering (Attack Surface Analysis)#

Without relying on internal client data, start with open-source intelligence (OSINT) and analyze exploitable information exposed online:

(1) Search Engines and Public Pages#

Search the organization name, historical notices, press releases, and official pages for:

  • Public email addresses (such as info@ or hr@)
  • Contact and duty-phone numbers
  • Combinations of employee names, titles, and contact details

(2) Business-Information Platforms#

Business-information platforms can help assess:

  • Publicly registered contact details
  • Contact information disclosed in tender notices
  • Partners and supply-chain relationships (potential lateral risk)

(3) Recruitment and Social-Platform Exposure#

Recruitment and professional-social platforms often unintentionally reveal:

  • HR, IT, and administrative roles
  • Organizational structures and department names
  • Employee work-email naming conventions

Simulated-Page and Content Risk Assessment (Non-Operational)#

A common question is whether employees can identify highly realistic pages or email content. The focus is not how to create phishing pages, but whether:

  • The organization can recognize legitimate domains
  • Email-security controls (SPF/DKIM/DMARC) are enabled
  • Employees notice unusual redirects, certificate problems, and URL differences

Analyzing the structural complexity and resource dependencies of real business pages helps estimate the cost of imitation and assess whether defensive controls are appropriate.

Building Simulation Pages or Software#

By 2025, web pages are relatively easy to reproduce technically. For an authorized training page, one of the simplest approaches is to save the page locally through a browser.

For example, open the page in a browser, press Ctrl+S, and save it locally for inspection.

This usually saves only the main HTML file; CSS, JavaScript, images, and other static resources may still point to the original site or a third-party CDN. When the local HTML is opened directly, common problems include:

  • Relative or cross-origin resource paths causing load failures
  • Resources returning 403 or failing to display because of the source site’s CORS or access controls
  • Broken styles and non-functional interactions

When saving a page for an authorized exercise, download all dependent static resources locally and fix their paths so it renders and runs offline.

For example, saving the blog page currently open in your browser requires more than Ctrl+S; its CSS, JavaScript, and image resources must also be collected to preserve the same appearance.

Phishing-Simulation Platforms#

After organizing the target list and preparing a simulation page, the next step is usually a data-collection and management platform. Mature open-source tools are available for authorized exercises, such as Gophish, along with other similar projects that can be selected according to requirements.

In practice, these ready-made platforms often have limitations, such as:

  • Inability to export URLs for separate authorized distribution
  • Inflexible data fields or collection logic
  • Limited page interaction and workflow customization
  • Inability to satisfy specialized testing requirements

For more complex or customized authorized exercises, existing platforms may need secondary development, or a lightweight collection system may be implemented independently. Technically, a web-based exercise is primarily the recording and analysis of user-submission behavior and data flows. The implementation is not complex: provide an endpoint that accepts HTTP requests and records visits and submissions. To reduce cost, use a general design such as:

  • One unified endpoint for different request types
  • A unique identifier for each participant, such as a UUID, to distinguish data sources
  • A web server, such as Nginx access.log, with log analysis to match paths, parameters, and identifiers
  • Use the data for security-awareness assessment or risk analysis, never for exploitation

This approach quickly creates a flexible, controllable exercise environment for internal testing or demonstrations without depending on a complex platform.

Collector Code#

The following is a simple collector written in Go with the Gin framework.

package main
import (
"encoding/json"
"fmt"
"net"
"net/http"
"os"
"strings"
"time"
"github.com/gin-gonic/gin"
)
// LoginRequest defines the request body (matching the JSON fields)
type LoginRequest struct {
Username string `json:"username" binding:"required"` // Username (required)
Password string `json:"password" binding:"required"` // Password (required)
Timestamp int64 `json:"timestamp" binding:"required"` // Timestamp (required; seconds or milliseconds)
UUID string `json:"uuid" binding:"required"` // Unique identifier (required)
}
// Fixed Auth value (replace with your own Base64 string, such as "mysecretkey")
const fixedAuthBase64 = "mysecretkey"
// isMobileUA determines whether the client is mobile based on User-Agent
func isMobileUA(ua string) bool {
ua = strings.ToLower(ua) // Normalize to lowercase
// Common mobile User-Agent keywords
mobileKeywords := []string{
"android", "iphone", "ipod", "ipad",
"windows phone", "mobile", "blackberry",
"webos", "iemobile", "opera mini",
}
for _, kw := range mobileKeywords {
if strings.Contains(ua, kw) {
return true
}
}
return false
}
func main() {
// Initialize the Gin engine
r := gin.Default()
// Load HTML templates (template directory: templates/*.html)
r.LoadHTMLGlob("templates/*")
r.GET("/page/:uuid", func(c *gin.Context) {
uuid := c.Param("uuid") // Get the UUID from the path
userAgent := c.Request.UserAgent() // Get the client User-Agent
isMobile := isMobileUA(userAgent) // Check whether the client is mobile
templateName := "desktop.html" // Default desktop template
if isMobile { // Use the mobile template for mobile devices
templateName = "mobile.html"
}
// Render the template and pass the UUID (available as {{.UUID}})
c.HTML(http.StatusOK, templateName, gin.H{"UUID": uuid})
})
// Register the login endpoint (POST /api/login)
r.POST("/api/user", loginHandler)
// Start the service (port: 30494)
fmt.Println("Server running on http://localhost:30494")
if err := r.Run(":30494"); err != nil {
panic(fmt.Sprintf("Failed to start server: %v", err))
}
}
// loginHandler handles login requests
func loginHandler(c *gin.Context) {
// -------------------------- 1. Validate the Auth header --------------------------
authHeader := c.GetHeader("Auth")
if authHeader != fixedAuthBase64 {
c.JSON(http.StatusUnauthorized, gin.H{
"code": 401,
"message": "Invalid Auth Header",
})
return
}
// -------------------------- 2. Parse and validate the request body --------------------------
var req LoginRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": fmt.Sprintf("Invalid Request Body: %v", err),
})
return
}
// -------------------------- 3. Get client information --------------------------
clientIP := getClientIP(c.Request) // Client IP
userAgent := c.Request.UserAgent() // Client User-Agent
serverTime := time.Now().Format(time.RFC3339) // Server time (RFC3339 format)
// -------------------------- 4. Build the log entry --------------------------
requestBody, err := json.MarshalIndent(req, "", " ") // Format the request body
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"code": 500,
"message": fmt.Sprintf("Failed to Marshal Request Body: %v", err),
})
return
}
logEntry := fmt.Sprintf(
"===== Request Log =====\n"+"IP: %s\nUA: %s\nServer Time: %s\nRequest Body:%s\n========================\n\n\n",
clientIP, userAgent, serverTime, string(requestBody),
)
// -------------------------- 5. Write to the local log file --------------------------
logFilePath := "./api_logs.txt" // Log-file path
if err := appendToLogFile(logFilePath, logEntry); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"code": 500,
"message": fmt.Sprintf("Failed to Write Log: %v", err),
})
return
}
// -------------------------- 6. Return a success response --------------------------
c.JSON(http.StatusOK, gin.H{
"code": 200,
"message": "Login request received and logged successfully",
"data": gin.H{
"username": req.Username,
},
})
}
// getClientIP gets the real client IP, preferring X-Forwarded-For when proxied
func getClientIP(r *http.Request) string {
// 1. Prefer the X-Forwarded-For header
forwardedFor := r.Header.Get("X-Forwarded-For")
if forwardedFor != "" {
// Take the first IP in the proxy chain
ips := strings.Split(forwardedFor, ",")
if len(ips) > 0 {
return strings.TrimSpace(ips[0])
}
}
// 2. Without a proxy, use RemoteAddr (format: IP:Port)
ip, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
return r.RemoteAddr // Return the original value on error
}
return ip
}
// appendToLogFile appends data to the log file (thread-safe)
func appendToLogFile(filePath, content string) error {
// Open the file: append | create if missing | write-only
file, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer file.Close() // Ensure the file is closed
// Write the data
_, err = file.WriteString(content)
return err
}

Access log
Access log

Collected information
Collected information

Support & Share

If this article helped you, please share or support!

Sponsor
How to Conduct a Phishing Simulation
https://blog.bytesycn.cn/posts/a40396ba-3375-4356-b866-bffb0929e8cb/
Author
Ryan Zhang
Published at
2025-12-19
Related PostsSmart
1
Offline Security Device Upgrade Guide: Download Links for Major Vendors (Continuously Updated)
KnowledgeSecurity devices in offline environments require manual updates, but vendor download links are scattered and difficult to find. This article collects offline upgrade links from major vendors for faster maintenance.
2
[Security Tool Vol. 2] testssl — Comprehensive SSL/TLS Security Testing
ToolsUse testssl.sh to perform comprehensive compliance and security checks on a site's SSL/TLS configuration.
3
Disable Burp Suite’s Automatic DNS Log Detection
TutorialBurp Suite is a cross-platform web-application penetration-testing tool built on Java. When it starts, it automatically performs DNSLog detection, which may trigger alerts on security devices such as STAs.
4
Information Leaks — A Responsibility Software Vendors Must Own
Personal ViewsBehind the frequent data leaks lies society’s increasingly blurred understanding of privacy. Developer negligence, institutional apathy, and user compromise have woven a exposed online world. Security is no longer merely a technical issue.
5
OpenSSH Security Upgrade Guide: Online and Offline Methods
TutorialOpenSSH is a core component for remote server access and administration. Its open-source nature sometimes exposes security vulnerabilities, but also drives continuous improvement. Upgrading is the most effective response, yet many Linux servers run in isolated environments and cannot update directly over the network. This guide explains how to securely upgrade OpenSSH by compiling and installing it offline.
Random PostsRandom

Comments

Profile Image of the Author
Ryan Zhang
Keep building, keep thinking, keep creating.
Announcement
Welcome to my blog!
Categories
Tags
Latest Moments
Site Statistics
Posts
30
Categories
7
Tags
42
Total Words
117,260
Running Days
0 days
Last Activity
0 days ago
Table of Contents