# Tutorial: your first real high-interaction (Live) session

**Audience:** Operators who have already run a Contained/Emulated lab and now
want to see the Live tier **actually execute** attacker commands on a real
disposable VM.

**Time:** about 30-40 minutes
**Outcome:** An attacker connects to your SSH (and optionally Telnet/HTTP)
decoys, exercises real guest execution / reverse-proxy, and you confirm the
work landed on a throwaway backend, not on a simulated shell.

!!! danger "Live runs real code"
    In Live tier, the attacker's commands execute for real on the backend VM.
    Use a **disposable** VM you can destroy, keep it on an isolated network with
    no real egress, and never point Live at anything you care about. Contained
    and Emulated never do this, only Live, and only when you opt in.

## What you will learn

1. Why Live is gated and what "opt-in" means in practice
2. How to stand up a throwaway backend VM as the execution guest
3. How to start the sensor in Live tier pointed at that VM
4. How to connect as an attacker and prove real execution
5. How to confirm the tier and read the session evidence

## Prerequisites

- A working Contained/Emulated lab (see
  [beginner lab](beginner-student-lab.md)), you understand starting the sensor
  and connecting with `ssh`.
- A **disposable** Linux VM with an SSH server and throwaway credentials,
  reachable from the sensor host. This tutorial uses a local Docker container as
  the burnable VM so you need nothing but Docker.
- The `sensor` binary built (`make build` or your usual build).

## Step 1: Understand the gates (why Live is off by default)

Live only engages when **all** of these are true:

- requested tier is `live`,
- `CYBERHALLUCINET_LIVE_ACK=I_UNDERSTAND_LIVE_INTERACTION` (exact string),
- `--profile=production`,
- a Z13 backend zone is present (configuring a backend satisfies this),
- the fleet ceiling allows `live`.

Miss any one and the sensor **fails closed**: it silently serves the safe
Emulated shell instead of executing anything. That is by design.

## Step 2: Create a throwaway backend VM

For the lab we use a container as the disposable "VM". Create one running an
SSH server with a throwaway account:

```bash
docker run -d --name chn-live-guest \
  -p 127.0.0.1:22022:22 \
  --rm \
  lscr.io/linuxserver/openssh-server:latest >/dev/null 2>&1 || true

# Simpler alternative: any Linux image with sshd and a guest:guestpw login,
# published on 127.0.0.1:22022. The only requirements are:
#   - reachable host:port over SSH
#   - a throwaway username/password (NEVER real/admin credentials)
```

!!! tip "Real deployments"
    In production the backend is a real disposable VM (its own microVM,
    cloud instance, or isolated host). The container here is only to make the
    tutorial self-contained. Whatever you use, it must be **burnable** and
    network-isolated.

Confirm you can reach it and log in with the throwaway account (say
`guest` / `guestpw` on `127.0.0.1:22022`). If your image uses different
credentials, substitute them below.

## Step 3: Start the sensor in Live tier

Point the sensor's SSH decoy at the backend VM. Keep the decoy on loopback.

```bash
export CYBERHALLUCINET_LIVE_ACK=I_UNDERSTAND_LIVE_INTERACTION

sensor \
  --profile=production \
  --interaction=live \
  --listen-status=127.0.0.1:8080 \
  --listen-ssh=127.0.0.1:2222 \
  --live-backend='guest:guestpw@127.0.0.1:22022' \
  --live-pool-warm=1 \
  --live-pool-max=2 \
  --live-session-minutes=15 \
  --live-idle-minutes=5
```

On startup you should see a log line like:

```
sensor: LIVE shell proxy enabled: 1 disposable VM SSH target(s), warm=1 max=2
```

If instead you see `no --live-backend / --live-http-backend configured`, the
backend flag did not parse: recheck the `user:pass@host:port` form.

## Step 4: Confirm the active tier

Query the private status endpoint (loopback only):

```bash
curl -s http://127.0.0.1:8080/healthz | python3 -m json.tool
```

Look for:

```json
{
  "requested_tier": "live",
  "active_tier": "live",
  "downgrade_reason": ""
}
```

If `active_tier` is `contained`, read `downgrade_reason` and fix the gate it
names (for example `live_ack_required` or `production_attestation_required`).
See the [reference gates table](../reference/live-proxy.md#activation-gates).

## Step 5: Play the attacker and prove real execution

Connect to the **decoy** (not the backend) and run commands:

```bash
ssh -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null app@127.0.0.1
```

Use the decoy persona password (research/synthetic). Once in, try:

```bash
uname -a
whoami
FOO=hello; echo "$FOO from $(hostname)"
echo "written by attacker" > /tmp/chn-proof.txt && cat /tmp/chn-proof.txt
```

These are executing on the **backend VM**. Two ways to prove it:

- **State persists**: `FOO=hello` then `echo "$FOO"` returns `hello`: a
  simulated shell would not carry the variable.
- **Side effects are real**: open a separate shell on the backend VM and confirm
  the file exists:

```bash
ssh -p 22022 guest@127.0.0.1 'cat /tmp/chn-proof.txt'
# -> written by attacker
```

The file was created by the attacker's session on the real VM.

## Step 6: Read the evidence

The Live session is recorded like any other engagement:

- **TTY replay** captures the input/output stream (sanitized).
- **Session intel** records each command as `live_exec` with the response text.
- **Containment events** show `live_session` (guest leased) and `live_command`
  (per command): useful for SOC detections.

See [investigate-intel](../how-to/investigate-intel.md) for reading transcripts.

## Step 7: Tear down

```bash
# stop the sensor (Ctrl-C), then destroy the burnable backend:
docker rm -f chn-live-guest 2>/dev/null || true
rm -f /tmp/chn-proof.txt 2>/dev/null || true
```

Always destroy the backend VM after a Live session: treat it as contaminated.

## Optional: Telnet and HTTP Live checks

With the same Live gates and shell backend, Telnet reuses the SSH guest shell
after decoy login:

```bash
# sensor also needs --listen-telnet=127.0.0.1:2323
printf 'app\nanypass\necho chn-telnet-live && id -u\nexit\n' | nc 127.0.0.1 2323
```

For HTTP Live, run a burnable HTTP service on the guest (or another throwaway
origin) and point the sensor at it:

```bash
sensor ... --listen-http=127.0.0.1:8081 \
  --live-http-backend='http://127.0.0.1:18080'

curl -sS http://127.0.0.1:8081/anything
# body/headers come from the guest HTTP service (not persona Emulated routes)
```

FTP has no Live path: leave it Emulated/Contained.

## Checkpoint: did it work?

- [ ] Startup logged `LIVE shell proxy enabled` (and/or `LIVE HTTP reverse-proxy`)
- [ ] `active_tier` was `live` with empty `downgrade_reason`
- [ ] A shell variable persisted across commands
- [ ] A file the attacker wrote existed on the backend VM
- [ ] (Optional) Telnet Live returned real `id -u` output
- [ ] (Optional) HTTP Live returned the guest body
- [ ] You destroyed the backend VM afterward

## What to read next

- [Tutorial: fail-closed and the kill-switch](live-failclosed-killswitch.md) : 
  see Live degrade safely and drain on demand
- [Tutorial: a pool of backend VMs](live-backend-pool.md): multiple targets,
  capacity, reaping, and failover
- [How-to: enable Live](../how-to/live-proxy.md): the condensed procedure
- [Explanation: how it works](../architecture/live-proxy.md): marker framing,
  trust zones, residual risk
