Aller au contenu

Console d'urgence

Pourquoi une console d’urgence

Quand une alerte vous dit “quelque chose d’étrange tourne sur l’hôte X”, vous voulez souvent regarder tout de suite. Installer SSH/RDP partout = grande surface d’attaque, charge de gestion, et pas de trail forensique. La console d’urgence ouvre via le tunnel WS de l’agent un shell court et ciblé — sans ouvrir de ports, sans credentials permanents sur l’hôte, avec une journalisation complète côté serveur.

Flux d’authentification (identique sur tous les OS)

  1. L’opérateur clique Ouvrir la console d’urgence sur un agent.
  2. Le dashboard demande raison (≥20 caractères) + code TOTP.
  3. L’API hub valide le rôle (admin/owner), TOTP, et le rate-limit (3 sessions/h/utilisateur).
  4. Le hub signe un token de session console Ed25519 (TTL 15 min, nonce, lié à l’agent) et pousse un frame console_start à l’agent via la WebSocket existante.
  5. L’agent vérifie signature + nonce + TTL, spawn un shell local, ouvre un stream de touches vers le hub.
  6. Le navigateur ouvre wss://api.monsys.ai/ws/console/<session_id> — flux binaire bidirectionnel.

Chaque octet I/O est écrit dans console_audit_log côté hub (direction=‘I’ pour l’entrée, ‘O’ pour la sortie) avec sequence_num et agent_id. À la fin de la session, un SHA256 du log complet est calculé et fixé sur console_sessions.audit_hash comme preuve forensique.

Côté Linux — bash --restricted sous monsys-console

À l’installation de l’agent :

  • useradd -r -s /bin/false -d /var/lib/monsys/console monsys-console
  • .bashrc avec prompt rouge [MONSYS-CONSOLE] + HISTTIMEFORMAT

À chaque session :

Fenêtre de terminal
setpriv --reuid=monsys-console --regid=monsys-console \
--init-groups --inh-caps=-all \
-- /bin/bash --restricted \
--rcfile /var/lib/monsys/console/.bashrc

Bash restricted bloque cd, les redirections avec >, et la modification de PATH. Les caps sont stripées. Le fragment sudoers pour monsys-console est vide → pas d’escalation possible.

Côté Windows — ConPTY + PowerShell avec JEA

Sous Windows, une pseudo-console (ConPTY, API native depuis Win10 1809) donne une vraie expérience terminal (couleurs, resize, ctrl-c), et Just Enough Administration (JEA) applique la whitelist côté serveur.

À l’installation (install.ps1) :

  • Crée le module MonsysJEA sous $Env:ProgramFiles\WindowsPowerShell\Modules\
  • Écrit le Role Capability File MonsysConsole.psrc avec la whitelist
  • Écrit le Session Configuration File monsys-console-jea.pssc avec RunAsVirtualAccount=$true, LanguageMode=NoLanguage, SessionType=RestrictedRemoteServer
  • Register-PSSessionConfiguration -Name monsys-console-jea

À chaque session :

powershell.exe -NoLogo -NoProfile -NoExit \
-ConfigurationName monsys-console-jea

Stdin/stdout du ConPTY est mappé sur le stream WS.

Ce que l’opérateur PEUT (whitelist)

Ensemble IR forensique, ~60 cmdlets :

CatégorieCmdlets
ProcessGet-Process, Stop-Process, Wait-Process, Debug-Process
ServiceGet/Stop/Start/Restart/Suspend/Resume-Service, Set-Service
Event logGet-EventLog, Get-WinEvent (pas de Clear-EventLog)
RéseauGet-NetTCPConnection, Get-NetUDPEndpoint, Get-NetAdapter, Get-NetIPAddress, Get-NetIPConfiguration, Get-NetRoute, Get-DnsClient*, Resolve-DnsName, Test-Connection, Test-NetConnection
ContainmentDisable/Enable-NetAdapter, New/Remove/Get-NetFirewallRule, Set-NetFirewallProfile
UtilisateursGet-LocalUser, Get-LocalGroup, Get-LocalGroupMember (pas Add/Set/Remove)
FilesystemGet-ChildItem, Get-Item, Get-Content, Get-ItemProperty, Get-FileHash, Test-Path, Resolve-Path, Get-Acl, Get-AuthenticodeSignature
TâchesGet-ScheduledTask, Disable-ScheduledTask
WMI/CIMGet-CimInstance, Get-CimClass (pas d’Invoke-CimMethod)
PerfGet-Counter, Get-ComputerInfo, Get-HotFix
PipelineForEach-Object, Where-Object, Select-Object, Sort-Object, Group-Object, Measure-Object, Compare-Object, Format-*, Out-*, Select-String
PowerRestart-Computer, Stop-Computer

Ce que l’opérateur NE PEUT PAS (bloqué par JEA)

  • Invoke-Expression, Invoke-Command — pas d’exécution arbitraire
  • New-LocalUser, Add-LocalGroupMember, Set-LocalUser — pas de nouveaux comptes privilégiés
  • Remove-Item, Format-Volume — pas de destruction
  • Clear-EventLog — pas de tampering de preuves
  • Set-Acl sur des chemins critiques — pas de modifications de permissions
  • .exe hors whitelist
  • New-PSSession — pas de pivoting vers d’autres hôtes
  • Scripts ou expansion de variables (LanguageMode=NoLanguage) — uniquement des invocations de cmdlets isolées

Tentative d’une cmdlet bloquée → erreur rouge côté serveur :

The term 'Remove-Item' is not recognized as the name of a cmdlet, function, ...

Les transcripts JEA sont aussi écrits localement sous $Env:ProgramData\monsys\console-transcripts\ comme trail forensique secondaire. La trail primaire reste console_audit_log côté hub.

Fin de session

La session se termine sur :

  • Déconnexion du navigateur
  • TTL 15 min atteint
  • exit / Exit-PSSession
  • Tenant suspendu → le hub ferme toutes les sessions ouvertes

À la fermeture, un SHA256 du console_audit_log complet (ordre sequence_num) est calculé et épinglé sur la row de session. Ce hash peut être comparé plus tard pour prouver l’intégrité du log.

Permissions résumé

LinuxWindows
Shellbash --restrictedpowershell (LanguageMode=NoLanguage)
Contexte utilisateurmonsys-console (low-priv)JEA RunAs virtual account (éphémère)
WhitelistBash restrictedJEA RoleCapability (~60 cmdlets)
Destruction filesystemBloquée (redirects)Remove-Item hors whitelist
Privilege escalationPas d’entrée sudoersVirtual account, pas admin
Audit (hub)console_audit_log avec SHA256 lockdownidem
Audit (host fallback)n/a$ProgramData\monsys\console-transcripts\