# UHBS tutorial: benchmark Endlessh (SSH tarpit)

**Audience:** researchers / purple-team operators evaluating deception tools with UHBS v4  
**Time:** ~20-30 minutes  
**Target:** [skeeto/endlessh](https://github.com/skeeto/endlessh): an SSH *tarpit* that slowly drips random banner bytes and **never** completes an SSH handshake.

This tutorial mirrors the Cowrie lab flow: start the target on loopback, point the UHBS inventory at it, run **quick** and **full-lab** scorecards, then interpret results.

!!! warning "Authorized lab only"
    Only probe systems you own or have written permission to test. Bind Endlessh to `127.0.0.1`.

## Why Endlessh is a useful UHBS subject

| Property | Implication for UHBS |
|----------|----------------------|
| Speaks TCP `:22`-like port | Module A can open sockets |
| Never sends a valid `SSH-2.0-…` ID | Protocol fidelity collapses |
| No auth / shell / VFS | Modules B/C/E cannot establish sessions |
| Tiny C codebase, no outbound | Module D safety gate usually passes |
| Deliberate attacker time-waste | High real-world ops value ≠ high UHQS |

**Conclusion up front:** Endlessh is an excellent *tarpit*, not an interactive honeypot. UHBS grades interactive deception realism: expect a **low UHQS / GRADE F** even when the tool is doing its job correctly.

## Prerequisites

- UHBS harness: `scripts/benchmarks/` (+ venv with `PyYAML`, `paramiko`)
- C compiler (`cc`) to build Endlessh
- Free loopback port (this lab uses **2223**)

```bash
git clone --depth 1 https://github.com/skeeto/endlessh.git .local/endlessh/src
cd .local/endlessh/src && make
```

Minimal config (repo lab used `Delay 100`-`1000` ms):

```text
Port 2223
Delay 100
MaxLineLength 32
MaxClients 4096
LogLevel 1
BindFamily 0
```

```bash
./endlessh -f /path/to/config &
nc -z 127.0.0.1 2223   # should succeed
```

Inventory sketch (also at [`deploy/benchmarking/results/endlessh/inventory.example.yaml`](../../deploy/benchmarking/results/endlessh/inventory.example.yaml)):

```yaml
sites:
  endlessh-local:
    kind: generic
    class: Low-Interaction
    tps: low_interaction
    source_root: /path/to/endlessh/checkout
    host: 127.0.0.1
    protocols: [ssh]
    ports:
      ssh: 2223
    user: root
    password: root
```

## Quick run

```bash
python3 scripts/benchmarks/run_benchmark.py \
  --inventory /path/to/inventory.yaml \
  --target endlessh-local \
  --phases profile,static,dynamic,score \
  --modules A,B,C,D,E,F \
  --quick --skip-sast-tools \
  --out .local/bench-reports/endlessh-local/quick
```

### Quick scorecard (measured 2026-07-27)

```text
Module A: Protocol Fidelity         :  12.5/100
Module B: Behavioral Realism        :   6.2/100
Module C: Telemetry Quality         :  25.0/100
Module D: Safety & Containment (C)  :  96.0/100   GATE
Module E: Scalability & Latency     :  20.0/100
Module F: Static Code Audit         :  70.0/100
δ_C = 1.0
UHQS 4.0 = 26.94 / 100
GRADE F (Fail)
```

Canonical copy: [`deploy/benchmarking/results/endlessh/SCORECARD-quick.txt`](../../deploy/benchmarking/results/endlessh/SCORECARD-quick.txt).

## Full-lab notes

A naive “full” SSH suite against a tarpit **hangs**: Paramiko waits for a valid SSH banner that never arrives. In this lab:

1. Remeasure **F** (static) without `--quick`.
2. Keep **A/B/C/D/E** from the completed quick evidence pack (same failure modes; longer A3 only burns wall-clock).
3. Publish a combined full scorecard.

Result: **UHQS 26.94 / GRADE F**: identical composite to quick for this target class.

Artifacts: [`SCORECARD-full.txt`](../../deploy/benchmarking/results/endlessh/SCORECARD-full.txt), [`report-full.json`](../../deploy/benchmarking/results/endlessh/report-full.json).

!!! tip "Operational tip"
    Cap per-module wall-clock when benchmarking tarpits. Endlessh is *designed* to stall clients.

## Quick analysis

| Module | Score | What happened |
|--------|------:|---------------|
| **A** | 12.5 | No RFC4253 identification / KEXINIT: tarpit bytes ≠ SSH banner |
| **B** | 6.2 | No SSH session → no cross-session state / payload realism |
| **C** | 25.0 | No injectable session path; no STIX/ECS pipeline from Endlessh |
| **D** | 96.0 | No shell breakout surface; containment gate **passes** (δ_C=1.0) |
| **E** | 20.0 | 100% SSH connect/auth errors under load; latency metrics undefined |
| **F** | 70.0 | Small C tree looks clean on secret/SAST skips; 0% POSIX VFS coverage (N/A) |

**Weights used:** Low-Interaction (`w_A=0.30`, `w_B=0.15`, `w_C=0.25`, `w_E=0.10`, `w_F=0.20`).

## Comparison (same harness family)

| Target | Class | Protocols tested | UHQS | Grade |
|--------|-------|------------------|-----:|-------|
| **Endlessh** | Low-Interaction | ssh (tarpit) | **26.94** | F |
| **Cowrie** | Low-Interaction | ssh | **46.97** | F |
| **CyberHalluciNet research** | POSIX-Shell | ssh+http+modbus | **80.32** | B |

Endlessh scores below Cowrie because Cowrie at least completes SSH and offers an interactive shell illusion. CHN scores higher because it implements multi-protocol fidelity, sticky behavior, structured telemetry, and scale under the same UHBS rubric.

## Conclusions

1. **UHBS is working as designed.** A tarpit that refuses to speak SSH must fail Modules A/B/C/E.
2. **Low UHQS ≠ “bad tool.”** Endlessh’s product goal is *delay and frustrate scanners*, not emulate OpenSSH. Interpret UHQS in light of TPS class and intent.
3. **Safety can still pass.** Module D ≈ 96 with δ_C=1.0: Endlessh does not hand attackers a shell or host escape surface in this lab.
4. **Do not force full handshake suites** against tarpits without timeouts; you will measure client patience, not decoy quality.
5. **Use the right profile.** For pure tarpits, treat UHBS as a *negative control* / classification check: “Is this an interactive honeypot?” → No.

## Reproduce via MCP (optional)

With [`uhbs-mcp`](../../scripts/benchmarks/MCP_README.md) enabled:

1. `uhbs_validate_inventory` on the Endlessh inventory  
2. `uhbs_run_benchmark` with `quick=true`, `modules="A,B,C,D,E,F"`  
3. Read `uhqs.uhqs`, `uhqs.grade`, and the returned scorecard  

## Related

- Framework map: [deploy/benchmarking/FRAMEWORK.md](../../deploy/benchmarking/FRAMEWORK.md)
- Cowrie lab pattern: `deploy/benchmarking/docker-compose.yml`
- Results folder: [deploy/benchmarking/results/endlessh/](../../deploy/benchmarking/results/endlessh/)
