MMCT TEAM
Server IP : 217.21.85.138  /  Your IP : 216.73.216.103
Web Server : LiteSpeed
System : Linux in-mum-web906.main-hosting.eu 4.18.0-553.37.1.lve.el8.x86_64 #1 SMP Mon Feb 10 22:45:17 UTC 2025 x86_64
User : u915722082 ( 915722082)
PHP Version : 7.4.33
Disable Function : system, exec, shell_exec, passthru, mysql_list_dbs, ini_alter, dl, symlink, link, chgrp, leak, popen, apache_child_terminate, virtual, mb_send_mail
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : OFF  |  Python : OFF
Directory (0755) :  /home/u915722082/public_html/

[  Home  ][  C0mmand  ][  Upload File  ]

Current File : /home/u915722082/public_html/scan-suspicious.php
<?php
/**
 * scan-suspicious.php
 * Place: /home/u915722082/domains/thedotstudios.com/public_html/scan-suspicious.php
 *
 * Scans /home/u915722082/domains for suspicious files and writes:
 *  - suspicious-report.txt (detailed) next to this script
 *  - appends a summary to attack-report.txt and cron-log.txt (next to this script)
 *
 * Run: php scan-suspicious.php
 */

date_default_timezone_set('Asia/Kolkata');

$SCRIPT_DIR = __DIR__; // /home/.../thedotstudios.com/public_html
$BASE = '/home/u915722082/domains';

$REPORT = $SCRIPT_DIR . '/suspicious-report.txt';
$ATTACK_REPORT = $SCRIPT_DIR . '/attack-report.txt';
$CRON_LOG = $SCRIPT_DIR . '/cron-log.txt';
$SNAPSHOT = $SCRIPT_DIR . '/filelist.json';

/* ---------- Config ---------- */
$RECENT_DAYS = 7;            // consider files modified within last N days
$MAX_READ_BYTES = 131072;    // read at most 128KB of each file
$CHECK_PHP_CONTENT = true;
$USE_SNAPSHOT = true;

// Ensure report files exist and are writable
foreach ([$REPORT, $ATTACK_REPORT, $CRON_LOG] as $f) {
    if (!file_exists($f)) {
        @file_put_contents($f, "Created: " . date('Y-m-d H:i:s') . PHP_EOL);
        @chmod($f, 0644);
    }
}

// Exclusions to reduce noise (adjust if needed)
$EXCLUDES = [
    __FILE__,
    $REPORT,
    $ATTACK_REPORT,
    $CRON_LOG,
    $SNAPSHOT,
    $SCRIPT_DIR . '/logs', // central logs dir (don't scan logs folder)
    '/home/u915722082/domains/*/public_html/storage/framework/sessions',
    '/home/u915722082/domains/*/public_html/cache',
];

/* ---------- Suspicious rules ---------- */
$suspiciousNames = [
    '/\bzz\.php\b/i', '/\bshell\.php\b/i', '/\bbackdoor\b/i', '/\bcmd\.php\b/i',
    '/\bphpinfo\.php\b/i', '/\bx\.php\b/i', '/\buploader\.php\b/i', '/\bupload\.php\b/i'
];

$suspiciousContent = [
    '/eval\s*\(/i' => 'uses eval()',
    '/base64_decode\s*\(/i' => 'uses base64_decode()',
    '/gzinflate\s*\(/i' => 'uses gzinflate()/gzuncompress()',
    '/gzuncompress\s*\(/i' => 'uses gzuncompress()',
    '/str_rot13\s*\(/i' => 'uses str_rot13()',
    '/shell_exec\s*\(/i' => 'uses shell_exec()',
    '/system\s*\(/i' => 'uses system()',
    '/passthru\s*\(/i' => 'uses passthru()',
    '/exec\s*\(/i' => 'uses exec()',
    '/preg_replace\s*\(\s*.*\/e.*/i' => 'uses preg_replace with /e modifier',
    '/assert\s*\(/i' => 'uses assert()',
    '/curl_exec\s*\(/i' => 'uses curl_exec()',
    '/fopen\s*\(\s*[\'"]http/i' => 'opens remote http stream',
    '/[A-Za-z0-9\/+]{200,}/' => 'very long base64-like string (possible encoded payload)'
];

$suspiciousPaths = [
    '/\/uploads\//i',
    '/wp-content\/uploads/i',
    '/\/tmp\//i',
    '/\/cache\//i',
    '/\/backup\//i',
];

/* ---------- Helpers ---------- */

function is_world_writable($perm_octal) {
    $perm = intval($perm_octal, 8);
    // check group or other write bit
    return (bool) (($perm & 0x0002) || ($perm & 0x0010) || ($perm & 0x0020));
}

function match_excludes($path, $excludes) {
    foreach ($excludes as $ex) {
        if (strpos($ex, '*') !== false) {
            $pattern = '#^' . str_replace('\\*', '.*', preg_quote($ex, '#')) . '$#i';
            if (preg_match($pattern, $path)) return true;
        } else {
            if (strpos($path, $ex) === 0) return true;
        }
    }
    return false;
}

/* ---------- Load snapshot if any ---------- */
$prev = [];
if ($USE_SNAPSHOT && file_exists($SNAPSHOT)) {
    $j = @file_get_contents($SNAPSHOT);
    $prev = json_decode($j, true) ?: [];
}

/* ---------- Walk files ---------- */
$rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($BASE, FilesystemIterator::SKIP_DOTS));
$suspicious = [];
$now = time();
$recent_threshold = $now - ($RECENT_DAYS * 86400);

foreach ($rii as $file) {
    if (!$file->isFile()) continue;
    $path = $file->getPathname();

    if (match_excludes($path, $EXCLUDES)) continue;

    $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
    $size = $file->getSize();
    $mtime = $file->getMTime();
    $owner = function_exists('posix_getpwuid') ? (@posix_getpwuid(@fileowner($path))['name'] ?? @fileowner($path)) : @fileowner($path);
    $perm = substr(sprintf('%o', @fileperms($path)), -4);

    $reasons = [];

    // filename patterns
    foreach ($suspiciousNames as $pat) {
        if (preg_match($pat, $path)) { $reasons[] = "Suspicious filename pattern matched: {$pat}"; break; }
    }

    // suspicious path patterns
    foreach ($suspiciousPaths as $pat) {
        if (preg_match($pat, $path)) {
            if ($ext === 'php') $reasons[] = "PHP in suspicious path: {$pat}";
            else $reasons[] = "File in suspicious path: {$pat}";
            break;
        }
    }

    // owner is typically webserver user?
    $lowowner = strtolower((string)$owner);
    if (in_array($lowowner, ['nobody','www-data','apache','httpd','wwwrun'])) {
        $reasons[] = "Owned by webserver user: {$owner}";
    }

    // world/group writable
    if (is_world_writable($perm)) {
        $reasons[] = "Group/other writable (perm {$perm})";
    }

    // recent file
    if ($mtime >= $recent_threshold) {
        $reasons[] = "Recently modified: " . date('Y-m-d H:i:s', $mtime);
    }

    // new since snapshot
    if ($USE_SNAPSHOT && !isset($prev[$path])) {
        $reasons[] = "New file since last snapshot";
    }

    $excerpt = '';
    if ($ext === 'php' && $CHECK_PHP_CONTENT) {
        $content = @file_get_contents($path, false, null, 0, $MAX_READ_BYTES);
        if ($content !== false && $content !== '') {
            foreach ($suspiciousContent as $pat => $desc) {
                if (preg_match($pat, $content)) $reasons[] = $desc . " (pattern: $pat)";
            }
            if (preg_match('/[A-Za-z0-9\/+]{200,}/', $content)) $reasons[] = 'Very long base64-like string detected';
            if (preg_match_all('/chr\s*\(/i', $content) > 5) $reasons[] = 'Many chr() calls (possible obfuscation)';
            // excerpt
            $lines = preg_split("/\r\n|\n|\r/", $content);
            $excerpt = implode("\n", array_slice($lines, 0, 12));
        } else {
            $excerpt = '[unreadable or empty]';
        }
    }

    if (!empty($reasons)) {
        $suspicious[$path] = [
            'owner' => $owner,
            'perm' => $perm,
            'size' => $size,
            'mtime' => date('Y-m-d H:i:s', $mtime),
            'reasons' => $reasons,
            'excerpt' => $excerpt
        ];
    }
}

/* ---------- Write report ---------- */
$nowLabel = date('Y-m-d H:i:s');
$header = "Suspicious scan run at: $nowLabel\nBase: $BASE\nDetected: ".count($suspicious)." suspicious files\n\n";
file_put_contents($REPORT, $header, LOCK_EX);

foreach ($suspicious as $path => $info) {
    $block = "-------------------------------\n";
    $block .= "File: $path\n";
    $block .= "Owner: {$info['owner']}  Perm: {$info['perm']}  Size: {$info['size']}  MTime: {$info['mtime']}\n";
    $block .= "Reasons:\n";
    foreach ($info['reasons'] as $r) $block .= " - $r\n";
    if (!empty($info['excerpt'])) {
        $block .= "Excerpt (first lines / <=128KB):\n";
        $block .= $info['excerpt'] . "\n";
    }
    $block .= "\n";
    file_put_contents($REPORT, $block, FILE_APPEND | LOCK_EX);
}

// append summary to attack-report and cron-log
$appendBlock = "=== Suspicious scan summary at $nowLabel ===\nDetected: ".count($suspicious)." suspicious files. See suspicious-report.txt\n\n";
file_put_contents($ATTACK_REPORT, $appendBlock, FILE_APPEND | LOCK_EX);
file_put_contents($CRON_LOG, $appendBlock, FILE_APPEND | LOCK_EX);

/* ---------- Update snapshot ---------- */
if ($USE_SNAPSHOT) {
    $snap = [];
    $rii2 = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($BASE, FilesystemIterator::SKIP_DOTS));
    foreach ($rii2 as $file) {
        if ($file->isFile()) {
            $p = $file->getPathname();
            if (match_excludes($p, $EXCLUDES)) continue;
            $snap[$p] = ['size' => $file->getSize(), 'mtime' => $file->getMTime()];
        }
    }
    file_put_contents($SNAPSHOT, json_encode($snap, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), LOCK_EX);
}

echo "Scan complete. Found ".count($suspicious)." suspicious files. Report: $REPORT\n";
?>

MMCT - 2023