88 lines
4.5 KiB
PHP
88 lines
4.5 KiB
PHP
<?php
|
|
// WEVIA Intent Helper : incident-postgres-cron-scan
|
|
// Wired by Opus 20 Apr - supervisor level
|
|
// Doctrine #2 zero regression, #3 GOLD-first, NO deletion - pure forensics
|
|
// Trigger : malicious cron postgres detected curl pastebin | sh since 2 Mar 2026
|
|
|
|
header('Content-Type: application/json');
|
|
|
|
$TS = date('Ymd-His');
|
|
$VAULT = '/opt/wevads/vault/incident-20260420-postgres-cron';
|
|
$out = [];
|
|
|
|
// Create vault dir for incident artifacts
|
|
@mkdir($VAULT, 0755, true);
|
|
|
|
// === 1. BACKUP crontab postgres INTACT ===
|
|
$cron_raw = @shell_exec('sudo cat /var/spool/cron/crontabs/postgres 2>&1');
|
|
@file_put_contents("$VAULT/crontab-postgres-{$TS}.txt", $cron_raw);
|
|
$out['crontab_backup'] = "$VAULT/crontab-postgres-{$TS}.txt";
|
|
$out['crontab_content'] = $cron_raw;
|
|
|
|
// === 2. List ALL cron jobs system-wide ===
|
|
$out['all_user_crontabs'] = trim(@shell_exec('sudo ls -la /var/spool/cron/crontabs/ 2>&1'));
|
|
$out['etc_cron_files'] = trim(@shell_exec('sudo find /etc/cron.d /etc/cron.daily /etc/cron.hourly /etc/cron.weekly /etc/cron.monthly /etc/crontab 2>/dev/null -type f -exec ls -la {} +'));
|
|
|
|
// === 3. Files owned by postgres outside PG data dir (prévention scope) ===
|
|
$out['postgres_files_outside_pgdata'] = trim(@shell_exec(
|
|
'sudo find / -user postgres -type f 2>/dev/null | grep -v "^/var/lib/postgresql" | grep -v "^/proc" | grep -v "^/sys" | head -50'
|
|
));
|
|
|
|
// === 4. Authorized_keys / SSH persistence ===
|
|
$out['postgres_ssh'] = trim(@shell_exec('sudo ls -la /var/lib/postgresql/.ssh 2>&1'));
|
|
$out['postgres_authorized_keys'] = trim(@shell_exec('sudo cat /var/lib/postgresql/.ssh/authorized_keys 2>/dev/null || echo NONE'));
|
|
$out['all_authorized_keys'] = trim(@shell_exec('sudo find / -name authorized_keys -type f 2>/dev/null | head -20'));
|
|
|
|
// === 5. Systemd user services (persistence vector) ===
|
|
$out['systemd_user_services'] = trim(@shell_exec('sudo find /etc/systemd/system /var/lib/systemd /home -name "*.service" 2>/dev/null | grep -iE "postgres|miner|crypto|kworker|kdevtmpfs|kinsing" | head -20'));
|
|
|
|
// === 6. LD_PRELOAD + /etc/ld.so.preload (rootkit vector) ===
|
|
$out['ld_preload_env'] = trim(@shell_exec('env | grep -i preload ; cat /etc/ld.so.preload 2>/dev/null || echo NO_PRELOAD'));
|
|
|
|
// === 7. Hidden binaries in /tmp /var/tmp /dev/shm ===
|
|
$out['hidden_binaries'] = trim(@shell_exec('sudo find /tmp /var/tmp /dev/shm -type f \( -name ".*" -o -executable \) 2>/dev/null | head -30'));
|
|
|
|
// === 8. Listening ports not in WEVAL expected set ===
|
|
$out['listening_ports'] = trim(@shell_exec('sudo ss -ltnp 2>/dev/null | head -40'));
|
|
|
|
// === 9. Processes started by postgres (non-pg DB) ===
|
|
$out['postgres_non_db_procs'] = trim(@shell_exec(
|
|
"ps -eo pid,user,etimes,cmd 2>/dev/null | awk '\$2==\"postgres\" && \$4 !~ /^postgres/ && \$4 !~ /^\\/usr\\/lib\\/postgres/ {print}' | head -20"
|
|
));
|
|
|
|
// === 10. Recent files (<7 days) in /tmp /var/tmp - typical dropper locations ===
|
|
$out['recent_tmp_files'] = trim(@shell_exec('sudo find /tmp /var/tmp -type f -mtime -7 2>/dev/null | head -30'));
|
|
|
|
// === 11. Pastebin URL fetch (read only, log content seen) ===
|
|
$pb = @shell_exec('curl -s --max-time 10 https://pastebin.com/raw/C0Y31fxq 2>/dev/null');
|
|
$out['pastebin_current_content_len'] = strlen((string)$pb);
|
|
$out['pastebin_current_content_md5'] = md5((string)$pb);
|
|
$out['pastebin_current_content_snippet'] = substr((string)$pb, 0, 500);
|
|
@file_put_contents("$VAULT/pastebin-content-{$TS}.txt", $pb);
|
|
|
|
// === 12. Crowdsec / fail2ban events ===
|
|
$out['crowdsec_decisions'] = trim(@shell_exec('sudo cscli decisions list 2>/dev/null | head -20'));
|
|
|
|
// === 13. Syslog last 500 lines grep cron postgres ===
|
|
$out['syslog_cron_postgres'] = trim(@shell_exec('sudo grep -E "CRON.*postgres" /var/log/syslog /var/log/syslog.1 2>/dev/null | tail -30'));
|
|
|
|
// === Save full dump ===
|
|
$full_path = "$VAULT/scan-{$TS}.json";
|
|
@file_put_contents($full_path, json_encode($out, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
|
|
|
// === Summary ===
|
|
echo json_encode([
|
|
'tool' => 'incident-postgres-cron-scan',
|
|
'status' => 'diagnostic_only_no_deletion',
|
|
'vault_dir' => $VAULT,
|
|
'full_dump' => $full_path,
|
|
'ts' => date('c'),
|
|
'summary' => [
|
|
'malicious_cron_present' => (strpos($cron_raw, 'pastebin.com/raw/C0Y31fxq') !== false),
|
|
'pastebin_content_md5' => $out['pastebin_current_content_md5'],
|
|
'pastebin_size' => $out['pastebin_current_content_len'],
|
|
'files_postgres_outside_pg' => substr_count($out['postgres_files_outside_pgdata'], "\n") + 1,
|
|
],
|
|
'next_step' => 'Review vault dump, decide removal (Option B) or escalate',
|
|
], JSON_PRETTY_PRINT);
|