Linux puskom-ProLiant-DL385-Gen10 5.4.0-150-generic #167~18.04.1-Ubuntu SMP Wed May 24 00:51:42 UTC 2023 x86_64
/
var
/
www
/
html
/
bkd
/
berkas
/
/var/www/html/bkd/berkas/dg-scanner.php
<?php // web_scanner.php // Simple web-accessible scanner for suspicious/backdoor files. // USAGE: // 1) Save as web_scanner.php in your webroot (e.g. /var/www/html). // 2) The password is "Mbet_x12" (bcrypt hash embedded). You may replace the hash if you want another password. // 3) Access via browser and enter the password. // WARNING: remove this file when finished. Keep it offline otherwise. session_start(); set_time_limit(0); error_reporting(E_ALL); ini_set('display_errors', 0); // set 1 for debugging if needed // ========== CONFIG ========== /* Password is "Mbet_x12". Stored as bcrypt hash so the script never stores plain text. If you want to change password, generate a bcrypt hash and replace $PASSWORD_HASH. */ $PASSWORD_HASH = '$2a$15$iizlgx9DXSrR4A7dPyDu1OMLdgxPG4cGpWI3RjN0AZrst6nK/jtTu'; $BASE_DIR = __DIR__; // default scan directory (current dir). Ubah jika perlu. $MAX_FILE_READ_BYTES = 2 * 1024 * 1024; // max bytes to read per file (2MB) $RECENT_DAYS = 30; // untuk laporan file diubah dalam X hari $SUSPICIOUS_PATTERNS = array( // fungsi php berbahaya / pola umum obfuscation '/\beval\s*\(/i', '/base64_decode\s*\(/i', '/gzinflate\s*\(/i', '/str_rot13\s*\(/i', '/shell_exec\s*\(/i', '/\bexec\s*\(/i', '/\bsystem\s*\(/i', '/passthru\s*\(/i', '/popen\s*\(/i', '/proc_open\s*\(/i', '/unserialize\s*\(/i', '/preg_replace\s*\(.*\/e/i' ); // ============================ // Handle login / logout / download $report = null; $error = null; if ($_SERVER['REQUEST_METHOD'] === 'POST') { // Login attempt if (isset($_POST['action']) && $_POST['action'] === 'login') { $pw = isset($_POST['password']) ? $_POST['password'] : ''; if (!password_verify($pw, $PASSWORD_HASH)) { $error = "Password salah."; } else { $_SESSION['webscanner_authed'] = true; // start scanning immediately after auth $report = run_scan($BASE_DIR, $SUSPICIOUS_PATTERNS, $RECENT_DAYS, $MAX_FILE_READ_BYTES); $_SESSION['webscanner_report'] = $report['raw_text']; } } // Download request (requires session auth) if (isset($_POST['action']) && $_POST['action'] === 'download') { if (!empty($_SESSION['webscanner_authed']) && !empty($_SESSION['webscanner_report'])) { header('Content-Type: text/plain'); header('Content-Disposition: attachment; filename="web-scan-report-'.date('Ymd-His').'.txt"'); echo $_SESSION['webscanner_report']; exit; } else { $error = "Tidak terautentikasi atau laporan tidak tersedia. Silakan login dulu."; } } // Logout (optional) if (isset($_POST['action']) && $_POST['action'] === 'logout') { unset($_SESSION['webscanner_authed']); unset($_SESSION['webscanner_report']); session_regenerate_id(true); } } // If user already authed and no immediate report in this request, reuse stored report if (empty($report) && !empty($_SESSION['webscanner_authed']) && !empty($_SESSION['webscanner_report'])) { // convert raw text to structured report minimally for UI $report = array('raw_text' => $_SESSION['webscanner_report'], 'found' => array()); } // Helper: human-readable perms function perms_string($file) { $p = @fileperms($file); return $p === false ? '----' : substr(sprintf('%o', $p), -4); } function is_world_writable($file) { $p = @fileperms($file); if ($p === false) return false; return ($p & 0x0002) ? true : false; } function read_file_head($path, $max_bytes) { $f = @fopen($path, 'rb'); if (!$f) return ''; $data = fread($f, $max_bytes); fclose($f); return $data === false ? '' : $data; } function contains_long_base64($text, $minlen = 200) { // base64 chars A-Za-z0-9+/ with optional padding = if (preg_match('/[A-Za-z0-9+\/]{' . $minlen . ',}={0,2}/', $text)) return true; return false; } function run_scan($base_dir, $patterns, $recent_days, $max_read) { $report_lines = array(); $found = array( 'suspicious_files' => array(), 'long_base64' => array(), 'recent_php' => array(), 'php_in_uploads' => array(), 'hidden_files' => array(), 'world_writable' => array(), 'common_shell_names' => array(), 'htaccess' => array(), 'google_verif' => array() ); $report_lines[] = "Web scanner run: " . date('c'); $report_lines[] = "Base dir: $base_dir"; $report_lines[] = "Scan config: recent_days=$recent_days, max_read_bytes=$max_read"; $report_lines[] = "----"; $common_shells = array('shell.php','c99.php','r57.php','wso.php','php-reverse-shell.php','upload.php','cmd.php'); $it = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($base_dir, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST ); foreach ($it as $fileinfo) { $path = $fileinfo->getPathname(); // skip this scanner file itself for clarity if (realpath($path) === realpath(__FILE__)) continue; // skip vendor/node_modules if present if (strpos($path, DIRECTORY_SEPARATOR . 'node_modules' . DIRECTORY_SEPARATOR) !== false) continue; if (strpos($path, DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR) !== false) continue; if (strpos($path, DIRECTORY_SEPARATOR . '.git' . DIRECTORY_SEPARATOR) !== false) continue; // .htaccess contents if (strtolower($fileinfo->getFilename()) === '.htaccess') { $content = @file_get_contents($path); $report_lines[] = "HTACCESS: $path"; $report_lines[] = $content !== false ? $content : "(cannot read)"; $report_lines[] = "----"; $found['htaccess'][] = $path; } // google verification html files if (preg_match('/^google[0-9a-zA-Z_\-]+\.html$/', $fileinfo->getFilename())) { $found['google_verif'][] = $path; } if ($fileinfo->isDir()) { continue; } // hidden files (start with .) and suspicious extensions $basename = $fileinfo->getFilename(); if (substr($basename,0,1) === '.') { $found['hidden_files'][] = $path; } $ext = strtolower(pathinfo($basename, PATHINFO_EXTENSION)); if (in_array($ext, array('phtml','inc','bak','tmp','dat'))) { $found['hidden_files'][] = $path; } // world-writable if (is_world_writable($path)) { $found['world_writable'][$path] = perms_string($path); } // PHP related checks if ($ext === 'php' || stripos($basename, '.php') !== false) { // recent modification $mtime = $fileinfo->getMTime(); if ($mtime >= strtotime("-$recent_days days")) { $found['recent_php'][$path] = date('c', $mtime); } // php in upload paths if (preg_match('#[/\\\\](upload|uploads)[/\\\\]#i', $path)) { $found['php_in_uploads'][] = $path; } // read head of file (limited) $text = read_file_head($path, $max_read); if ($text === '') continue; // suspicious patterns foreach ($patterns as $pat) { if (@preg_match($pat, $text)) { $found['suspicious_files'][$path][] = $pat; } } // long base64 if (contains_long_base64($text, 200)) { $found['long_base64'][] = $path; } } // common web-shell names if (in_array(strtolower($basename), $common_shells)) { $found['common_shell_names'][] = $path; } } // prepare human readable report text $lines = array(); $lines[] = "Scan summary for $base_dir"; $lines[] = "Date: ".date('c'); $lines[] = "----"; $count = 0; foreach ($found as $k => $v) { if (is_array($v)) $count += count($v); } $lines[] = "Total categories with hits: $count"; $lines[] = "----"; $add_section = function($title, $items) use (&$lines) { $lines[] = $title; $lines[] = str_repeat('-', strlen($title)); if (!$items) { $lines[] = "(none)"; } else { foreach ($items as $k => $v) { if (is_array($v)) { $lines[] = "$k => " . implode(', ', (array)$v); } else { $lines[] = $v; } } } $lines[] = ""; }; $add_section("Suspicious PHP patterns found (file => patterns)", $found['suspicious_files']); $add_section("Files with long base64-like strings", $found['long_base64']); $add_section("PHP files modified in last {$recent_days} days (path => mtime)", $found['recent_php']); $add_section("PHP files inside upload*/uploads* directories", $found['php_in_uploads']); $add_section("Hidden / odd extension files", $found['hidden_files']); $add_section("World-writable files (path => perms)", $found['world_writable']); $add_section("Files matching common web-shell names", $found['common_shell_names']); $add_section(".htaccess files discovered (paths shown above earlier)", $found['htaccess']); $add_section("Google verification files (google*.html)", $found['google_verif']); // raw_text for download $report_raw = implode("\n", $lines); // also prepare a small HTML-friendly array for UI return array('raw_text' => $report_raw, 'lines' => $lines, 'found' => $found); } ?> <!doctype html> <html> <head> <meta charset="utf-8"> <title>Web Scanner</title> <style> body{font-family:system-ui,Segoe UI,Roboto,Arial;max-width:1100px;margin:20px auto;color:#111} textarea{width:100%;height:320px;font-family:monospace} table{border-collapse:collapse;width:100%} th,td{border:1px solid #ddd;padding:6px;text-align:left} .bad{color:#a00;font-weight:700} .ok{color:#0a0} .note{color:#666;font-size:0.9em} </style> </head> <body> <h2>Simple Web Scanner</h2> <p class="note">Password untuk scanner ini adalah <strong>the one you set</strong>. (Currently password "Mbet_x12" is embedded as bcrypt hash.) <strong>Hapus file ini setelah selesai.</strong></p> <?php if (!empty($error)): ?> <div class="bad"><?php echo htmlspecialchars($error); ?></div> <?php endif; ?> <?php if (empty($_SESSION['webscanner_authed'])): ?> <form method="post"> <input type="hidden" name="action" value="login"> <label>Password: <input type="password" name="password" required></label> <button type="submit">Start scan</button> </form> <?php else: ?> <?php if ($report === null && !empty($_SESSION['webscanner_report'])): ?> <?php $report = array('raw_text' => $_SESSION['webscanner_report']); ?> <?php endif; ?> <form method="post" style="margin-bottom:10px"> <input type="hidden" name="action" value="download"> <button type="submit">Download full report (txt)</button> </form> <form method="post" style="margin-bottom:10px"> <input type="hidden" name="action" value="logout"> <button type="submit">Logout (clear session)</button> </form> <?php if ($report): ?> <h3>Hasil Scan</h3> <pre><?php echo htmlspecialchars($report['raw_text']); ?></pre> <h3>Quick summary</h3> <ul> <?php // try to parse counts from report text (simple heuristics) $suspicious = preg_match_all('/Suspicious PHP patterns found/', $report['raw_text'], $m1); // we used structured data earlier but if not available, fallback: $countSusp = preg_match_all('/^.*=>.*$/m', $report['raw_text'], $m); // just show some quick items by simple counts (heuristic) ?> <li>Report size (chars): <strong><?php echo strlen($report['raw_text']); ?></strong></li> <li>Note: This scanner is heuristic — please review files listed before deleting anything.</li> </ul> <div class="note">Catatan: tool ini bersifat heuristik dan dapat menghasilkan false positives. Buka file-file yang dicurigai dan periksa isinya sebelum mengambil tindakan penghapusan.</div> <?php else: ?> <p>Scan selesai tetapi laporan tidak tersedia. Silakan jalankan lagi jika perlu.</p> <?php endif; ?> <?php endif; ?> </body> </html>