# Tutorial: Hikvision engagement traps (breadcrumbs, honeytokens, topology)

**Audience:** Operators and purple-teamers who already run the Hikvision App-webs face and want high-fidelity signals for *human* recon, credential exfil reuse, and lateral-looking pivots.

**Time:** ~25-35 min  
**Outcome:** You exercise three planted traps, see Critical CTI tags in the outbox, and know what each alert means (and what it does *not* mean).

**Related:** Base face setup: [Hikvision App-webs decoy](hikvision-http-decoy.md) (Path A). Estate canaries (Ops planter): [Plant your first tripwire](plant-your-first-tripwire.md).

!!! warning "Not score-gated AI"
    These traps are **always planted** when `CYBERHALLUCINET_HTTP_HIKVISION=1` (per peer session). They do **not** turn on AI because a bot/human classifier fired ([SEC-AI-001](../security/invariants.md)). Bots that never open HTML comments or follow planted paths simply never hit them.

!!! note "No real cloud or RFC1918 listeners"
    Fiction `AKIA…` keys are non-authorizing lab markers. Synthetic NVR/NAS IPs (e.g. `10.10.20.5`) appear **only in XML bodies**: the sensor does not bind those addresses. Lateral signal = HTTP hit on the planted `managementURL` path.

## What you will learn

1. Breadcrumb: plant in login HTML → hit = Critical human recon  
2. Honeytoken: users / configurationFile → marker issue → reuse in a request = Critical  
3. Topology: post-compromise NAS fiction → planted path hit = Critical lateral attempt  
4. How to confirm tags in the CTI outbox

## Prerequisites

- Complete [Hikvision Path A](hikvision-http-decoy.md) once (sensor build, pack flag, CTI outbox)
- Same lab ports as Path A (`127.0.0.1:8081` below)

```bash
export CYBERHALLUCINET_HTTP_HIKVISION=1
export CYBERHALLUCINET_CTI_ENABLED=1
export CYBERHALLUCINET_CTI_OUTBOX=/tmp/chn-intel-hik/outbox
export CYBERHALLUCINET_CTI_LOG_DIR=/tmp/chn-intel-hik/logs
export CYBERHALLUCINET_CTI_IMMEDIATE=1
mkdir -p "$CYBERHALLUCINET_CTI_OUTBOX" "$CYBERHALLUCINET_CTI_LOG_DIR"

./bin/sensor \
  --profile=research \
  --listen-http=127.0.0.1:8081 \
  --intel-dir=/tmp/chn-intel-hik
```

Keep this sensor running in one terminal. Use another for the curls below.

## Mental model

```text
Peer session (source IP)
    │
    ├─ GET /  ──plant──► HTML comment /_internal_v2/camera_diag_<id>.php
    │                         │
    │                         └─ GET that path ──► human_recon_breadcrumb (Critical)
    │
    ├─ GET …/Security/users or configurationFile ──plant──► chn-canary-… (+ fiction AKIA)
    │                         │
    │                         └─ later request containing marker ──► honeytoken_reuse (Critical)
    │
    └─ after CVE fiction (PUT /SDK/webLanguage or users?auth=…)
          GET …/Network/nas ──plant──► NVR/NAS XML + managementURL tripwire path
                                          │
                                          └─ GET managementURL ──► lateral_topology (Critical)
```

TDD IDs: **TDD-286** (breadcrumb), **TDD-287** (honeytoken), **TDD-288** (topology).

---

## Trap 1: Breadcrumb (human recon)

Bots usually hit hardcoded CVE paths. Humans who view-source the login page may follow developer comments.

### Steps

```bash
BASE=http://127.0.0.1:8081

# 1) Fetch login HTML (plants a per-peer breadcrumb)
html=$(curl -sS "$BASE/")
printf '%s\n' "$html" | head -20

# 2) Extract the planted path from the HTML comment
path=$(printf '%s' "$html" | grep -oE '/_internal_v2/camera_diag_[a-f0-9]+\.php' | head -1)
echo "planted breadcrumb: $path"
test -n "$path" || { echo "no breadcrumb planted: is Hikvision flag on?"; exit 1; }

# 3) Hit the breadcrumb (this is the high-fidelity signal)
curl -sS -D- "$BASE$path" -o /tmp/hik-breadcrumb.xml | head
cat /tmp/hik-breadcrumb.xml
```

### What to expect

| Signal | Value |
|--------|--------|
| HTTP | `200` App-webs XML (`ResponseStatus`) |
| CTI / capture tags | `hikvision_tripwire`, `human_recon_breadcrumb`, `human_adversary_recon`, `critical` |
| Canary hook | `OnCanaryObserved` kind `hik_breadcrumb` (feeds `agent.canary_observed` when telemetry is armed) |

### Negative check

```bash
# Unplanted diag path must not fire the breadcrumb tripwire
curl -sS -D- "$BASE/_internal_v2/camera_diag_deadbeef.php" -o /dev/null | head -1
```

You may get a normal persona/404 response, that is fine. Only **planted** paths trip Critical recon.

---

## Trap 2: Honeytokens (config / users)

When an attacker dumps users or downloads `configurationFile`, the face embeds a unique `chn-canary-…` marker (and a fiction cloud key id in users XML). Issuance is registered like other markers. If the same marker later appears in a request from that engagement, you get a Critical reuse alert.

### Steps

```bash
BASE=http://127.0.0.1:8081

# 1) Dump users (marks compromise + embeds canary)
users=$(curl -sS "$BASE/ISAPI/Security/users?auth=YWRtaW46")
printf '%s\n' "$users"

marker=$(printf '%s' "$users" | grep -oE 'chn-canary-[a-f0-9]+' | head -1)
echo "honeytoken: $marker"
test -n "$marker" || { echo "no canary in users XML"; exit 1; }

# Optional: configurationFile also embeds the same session canary (XOR W200 blob)
curl -sS "$BASE/ISAPI/System/configurationFile" -o /tmp/hik-config.bin
xxd /tmp/hik-config.bin | head

# 2) Simulate "attacker uses the stolen marker" back at the decoy
curl -sS -D- -X POST "$BASE/ISAPI/System/deviceInfo" \
  --data "token=$marker" -o /tmp/hik-reuse.xml | head
cat /tmp/hik-reuse.xml
```

### What to expect

| Step | Signal |
|------|--------|
| Users / config download | Body contains `chn-canary-…`; users XML may also show fiction `AKIA…` under `svc_backup` |
| Issuance | `OnMarkerIssued` with protocol `hikvision` (telemetry: marker issued) |
| Reuse POST | Tags `honeytoken_reuse`, `hikvision_tripwire`, `critical` |

### Ops note

External use of a fiction `AKIA…` against real AWS is **not** detected by the sensor alone. Wire Ops canary/intelstore watchers separately if you want cloud-side validation ([catch a stolen cloud key](catch-a-stolen-cloud-key.md): plugin status may still be Partial).

With AI mode on, the broker may also inject `<!-- chn-canary-… -->` into `hikvision.isapi_xml` fills at `CYBERHALLUCINET_CANARY_INJECT_RATE` (default 0.1). Go `ValidateHikvisionISAPIXML` remains the wire authority.

---

## Trap 3: Synthetic topology (post-compromise pivot bait)

After the session is marked compromised, NAS/network fiction advertises internal NVR/NAS names and a **management URL path**. Following that path is treated as lateral-looking recon. The sensor never opens sockets on the fiction IPs.

### Steps

```bash
BASE=http://127.0.0.1:8081

# 1) Pre-compromise: NAS list should be empty (no pivot fiction yet)
curl -sS "$BASE/ISAPI/System/Network/nas"
echo

# 2) Compromise fiction (CVE-2021-36260 language PUT)
curl -sS -X PUT "$BASE/SDK/webLanguage" \
  -H 'Content-Type: application/xml' \
  --data '$(id)' >/dev/null

# 3) Post-compromise NAS fiction
nas=$(curl -sS "$BASE/ISAPI/System/Network/nas")
printf '%s\n' "$nas"

printf '%s' "$nas" | grep -E 'nvr-cluster-01|nas-backup|10\.10\.20\.|managementURL|_internal_v2/nvr_proxy_'

# 4) Hit the planted managementURL path
topo=$(printf '%s' "$nas" | grep -oE '/_internal_v2/nvr_proxy_[a-f0-9]+\.cgi' | head -1)
echo "topology tripwire: $topo"
test -n "$topo" || { echo "no topology path: did compromise succeed?"; exit 1; }

curl -sS -D- "$BASE$topo" -o /tmp/hik-topo.xml | head
cat /tmp/hik-topo.xml
```

### What to expect

| Phase | Signal |
|-------|--------|
| Pre-compromise NAS | Empty `<NASList>` (no corp hostnames) |
| Post-compromise NAS | `nvr-cluster-01.corp.internal`, `nas-backup.corp.internal`, fiction `10.10.20.5`, `managementURL` |
| Tripwire GET | Tags `lateral_topology`, `lateral_movement_attempt`, `hikvision_tripwire`, `critical` |

Users auth-bypass (`/ISAPI/Security/users?auth=…`) also marks compromise and plants topology the same way.

---

## Confirm CTI tags in the outbox

With `CYBERHALLUCINET_CTI_IMMEDIATE=1` and an outbox set:

```bash
# Recent jobs / tags (shape depends on FS outbox layout)
find "$CYBERHALLUCINET_CTI_OUTBOX" -type f 2>/dev/null | head
grep -R -l -E 'human_recon_breadcrumb|honeytoken_reuse|lateral_topology|hikvision_tripwire|critical' \
  "$CYBERHALLUCINET_CTI_OUTBOX" 2>/dev/null | head
```

If Investigate / deaddrop is wired, look for the same tag strings on the HTTP capture events for that peer.

| Tripwire tag | Meaning | Typical severity tags |
|--------------|---------|------------------------|
| `human_recon_breadcrumb` | Manual follow of planted HTML comment path (same peer IP) | `critical`, `human_adversary_recon` |
| `honeytoken_reuse` | Planted canary echoed back in a request | `critical`, `honeytoken_reuse` |
| `lateral_topology` | Followed post-compromise NAS `managementURL` (same peer IP) | `critical`, `lateral_movement_attempt` |

All three also carry `hikvision_tripwire` and the literal tag `critical`. Breadcrumb/topology paths are **peer-IP scoped**; honeytoken reuse still correlates if the stolen marker is presented from another IP.

---

## Purple-team script (one shot)

```bash
#!/usr/bin/env bash
set -euo pipefail
BASE=${BASE:-http://127.0.0.1:8081}

html=$(curl -sS "$BASE/")
bc=$(printf '%s' "$html" | grep -oE '/_internal_v2/camera_diag_[a-f0-9]+\.php' | head -1)
curl -sS "$BASE$bc" >/dev/null
echo "OK breadcrumb $bc"

users=$(curl -sS "$BASE/ISAPI/Security/users?auth=YWRtaW46")
marker=$(printf '%s' "$users" | grep -oE 'chn-canary-[a-f0-9]+' | head -1)
curl -sS -X POST "$BASE/ISAPI/System/deviceInfo" --data "token=$marker" >/dev/null
echo "OK honeytoken reuse $marker"

curl -sS -X PUT "$BASE/SDK/webLanguage" --data 'x' >/dev/null
nas=$(curl -sS "$BASE/ISAPI/System/Network/nas")
topo=$(printf '%s' "$nas" | grep -oE '/_internal_v2/nvr_proxy_[a-f0-9]+\.cgi' | head -1)
curl -sS "$BASE$topo" >/dev/null
echo "OK topology $topo"
```

---

## Troubleshooting

| Symptom | Check |
|---------|--------|
| No `/_internal_v2/camera_diag_…` in `/` | Pack flag on? Hitting the Hikvision listener (not another HTTP face)? |
| Breadcrumb GET does nothing special | Path must match the **exact** planted string (including hex suffix) |
| No `chn-canary-` in users | Use `/ISAPI/Security/users` with the pack enabled |
| NAS never shows NVR hosts | Compromise first (`PUT /SDK/webLanguage` or users `auth=`); same source IP for NAS GET |
| No Critical tags in outbox | `CYBERHALLUCINET_CTI_ENABLED=1`, outbox path writable, `CTI_IMMEDIATE=1` for lab |
| Expecting AI to “turn on” after breadcrumb | It will not: by design (SEC-AI-001). AI is operator `--mode=ai` / tier, not trap-driven |

## Next steps

- [Hikvision App-webs decoy](hikvision-http-decoy.md): Path B images, Path C ops fetch  
- [Plant your first tripwire](plant-your-first-tripwire.md): Ops estate canaries  
- [Purple team how-to](../how-to/purple-team.md): detection validation habits  
- TDD registry: TDD-286…288 in [docs/tdd/README.md](../tdd/README.md)
