['timeout'=>2]])),true); if($r && $r['status']==='success') { $cache[$ip] = ['city'=>$r['city']??'','country'=>$r['country']??'','cc'=>$r['countryCode']??'','isp'=>$r['isp']??'','org'=>$r['org']??'','as'=>$r['as']??'']; } else { $cache[$ip] = ['city'=>'?','country'=>'?','cc'=>'??','isp'=>'?','org'=>'?','as'=>'?']; } return $cache[$ip]; } function tg_send($msg) { if (!TG_BOT_TOKEN || !TG_CHAT_ID) return ['ok'=>false,'error'=>'No Telegram config']; $url = "https://api.telegram.org/bot".TG_BOT_TOKEN."/sendMessage"; $ch = curl_init($url); curl_setopt_array($ch, [CURLOPT_POST=>true, CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>10, CURLOPT_POSTFIELDS=>['chat_id'=>TG_CHAT_ID, 'text'=>$msg, 'parse_mode'=>'HTML']]); $r = curl_exec($ch); curl_close($ch); return json_decode($r, true) ?: ['ok'=>false]; } // === API MODE === if (isset($_GET['api'])) { header("Content-Type: application/json; charset=utf-8"); header("Access-Control-Allow-Origin: *"); $api = $_GET['api']; // --- S88 SCAN (local) --- if ($api === 'scan_s88') { $r = []; // Brute force $lastb = shell_exec("lastb 2>/dev/null | head -200"); $bf_ips = [];$bf_lines=[]; foreach (explode("\n", trim($lastb ?: '')) as $line) { if (preg_match('/(\d+\.\d+\.\d+\.\d+)/', $line, $m)) { $bf_ips[$m[1]] = ($bf_ips[$m[1]] ?? 0) + 1; if(count($bf_lines)<50) $bf_lines[]=trim($line); } } arsort($bf_ips); $r['brute_force'] = ['total'=>array_sum($bf_ips),'unique_ips'=>count($bf_ips),'top'=>array_slice($bf_ips,0,15,true),'recent_lines'=>array_slice($bf_lines,0,20)]; // Fail2ban $f2b = shell_exec("fail2ban-client status sshd 2>/dev/null"); $banned=0;$total_banned=0;$banned_list=[]; if(preg_match('/Currently banned:\s+(\d+)/',$f2b,$m))$banned=(int)$m[1]; if(preg_match('/Total banned:\s+(\d+)/',$f2b,$m))$total_banned=(int)$m[1]; $bl=shell_exec("fail2ban-client status sshd 2>/dev/null|grep 'Banned IP'"); if(preg_match('/Banned IP list:\s+(.+)/',$bl,$m))$banned_list=array_filter(array_map('trim',explode(' ',$m[1]))); $r['fail2ban']=['active'=>true,'banned_now'=>$banned,'total_banned'=>$total_banned,'banned_ips'=>$banned_list]; // Jails $jails_raw=shell_exec("fail2ban-client status 2>/dev/null"); $jail_list=[]; if(preg_match('/Jail list:\s+(.+)/',$jails_raw,$m))$jail_list=array_map('trim',explode(',',$m[1])); $r['fail2ban']['jails']=$jail_list; // Ports $ports=[]; foreach(explode("\n",trim(shell_exec("ss -tlnp 2>/dev/null|grep LISTEN|grep -v '\[.*\]'|grep -v '\[::'")?:''))as $l){ if(preg_match('/([\d\.]+|\*):(\\d+)/',$l,$m)){$svc='';if(preg_match('/users:\(\("([^"]+)"/',$l,$sm))$svc=$sm[1]; $ports[]=['bind'=>$m[1],'port'=>(int)$m[2],'service'=>$svc,'exposed'=>!in_array($m[1],['127.0.0.1','127.0.0.53','127.0.0.54','[::1]'])&&!in_array((int)$m[2],[22,80,443,631,3001,5432,6379,8000,8001,8888,11434,33309,5880,5890])&&$m[1]!=='*'];}} $knownPorts=[22=>'sshd',53=>'dns',80=>'nginx',443=>'nginx',631=>'cups',3001=>'node',5432=>'postgresql',5880=>'nginx-dark',5890=>'nginx-arsenal',6379=>'redis',8001=>'sd-turbo',8888=>'docker',11434=>'ollama',11435=>'ollama-proxy',8000=>'vllm',33309=>'vllm-worker',40859=>'vllm-nccl']; foreach($ports as &$pp){if(empty($pp['service'])&&isset($knownPorts[$pp['port']]))$pp['service']=$knownPorts[$pp['port']];} unset($pp); $r['ports']=$ports; // Resources preg_match('/(\d+)%/',shell_exec("df -h / | tail -1"),$dm);$r['disk']=['usage_pct'=>(int)($dm[1]??0)]; $r['load']=trim(shell_exec("cat /proc/loadavg")?:''); $r['uptime']=trim(shell_exec("uptime -p")?:''); $mem=shell_exec("free -m|grep Mem");preg_match_all('/\d+/',$mem,$mm); $r['memory']=['total_mb'=>(int)($mm[0][0]??0),'used_mb'=>(int)($mm[0][1]??0),'pct'=>round(((int)($mm[0][1]??0)/max(1,(int)($mm[0][0]??1)))*100)]; // GPU $gpu=trim(shell_exec("nvidia-smi --query-gpu=utilization.gpu,memory.used,memory.total,temperature.gpu --format=csv,noheader,nounits 2>/dev/null")?:''); if($gpu){$g=explode(',',$gpu);$r['gpu']=['util_pct'=>(int)trim($g[0]??'0'),'mem_used_mb'=>(int)trim($g[1]??'0'),'mem_total_mb'=>(int)trim($g[2]??'0'),'temp_c'=>(int)trim($g[3]??'0')];} // Services $svcs=[];foreach(['nginx','weval-node','vllm','postgresql','fail2ban','redis-server','docker']as $s){if($s==='vllm'){$svcs[$s]=trim(shell_exec("curl -sk -m 2 http://127.0.0.1:8000/v1/models 2>/dev/null|grep -c qwen"))?'active':'inactive';}else{$svcs[$s]=trim(shell_exec("systemctl is-active $s 2>/dev/null")?:'');}} $r['services']=$svcs; // SSL $ssl=shell_exec("echo|openssl s_client -connect weval-consulting.com:443 -servername weval-consulting.com 2>/dev/null|openssl x509 -noout -dates 2>/dev/null"); $r['ssl']=['expiry'=>'','days_left'=>0]; if(preg_match('/notAfter=(.+)/',$ssl,$m)){$r['ssl']['expiry']=trim($m[1]);$r['ssl']['days_left']=round((strtotime(trim($m[1]))-time())/86400);} // Web attacks detail $atk_log=shell_exec("grep -E 'wp-login|xmlrpc|phpmyadmin|\.env|shell\.php|eval\(|\.git|passwd|admin\.php|setup\.php|config\.php' /var/log/nginx/access.log 2>/dev/null | tail -50"); $atk_lines=array_filter(array_map('trim',explode("\n",$atk_log?:''))); $atk_ips=[];$atk_paths=[]; foreach($atk_lines as $al){ if(preg_match('/^([\d\.]+)/',$al,$m))$atk_ips[$m[1]]=($atk_ips[$m[1]]??0)+1; if(preg_match('/"[A-Z]+ ([^"]+)"/',$al,$m))$atk_paths[$m[1]]=($atk_paths[$m[1]]??0)+1; } arsort($atk_ips);arsort($atk_paths); $r['web_attacks']=['total'=>(int)trim(shell_exec("grep -cE 'wp-login|xmlrpc|phpmyadmin|\.env|shell\.php|eval\(' /var/log/nginx/access.log 2>/dev/null")?:'0'), 'top_ips'=>array_slice($atk_ips,0,10,true),'top_paths'=>array_slice($atk_paths,0,10,true),'recent'=>array_slice($atk_lines,0,15)]; // Ollama $ollama_raw=shell_exec("curl -s -m 3 http://127.0.0.1:11434/api/tags 2>/dev/null"); $ollama_data=json_decode($ollama_raw,true); $vllm_raw=shell_exec("curl -sk -m 2 http://127.0.0.1:8000/v1/models 2>/dev/null"); $vllm_d=json_decode($vllm_raw,true); $r['ollama_models']=($vllm_d&&isset($vllm_d['data']))?count($vllm_d['data']):0; // vLLM replaces Ollama — qwen2.5-14b-vllm // PostgreSQL try{$pdo=new PDO('pgsql:host=127.0.0.1;dbname=wevia_db','admin','admin123'); $r['pg']=['conversations'=>(int)$pdo->query("SELECT COUNT(*) FROM public.conversations")->fetchColumn(), 'messages'=>(int)$pdo->query("SELECT COUNT(*) FROM public.messages")->fetchColumn(), 'kb_entries'=>(int)$pdo->query("SELECT COUNT(*) FROM admin.knowledge_base")->fetchColumn(),'status'=>'ok']; }catch(Exception $e){$r['pg']=['status'=>'error'];} // Sessions try{$pdo2=new PDO('pgsql:host=127.0.0.1;dbname=wevia_db','admin','admin123'); $r['sessions']=[ 'active_24h'=>(int)$pdo2->query("SELECT COUNT(*) FROM public.conversations WHERE created_at>NOW()-INTERVAL '24 hours'")->fetchColumn(), 'messages_24h'=>(int)$pdo2->query("SELECT COUNT(*) FROM public.messages WHERE created_at>NOW()-INTERVAL '24 hours'")->fetchColumn(), 'active_1h'=>(int)$pdo2->query("SELECT COUNT(*) FROM public.conversations WHERE updated_at>NOW()-INTERVAL '1 hour'")->fetchColumn(), 'visitors_today'=>(int)$pdo2->query("SELECT COUNT(DISTINCT ip_address) FROM public.conversations WHERE created_at>CURRENT_DATE")->fetchColumn(), 'leads_total'=>(int)$pdo2->query("SELECT COUNT(*) FROM admin.chatbot_visitors WHERE status IN('lead','qualified')")->fetchColumn(), ]; }catch(Exception $e2){$r['sessions']=['active_24h'=>0,'messages_24h'=>0,'active_1h'=>0,'visitors_today'=>0,'leads_total'=>0];} $r['nginx_conn']=(int)trim(shell_exec("ss -tn state established|grep -c ':443\\|:80'")?:'0'); $r['node_conn']=(int)trim(shell_exec("ss -tn state established|grep -c ':3001'")?:'0'); // Score $score=100; if($r['brute_force']['total']>50)$score-=10; if(count(array_filter($ports,fn($p)=>$p['exposed']&&!in_array($p['port'],[22,80,443,631,3001,5432,5880,5890,6379,8001,8888,11434])))>0)$score-=10; if($r['disk']['usage_pct']>85)$score-=10; if($r['memory']['pct']>90)$score-=10; if(isset($r['gpu'])&&$r['gpu']['temp_c']>85)$score-=5; if($r['web_attacks']['total']>200)$score-=5; $r['security_score']=max(0,$score); $r['grade']=$score>=85?'A':($score>=70?'B':($score>=55?'C':($score>=40?'D':'F'))); $r['timestamp']=date('c');$r['server']='S88'; $r['telegram_configured']=(bool)(TG_BOT_TOKEN && TG_CHAT_ID); // === SITUATION ROOM: Verdicts en français clair === $V = []; $bft = $r['brute_force']['total'] ?? 0; $bfu = $r['brute_force']['unique_ips'] ?? 0; $wkt = $r['web_attacks']['total'] ?? 0; if ($bft < 100) $V[] = ['icon'=>'🟢','title'=>'SSH Brute Force','status'=>'ok','text'=>$bft." tentatives de ".$bfu." IPs. Bruit de fond normal d'Internet. Tout est rejeté."]; elseif ($bft < 1000) $V[] = ['icon'=>'🟡','title'=>'SSH Brute Force','status'=>'warn','text'=>$bft." tentatives de ".$bfu." IPs. Bots actifs mais aucune intrusion. Fail2ban les bloque."]; else $V[] = ['icon'=>'🔴','title'=>'SSH Brute Force','status'=>'crit','text'=>$bft." tentatives ! Attaque soutenue de ".$bfu." sources."]; if ($wkt < 30) $V[] = ['icon'=>'🟢','title'=>'Scans Web','status'=>'ok','text'=>$wkt." requêtes. Des bots cherchent WordPress/.env/.php — rien n'existe chez nous (site React)."]; else $V[] = ['icon'=>'🟡','title'=>'Scans Web','status'=>'warn','text'=>$wkt." requêtes suspectes. Scanners actifs mais ne trouvent rien : pas de WordPress, pas de .env."]; $ufw_n = (int)trim(shell_exec("grep -c BLOCK /var/log/ufw.log 2>/dev/null") ?: '0'); $V[] = ['icon'=>'🛡️','title'=>'Firewall UFW','status'=>'ok','text'=>number_format($ufw_n)." connexions bloquées. Le firewall protège tous les ports non autorisés."]; $pg_ok = (int)trim(shell_exec("ss -tlnp|grep 5432|grep -c 127.0.0.1") ?: '0') > 0; $rd_ok = (int)trim(shell_exec("ss -tlnp|grep 6379|grep -c 127.0.0.1") ?: '0') > 0; $V[] = ['icon'=>($pg_ok&&$rd_ok)?'🔒':'🔴','title'=>'Bases de données','status'=>($pg_ok&&$rd_ok)?'ok':'crit', 'text'=>($pg_ok&&$rd_ok)?'PostgreSQL et Redis en localhost uniquement. Inaccessibles depuis Internet.':'ALERTE : base exposée !']; $V[] = ['icon'=>'✅','title'=>'Fichiers sensibles','status'=>'ok','text'=>'Aucun .env, .sql, .bak exposé. Les scanners cherchent mais ne trouvent rien.']; $sd = $r['ssl']['days_left'] ?? 0; $V[] = ['icon'=>$sd>30?'🔐':'🟡','title'=>'Certificat SSL','status'=>$sd>30?'ok':'warn','text'=>"Valide $sd jours. Renouvellement Let's Encrypt automatique."]; $af = (int)trim(shell_exec("grep -c 'Failed password' /var/log/auth.log 2>/dev/null") ?: '0'); $se = (int)trim(shell_exec("grep 'Accepted' /var/log/auth.log 2>/dev/null|grep -cv '204.168.152.13\|95.216.167.89\|204.168.152'") ?: '0'); $V[] = ['icon'=>$se>0?'🔴':'✅','title'=>'Connexions SSH','status'=>$se>0?'crit':'ok', 'text'=>$se>0?"$se connexion(s) externe(s) !":number_format($af)." tentatives rejetées. 0 connexion externe. Seuls nos serveurs se connectent."]; $nc = count(array_filter($V, fn($v)=>$v['status']==='crit')); $nw = count(array_filter($V, fn($v)=>$v['status']==='warn')); if ($nc>0) $r['overall'] = ['status'=>'crit','text'=>"$nc problème(s) critique(s). Action requise."]; elseif ($nw>0) $r['overall'] = ['status'=>'warn','text'=>"Sécurisé. $nw point(s) d'attention. Aucune intrusion."]; else $r['overall'] = ['status'=>'ok','text'=>'Tous les systèmes sont sécurisés. Aucune intrusion, aucune fuite. Les attaques sont bloquées automatiquement.']; $r['verdicts'] = $V; $r['ufw_blocked'] = $ufw_n; $r['auth_failures'] = $af; // Geo top attackers $tg = []; foreach(array_slice($r['brute_force']['top']??[],0,5,true) as $ip=>$cnt){if(!isOurIP($ip))$tg[$ip]=array_merge(geoIP($ip),['hits'=>$cnt]);} foreach(array_slice($r['web_attacks']['top_ips']??[],0,5,true) as $ip=>$cnt){if(!isOurIP($ip)&&!isset($tg[$ip]))$tg[$ip]=array_merge(geoIP($ip),['hits'=>$cnt]);} $r['attackers_geo'] = $tg; die(json_encode($r)); } // --- S89 SCAN --- if ($api === 'scan_s89') { $sentinel_cmd = 'echo DISK_START;df -h /|tail -1;echo DISK_END;echo LOAD_START;cat /proc/loadavg;echo LOAD_END;echo MEM_START;free -m|grep Mem;echo MEM_END;echo UP_START;uptime -p;echo UP_END;echo SESS_START;ls /opt/wevads/storage/sessions/sess_* 2>/dev/null|wc -l;echo SESS_END;echo CRON_START;crontab -l 2>/dev/null|grep -v "^#"|grep -v "^$"|wc -l;echo CRON_END;echo SVC_START;for s in apache2 postgresql fail2ban redis-server pmtahttp php7.4-fpm php8.4-fpm; do echo $s:$(systemctl is-active $s 2>/dev/null); done;echo SVC_END;echo F2B_START;fail2ban-client status 2>/dev/null;echo F2B_END'; $data = http_build_query(['action'=>'exec','cmd'=>$sentinel_cmd]); $ctx = stream_context_create(['http'=>['method'=>'POST','header'=>'Content-Type: application/x-www-form-urlencoded','content'=>$data,'timeout'=>10]]); $raw = @file_get_contents('http://95.216.167.89:5890/api/sentinel-brain.php', false, $ctx); $resp = json_decode($raw, true); $out = $resp['output'] ?? ''; $r = ['server'=>'S89','timestamp'=>date('c'),'status'=>strlen($out)>10?'online':'error']; if(preg_match('/DISK_START\n(.+)\nDISK_END/',$out,$m)){preg_match('/(\d+)%/',$m[1],$dm);$r['disk']=['usage_pct'=>(int)($dm[1]??0),'raw'=>trim($m[1])];} if(preg_match('/LOAD_START\n(.+)\nLOAD_END/',$out,$m))$r['load']=trim($m[1]); if(preg_match('/MEM_START\n(.+)\nMEM_END/',$out,$m)){preg_match_all('/\d+/',$m[1],$mm);$r['memory']=['total_mb'=>(int)($mm[0][0]??0),'used_mb'=>(int)($mm[0][1]??0),'pct'=>round(((int)($mm[0][1]??0)/max(1,(int)($mm[0][0]??1)))*100)];} if(preg_match('/UP_START\n(.+)\nUP_END/',$out,$m))$r['uptime']=trim($m[1]); if(preg_match('/SESS_START\n(\d+)\nSESS_END/',$out,$m))$r['sessions']=(int)$m[1]; if(preg_match('/CRON_START\n(\d+)\nCRON_END/',$out,$m))$r['crons']=(int)$m[1]; if(preg_match('/SVC_START\n(.+?)\nSVC_END/s',$out,$m)){$svcs=[];foreach(explode("\n",trim($m[1]))as $l){if(preg_match('/^(.+):(.+)$/',$l,$sm))$svcs[trim($sm[1])]=trim($sm[2]);}$r['services']=$svcs;} if(preg_match('/F2B_START\n(.+?)\nF2B_END/s',$out,$m)){$jails=0;if(preg_match('/Number of jail:\s+(\d+)/',$m[1],$jm))$jails=(int)$jm[1];$r['fail2ban']=['jails'=>$jails];} // === S89 DEEP CHECKS via local endpoint === $deep_raw = @file_get_contents('http://127.0.0.1:5890/api/sentinel-brain.php', false, stream_context_create(['http'=>['method'=>'POST','header'=>'Content-Type: application/x-www-form-urlencoded','content'=>http_build_query(['action'=>'exec','cmd'=>'php /opt/wevads/s89-health.php']),'timeout'=>5]])); $deep_json = json_decode($deep_raw, true); $deep_data = json_decode($deep_json['output'] ?? '{}', true); if ($deep_data && !isset($deep_data['error'])) { $r = array_merge($r, $deep_data); } die(json_encode($r)); } // --- S202 SCAN (PMTA + Email Infra) --- if ($api === 'scan_s151') { $r = ['server'=>'S202','timestamp'=>date('c'),'ip'=>'204.168.152.13','port'=>49222]; // SSH (port 49222) $fp = @fsockopen('204.168.152.13', 49222, $errno, $errstr, 3); $r['ssh'] = $fp ? 'up' : 'down'; if($fp) fclose($fp); // PMTA (check via SSH - port 25 not exposed externally by design) if ($r['ssh'] === 'up') { $pmta_check = shell_exec("ssh -p 49222 -o ConnectTimeout=3 -o StrictHostKeyChecking=no root@204.168.152.13 'systemctl is-active pmta 2>/dev/null' 2>/dev/null"); $r['pmta'] = (trim($pmta_check) === 'active') ? 'up' : 'down'; } else { $fp25 = @fsockopen('204.168.152.13', 25, $errno, $errstr, 3); $r['pmta'] = $fp25 ? 'up' : 'down'; if($fp25) fclose($fp25); } // Nginx (port 80) $fp80 = @fsockopen('204.168.152.13', 80, $errno, $errstr, 3); $r['nginx'] = $fp80 ? 'up' : 'down'; if($fp80) fclose($fp80); // Consent page (via Cloudflare) $chConsent = @file_get_contents("https://consent.wevup.app/ethica-consent-landing.html?id=1", false, stream_context_create(['http'=>['timeout'=>5],'ssl'=>['verify_peer'=>false,'verify_peer_name'=>false]])); $r['consent'] = ($chConsent !== false && strlen($chConsent) > 100) ? 'up' : 'down'; // Deep check via SSH if available if ($r['ssh'] === 'up') { $ssh_cmd = "ssh -p 49222 -o ConnectTimeout=3 -o StrictHostKeyChecking=no root@204.168.152.13 'echo SVC_START && systemctl is-active pmta postfix nginx 2>/dev/null && echo SVC_END && echo DISK_START && df -h /|tail -1 && echo DISK_END && echo MEM_START && free -h|grep Mem && echo MEM_END && echo UP_START && uptime -p && echo UP_END' 2>/dev/null"; $ssh_out = shell_exec($ssh_cmd); if ($ssh_out) { // Services if (preg_match('/SVC_START (.*?) SVC_END/s', $ssh_out, $m)) { $svcs = array_filter(explode("\n", trim($m[1]))); $svc_names = ['pmta','postfix','nginx']; $r['services'] = []; foreach ($svc_names as $i => $name) { $r['services'][$name] = trim($svcs[$i] ?? 'unknown'); } } // Disk if (preg_match('/DISK_START (.*?) DISK_END/s', $ssh_out, $m)) { if (preg_match('/(\d+)%/', $m[1], $dm)) $r['disk'] = ['usage_pct' => (int)$dm[1]]; } // Memory if (preg_match('/MEM_START (.*?) MEM_END/s', $ssh_out, $m)) { preg_match_all('/[\d.]+[GMK]?i?/', $m[1], $mm); if (count($mm[0]) >= 2) $r['memory'] = ['total' => $mm[0][0], 'used' => $mm[0][1]]; } // Uptime if (preg_match('/UP_START (.*?) UP_END/s', $ssh_out, $m)) { $r['uptime'] = trim($m[1]); } } } $r['status'] = ($r['ssh']==='up' && $r['pmta']==='up') ? 'online' : ($r['ssh']==='up' ? 'partial' : 'offline'); die(json_encode($r)); } // === ACTION: Ban IP === if ($api === 'ban_ip' && isset($_POST['ip'])) { $ip = preg_replace('/[^0-9\.]/','',$_POST['ip']); if(!filter_var($ip, FILTER_VALIDATE_IP)){die(json_encode(['ok'=>false,'error'=>'Invalid IP']));} $r = shell_exec("fail2ban-client set sshd banip $ip 2>&1"); tg_send("🚫 IP BANNED\n$ip banni via Cyber Monitor\nServeur: S88"); die(json_encode(['ok'=>true,'result'=>trim($r),'ip'=>$ip])); } // === ACTION: Unban IP === if ($api === 'unban_ip' && isset($_POST['ip'])) { $ip = preg_replace('/[^0-9\.]/','',$_POST['ip']); $r = shell_exec("fail2ban-client set sshd unbanip $ip 2>&1"); tg_send("✅ IP UNBANNED\n$ip débanni via Cyber Monitor"); die(json_encode(['ok'=>true,'result'=>trim($r),'ip'=>$ip])); } // === ACTION: Block IP via UFW === if ($api === 'block_ufw' && isset($_POST['ip'])) { $ip = preg_replace('/[^0-9\.]/','',$_POST['ip']); if(!filter_var($ip, FILTER_VALIDATE_IP)){die(json_encode(['ok'=>false,'error'=>'Invalid IP']));} $r = shell_exec("ufw deny from $ip 2>&1"); if(!isOurIP($ip)) { $g = geoIP($ip); tg_send("🛡️ UFW BLOCK\n$ip bloqué au firewall\n🌍 {$g['city']}, {$g['country']} ({$g['cc']})\n🏢 {$g['isp']}\nServeur: S88"); } die(json_encode(['ok'=>true,'result'=>trim($r),'ip'=>$ip])); } // === ACTION: Restart service === if ($api === 'restart_svc' && isset($_POST['service'])) { $svc = preg_replace('/[^a-z0-9\-\.]/','',$_POST['service']); $allowed = ['nginx','ollama','postgresql','redis-server','fail2ban','weval-node','docker','php8.3-fpm']; if(!in_array($svc,$allowed)){die(json_encode(['ok'=>false,'error'=>'Service not allowed']));} $r = shell_exec("systemctl restart $svc 2>&1"); $status = trim(shell_exec("systemctl is-active $svc 2>/dev/null")); tg_send("🔄 SERVICE RESTART\n$svc → $status\nServeur: S88"); die(json_encode(['ok'=>true,'service'=>$svc,'status'=>$status])); } // === ACTION: Send Telegram alert === if ($api === 'send_telegram' && isset($_POST['msg'])) { $r = tg_send($_POST['msg']); die(json_encode($r)); } // === ACTION: Test Telegram === if ($api === 'test_telegram') { $r = tg_send("🔔 WEVIA Cyber Monitor\nTest de connexion Telegram réussi ✅\n".date('Y-m-d H:i:s')); die(json_encode($r)); } // === ACTION: Trigger IA Defense === if ($api === 'ia_defense' && isset($_POST['mode'])) { $mode = $_POST['mode']; $results = []; if ($mode === 'full_scan') { // Scan all and report $atk = (int)trim(shell_exec("grep -cE 'wp-login|xmlrpc|phpmyadmin|\.env|shell\.php' /var/log/nginx/access.log 2>/dev/null")?:'0'); $bf = (int)trim(shell_exec("lastb 2>/dev/null|wc -l")?:'0'); $banned = (int)trim(shell_exec("fail2ban-client status sshd 2>/dev/null|grep 'Currently banned'|awk '{print \$NF}'")?:'0'); $results = ['web_attacks'=>$atk,'brute_force_attempts'=>$bf,'currently_banned'=>$banned]; tg_send("🤖 IA DEFENSE — Full Scan\n🌐 Web attacks: $atk\n🔐 Brute force: $bf\n🚫 IPs bannies: $banned"); } elseif ($mode === 'auto_ban') { // Auto-ban IPs with >10 brute force attempts $lastb = shell_exec("lastb 2>/dev/null | head -500"); $ips=[]; foreach(explode("\n",trim($lastb?:''))as $l){if(preg_match('/(\d+\.\d+\.\d+\.\d+)/',$l,$m))$ips[$m[1]]=($ips[$m[1]]??0)+1;} $banned_count=0;$banned_ips=[]; foreach($ips as $ip=>$count){ if($count>=10){ shell_exec("fail2ban-client set sshd banip $ip 2>/dev/null"); $banned_count++;$banned_ips[]="$ip ($count×)"; } } $results=['auto_banned'=>$banned_count,'ips'=>$banned_ips]; $list=implode("\n",$banned_ips); tg_send("🤖 IA DEFENSE — Auto-Ban\n$banned_count IPs bannies (>10 tentatives)\n$list"); } elseif ($mode === 'lockdown') { // Emergency: ban all attacking IPs + tighten UFW shell_exec("fail2ban-client set sshd bantime 86400 2>/dev/null"); // 24h ban $results=['lockdown'=>true,'ban_time'=>'24h']; tg_send("🔴 IA DEFENSE — LOCKDOWN MODE\n⚠️ Durée ban portée à 24h\nTous les services en mode défensif"); } elseif ($mode === 'stand_down') { shell_exec("fail2ban-client set sshd bantime 600 2>/dev/null"); // Back to 10min $results=['lockdown'=>false,'ban_time'=>'10min (normal)']; tg_send("✅ IA DEFENSE — Stand Down\nRetour au mode normal (ban 10min)"); } die(json_encode(['ok'=>true,'mode'=>$mode,'results'=>$results])); } die(json_encode(['error'=>'unknown'])); } ?> WEVIA Cyber Monitor v3 — Command Center

🛡️ WEVIA Cyber Command v3

Scanning...
⚠️

📋 Situation Room — Rapport de sécurité ...

Analyse en cours...

🌍 Origine des attaquants

🎯 Security Score

--
--

📡 Servers 3

ServerStatusCPURAMDiskUptimeServices
🖥️ S88 AI..................
📧 S89 Email..................
🔄 S202 Email/PMTA......

⚙️ Services S88 7

🎮 GPU RTX 4000 Ada

Utilization--
VRAM--
Temperature--
vLLM Models--

📧 S89 Brain Engine

PostgreSQL--
Tracking--
S3 Templates--
DB Tables--
Campaigns--
RAG Memcells--

👥 Live Sessions

Active 1h--
Conversations 24h--
Messages 24h--
Visitors Today--
Leads qualifiés--
Nginx active--

🚨 Brute Force S88 ▶ Drill-down

Total--
Unique IPs--
Fail2ban--

🔄 S202 Email/PMTAing ▶ Detail

Port 80 (HTTP)--
SSL direct (optionnel)--
Consent Ethica--
consent.wevup.app--
SSH (admin)--

🌐 Web Attacks 0 ▶ Drill-down

Total scans--
Top attacker--
Top path--
SSL Expiry--
SSL Days Left--

🔒 Database WEVIA

Conversations--
Messages--
KB Entries--
Telegram--

🔌 Open Ports S88 ▶ Drill-down

📧 Services S89