Skip to content

Latest commit

 

History

History
488 lines (331 loc) · 16.6 KB

File metadata and controls

488 lines (331 loc) · 16.6 KB

LaraC2 Shell -- User Guide

Step-by-step guide to configuring, connecting, and operating the MDE Live Response Interactive Shell.


Quick Start

Prerequisites

  • PowerShell Core 7.0+ -- install from PowerShell releases. Works on Windows, Linux, macOS.
  • Internal mode -- a portal account with Live Response access. Nothing else to configure.
  • Official mode -- an Azure app registration with Machine.Read.All, Machine.LiveResponse, and Library.Manage (with admin consent).

The fastest path (interactive)

git clone https://github.com/akefallonitis/larac2shell.git
cd larac2shell
pwsh -File shell/Invoke-MDEShell.ps1

The shell opens a unified 7-method auth menu. Pick one, authenticate, select a machine, and you're in a REPL. No config files, no flags.

Non-interactive (for CI / scripts)

# Pre-select mode to narrow the menu to just internal or just official
pwsh -File shell/Invoke-MDEShell.ps1 -Mode internal
pwsh -File shell/Invoke-MDEShell.ps1 -Mode official

# Run one command and exit. Exit code = remote command's exit code.
pwsh -File shell/Invoke-MDEShell.ps1 -Machine myhost -Command 'whoami'

# Unattended official mode (config with client credentials)
pwsh -File shell/Invoke-MDEShell.ps1 -Config shell/config/shell-config.json -Machine myhost -Command 'Get-Process explorer'

Switching modes inline

Once you're in the REPL you don't have to quit to change mode:

[INT myhost C:\]> mode
  Current mode: Internal API
  Switch with: 'mode internal' or 'mode official'.

[INT myhost C:\]> mode official
  [Mode] Switching from Internal API to official...
  (auth menu for official mode — pick 6 for device code or 7 for client credentials)
  [Mode] Now in official mode.
  Run 'machines' to list targets or 'connect <name|id>' to select one.

The switch disconnects the current LR session, wipes the old auth state, and re-runs the auth flow for the target mode. Machine selection is left to you — run machines to list, or connect <name|id> to jump to a target. One command, no restart.


Configuration (optional)

A config file is only required for one scenario: running the shell unattended in official mode with a client secret. Every other method authenticates interactively and stores nothing on disk.

If you don't need unattended client-credentials auth, skip this section entirely.

Creating the config file

Copy-Item shell/config/shell-config.example.json shell/config/shell-config.json
# Then edit the file: set official.tenantId, official.clientId, official.clientSecret

Config schema

{
  "official": {
    "tenantId":     "YOUR-TENANT-ID",
    "clientId":     "YOUR-CLIENT-ID",
    "clientSecret": "YOUR-CLIENT-SECRET",
    "useDeviceCode": false
  },
  "defaults": {
    "pollIntervalOfficial": 2,
    "pollIntervalInternal": 1,
    "commandTimeoutSeconds": 0,
    "defaultMachine": ""
  }
}
Field Required Description
official.tenantId Client creds / device code Azure AD tenant GUID
official.clientId Client creds / device code App registration client ID
official.clientSecret Client creds only App registration client secret
official.useDeviceCode No Set true to use device code instead of client credentials
defaults.pollIntervalOfficial No Seconds between status polls, official mode (default 2)
defaults.pollIntervalInternal No Seconds between status polls, internal mode (default 1)
defaults.commandTimeoutSeconds No Client-side timeout ceiling. 0 or unset = server decides (up to 1800s). The example config ships with 300. Per-command overrides (findfile, analyze, trace, getfile) are applied independently of this value.
defaults.defaultMachine No Auto-select this machine on startup (name substring or ID prefix)

App registration permissions

For official mode, the app registration needs these Application permissions with admin consent:

  • Machine.Read.All -- list enrolled machines
  • Machine.LiveResponse -- execute Live Response commands
  • Library.Manage -- manage library files

Config loading priority

  • CLI parameter -Mode narrows the auth menu; omit it to see all 7 methods.
  • CLI parameter -Machine overrides defaults.defaultMachine.
  • CLI parameter -Config overrides the LARAC2_CONFIG environment variable.

Security notes

  • The clientSecret is only read from the config file -- it is never accepted on the command line.
  • Restrict filesystem permissions on any config file containing a secret (Unix: chmod 600).
  • Internal-mode credentials (username, password, TOTP secret, cookies, TAP, passkey) are prompted interactively and never persisted to disk.
  • PSReadLine history is disabled while the shell is running, so nothing you type at the [API ...]> prompt ends up in the history file.

Connecting

Unified Auth Menu

When launching without the -Mode parameter, the shell presents a single screen with all 7 authentication methods. The API mode is derived from the choice:

  Select API mode:

    Internal API  (security.microsoft.com -- near real-time, ~2-5s/cmd)
    1  Credentials + MFA        username + password, TOTP/push/SMS [auto-refresh]
    2  Software passkey          FIDO2/WebAuthn JSON key file [auto-refresh]
    3  ESTS cookie               ESTSAUTHPERSISTENT from browser (~24hr)
    4  Temporary Access Pass     one-time admin-issued code
    5  Direct sccauth + XSRF     cookies from browser DevTools (~1hr)

    Official API  (api.securitycenter.microsoft.com -- CI/CD ready, ~20-60s/cmd)
    6  Device code               browser login (interactive)
    7  Client credentials        app registration with client secret

  Auth method (1-7):

Choices 1-5 set internal mode. Choices 6-7 set official mode.

Authentication Details

Method 1 -- Credentials + MFA

Enter username (UPN) and optionally a Base32 TOTP secret. With TOTP secret, MFA is fully automatic (no prompts). Without it, the shell supports push notifications (approve in Authenticator) or SMS codes. This method supports silent re-authentication when the session expires.

Tenant ID is auto-resolved from the username via OpenID discovery -- no need to provide it manually.

Method 2 -- Software Passkey

Provide the path to a FIDO2/WebAuthn JSON key file. Supports local PEM keys and Azure Key Vault HSM keys. This method supports silent re-authentication.

Method 3 -- ESTS Cookie

Paste the ESTSAUTHPERSISTENT cookie value from browser DevTools (Application > Cookies > login.microsoftonline.com). Lasts approximately 24 hours. Cannot auto-refresh.

Method 4 -- Temporary Access Pass

Enter your UPN and the one-time TAP code issued by an admin. Useful for break-glass access or onboarding. Cannot auto-refresh.

Method 5 -- Direct sccauth + XSRF

Paste the sccauth cookie and XSRF-TOKEN from browser DevTools. Lasts approximately 1 hour. Cannot auto-refresh.

Method 6 -- Device Code

Opens a browser URL for you to authenticate. Token expires in approximately 1 hour and cannot auto-refresh.

Method 7 -- Client Credentials

Uses a client secret from the config file. Auto-refreshes silently before expiry. Best for unattended/CI/CD operation.

Auth Refresh Behavior

Auth Method Auto-Refresh Session Lifetime
Client credentials (official) Yes, silent Indefinite
Device code (official) No ~1 hour
Credentials + TOTP (internal) Yes, silent Indefinite
Software passkey (internal) Yes, silent Indefinite
ESTS cookie (internal) No ~24 hours
Temporary Access Pass (internal) No ~1 hour
Direct sccauth (internal) No ~1 hour

Re-authentication

The connect command detects expired sessions and re-authenticates automatically. For methods with stored credentials, this is silent. For one-time methods, the shell prompts again.

Post-Authentication Init

After authentication, the shell automatically:

  1. Checks LR configuration (internal mode): Warns if unsigned script execution is disabled in the tenant.
  2. Uploads executor stubs: Checks if executor_b64.ps1 and executor_b64.sh exist in the MDE Library. Uploads them from the local stubs/ directory if missing. These are required for arbitrary command execution.

Machine Selection

After authentication, the shell displays a numbered machine list:

  #   Machine Name             OS              Status      Last Seen
  --  -----------------------  --------------  ----------  --------------------
   1  myhost                 Windows         Active      2026-04-02 14:22
   2  webserver-01             Linux           Active      2026-04-02 14:20
   3  file-server              Windows         Inactive    2026-03-29 08:00

  Select machine (number or name):

Select by:

  • Number: Enter the row number (e.g., 1)
  • Name substring: Enter part of the name (e.g., black)
  • ID prefix: Enter the start of the machine GUID

The shell connects to the selected machine and creates an LR session (internal mode) or prepares for stateless execution (official mode).


Running Commands

Native LR Commands (No Wrapper)

The 25 native commands are sent directly to the API using their proper command definitions. In internal mode, all native commands use the session's cached command definitions with proper param_id/value pairs.

[API myhost]> processes
[API myhost]> connections
[API myhost]> dir C:\Windows\Temp
[API myhost]> registry HKLM\Software\Microsoft
[API myhost]> getfile C:\Windows\System32\drivers\etc\hosts

Arbitrary Commands (B64 Wrapper -- Automatic)

Everything that is not a shell command or native LR command is automatically Base64-encoded and executed via the executor stub. You type commands naturally:

[API myhost]> whoami
[API myhost]> ipconfig /all
[API myhost]> Get-Process | Sort-Object CPU -Descending | Select-Object -First 10
[API myhost]> cat /etc/passwd

The shell detects the target OS and selects the right executor and encoding:

  • Windows: UTF-16-LE Base64 via executor_b64.ps1 (PowerShell)
  • Linux/macOS: UTF-8 Base64 via executor_b64.sh (bash)

Pipeline detection: Commands with pipes (|), semicolons (;), redirects (>>), or subexpressions ($() are always B64-wrapped, even if the first word is a native LR verb. For example, dir C:\ | Select-Object goes through B64, not native dir.

Library Scripts (Upload + Run)

For large or complex scripts:

[API myhost]> library upload ./my_investigation.ps1
[Library] Uploaded: my_investigation.ps1

[API myhost]> run my_investigation.ps1 -Param1 value1

Multi-Machine Execution

The multi command runs a single command across multiple machines at once:

[API myhost]> multi whoami
[Multi] Running 'whoami' on 4 machine(s)...

MachineName      Status    TimeMs Output
-----------      ------    ------ ------
myhost         Succeeded   4200 nt authority\system
webserver-01     Succeeded   3800 root
file-server      Succeeded   5100 nt authority\system

Filter by name pattern or limit the number of targets:

[API myhost]> multi -filter ws* hostname
[API myhost]> multi -top 3 id

Library Management

List Library Files

[API myhost]> library

Upload a File

[API myhost]> library upload ./scripts/collect_data.ps1
[Library] Uploaded: collect_data.ps1

Files over 20MB will produce a warning (documented API limit).

Delete a File

[API myhost]> library delete old_script.ps1

Download a File

[INT myhost]> library download executor_b64.ps1

Internal mode: Direct download from the library API.

Official mode: The public API has no direct library-content endpoint, so the shell issues a getfile against the endpoint's local library cache path (Windows: C:\ProgramData\Microsoft\Windows Defender Advanced Threat Protection\Downloads\, Linux: /var/opt/microsoft/mdatp/response/, macOS: /Library/Application Support/Microsoft/Defender/response/). Requires a machine to be selected, and the file must already be synced to that endpoint — library sync can take up to 10 minutes after upload.

Force Refresh

The library list is cached for 5 minutes. Force a refresh with:

[API myhost]> library refresh

Action Management

List Active Actions

[API myhost]> actions

List All Actions

[API myhost]> actions all

Cancel an Action

[API myhost]> actions cancel a1b2c3d4

Partial GUID matching is supported -- the shell finds the first action whose ID starts with your input.


Session Management

Internal Mode Sessions

Internal mode maintains a persistent LR session per machine:

  • Session creation: Automatic on first command after connect
  • 30-minute inactivity timeout: The shell detects this and auto-reconnects on the next command.
  • Session disconnect: Automatic when switching machines or running disconnect
  • Auth expiry: The shell attempts silent re-authentication (credential+TOTP or passkey). Otherwise, it prompts.
  • Session reuse: Transparent. The shell auto-connects, auto-reconnects, and handles cross-machine switching without user intervention.

Official Mode

Official mode is stateless -- each command is an independent API call. There is no persistent session to manage. The ActiveRequestAlreadyExists error is handled by the rate limiter (cancel conflicting actions + retry).

Checking Status

[API myhost]> status
  ------
  Mode        : official
  Auth Method : OAuth2 Client Credentials / Device Code
  Auth Status : Connected (token valid)
  Details     : Token expires in 45m
  Machine     : myhost
  Machine ID  : abc123def456...
  OS          : Windows
  ------

Internal mode also shows session ID, session age, and current working directory.

Switching Machines

[API myhost]> connect webserver-01
[Session] Disconnecting from previous machine...
[Machines] Selected: webserver-01 (Active - Linux)

Or use the picker:

[API myhost]> machines

Tips

Prompt Format

[API myhost]>          # Official mode
[INT myhost C:\]>      # Internal mode (with working directory)
[(no machine)]>          # No machine selected

Tab Completion

Press Tab to autocomplete commands, subcommands, and machine names.

Aliases

Use short aliases: ls for dir, ps for processes, download for getfile, netstat for connections.

Large Commands

If a command is too large for the Args field (~30KB limit), upload it as a library script:

library upload ./large_script.ps1
run large_script.ps1

Cross-OS Targeting

The shell auto-detects the target OS and selects the appropriate executor and encoding. No manual changes needed when switching between Windows and Linux/macOS targets.

Important: .sh stubs must have Unix line endings (LF, not CRLF) or bash will fail with "ambiguous redirect". Official API library upload does not sync .sh files to Linux/macOS endpoints -- upload via Internal API (portal) or the Defender portal UI first.

PSReadLine History

The shell disables PSReadLine history saving (HistorySaveStyle = SaveNothing) to prevent commands from being written to the history file on disk.

Config-Free Usage

pwsh -File shell/Invoke-MDEShell.ps1

The shell prompts for everything interactively.

Token and Session Lifetimes

Token/Session Lifetime Auto-Refresh
sccauth (internal) ~1 hour Yes (credential+TOTP/passkey)
XSRF-TOKEN (internal) 4 minutes Yes (automatic)
Bearer token (official) ~1 hour Yes (client credentials only)
LR session (internal) 30-min inactivity Yes (auto-reconnect)
Machine list cache 5 minutes machines refresh to force
Library list cache 5 minutes library refresh to force
Default timeout 1800s Server decides, not client

CLI Parameters

Parameter Description
-Mode official|internal Set API mode (skips unified menu)
-Config <path> Path to JSON config file
-Machine <name|id> Pre-select a machine (skips picker)
-Command <cmd> Run a single command non-interactively and exit
-PasskeyPath <path> Path to software passkey JSON file (internal mode)

Non-Interactive Scripting

# Run a command and capture output
$output = pwsh -File shell/Invoke-MDEShell.ps1 -Mode official -Config config.json `
    -Machine myhost -Command 'Get-Process explorer'

# Check exit code
echo $LASTEXITCODE

The exit code matches the remote command's exit code (0 = success).