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)
- L’opérateur clique Ouvrir la console d’urgence sur un agent.
- Le dashboard demande raison (≥20 caractères) + code TOTP.
- L’API hub valide le rôle (admin/owner), TOTP, et le rate-limit (3 sessions/h/utilisateur).
- 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. - L’agent vérifie signature + nonce + TTL, spawn un shell local, ouvre un stream de touches vers le hub.
- 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.bashrcavec prompt rouge[MONSYS-CONSOLE]+HISTTIMEFORMAT
À chaque session :
setpriv --reuid=monsys-console --regid=monsys-console \ --init-groups --inh-caps=-all \ -- /bin/bash --restricted \ --rcfile /var/lib/monsys/console/.bashrcBash 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
MonsysJEAsous$Env:ProgramFiles\WindowsPowerShell\Modules\ - Écrit le Role Capability File
MonsysConsole.psrcavec la whitelist - Écrit le Session Configuration File
monsys-console-jea.psscavecRunAsVirtualAccount=$true,LanguageMode=NoLanguage,SessionType=RestrictedRemoteServer Register-PSSessionConfiguration -Name monsys-console-jea
À chaque session :
powershell.exe -NoLogo -NoProfile -NoExit \ -ConfigurationName monsys-console-jeaStdin/stdout du ConPTY est mappé sur le stream WS.
Ce que l’opérateur PEUT (whitelist)
Ensemble IR forensique, ~60 cmdlets :
| Catégorie | Cmdlets |
|---|---|
| Process | Get-Process, Stop-Process, Wait-Process, Debug-Process |
| Service | Get/Stop/Start/Restart/Suspend/Resume-Service, Set-Service |
| Event log | Get-EventLog, Get-WinEvent (pas de Clear-EventLog) |
| Réseau | Get-NetTCPConnection, Get-NetUDPEndpoint, Get-NetAdapter, Get-NetIPAddress, Get-NetIPConfiguration, Get-NetRoute, Get-DnsClient*, Resolve-DnsName, Test-Connection, Test-NetConnection |
| Containment | Disable/Enable-NetAdapter, New/Remove/Get-NetFirewallRule, Set-NetFirewallProfile |
| Utilisateurs | Get-LocalUser, Get-LocalGroup, Get-LocalGroupMember (pas Add/Set/Remove) |
| Filesystem | Get-ChildItem, Get-Item, Get-Content, Get-ItemProperty, Get-FileHash, Test-Path, Resolve-Path, Get-Acl, Get-AuthenticodeSignature |
| Tâches | Get-ScheduledTask, Disable-ScheduledTask |
| WMI/CIM | Get-CimInstance, Get-CimClass (pas d’Invoke-CimMethod) |
| Perf | Get-Counter, Get-ComputerInfo, Get-HotFix |
| Pipeline | ForEach-Object, Where-Object, Select-Object, Sort-Object, Group-Object, Measure-Object, Compare-Object, Format-*, Out-*, Select-String |
| Power | Restart-Computer, Stop-Computer |
Ce que l’opérateur NE PEUT PAS (bloqué par JEA)
Invoke-Expression,Invoke-Command— pas d’exécution arbitraireNew-LocalUser,Add-LocalGroupMember,Set-LocalUser— pas de nouveaux comptes privilégiésRemove-Item,Format-Volume— pas de destructionClear-EventLog— pas de tampering de preuvesSet-Aclsur des chemins critiques — pas de modifications de permissions.exehors whitelistNew-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é
| Linux | Windows | |
|---|---|---|
| Shell | bash --restricted | powershell (LanguageMode=NoLanguage) |
| Contexte utilisateur | monsys-console (low-priv) | JEA RunAs virtual account (éphémère) |
| Whitelist | Bash restricted | JEA RoleCapability (~60 cmdlets) |
| Destruction filesystem | Bloquée (redirects) | Remove-Item hors whitelist |
| Privilege escalation | Pas d’entrée sudoers | Virtual account, pas admin |
| Audit (hub) | console_audit_log avec SHA256 lockdown | idem |
| Audit (host fallback) | n/a | $ProgramData\monsys\console-transcripts\ |