feat: rootless podman, session hardening, boot stability, sidebar fix

Rootless podman migration (TASK-11):
- Remove sudo from all podman calls in PodmanClient + 8 backend files
- Remove sudo from all podman/docker calls in deploy script
- Restore full systemd security hardening: NoNewPrivileges,
  RestrictAddressFamilies, MemoryDenyWriteExecute, RestrictRealtime,
  RestrictNamespaces, RestrictSUIDSGID, SystemCallFilter, ProtectSystem=strict
- Enable loginctl linger for rootless container persistence
- Remove Ollama from auto-deploy (marketplace-only)

Session & auth hardening:
- Increase MAX_CONCURRENT_SESSIONS 20→50 (prevents eviction storms)
- Debounced 401 redirect in rpc-client.ts (prevents redirect storms)

Boot stability:
- optimize-debian.sh: adds chrony, swap, removes policy-rc.d
- deploy script: pre-restart chrony + swap setup
- ISO build: chrony package, swap file creation
- BootScreen: no longer clears localStorage (prevents splash replay)
- RootRedirect: sole owner of localStorage clearing on server ready

UI fixes:
- Sidebar opacity default changed from 0→visible (fixes missing sidebar
  after page-persistence login without entrance animation)
- Console.log/error wrapped in import.meta.env.DEV guards
- Remove unused route import from RootRedirect

Beta tracking:
- CLAUDE.md: beta freeze protocol added
- MASTER_PLAN.md: TASK-11, TASK-17, phase structure
- BETA-PROGRESS.md: initial tracking doc
- Tagged v1.2.0-alpha.1 as pre-rootless baseline

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-18 13:53:27 +00:00
co-authored by Claude Opus 4.6
parent 934d120243
commit 870ff095d8
48 changed files with 2979 additions and 2196 deletions
@@ -0,0 +1,619 @@
# Archipelago Attack Surface Analysis
**Target:** 192.168.1.228
**Date:** 2026-03-18
**Scope:** Authorized security assessment — full infrastructure
**Assessor:** Automated recon + source code review
---
## 1. Target Overview
### Technologies Detected
| Layer | Technology | Version |
|-------|-----------|---------|
| OS | Debian 12 (Bookworm) | x86_64, kernel unknown |
| Web Server | nginx | 1.22.1 |
| Reverse Proxy (alt) | OpenResty | (port 81, Nginx Proxy Manager) |
| Backend | Rust (custom binary) | 0.1.0 (`archipelago`) |
| Frontend | Vue 3 + TypeScript + Vite 7 | SPA at `/` |
| Container Runtime | Podman (rootless) | — |
| Lightning | LND | auto-generated TLS cert |
| Bitcoin | Bitcoin Core/Knots | mainnet, block 941146 |
| Monitoring | Grafana | 10.2.0 |
| Uptime | Uptime Kuma | (port 3001) |
| Proxy Manager | Nginx Proxy Manager | 2.14.0 |
| SSH | OpenSSH | 9.2p1 Debian 2+deb12u7 |
| TLS | Self-signed cert | CN=archipelago.local, expires 2027-02-17 |
### Open Ports and Services
| Port | Service | Protocol | Direct Access |
|------|---------|----------|---------------|
| 22 | SSH (OpenSSH 9.2p1) | TCP | Yes |
| 80 | Nginx (main reverse proxy) | HTTP | Yes |
| 81 | Nginx Proxy Manager (OpenResty) | HTTP | Yes |
| 443 | Nginx (HTTPS, self-signed) | HTTPS | Yes |
| 3000 | Grafana | HTTP | Yes |
| 3001 | Uptime Kuma | HTTP | Yes |
| 5678 | Archipelago Rust backend | HTTP | Yes (behind nginx) |
| 7777 | IndeedHub (nginx 1.29.6) | HTTP | Yes |
| 8080 | LND REST API | HTTPS (TLS) | Yes |
| 8334 | Bitcoin UI (custom nginx) | HTTP | Inferred from config |
| 8083 | FileBrowser | HTTP | Inferred from config |
| 8888 | SearXNG | HTTP | Inferred from config |
| 9000 | Portainer | HTTP | Yes |
| 11434 | Ollama (local LLM) | HTTP | Inferred from config |
| 3141/3142 | Claude OAuth Proxy | HTTP | Internal |
### Subdomains Discovered
- `archipelago.local` (self-signed cert SAN)
- No external subdomains (internal LAN deployment)
---
## 2. Complete Endpoint Map
### 2.1 Nginx HTTP Routes (Port 80/443)
#### Unauthenticated Endpoints
| Method | Path | Backend | Source | Auth Enforced |
|--------|------|---------|--------|---------------|
| GET | `/health` | 127.0.0.1:5678 | nginx config line ~45 | **None** |
| GET | `/electrs-status` | 127.0.0.1:5678 | nginx config, CORS `*` | **None** |
| GET | `/lnd-connect-info` | 127.0.0.1:5678 | nginx config, CORS `*` | **None** |
| GET | `/content` | 127.0.0.1:5678 | nginx config | **None** (P2P) |
| GET | `/content/*` | 127.0.0.1:5678 | nginx config | **None** (P2P) |
| POST | `/dwn` | 127.0.0.1:5678 | nginx config | **None** (P2P) |
| GET | `/dwn/health` | 127.0.0.1:5678 | nginx config | **None** |
| POST | `/archipelago/node-message` | 127.0.0.1:5678 | nginx config | **None** (P2P) |
| GET | `/` | Static SPA | nginx config | **None** |
| GET | `/assets/*` | Static files | nginx config | **None** |
| GET | `/nostr-provider.js` | Static file | nginx config | **None** |
#### Authenticated Endpoints (Session Cookie Required)
| Method | Path | Backend | Source | Notes |
|--------|------|---------|--------|-------|
| POST | `/rpc/v1` | 127.0.0.1:5678 | nginx config | Rate limited: 20r/s, burst 40. 1MB body. 600s timeout |
| WS | `/ws/db` | 127.0.0.1:5678 | nginx config | WebSocket upgrade. 86400s timeout |
| GET | `/api/container/logs*` | 127.0.0.1:5678 | handler.rs | Query: `?app_id=&lines=` |
| GET | `/proxy/lnd/*` | 127.0.0.1:8080 | handler.rs | Proxies to LND REST API |
| GET | `/aiui/api/claude/*` | 127.0.0.1:3141 | nginx config | Streaming. 300s timeout |
| GET | `/aiui/api/ollama/*` | 127.0.0.1:11434 | nginx config | Streaming. 300s timeout |
| GET | `/aiui/api/openrouter/*` | openrouter.ai | nginx config | External API proxy |
| GET | `/aiui/api/web-search` | 127.0.0.1:8888 | nginx config | SearXNG. 30s timeout |
#### App Proxy Routes (`/app/*`)
All inject `nostr-provider.js`, strip X-Frame-Options, re-apply SAMEORIGIN.
| Path | Backend Port | Timeout | Special |
|------|-------------|---------|---------|
| `/app/bitcoin-ui/` | 8334 | 5s | — |
| `/app/electrumx/` | 50002 | 5s | — |
| `/app/grafana/` | 3000 | 5s | — |
| `/app/uptime-kuma/` | 3001 | 5s | — |
| `/app/searxng/` | 8888 | 5s | — |
| `/app/portainer/` | 9000 | 5s | — |
| `/app/filebrowser/` | 8083 | 5s | 10GB upload limit; path traversal check |
| `/app/jellyfin/` | 8096 | 5s | — |
| `/app/photoprism/` | 2342 | 5s | — |
| `/app/onlyoffice/` | 9980 | 5s | — |
| `/app/tailscale/` | 8240 | 5s | — |
| `/app/ollama/` | 11434 | 5s | — |
| `/app/nginx-proxy-manager/` | 81 | 5s | — |
| `/app/lnd/` | 8081 | 300s | Long timeout |
| `/app/mempool/` | 4080 | 300s | Long timeout |
| `/app/fedimint/` | 8175 | 300s | Long timeout |
| `/app/fedimint-gateway/` | 8176 | 300s | Long timeout |
| `/app/nextcloud/` | 8085 | 300s | — |
| `/app/vaultwarden/` | 8082 | 300s | Password manager |
| `/app/immich/` | 2283 | 300s | — |
| `/app/penpot/` | 9001 | 300s | — |
| `/app/indeedhub/` | 7777 | 5s | Complex URL rewriting, WebSocket |
#### External Site Proxies (Separate Ports)
| Port | Upstream | Purpose |
|------|----------|---------|
| 8901 | botfights.net | Nostr proxy |
| 8902 | 484.kitchen | Nostr proxy |
| 8903 | present.l484.com | Nostr proxy |
### 2.2 Rust Backend RPC Methods (`POST /rpc/v1`)
**Protocol:** JSON-RPC 2.0
**Content-Type:** `application/json`
**Auth:** Session cookie (except where noted)
#### Unauthenticated RPC Methods (No Session Required)
| Method | Parameters | Returns | Source |
|--------|-----------|---------|--------|
| `auth.login` | `password` | Sets session cookie | `api/rpc/auth.rs` |
| `auth.login.totp` | `token`, `code` | Session | `api/rpc/auth.rs` |
| `auth.login.backup` | `token`, `backup_code` | Session | `api/rpc/auth.rs` |
| `auth.isOnboardingComplete` | — | `boolean` | `api/rpc/auth.rs` |
| `auth.isSetup` | — | `boolean` | `api/rpc/auth.rs` |
| `backup.restore-identity` | `backup_file`, `password` | `{did}` | `api/rpc/mod.rs` |
| `federation.get-state` | — | `{state}` | P2P inter-node |
| `federation.peer-joined` | `peer_did`, `address` | — | P2P inter-node |
| `federation.peer-address-changed` | `peer_did`, `new_address` | — | P2P inter-node |
#### Authenticated RPC Methods (150+ total, grouped by domain)
<details>
<summary><b>Authentication & Session (12 methods)</b></summary>
| Method | Parameters | Purpose |
|--------|-----------|---------|
| `auth.logout` | — | Invalidate session |
| `auth.changePassword` | `currentPassword`, `newPassword` | Change password |
| `auth.onboardingComplete` | — | Mark onboarding done |
| `auth.resetOnboarding` | — | Reset onboarding |
| `auth.totp.setup.begin` | — | Get TOTP secret + QR |
| `auth.totp.setup.confirm` | `code` | Confirm TOTP setup |
| `auth.totp.disable` | `password` | Disable 2FA |
| `auth.totp.status` | — | Check 2FA enabled |
</details>
<details>
<summary><b>Container Management (10 methods)</b></summary>
| Method | Parameters | Purpose |
|--------|-----------|---------|
| `container-install` | `image`, `name` | Install container |
| `container-start` | `app_id` | Start container |
| `container-stop` | `app_id` | Stop container |
| `container-remove` | `app_id` | Remove container |
| `container-list` | — | List all containers |
| `container-status` | `app_id` | Container status |
| `container-logs` | `app_id`, `lines` | Container logs |
| `container-health` | `app_id` | Container health |
| `bundled-app-start` | `app_id` | Start bundled app |
| `bundled-app-stop` | `app_id` | Stop bundled app |
</details>
<details>
<summary><b>Package Management (5 methods)</b></summary>
| Method | Parameters | Purpose |
|--------|-----------|---------|
| `package.install` | `package_id`, `version` | Install from marketplace |
| `package.start` | `package_id` | Start package |
| `package.stop` | `package_id` | Stop package |
| `package.restart` | `package_id` | Restart package |
| `package.uninstall` | `package_id` | Uninstall |
</details>
<details>
<summary><b>Bitcoin & Lightning (15 methods)</b></summary>
| Method | Parameters | Purpose |
|--------|-----------|---------|
| `bitcoin.getinfo` | — | Bitcoin Core info |
| `lnd.getinfo` | — | LND node info |
| `lnd.listchannels` | — | List channels |
| `lnd.openchannel` | `peer_pubkey`, `local_funding_amount` | Open channel |
| `lnd.closechannel` | `channel_point` | Close channel |
| `lnd.newaddress` | — | Generate address |
| `lnd.sendcoins` | `address`, `amount_sats` | Send BTC |
| `lnd.createinvoice` | `amount_sats`, `memo` | Create invoice |
| `lnd.payinvoice` | `payment_request` | Pay invoice |
| `lnd.create-psbt` | `inputs`, `outputs` | Create PSBT |
| `lnd.finalize-psbt` | `psbt` | Broadcast PSBT |
| `lnd.create-raw-tx` | `inputs`, `outputs` | Raw transaction |
| `lnd.gettransactions` | — | Wallet history |
| `lnd.connect-info` | — | LND connection string |
</details>
<details>
<summary><b>Identity & Crypto (30+ methods)</b></summary>
Covers: identity CRUD, DID resolution, Nostr key operations, NIP-04/NIP-44 encryption/decryption, verifiable credentials (issue/verify/revoke), presentations, DHT DID, NIP-05 names, key export.
</details>
<details>
<summary><b>Node & P2P (15+ methods)</b></summary>
Covers: node DID, challenge signing, backup creation, Tor address, Nostr publishing, peer management, message sending, peer discovery.
</details>
<details>
<summary><b>Federation (10 methods)</b></summary>
Covers: invite generation, joining, node listing, node removal, trust scoring, state sync, app deployment.
</details>
<details>
<summary><b>Mesh Networking (20+ methods)</b></summary>
Covers: status, peers, messaging, broadcast, LoRa configuration, invoice relay, GPS coordinates, emergency alerts, deadman switch, Bitcoin tx relay, Lightning relay, block headers, X3DH prekey rotation.
</details>
<details>
<summary><b>Ecash Wallet (6 methods)</b></summary>
Covers: balance, mint, melt, send, receive, transaction history.
</details>
<details>
<summary><b>Content Sharing (7 methods)</b></summary>
Covers: list own content, add/remove files, pricing, availability, browse/download from peers.
</details>
<details>
<summary><b>DWN (7 methods)</b></summary>
Covers: status, sync, protocol management, message query/write.
</details>
<details>
<summary><b>Network & Infrastructure (20+ methods)</b></summary>
Covers: network interfaces, WiFi scan/config, Ethernet config, DNS config, UPnP router discovery/forwarding, Tor service management (list/create/delete/rotate), Nostr relay management, VPN config.
</details>
<details>
<summary><b>System Management (15+ methods)</b></summary>
Covers: system stats, processes, temperature, USB detection, disk status/cleanup, factory reset, monitoring (current/history/alerts), updates (check/download/apply/rollback), backup (create/list/verify/restore/USB/S3).
</details>
<details>
<summary><b>Other (10+ methods)</b></summary>
Covers: server naming, analytics opt-in/out, webhook config, security secret rotation, marketplace discovery/publishing.
</details>
### 2.3 Direct HTTP Endpoints (Backend)
| Method | Path | Auth | Source |
|--------|------|------|--------|
| GET | `/health` | None | `handler.rs:~120` |
| GET | `/electrs-status` | None | `handler.rs` |
| GET | `/lnd-connect-info` | None | `handler.rs` |
| GET | `/content` | None | `handler.rs` |
| GET | `/content/*` | None | `handler.rs` (Range header support) |
| POST | `/archipelago/node-message` | P2P validation | `handler.rs` |
| GET | `/dwn/health` | None | `handler.rs` |
| POST | `/dwn` | None (P2P) | `handler.rs` |
| WS | `/ws/db` | Session cookie | `handler.rs:514-625` |
| GET | `/api/container/logs*` | Session | `handler.rs` |
| GET | `/proxy/lnd/*` | Session | `handler.rs` |
### 2.4 Direct Port Services
| Port | Service | Own Auth | Notes |
|------|---------|----------|-------|
| 3000 | Grafana | Session/Basic | Login page directly accessible |
| 3001 | Uptime Kuma | Session | Redirects to /dashboard |
| 81 | Nginx Proxy Manager | Session | Login page directly accessible |
| 7777 | IndeedHub | Nostr NIP-07 | Full app accessible |
| 8080 | LND REST | TLS + Macaroon | Requires valid macaroon header |
| 8334 | Bitcoin UI | None/Basic Auth on `/bitcoin-rpc/` | Hardcoded creds in nginx config |
| 9000 | Portainer | Session | Redirects to timeout (possibly unconfigured) |
### 2.5 WebSocket Endpoints
| Path | Auth | Protocol | Features |
|------|------|----------|----------|
| `/ws/db` | Session cookie | JSON Patch | 30s ping, 5min inactivity timeout, state streaming |
| `/app/indeedhub/ws/` | Nostr | WebSocket | 86400s timeout |
---
## 3. Attack Surface Map
### 3.1 Input Vectors
| Vector | Endpoint(s) | Input Type | Validation |
|--------|------------|------------|------------|
| Password login | `auth.login` | JSON body (`password`) | Bcrypt comparison, rate limited (5/min) |
| TOTP code | `auth.login.totp` | JSON body (`code`) | Constant-time comparison, 5 attempts |
| RPC method dispatch | `/rpc/v1` | JSON body (`method`, `params`) | Switch on method name, typed params |
| Container image install | `container-install` | JSON body (`image`) | Image name passed to Podman |
| File upload | `/app/filebrowser/` | Multipart/file body | 10GB limit, path traversal check |
| P2P messages | `/archipelago/node-message` | JSON body | Source validation (Tor onion) |
| DWN writes | `/dwn` | JSON body | Protocol validation |
| Content download | `/content/*` | URL path + Range header | Path-based content ID lookup |
| Bitcoin transactions | `lnd.sendcoins`, `lnd.payinvoice` | JSON body (address, amount) | Address validation |
| DNS configuration | `network.configure-dns` | JSON body (servers) | Server address validation |
| WiFi config | `network.configure-wifi` | JSON body (ssid, password) | — |
| Package install | `package.install` | JSON body (id, version, url) | marketplace URL fetched |
| Federation join | `federation.join` | JSON body (invite code) | Code validation |
| Webhook config | `webhook.configure` | JSON body (url, events) | URL stored, callbacks sent |
| Bitcoin RPC proxy | `8334:/bitcoin-rpc/` | JSON body (method, params) | Basic Auth (hardcoded) |
| Factory reset | `system.factory-reset` | JSON body (`confirm: true`) | Auth + confirm flag |
### 3.2 Authentication Mechanisms
| Mechanism | Used By | Strength |
|-----------|---------|----------|
| Password + bcrypt (cost 12) | Main login | Strong (rate limited) |
| TOTP (RFC 6238) | 2FA | Strong (constant-time, replay-protected) |
| Session cookie (256-bit random) | All authenticated endpoints | Strong (HttpOnly, SameSite=Strict) |
| Remember-me (HMAC-SHA256) | Session persistence | Medium (derived from machine-id) |
| CSRF token | State-changing operations | Present but enforcement unclear |
| Macaroon (LND) | LND REST API | Strong (but exposed via endpoint) |
| Basic Auth (hardcoded) | Bitcoin UI RPC proxy | **Weak** (hardcoded in config) |
| Default creds (Grafana) | Grafana admin | **Weak** (admin:admin works) |
| No auth | 8 HTTP endpoints, 6 RPC methods | **N/A** |
### 3.3 Data Flow
```
User Browser
├─[Session Cookie]──→ Nginx (80/443)
│ ├──→ /rpc/v1 ──→ Rust Backend (5678) ──→ Podman containers
│ ├──→ /ws/db ──→ WebSocket state stream
│ ├──→ /app/* ──→ Container UIs (iframes)
│ └──→ /aiui/* ──→ Claude Proxy (3141) ──→ Anthropic API
├─[No Auth]──→ /health, /electrs-status, /lnd-connect-info, /content, /dwn
├─[Direct Port]──→ Grafana:3000 (admin:admin)
├─[Direct Port]──→ NPM:81 (session)
├─[Direct Port]──→ LND:8080 (TLS + macaroon)
└─[Direct Port]──→ Bitcoin UI:8334 (Basic Auth hardcoded)
```
---
## 4. Interesting Findings
### CRITICAL
#### 4.1 Unauthenticated LND Admin Macaroon Exposure
- **Endpoint:** `GET /lnd-connect-info` (no auth required)
- **Confirmed:** Returns full admin macaroon (base64url), TLS certificate, gRPC port (10009), REST port (8080)
- **Macaroon permissions:** `address:rw`, `info:rw`, `invoices:rw`, `macaroon:generate/rw`, `message:rw`, `offchain:rw`, `onchain:rw`, `peers:rw`, `signer:generate/read`
- **Impact:** Any host on the LAN can retrieve the admin macaroon and gain **full control** of the Lightning node — send all funds, open/close channels, create invoices, sign messages. This is the equivalent of exposing a root password to the Bitcoin wallet.
- **CORS:** `Access-Control-Allow-Origin: *` (any origin)
**Proof:**
```bash
curl -sk http://192.168.1.228/lnd-connect-info
# Returns: {"cert_base64url":"MIIC...","grpc_port":10009,"macaroon_base64url":"AgED...","rest_port":8080}
```
#### 4.2 Grafana Default Credentials (admin:admin)
- **Endpoint:** `http://192.168.1.228:3000`
- **Confirmed:** `admin:admin` returns full organization data
- **Version:** Grafana 10.2.0 (commit 895fbafb7a)
- **Impact:** Full access to monitoring dashboards, data sources, alert rules. Can potentially access connected databases, execute queries, and pivot to other services via configured data sources.
**Proof:**
```bash
curl -sk http://192.168.1.228:3000/api/org -u admin:admin
# Returns: {"id":1,"name":"Main Org.","address":{...}}
```
#### 4.3 Bitcoin RPC Full Access via Hardcoded Credentials
- **Endpoint:** `POST http://192.168.1.228:8334/bitcoin-rpc/`
- **Credentials:** `archipelago:archipelago123` (hardcoded in `docker/bitcoin-ui/nginx.conf`)
- **Confirmed:** Returns full `getblockchaininfo` — mainnet, block 941146, 828GB on disk
- **Impact:** Full Bitcoin Core RPC access. Depending on wallet configuration, could call `sendtoaddress`, `dumpprivkey`, `listunspent`, or any other RPC method. Mainnet node with real funds.
**Proof:**
```bash
curl -sk -X POST http://192.168.1.228:8334/bitcoin-rpc/ \
-u archipelago:archipelago123 \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"1.0","id":"test","method":"getblockchaininfo","params":[]}'
# Returns: {"result":{"chain":"main","blocks":941146,...},"error":null}
```
### HIGH
#### 4.4 Unauthenticated Content Catalog Exposure
- **Endpoint:** `GET /content`
- **Confirmed:** Returns complete file catalog — filenames, sizes, MIME types, UUIDs
- **Data leaked:** Personal music files with full paths (`/Music/1 - Govcucks.wav`, etc.)
- **Impact:** Information disclosure of personal files shared via P2P. File UUIDs could be used to download content via `/content/{id}`.
#### 4.5 Nginx Proxy Manager Accessible on LAN
- **Endpoint:** `http://192.168.1.228:81`
- **API Status:** `{"status":"OK","setup":false,"version":{"major":2,"minor":14,"revision":0}}`
- **`setup: false`** — Unclear if this means initial setup hasn't completed (would allow admin takeover) or refers to some other state
- **Impact:** NPM controls reverse proxy routing for all services. Compromise = ability to redirect traffic, intercept credentials, or add malicious proxy rules.
### MEDIUM
#### 4.6 Version and Service Information Disclosure
| Source | Information Exposed |
|--------|-------------------|
| HTTP `Server` header | `nginx/1.22.1` |
| Port 81 `Server` header | `openresty` |
| Port 3000 `/api/health` | Grafana 10.2.0, commit hash, database status |
| Port 81 `/api/` | NPM version 2.14.0 |
| Port 8080 TLS cert | `lnd autogenerated cert`, internal IPs, Tailscale IPs |
| Port 443 TLS cert | SANs include: 192.168.1.228, 192.168.1.198, 10.0.0.1, archipelago.local |
| SSH banner | OpenSSH 9.2p1 Debian 2+deb12u7, ECDSA + ED25519 host keys |
| `/electrs-status` | Blockchain sync: 99%, index size 124.8GB, network height |
| `/dwn/health` | 1027 messages, 10 protocols, 551KB storage |
| `auth.isOnboardingComplete` | Node setup state (returns `true`) |
| Error responses | "Password Incorrect" (confirms account exists) |
#### 4.7 LND TLS Certificate Leaks Internal Network Topology
The LND auto-generated TLS cert (port 8080) exposes SANs including:
- Internal IPs: `192.168.1.228`, `10.88.0.1` (Podman bridge)
- Tailscale IPs: `2A00:23C5:E31:A001:572F:29BF:5A00:2D46` (IPv6)
- Link-local IPs: 5 different `FE80::` addresses (reveals all network interfaces)
#### 4.8 CSP Allows `unsafe-inline`
```
script-src 'self' 'unsafe-inline'
style-src 'self' 'unsafe-inline'
```
While necessary for the Vue SPA, `unsafe-inline` for scripts significantly weakens XSS protection. If any injection point exists, inline script execution is possible.
#### 4.9 `connect-src` Allows Broad Connections
```
connect-src 'self' ws: wss: http://192.168.1.228:* https:
```
Allows JavaScript to connect to ANY port on the host and ANY HTTPS endpoint. An XSS payload could exfiltrate data to external servers or interact with any local service port.
#### 4.10 DWN Endpoint Accepts Unauthenticated Queries
- **Endpoint:** `POST /dwn`
- **Confirmed:** Accepts JSON queries and returns results
- **Impact:** Remote parties can query DWN records. While designed for P2P, the lack of access control means any network-adjacent attacker can enumerate stored data.
### LOW / INFORMATIONAL
#### 4.11 Login Rate Limiting Works
Rate limiting triggers after 4 failed attempts (returns HTTP 429). Effective against brute force. However, the limit is per-IP, not per-account — an attacker with multiple IPs could parallelize attempts.
#### 4.12 CORS Properly Restricts Origins
CORS preflight for `Origin: http://evil.com` returns no `Access-Control-Allow-Origin` header. Only configured origins (`http://192.168.1.228`, `http://localhost:8100`) are allowed. WebSocket also returns 401 without valid session.
#### 4.13 Path Traversal Mitigated
`/content/../../../etc/passwd` returns the SPA index.html (nginx catches it). URL-encoded traversal (`%2f..%2f`) returns 400 Bad Request. FileBrowser has explicit `..` regex checks in nginx config.
#### 4.14 Git/Env Files Not Exposed
`/.git/HEAD` and `/.env` both return the SPA index.html (Vue Router catch-all). No source code or credential leakage.
#### 4.15 Security Headers Present
All security headers are properly set: HSTS, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy, X-DNS-Prefetch-Control. This is above average for self-hosted applications.
---
## 5. Priority Targets
### Rank 1: LND Admin Macaroon via `/lnd-connect-info` (CRITICAL)
- **What:** Unauthenticated HTTP endpoint returns full admin macaroon for LND Lightning node
- **Why it's critical:** Grants complete control over Lightning funds — send payments, drain channels, create invoices. No authentication required. Accessible to any device on the LAN.
- **Category:** Broken Access Control (OWASP A01:2021)
- **Remediation:** Require session authentication on `/lnd-connect-info`. Use read-only macaroon for status checks; only expose admin macaroon via authenticated RPC.
### Rank 2: Bitcoin RPC via Hardcoded Credentials (CRITICAL)
- **What:** Port 8334 proxies Bitcoin Core RPC with hardcoded Basic Auth `archipelago:archipelago123`
- **Why it's critical:** Mainnet Bitcoin node. If wallet is loaded, attacker can send transactions, export private keys, or manipulate the mempool. Credentials are in version-controlled nginx config.
- **Category:** Security Misconfiguration (OWASP A05:2021), Hardcoded Credentials
- **Remediation:** Remove hardcoded credentials from nginx config. Proxy Bitcoin RPC through the authenticated Rust backend only. Restrict port 8334 to localhost.
### Rank 3: Grafana Default Credentials (HIGH)
- **What:** Grafana on port 3000 accepts `admin:admin`
- **Why it's critical:** Full admin access to monitoring infrastructure. Grafana can query connected data sources (Prometheus, InfluxDB), potentially exposing system metrics, logs, and providing a pivot point. Version 10.2.0 may have known CVEs.
- **Category:** Identification and Authentication Failures (OWASP A07:2021)
- **Remediation:** Change default password. Restrict Grafana to localhost access only (proxy through authenticated nginx). Consider enabling Grafana's built-in auth proxy mode.
### Rank 4: Unauthenticated Content Catalog (HIGH)
- **What:** `GET /content` exposes personal files (names, sizes, UUIDs) without authentication
- **Why it's concerning:** Reveals personal data. UUIDs may allow direct file download via `/content/{id}`. Designed for P2P but accessible from any LAN host.
- **Category:** Broken Access Control (OWASP A01:2021)
- **Remediation:** Require peer authentication (DID signature verification) for content catalog access, not just content downloads.
### Rank 5: Nginx Proxy Manager Direct Access (HIGH)
- **What:** Port 81 serves NPM admin interface directly on LAN with `setup: false` status
- **Why it's concerning:** NPM controls all reverse proxy rules. If the "setup" state allows initial admin creation by anyone, an attacker could take over routing. Even with auth, direct port access bypasses the main nginx security headers.
- **Category:** Security Misconfiguration (OWASP A05:2021)
- **Remediation:** Restrict port 81 to localhost. Only expose NPM through the authenticated `/app/nginx-proxy-manager/` proxy path.
### Rank 6: Service Ports Directly Accessible on LAN (MEDIUM)
- **What:** Ports 3000, 3001, 7777, 8080, 8334, 9000 are directly accessible, bypassing the main nginx proxy and its security headers/CSP/CORS
- **Why it's concerning:** Each service has its own (potentially weaker) authentication. Direct access bypasses rate limiting, security headers, and session validation at the nginx layer.
- **Category:** Security Misconfiguration (OWASP A05:2021)
- **Remediation:** Bind container ports to `127.0.0.1` or Podman bridge network only. All external access should flow through the nginx proxy on port 80/443.
### Rank 7: RPC Input Injection Surface (MEDIUM)
- **What:** 150+ RPC methods accept JSON parameters that control container operations, system commands, network config, file operations, and Bitcoin transactions
- **Why it's concerning:** Methods like `container-install` (image name → Podman), `network.configure-dns` (DNS servers), `webhook.configure` (arbitrary URL callbacks), `package.install` (marketplace URL fetch) all accept user-controlled strings that interact with system commands or external services.
- **Category:** Injection (OWASP A03:2021), SSRF (OWASP A10:2021)
- **Remediation:** Audit each method for proper input sanitization. Especially: container image names (prevent registry confusion), webhook URLs (prevent SSRF), DNS servers (prevent DNS rebinding), marketplace URLs (prevent SSRF).
### Rank 8: CSP `unsafe-inline` + Broad `connect-src` (MEDIUM)
- **What:** CSP allows inline scripts and connections to any port on the host or any HTTPS endpoint
- **Why it's concerning:** If any XSS vector exists (e.g., in app iframe content, reflected parameters, or injected HTML), the attacker can execute arbitrary JavaScript and exfiltrate data to external servers or interact with all local services.
- **Category:** XSS / Security Misconfiguration (OWASP A03/A05:2021)
- **Remediation:** Migrate to nonce-based CSP. Restrict `connect-src` to specific required ports/domains.
---
## Appendix: Security Headers (Full)
```http
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-DNS-Prefetch-Control: off
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline';
style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:;
font-src 'self' data:; connect-src 'self' ws: wss: http://192.168.1.228:* https:;
frame-src 'self' http://192.168.1.228:* https:; frame-ancestors 'self';
base-uri 'self'; form-action 'self';
Server: nginx/1.22.1
```
## Appendix: Rate Limiting Configuration
| Layer | Target | Rate | Burst |
|-------|--------|------|-------|
| Nginx | `/rpc/` | 20 req/s | 40 |
| Backend | `auth.login` | 5 per 60s per IP | — |
| Backend | Financial ops (send, pay) | 5-10 per 300s | — |
| Backend | Auth changes (password, TOTP) | 3 per 300s | — |
| Backend | Container ops | 5 per 300s | — |
| Backend | Federation join | 5 per 60s | — |
## Appendix: Authentication Summary
| What's Good | What Needs Work |
|-------------|-----------------|
| Bcrypt cost 12 for passwords | `/lnd-connect-info` unauthenticated |
| Argon2id for TOTP key derivation | Bitcoin RPC hardcoded creds |
| ChaCha20-Poly1305 for TOTP secret encryption | Grafana default admin:admin |
| 256-bit random session tokens | Service ports directly accessible |
| HttpOnly + SameSite=Strict cookies | CSP unsafe-inline |
| Rate limiting on login (5/min) | NPM port 81 open on LAN |
| CORS origin validation | connect-src too permissive |
| Session rotation on password change | Initial password only 8 chars |
| TOTP replay protection | Error messages confirm account existence |
| AES-256-GCM secrets at rest | Rate limiter enforcement unclear for some methods |
+659 -1
View File
@@ -1 +1,659 @@
# Nmap 7.98 scan initiated Fri Mar 6 01:40:27 2026 as: nmap -sV -sC --top-ports 1000 -oN /Users/dorian/Projects/archy/loop/pentest/recon/nmap.txt 192.168.1.228
# Nmap 7.98 scan initiated Wed Mar 18 11:29:44 2026 as: nmap -sV -sC --top-ports 1000 -oN /Users/dorian/Projects/archy/loop/pentest/recon/nmap.txt 192.168.1.228
Nmap scan report for 192.168.1.228
Host is up (0.0030s latency).
Not shown: 980 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u7 (protocol 2.0)
| ssh-hostkey:
| 256 60:1f:1b:cb:db:5d:25:bf:35:37:9e:22:4c:c1:75:d5 (ECDSA)
|_ 256 1e:3f:6a:b7:4b:e2:d8:8b:ee:34:a4:fd:3b:e3:b7:44 (ED25519)
80/tcp open http nginx 1.22.1
|_http-server-header: nginx/1.22.1
|_http-title: Archipelago OS
81/tcp open http OpenResty web app server
|_http-title: Nginx Proxy Manager
|_http-server-header: openresty
443/tcp open ssl/http nginx 1.22.1
| ssl-cert: Subject: commonName=archipelago.local/organizationName=Archipelago/countryName=US
| Subject Alternative Name: DNS:archipelago.local, DNS:localhost, IP Address:127.0.0.1, IP Address:192.168.1.228, IP Address:192.168.1.198, IP Address:10.0.0.1
| Not valid before: 2026-02-17T21:33:45
|_Not valid after: 2027-02-17T21:33:45
|_http-title: Archipelago OS
|_ssl-date: TLS randomness does not represent time
|_http-server-header: nginx/1.22.1
3000/tcp open http Grafana http
|_http-trane-info: Problem with XML parsing of /evox/about
| http-robots.txt: 1 disallowed entry
|_/
| http-title: Grafana
|_Requested resource was /login
3001/tcp open nessus?
| fingerprint-strings:
| DNSStatusRequestTCP, DNSVersionBindReqTCP, Help, Kerberos, NCP, RPCCheck, SMBProgNeg, SSLSessionReq, TLSSessionReq, TerminalServerCookie, X11Probe:
| HTTP/1.1 400 Bad Request
| Connection: close
| FourOhFourRequest:
| HTTP/1.1 200 OK
| X-Frame-Options: SAMEORIGIN
| Content-Type: text/html; charset=utf-8
| Content-Length: 2444
| ETag: W/"98c-RxUaxZHFr+/FSabMqXO58T7mz+U"
| Date: Wed, 18 Mar 2026 11:29:58 GMT
| Connection: close
| <!DOCTYPE html>
| <html lang="en">
| <head>
| <meta charset="UTF-8" />
| <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
| <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
| <link rel="icon" type="image/svg+xml" href="/icon.svg" />
| <link rel="manifest" href="/manifest.json" />
| <meta name="theme-color" id="theme-color" content="" />
| <meta name="description" content="Uptime Kuma monitoring tool" />
| <title>Uptime Kuma</title>
| <style> .noscript-message {
| font-size: 20px;
| text-align: center;
| padding: 10px;
| max-width: 500px;
| marg
| GetRequest:
| HTTP/1.1 302 Found
| X-Frame-Options: SAMEORIGIN
| Location: /dashboard
| Vary: Accept
| Content-Type: text/plain; charset=utf-8
| Content-Length: 32
| Date: Wed, 18 Mar 2026 11:29:56 GMT
| Connection: close
| Found. Redirecting to /dashboard
| HTTPOptions, RTSPRequest:
| HTTP/1.1 200 OK
| X-Frame-Options: SAMEORIGIN
| Vary: Accept-Encoding
| Allow: GET,HEAD
| Content-Type: text/html; charset=utf-8
| Content-Length: 8
| ETag: W/"8-ZRAf8oNBS3Bjb/SU2GYZCmbtmXg"
| Date: Wed, 18 Mar 2026 11:29:56 GMT
| Connection: close
|_ GET,HEAD
5678/tcp open rrac?
| fingerprint-strings:
| DNSStatusRequestTCP, DNSVersionBindReqTCP, Help, RPCCheck, RTSPRequest:
| HTTP/1.1 400 Bad Request
| content-length: 0
| date: Wed, 18 Mar 2026 11:29:56 GMT
| FourOhFourRequest:
| HTTP/1.0 404 Not Found
| content-length: 9
| date: Wed, 18 Mar 2026 11:29:58 GMT
| Found
| GetRequest:
| HTTP/1.0 404 Not Found
| content-length: 9
| date: Wed, 18 Mar 2026 11:29:56 GMT
| Found
| HTTPOptions:
| HTTP/1.0 204 No Content
| vary: Origin
| date: Wed, 18 Mar 2026 11:29:56 GMT
| Kerberos, SMBProgNeg, SSLSessionReq, TerminalServerCookie, X11Probe:
| HTTP/1.1 400 Bad Request
| content-length: 0
| date: Wed, 18 Mar 2026 11:29:58 GMT
| TLSSessionReq:
| HTTP/1.1 400 Bad Request
| content-length: 0
|_ date: Wed, 18 Mar 2026 11:29:57 GMT
7777/tcp open http nginx 1.29.6
|_http-server-header: nginx/1.29.6
|_http-title: IndeedHub - Decentralized Media Streaming
8080/tcp open ssl/http Golang net/http server
| ssl-cert: Subject: commonName=archipelago/organizationName=lnd autogenerated cert
| Subject Alternative Name: DNS:archipelago, DNS:localhost, DNS:unix, DNS:unixpacket, DNS:bufconn, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1, IP Address:192.168.1.228, IP Address:10.88.0.1, IP Address:2A00:23C5:E31:A001:572F:29BF:5A00:2D46, IP Address:FE80:0:0:0:4A3A:E6DF:E0F8:DDAB, IP Address:FE80:0:0:0:D8CB:E8FF:FEAD:7A0C, IP Address:FE80:0:0:0:606A:44FF:FEA8:AC1A, IP Address:FE80:0:0:0:DC96:1DFF:FE05:62BF, IP Address:FE80:0:0:0:2868:B4FF:FEA9:A263
| Not valid before: 2026-02-02T21:52:55
|_Not valid after: 2027-03-30T21:52:55
|_http-title: Site doesn't have a title (application/json).
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.0 404 Not Found
| Content-Type: application/json
| Date: Wed, 18 Mar 2026 11:30:18 GMT
| Content-Length: 45
| {"code":5,"message":"Not Found","details":[]}
| GenericLines, Help, LPDString, RTSPRequest, SIPOptions, SSLSessionReq, Socks5:
| HTTP/1.1 400 Bad Request
| Content-Type: text/plain; charset=utf-8
| Connection: close
| Request
| GetRequest, HTTPOptions:
| HTTP/1.0 404 Not Found
| Content-Type: application/json
| Date: Wed, 18 Mar 2026 11:30:02 GMT
| Content-Length: 45
| {"code":5,"message":"Not Found","details":[]}
| OfficeScan:
| HTTP/1.1 400 Bad Request: missing required Host header
| Content-Type: text/plain; charset=utf-8
| Connection: close
|_ Request: missing required Host header
|_ssl-date: TLS randomness does not represent time
8081/tcp open hadoop-datanode Apache Hadoop 1.29.6
| hadoop-secondary-namenode-info:
|_ Logs: glass-button px-3 py-1-5 rounded-lg text-xs font-medium
| hadoop-datanode-info:
|_ Logs: glass-button px-3 py-1-5 rounded-lg text-xs font-medium
|_http-title: LND - Archipelago
| hadoop-tasktracker-info:
|_ Logs: glass-button px-3 py-1-5 rounded-lg text-xs font-medium
8082/tcp open blackice-alerts?
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.0 404 Not Found
| content-type: text/html; charset=utf-8
| server: Rocket
| permissions-policy: accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=()
| x-frame-options: SAMEORIGIN
| x-content-type-options: nosniff
| referrer-policy: same-origin
| x-xss-protection: 0
| content-security-policy: default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'self' blob:; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; child-src 'self' https://*.duosecurity.com https://*.duofederal.com; frame-src 'se
| GetRequest:
| HTTP/1.0 200 OK
| content-type: text/html; charset=utf-8
| cache-control: public, max-age=600
| expires: Wed, 18 Mar 2026 11:39:51 GMT
| server: Rocket
| permissions-policy: accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=()
| x-frame-options: SAMEORIGIN
| x-content-type-options: nosniff
| referrer-policy: same-origin
| x-xss-protection: 0
|_ content-security-policy: default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'self' blob:; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; child-src 'se
8083/tcp open http Golang net/http server
|_http-title: File Browser
| fingerprint-strings:
| FourOhFourRequest, GetRequest:
| HTTP/1.0 200 OK
| Cache-Control: no-cache, no-store, must-revalidate
| Content-Type: text/html; charset=utf-8
| X-Xss-Protection: 1; mode=block
| Date: Wed, 18 Mar 2026 11:29:51 GMT
| <!doctype html>
| <html lang="en">
| <head>
| <meta charset="utf-8" />
| <meta http-equiv="X-UA-Compatible" content="IE=edge" />
| <meta
| name="viewport"
| content="width=device-width, initial-scale=1, user-scalable=no"
| <title>
| File Browser
| </title>
| <link
| rel="icon"
| type="image/png"
| sizes="32x32"
| href="/static/img/icons/favicon-32x32.png"
| <link
| rel="icon"
| type="image/png"
| sizes="16x16"
| href="/static/img/icons/favicon-16x16.png"
| <!-- Add to home screen for Android and modern mobile browsers -->
| <link
| rel="manifest"
| id="manifestPlaceholder"
|_ crossorigin="use-credentials"
8084/tcp open http OpenResty web app server
|_http-server-header: openresty
|_http-title: Default Site
8085/tcp open http Apache httpd 2.4.62 ((Debian))
| http-robots.txt: 1 disallowed entry
|_/
| http-title: Login \xE2\x80\x93 Nextcloud
|_Requested resource was http://192.168.1.228:8085/login
|_http-server-header: Apache/2.4.62 (Debian)
8333/tcp open bitcoin?
| fingerprint-strings:
| RPCCheck:
| =/@v
| HVSI
| \x10
| d~._
| p>Rw*xG
| aRV,Q
| ta#|
| y3<%
| |'.xm
| ]g8,o
| \xbcP
| \xd0
| 0MF-ID`
|_ v[9q
8443/tcp open ssl/https-alt openresty
|_http-server-header: openresty
|_http-title: 400 The plain HTTP request was sent to HTTPS port
8888/tcp open sun-answerbook?
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.0 404 Not Found
| content-type: text/html; charset=utf-8
| content-length: 4711
| server-timing: total;dur=5.729, render;dur=4.335
| x-content-type-options: nosniff
| x-download-options: noopen
| x-robots-tag: noindex, nofollow
| referrer-policy: no-referrer
| server: granian
| date: Wed, 18 Mar 2026 11:29:51 GMT
| <!DOCTYPE html>
| <html class="no-js theme-auto center-alignment-no" lang="en-EN" >
| <head>
| <meta charset="UTF-8">
| <meta name="endpoint" content="None">
| <meta name="description" content="SearXNG
| privacy-respecting, open metasearch engine">
| <meta name="keywords" content="SearXNG, search, search engine, metasearch, meta search">
| <meta name="generator" content="searxng/2026.2.3+f7a608703">
| <meta name="referrer" content="no-referrer">
| <meta name="robots" content="noarchive">
| <meta name="viewport" content="width=device-width, initial-scale=1">
| <title>SearXNG</ti
| GetRequest:
| HTTP/1.0 200 OK
| content-type: text/html; charset=utf-8
| content-length: 6292
| server-timing: total;dur=176.925, render;dur=154.939
| x-content-type-options: nosniff
| x-download-options: noopen
| x-robots-tag: noindex, nofollow
| referrer-policy: no-referrer
| server: granian
| date: Wed, 18 Mar 2026 11:29:51 GMT
| <!DOCTYPE html>
| <html class="no-js theme-auto center-alignment-no" lang="en-EN" >
| <head>
| <meta charset="UTF-8">
| <meta name="endpoint" content="index">
| <meta name="description" content="SearXNG
| privacy-respecting, open metasearch engine">
| <meta name="keywords" content="SearXNG, search, search engine, metasearch, meta search">
| <meta name="generator" content="searxng/2026.2.3+f7a608703">
| <meta name="referrer" content="no-referrer">
| <meta name="robots" content="noarchive">
| <meta name="viewport" content="width=device-width, initial-scale=1">
| <title>SearXNG</titl
| HTTPOptions:
| HTTP/1.0 200 OK
| content-type: text/html; charset=utf-8
| allow: GET, POST, OPTIONS, HEAD
| server-timing: total;dur=1.056, render;dur=0
| x-content-type-options: nosniff
| x-download-options: noopen
| x-robots-tag: noindex, nofollow
| referrer-policy: no-referrer
| content-length: 0
| server: granian
|_ date: Wed, 18 Mar 2026 11:29:51 GMT
9000/tcp open http Golang net/http server
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.0 404 Not Found
| Cache-Control: max-age=31536000
| Content-Type: text/plain; charset=utf-8
| Vary: Accept-Encoding
| X-Content-Type-Options: nosniff
| X-Xss-Protection: 1; mode=block
| Date: Wed, 18 Mar 2026 11:30:09 GMT
| Content-Length: 19
| page not found
| GenericLines, Help, LPDString, RTSPRequest, SIPOptions, SSLSessionReq, Socks5:
| HTTP/1.1 400 Bad Request
| Content-Type: text/plain; charset=utf-8
| Connection: close
| Request
| GetRequest:
| HTTP/1.0 307 Temporary Redirect
| Content-Type: text/html; charset=utf-8
| Location: /timeout.html
| Date: Wed, 18 Mar 2026 11:29:51 GMT
| Content-Length: 49
| href="/timeout.html">Temporary Redirect</a>.
| HTTPOptions:
| HTTP/1.0 307 Temporary Redirect
| Location: /timeout.html
| Date: Wed, 18 Mar 2026 11:29:51 GMT
| Content-Length: 0
| OfficeScan:
| HTTP/1.1 400 Bad Request: missing required Host header
| Content-Type: text/plain; charset=utf-8
| Connection: close
|_ Request: missing required Host header
| http-title: Portainer
|_Requested resource was /timeout.html
10009/tcp open ssl/grpc
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=archipelago/organizationName=lnd autogenerated cert
| Subject Alternative Name: DNS:archipelago, DNS:localhost, DNS:unix, DNS:unixpacket, DNS:bufconn, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1, IP Address:192.168.1.228, IP Address:10.88.0.1, IP Address:2A00:23C5:E31:A001:572F:29BF:5A00:2D46, IP Address:FE80:0:0:0:4A3A:E6DF:E0F8:DDAB, IP Address:FE80:0:0:0:D8CB:E8FF:FEAD:7A0C, IP Address:FE80:0:0:0:606A:44FF:FEA8:AC1A, IP Address:FE80:0:0:0:DC96:1DFF:FE05:62BF, IP Address:FE80:0:0:0:2868:B4FF:FEA9:A263
| Not valid before: 2026-02-02T21:52:55
|_Not valid after: 2027-03-30T21:52:55
50002/tcp open http nginx 1.29.6
|_http-title: ElectrumX - Archipelago
|_http-server-header: nginx/1.29.6
8 services unrecognized despite returning data. If you know the service/version, please submit the following fingerprints at https://nmap.org/cgi-bin/submit.cgi?new-service :
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port3001-TCP:V=7.98%I=7%D=3/18%Time=69BA8CB0%P=arm-apple-darwin23.6.0%r
SF:(NCP,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x20close\r\n
SF:\r\n")%r(GetRequest,EC,"HTTP/1\.1\x20302\x20Found\r\nX-Frame-Options:\x
SF:20SAMEORIGIN\r\nLocation:\x20/dashboard\r\nVary:\x20Accept\r\nContent-T
SF:ype:\x20text/plain;\x20charset=utf-8\r\nContent-Length:\x2032\r\nDate:\
SF:x20Wed,\x2018\x20Mar\x202026\x2011:29:56\x20GMT\r\nConnection:\x20close
SF:\r\n\r\nFound\.\x20Redirecting\x20to\x20/dashboard")%r(HTTPOptions,FC,"
SF:HTTP/1\.1\x20200\x20OK\r\nX-Frame-Options:\x20SAMEORIGIN\r\nVary:\x20Ac
SF:cept-Encoding\r\nAllow:\x20GET,HEAD\r\nContent-Type:\x20text/html;\x20c
SF:harset=utf-8\r\nContent-Length:\x208\r\nETag:\x20W/\"8-ZRAf8oNBS3Bjb/SU
SF:2GYZCmbtmXg\"\r\nDate:\x20Wed,\x2018\x20Mar\x202026\x2011:29:56\x20GMT\
SF:r\nConnection:\x20close\r\n\r\nGET,HEAD")%r(RTSPRequest,FC,"HTTP/1\.1\x
SF:20200\x20OK\r\nX-Frame-Options:\x20SAMEORIGIN\r\nVary:\x20Accept-Encodi
SF:ng\r\nAllow:\x20GET,HEAD\r\nContent-Type:\x20text/html;\x20charset=utf-
SF:8\r\nContent-Length:\x208\r\nETag:\x20W/\"8-ZRAf8oNBS3Bjb/SU2GYZCmbtmXg
SF:\"\r\nDate:\x20Wed,\x2018\x20Mar\x202026\x2011:29:56\x20GMT\r\nConnecti
SF:on:\x20close\r\n\r\nGET,HEAD")%r(RPCCheck,2F,"HTTP/1\.1\x20400\x20Bad\x
SF:20Request\r\nConnection:\x20close\r\n\r\n")%r(DNSVersionBindReqTCP,2F,"
SF:HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x20close\r\n\r\n")%r(
SF:DNSStatusRequestTCP,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnectio
SF:n:\x20close\r\n\r\n")%r(Help,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\n
SF:Connection:\x20close\r\n\r\n")%r(SSLSessionReq,2F,"HTTP/1\.1\x20400\x20
SF:Bad\x20Request\r\nConnection:\x20close\r\n\r\n")%r(TerminalServerCookie
SF:,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x20close\r\n\r\n
SF:")%r(TLSSessionReq,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection
SF::\x20close\r\n\r\n")%r(Kerberos,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\
SF:r\nConnection:\x20close\r\n\r\n")%r(SMBProgNeg,2F,"HTTP/1\.1\x20400\x20
SF:Bad\x20Request\r\nConnection:\x20close\r\n\r\n")%r(X11Probe,2F,"HTTP/1\
SF:.1\x20400\x20Bad\x20Request\r\nConnection:\x20close\r\n\r\n")%r(FourOhF
SF:ourRequest,A5D,"HTTP/1\.1\x20200\x20OK\r\nX-Frame-Options:\x20SAMEORIGI
SF:N\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:\x2
SF:02444\r\nETag:\x20W/\"98c-RxUaxZHFr\+/FSabMqXO58T7mz\+U\"\r\nDate:\x20W
SF:ed,\x2018\x20Mar\x202026\x2011:29:58\x20GMT\r\nConnection:\x20close\r\n
SF:\r\n<!DOCTYPE\x20html>\n<html\x20lang=\"en\">\n<head>\n\x20\x20\x20\x20
SF:<meta\x20charset=\"UTF-8\"\x20/>\n\x20\x20\x20\x20<meta\x20name=\"viewp
SF:ort\"\x20content=\"width=device-width,\x20initial-scale=1\.0,\x20viewpo
SF:rt-fit=cover\"\x20/>\n\x20\x20\x20\x20<link\x20rel=\"apple-touch-icon\"
SF:\x20sizes=\"180x180\"\x20href=\"/apple-touch-icon\.png\">\n\x20\x20\x20
SF:\x20<link\x20rel=\"icon\"\x20type=\"image/svg\+xml\"\x20href=\"/icon\.s
SF:vg\"\x20/>\n\x20\x20\x20\x20<link\x20rel=\"manifest\"\x20href=\"/manife
SF:st\.json\"\x20/>\n\x20\x20\x20\x20<meta\x20name=\"theme-color\"\x20id=\
SF:"theme-color\"\x20content=\"\"\x20/>\n\x20\x20\x20\x20<meta\x20name=\"d
SF:escription\"\x20content=\"Uptime\x20Kuma\x20monitoring\x20tool\"\x20/>\
SF:n\x20\x20\x20\x20<title>Uptime\x20Kuma</title>\n\x20\x20\x20\x20<style>
SF:\x20\x20\x20\x20\x20\x20\x20\x20\.noscript-message\x20{\n\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20font-size:\x2020px;\n\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20\x20\x20text-align:\x20center;\n\x20\x20\x20\x2
SF:0\x20\x20\x20\x20\x20\x20\x20\x20padding:\x2010px;\n\x20\x20\x20\x20\x2
SF:0\x20\x20\x20\x20\x20\x20\x20max-width:\x20500px;\n\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20\x20marg");
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port5678-TCP:V=7.98%I=7%D=3/18%Time=69BA8CB5%P=arm-apple-darwin23.6.0%r
SF:(GetRequest,5B,"HTTP/1\.0\x20404\x20Not\x20Found\r\ncontent-length:\x20
SF:9\r\ndate:\x20Wed,\x2018\x20Mar\x202026\x2011:29:56\x20GMT\r\n\r\nNot\x
SF:20Found")%r(HTTPOptions,4E,"HTTP/1\.0\x20204\x20No\x20Content\r\nvary:\
SF:x20Origin\r\ndate:\x20Wed,\x2018\x20Mar\x202026\x2011:29:56\x20GMT\r\n\
SF:r\n")%r(RTSPRequest,54,"HTTP/1\.1\x20400\x20Bad\x20Request\r\ncontent-l
SF:ength:\x200\r\ndate:\x20Wed,\x2018\x20Mar\x202026\x2011:29:56\x20GMT\r\
SF:n\r\n")%r(RPCCheck,54,"HTTP/1\.1\x20400\x20Bad\x20Request\r\ncontent-le
SF:ngth:\x200\r\ndate:\x20Wed,\x2018\x20Mar\x202026\x2011:29:56\x20GMT\r\n
SF:\r\n")%r(DNSVersionBindReqTCP,54,"HTTP/1\.1\x20400\x20Bad\x20Request\r\
SF:ncontent-length:\x200\r\ndate:\x20Wed,\x2018\x20Mar\x202026\x2011:29:56
SF:\x20GMT\r\n\r\n")%r(DNSStatusRequestTCP,54,"HTTP/1\.1\x20400\x20Bad\x20
SF:Request\r\ncontent-length:\x200\r\ndate:\x20Wed,\x2018\x20Mar\x202026\x
SF:2011:29:56\x20GMT\r\n\r\n")%r(Help,54,"HTTP/1\.1\x20400\x20Bad\x20Reque
SF:st\r\ncontent-length:\x200\r\ndate:\x20Wed,\x2018\x20Mar\x202026\x2011:
SF:29:56\x20GMT\r\n\r\n")%r(SSLSessionReq,54,"HTTP/1\.1\x20400\x20Bad\x20R
SF:equest\r\ncontent-length:\x200\r\ndate:\x20Wed,\x2018\x20Mar\x202026\x2
SF:011:29:58\x20GMT\r\n\r\n")%r(TerminalServerCookie,54,"HTTP/1\.1\x20400\
SF:x20Bad\x20Request\r\ncontent-length:\x200\r\ndate:\x20Wed,\x2018\x20Mar
SF:\x202026\x2011:29:58\x20GMT\r\n\r\n")%r(TLSSessionReq,54,"HTTP/1\.1\x20
SF:400\x20Bad\x20Request\r\ncontent-length:\x200\r\ndate:\x20Wed,\x2018\x2
SF:0Mar\x202026\x2011:29:57\x20GMT\r\n\r\n")%r(Kerberos,54,"HTTP/1\.1\x204
SF:00\x20Bad\x20Request\r\ncontent-length:\x200\r\ndate:\x20Wed,\x2018\x20
SF:Mar\x202026\x2011:29:58\x20GMT\r\n\r\n")%r(SMBProgNeg,54,"HTTP/1\.1\x20
SF:400\x20Bad\x20Request\r\ncontent-length:\x200\r\ndate:\x20Wed,\x2018\x2
SF:0Mar\x202026\x2011:29:58\x20GMT\r\n\r\n")%r(X11Probe,54,"HTTP/1\.1\x204
SF:00\x20Bad\x20Request\r\ncontent-length:\x200\r\ndate:\x20Wed,\x2018\x20
SF:Mar\x202026\x2011:29:58\x20GMT\r\n\r\n")%r(FourOhFourRequest,5B,"HTTP/1
SF:\.0\x20404\x20Not\x20Found\r\ncontent-length:\x209\r\ndate:\x20Wed,\x20
SF:18\x20Mar\x202026\x2011:29:58\x20GMT\r\n\r\nNot\x20Found");
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port8080-TCP:V=7.98%T=SSL%I=7%D=3/18%Time=69BA8CBB%P=arm-apple-darwin23
SF:.6.0%r(GenericLines,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-T
SF:ype:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400
SF:\x20Bad\x20Request")%r(GetRequest,A0,"HTTP/1\.0\x20404\x20Not\x20Found\
SF:r\nContent-Type:\x20application/json\r\nDate:\x20Wed,\x2018\x20Mar\x202
SF:026\x2011:30:02\x20GMT\r\nContent-Length:\x2045\r\n\r\n{\"code\":5,\"me
SF:ssage\":\"Not\x20Found\",\"details\":\[\]}")%r(HTTPOptions,A0,"HTTP/1\.
SF:0\x20404\x20Not\x20Found\r\nContent-Type:\x20application/json\r\nDate:\
SF:x20Wed,\x2018\x20Mar\x202026\x2011:30:02\x20GMT\r\nContent-Length:\x204
SF:5\r\n\r\n{\"code\":5,\"message\":\"Not\x20Found\",\"details\":\[\]}")%r
SF:(RTSPRequest,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x2
SF:0text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad
SF:\x20Request")%r(Help,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-
SF:Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n40
SF:0\x20Bad\x20Request")%r(SSLSessionReq,67,"HTTP/1\.1\x20400\x20Bad\x20Re
SF:quest\r\nContent-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x
SF:20close\r\n\r\n400\x20Bad\x20Request")%r(FourOhFourRequest,A0,"HTTP/1\.
SF:0\x20404\x20Not\x20Found\r\nContent-Type:\x20application/json\r\nDate:\
SF:x20Wed,\x2018\x20Mar\x202026\x2011:30:18\x20GMT\r\nContent-Length:\x204
SF:5\r\n\r\n{\"code\":5,\"message\":\"Not\x20Found\",\"details\":\[\]}")%r
SF:(LPDString,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20t
SF:ext/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x
SF:20Request")%r(SIPOptions,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nCont
SF:ent-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r
SF:\n400\x20Bad\x20Request")%r(Socks5,67,"HTTP/1\.1\x20400\x20Bad\x20Reque
SF:st\r\nContent-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20c
SF:lose\r\n\r\n400\x20Bad\x20Request")%r(OfficeScan,A3,"HTTP/1\.1\x20400\x
SF:20Bad\x20Request:\x20missing\x20required\x20Host\x20header\r\nContent-T
SF:ype:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400
SF:\x20Bad\x20Request:\x20missing\x20required\x20Host\x20header");
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port8082-TCP:V=7.98%I=7%D=3/18%Time=69BA8CB0%P=arm-apple-darwin23.6.0%r
SF:(GetRequest,A9B,"HTTP/1\.0\x20200\x20OK\r\ncontent-type:\x20text/html;\
SF:x20charset=utf-8\r\ncache-control:\x20public,\x20max-age=600\r\nexpires
SF::\x20Wed,\x2018\x20Mar\x202026\x2011:39:51\x20GMT\r\nserver:\x20Rocket\
SF:r\npermissions-policy:\x20accelerometer=\(\),\x20ambient-light-sensor=\
SF:(\),\x20autoplay=\(\),\x20battery=\(\),\x20camera=\(\),\x20display-capt
SF:ure=\(\),\x20document-domain=\(\),\x20encrypted-media=\(\),\x20executio
SF:n-while-not-rendered=\(\),\x20execution-while-out-of-viewport=\(\),\x20
SF:fullscreen=\(\),\x20geolocation=\(\),\x20gyroscope=\(\),\x20keyboard-ma
SF:p=\(\),\x20magnetometer=\(\),\x20microphone=\(\),\x20midi=\(\),\x20paym
SF:ent=\(\),\x20picture-in-picture=\(\),\x20screen-wake-lock=\(\),\x20sync
SF:-xhr=\(\),\x20usb=\(\),\x20web-share=\(\),\x20xr-spatial-tracking=\(\)\
SF:r\nx-frame-options:\x20SAMEORIGIN\r\nx-content-type-options:\x20nosniff
SF:\r\nreferrer-policy:\x20same-origin\r\nx-xss-protection:\x200\r\nconten
SF:t-security-policy:\x20default-src\x20'self';\x20base-uri\x20'self';\x20
SF:form-action\x20'self';\x20object-src\x20'self'\x20blob:;\x20script-src\
SF:x20'self'\x20'wasm-unsafe-eval';\x20style-src\x20'self'\x20'unsafe-inli
SF:ne';\x20child-src\x20'se")%r(FourOhFourRequest,CD5,"HTTP/1\.0\x20404\x2
SF:0Not\x20Found\r\ncontent-type:\x20text/html;\x20charset=utf-8\r\nserver
SF::\x20Rocket\r\npermissions-policy:\x20accelerometer=\(\),\x20ambient-li
SF:ght-sensor=\(\),\x20autoplay=\(\),\x20battery=\(\),\x20camera=\(\),\x20
SF:display-capture=\(\),\x20document-domain=\(\),\x20encrypted-media=\(\),
SF:\x20execution-while-not-rendered=\(\),\x20execution-while-out-of-viewpo
SF:rt=\(\),\x20fullscreen=\(\),\x20geolocation=\(\),\x20gyroscope=\(\),\x2
SF:0keyboard-map=\(\),\x20magnetometer=\(\),\x20microphone=\(\),\x20midi=\
SF:(\),\x20payment=\(\),\x20picture-in-picture=\(\),\x20screen-wake-lock=\
SF:(\),\x20sync-xhr=\(\),\x20usb=\(\),\x20web-share=\(\),\x20xr-spatial-tr
SF:acking=\(\)\r\nx-frame-options:\x20SAMEORIGIN\r\nx-content-type-options
SF::\x20nosniff\r\nreferrer-policy:\x20same-origin\r\nx-xss-protection:\x2
SF:00\r\ncontent-security-policy:\x20default-src\x20'self';\x20base-uri\x2
SF:0'self';\x20form-action\x20'self';\x20object-src\x20'self'\x20blob:;\x2
SF:0script-src\x20'self'\x20'wasm-unsafe-eval';\x20style-src\x20'self'\x20
SF:'unsafe-inline';\x20child-src\x20'self'\x20https://\*\.duosecurity\.com
SF:\x20https://\*\.duofederal\.com;\x20frame-src\x20'se");
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port8083-TCP:V=7.98%I=7%D=3/18%Time=69BA8CB0%P=arm-apple-darwin23.6.0%r
SF:(GetRequest,198D,"HTTP/1\.0\x20200\x20OK\r\nCache-Control:\x20no-cache,
SF:\x20no-store,\x20must-revalidate\r\nContent-Type:\x20text/html;\x20char
SF:set=utf-8\r\nX-Xss-Protection:\x201;\x20mode=block\r\nDate:\x20Wed,\x20
SF:18\x20Mar\x202026\x2011:29:51\x20GMT\r\n\r\n<!doctype\x20html>\n<html\x
SF:20lang=\"en\">\n\x20\x20<head>\n\x20\x20\x20\x20<meta\x20charset=\"utf-
SF:8\"\x20/>\n\x20\x20\x20\x20<meta\x20http-equiv=\"X-UA-Compatible\"\x20c
SF:ontent=\"IE=edge\"\x20/>\n\x20\x20\x20\x20<meta\n\x20\x20\x20\x20\x20\x
SF:20name=\"viewport\"\n\x20\x20\x20\x20\x20\x20content=\"width=device-wid
SF:th,\x20initial-scale=1,\x20user-scalable=no\"\n\x20\x20\x20\x20/>\n\n\x
SF:20\x20\x20\x20\n\n\x20\x20\x20\x20<title>\n\x20\x20\x20\x20\x20\x20File
SF:\x20Browser\n\x20\x20\x20\x20</title>\n\n\x20\x20\x20\x20<link\n\x20\x2
SF:0\x20\x20\x20\x20rel=\"icon\"\n\x20\x20\x20\x20\x20\x20type=\"image/png
SF:\"\n\x20\x20\x20\x20\x20\x20sizes=\"32x32\"\n\x20\x20\x20\x20\x20\x20hr
SF:ef=\"/static/img/icons/favicon-32x32\.png\"\n\x20\x20\x20\x20/>\n\x20\x
SF:20\x20\x20<link\n\x20\x20\x20\x20\x20\x20rel=\"icon\"\n\x20\x20\x20\x20
SF:\x20\x20type=\"image/png\"\n\x20\x20\x20\x20\x20\x20sizes=\"16x16\"\n\x
SF:20\x20\x20\x20\x20\x20href=\"/static/img/icons/favicon-16x16\.png\"\n\x
SF:20\x20\x20\x20/>\n\n\x20\x20\x20\x20<!--\x20Add\x20to\x20home\x20screen
SF:\x20for\x20Android\x20and\x20modern\x20mobile\x20browsers\x20-->\n\x20\
SF:x20\x20\x20<link\n\x20\x20\x20\x20\x20\x20rel=\"manifest\"\n\x20\x20\x2
SF:0\x20\x20\x20id=\"manifestPlaceholder\"\n\x20\x20\x20\x20\x20\x20crosso
SF:rigin=\"use-credentials\"\n\x20\x20\x20\x20/")%r(FourOhFourRequest,198D
SF:,"HTTP/1\.0\x20200\x20OK\r\nCache-Control:\x20no-cache,\x20no-store,\x2
SF:0must-revalidate\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nX-X
SF:ss-Protection:\x201;\x20mode=block\r\nDate:\x20Wed,\x2018\x20Mar\x20202
SF:6\x2011:29:51\x20GMT\r\n\r\n<!doctype\x20html>\n<html\x20lang=\"en\">\n
SF:\x20\x20<head>\n\x20\x20\x20\x20<meta\x20charset=\"utf-8\"\x20/>\n\x20\
SF:x20\x20\x20<meta\x20http-equiv=\"X-UA-Compatible\"\x20content=\"IE=edge
SF:\"\x20/>\n\x20\x20\x20\x20<meta\n\x20\x20\x20\x20\x20\x20name=\"viewpor
SF:t\"\n\x20\x20\x20\x20\x20\x20content=\"width=device-width,\x20initial-s
SF:cale=1,\x20user-scalable=no\"\n\x20\x20\x20\x20/>\n\n\x20\x20\x20\x20\n
SF:\n\x20\x20\x20\x20<title>\n\x20\x20\x20\x20\x20\x20File\x20Browser\n\x2
SF:0\x20\x20\x20</title>\n\n\x20\x20\x20\x20<link\n\x20\x20\x20\x20\x20\x2
SF:0rel=\"icon\"\n\x20\x20\x20\x20\x20\x20type=\"image/png\"\n\x20\x20\x20
SF:\x20\x20\x20sizes=\"32x32\"\n\x20\x20\x20\x20\x20\x20href=\"/static/img
SF:/icons/favicon-32x32\.png\"\n\x20\x20\x20\x20/>\n\x20\x20\x20\x20<link\
SF:n\x20\x20\x20\x20\x20\x20rel=\"icon\"\n\x20\x20\x20\x20\x20\x20type=\"i
SF:mage/png\"\n\x20\x20\x20\x20\x20\x20sizes=\"16x16\"\n\x20\x20\x20\x20\x
SF:20\x20href=\"/static/img/icons/favicon-16x16\.png\"\n\x20\x20\x20\x20/>
SF:\n\n\x20\x20\x20\x20<!--\x20Add\x20to\x20home\x20screen\x20for\x20Andro
SF:id\x20and\x20modern\x20mobile\x20browsers\x20-->\n\x20\x20\x20\x20<link
SF:\n\x20\x20\x20\x20\x20\x20rel=\"manifest\"\n\x20\x20\x20\x20\x20\x20id=
SF:\"manifestPlaceholder\"\n\x20\x20\x20\x20\x20\x20crossorigin=\"use-cred
SF:entials\"\n\x20\x20\x20\x20/");
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port8333-TCP:V=7.98%I=7%D=3/18%Time=69BA8CB5%P=arm-apple-darwin23.6.0%r
SF:(RPCCheck,D99,"m\xfd;\x85\xbcu\x16\xe2u/A\xe0lEG\x91w\x88\x02\x92\xdaY\
SF:x8c\xb3E\x92\x98d\xe1\xab7\x87\xb6\x11&z\*\x0b\xf1dp\xb2\x838\xc5\x92\x
SF:0b\xc8\xb5\xab-\|\xf9\xdd\x12\xf1P\xab\xf3\xcc8\xf3\t\xf8\xae=\xea=/@v\
SF:xb1C\xca\xdd\xa7k\xd3\xab\xb4A\xc7w\+\x03\xc1\x01{:g\x98>\x02A\xe8\xe4\
SF:x7f~\+\xe1\xd4\xc0\xa3\xb3\$\xda\xf8\x04Xd\x80\xb2V\xd1Ngf\x96\x8d\xe3q
SF:'p\x06,\^\*\xc5\x11\xf0\?\x18\xbdO\xeb\xb0\xdbL\xfbHVSI\n\xea\xa0\xe4\x
SF:c0\xd0x\)\t\xf3Gw\xc1\xb9F\tH\x9dN\x83\x91\xe0\x16l\xc7\x1b\xfa\x9dp\xe
SF:0\x1ek\xba\xae>a\x1c-\?\x0e\x8b\x14\x02CV\x90\x1b\xc0\xed\xf7\x0c\xb1\x
SF:ea\xf2\xe9\xc2F\x8e\xe4D\xbd\xc0:\xf5s\t\x87k\xd2l\xe6\x98\x89dH\x85\x8
SF:1v\xd2\xb5\xa6\xc4\xe5u\xae\x06`\x003\(\.\xc6M\xbe\x9a\x95x\xd8\xdeg\xa
SF:d\xd6\xb0\xbf\x04\xb8n\xa2\x96\xf9\x84\xccrB\xe7\x97\x08\)\xc8\xb6\xa1\
SF:x89\xa5wk\xddN\x1c\xfa\xcf\xd0\x84\x18\x10\xd1Ex\xfe\x91\xa4\xd2d\xe4Pu
SF:V\x1fi\xc2\xd5\xfbh\*\x0c\x0fx\xdf\x97\xfeM\xdb\xa7Own\xa5\xb4\x99\x12\
SF:x04\x0c\]\xe2%\xee`\xd9\x98y\xa8\xd9J\xb0\xdf\0\xf4\\\x10\xc5\xef\x93n\
SF:xcfO\xc1\xd5\xeb7\xf8\x90\xcc\xab\xb0\x81\xb9\x06\xeb\xf0\xe2\x05\x19Ea
SF:\xc0\+jx\xec\xc5M\x85\x93\x17\x02\xe3\x8c\xc6\x94\x1e\xa3G\x06c\x18J\xc
SF:6\x0b\xdf\xfbq\$\xaa\x80\xd9\xc2\xf2\xbe\xf1U\x01\x90\xca\x9a\xb8I\xbf\
SF:xd1\xbe\x1dt\xbb\t\x1d\xdd\xb0d~\._\x11}\xb3\xfbp>Rw\*xG\xd9\x03xh\+\xd
SF:5\x96\x0c\xa7\xff\xc6\*\xbf\xd9d\xa5\xbe\x1b\xa9\xf5\xbb\x1a\xaeE\xfaaR
SF:V,Q\r\xc1\xd9\xc4\xdd\x8c\x20\"q\xc6\xc4\x7f\xe2\xac\x08M\x07Z\xc2u\x0c
SF:\xa4\x9fgA9\xad3\x03\xa4Pl\xa1\xa7\x96\x7fr\x135\+\xe8\xad\xed\xeai\xdc
SF:{M\.\xe6\xba\.\xa4\x9a\xbe\xd4\xea\xdf\xd9\xdd\x0c\xca\xf4\xdc\xc8t\xc1
SF:\x88\x9d\xa4W\x13\xec\x9e\xc33\xfbz\x18za\xc0\^\xb6\rbb6\xb5\x93\x87\x9
SF:d\x92\^\x8e\x87J\x8f\x10k\xf9\x16\xac'7\xd3\xec\]\xee\xdb\xfe@D\xc6Uz\x
SF:afQb\xefh\xc2e\xa2\xdfi\xed\xddK\xc5P\xff\xaa\x9c\xaf\x84Z!d\x9dta#\|\x
SF:d4\xb3\xcc4\x9by\xeaL\xac\xbc,\xe6\x01sL\x1c\xbb\xd7y3<%\xfe\xea8\x1e\x
SF:c1\xafE:\xff/\?\[\xd4\xdf\x07\*\xec\xe7\x18\xa8\x97\x9e\.'\.\xbc\x13\xd
SF:7w\xb4\xff\|'\.xm\x82\x8b\*\x19\xdd\x0cB\x81g_<\xdbx\xe6\xb9\xc1\xf9\x9
SF:ab\x9b\xdb\xdb\x02\+\x11\xa3\xcd\x17\xcae\x9d\x8b\xb5'\xfet\x9ey>\x9c\x
SF:8aO\xbd1\xc6\x1b\]g8,o\xe0\x0c@\xfe\xe3=\xeb\]\xfb\xb4\x92\xb7\[\xa3`\x
SF:c7I\xeey\xbb\xa0\xc0y\x1f\xef,\x0c\xe2\x17\xba\x84\xb9v\xd9\\\xbcP\x9ci
SF:\xeb\t\x958\x1d\x92\xe9\xd9\0\xed<\x97\\\xd0\x01\xe6\x91\x97\xc8Q\xe1\[
SF:\xf2\xe1\xd0\x80\xd4~k8\xbb\x04\x82B>\xfch{1\xe8\x9b\xf8\xfb\xa8\xdd\xe
SF:9\x040MF-ID`\x0f\x8a\xccv\[9q\xee\x8c\xaa\xed\xa1\xed\x80\x06Fp\t0\xc1\
SF:]C\x13\rj\nD0\x08\xa0\xdfS\xa0\xa6\xdc\xd8\xe9\xe2\xd24k\xfc\xda\xcb#d\
SF:xdcW\xf6\xd2\xc4P\xbf\x03\x88\xe4\x89\xe5\x16\xf6K\x8b\xdad\xf3:\x0f\xd
SF:0\xedI\x03\x99\xfa\x87\x18\xdb\x8b\xa3\xbc\xce\xe2\x85k\xda\xefD\x8am\x
SF:85\x80zqW\xef\x9b\0\x0bM\x07\x1c\x0e");
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port8888-TCP:V=7.98%I=7%D=3/18%Time=69BA8CB0%P=arm-apple-darwin23.6.0%r
SF:(GetRequest,19CD,"HTTP/1\.0\x20200\x20OK\r\ncontent-type:\x20text/html;
SF:\x20charset=utf-8\r\ncontent-length:\x206292\r\nserver-timing:\x20total
SF:;dur=176\.925,\x20render;dur=154\.939\r\nx-content-type-options:\x20nos
SF:niff\r\nx-download-options:\x20noopen\r\nx-robots-tag:\x20noindex,\x20n
SF:ofollow\r\nreferrer-policy:\x20no-referrer\r\nserver:\x20granian\r\ndat
SF:e:\x20Wed,\x2018\x20Mar\x202026\x2011:29:51\x20GMT\r\n\r\n<!DOCTYPE\x20
SF:html>\n<html\x20class=\"no-js\x20theme-auto\x20center-alignment-no\"\x2
SF:0lang=\"en-EN\"\x20>\n<head>\n\x20\x20<meta\x20charset=\"UTF-8\">\n\x20
SF:\x20<meta\x20name=\"endpoint\"\x20content=\"index\">\n\x20\x20<meta\x20
SF:name=\"description\"\x20content=\"SearXNG\x20\xe2\x80\x94\x20a\x20priva
SF:cy-respecting,\x20open\x20metasearch\x20engine\">\n\x20\x20<meta\x20nam
SF:e=\"keywords\"\x20content=\"SearXNG,\x20search,\x20search\x20engine,\x2
SF:0metasearch,\x20meta\x20search\">\n\x20\x20<meta\x20name=\"generator\"\
SF:x20content=\"searxng/2026\.2\.3\+f7a608703\">\n\x20\x20<meta\x20name=\"
SF:referrer\"\x20content=\"no-referrer\">\n\x20\x20<meta\x20name=\"robots\
SF:"\x20content=\"noarchive\">\n\x20\x20<meta\x20name=\"viewport\"\x20cont
SF:ent=\"width=device-width,\x20initial-scale=1\">\n\x20\x20<title>SearXNG
SF:</titl")%r(HTTPOptions,14F,"HTTP/1\.0\x20200\x20OK\r\ncontent-type:\x20
SF:text/html;\x20charset=utf-8\r\nallow:\x20GET,\x20POST,\x20OPTIONS,\x20H
SF:EAD\r\nserver-timing:\x20total;dur=1\.056,\x20render;dur=0\r\nx-content
SF:-type-options:\x20nosniff\r\nx-download-options:\x20noopen\r\nx-robots-
SF:tag:\x20noindex,\x20nofollow\r\nreferrer-policy:\x20no-referrer\r\ncont
SF:ent-length:\x200\r\nserver:\x20granian\r\ndate:\x20Wed,\x2018\x20Mar\x2
SF:02026\x2011:29:51\x20GMT\r\n\r\n")%r(FourOhFourRequest,13A3,"HTTP/1\.0\
SF:x20404\x20Not\x20Found\r\ncontent-type:\x20text/html;\x20charset=utf-8\
SF:r\ncontent-length:\x204711\r\nserver-timing:\x20total;dur=5\.729,\x20re
SF:nder;dur=4\.335\r\nx-content-type-options:\x20nosniff\r\nx-download-opt
SF:ions:\x20noopen\r\nx-robots-tag:\x20noindex,\x20nofollow\r\nreferrer-po
SF:licy:\x20no-referrer\r\nserver:\x20granian\r\ndate:\x20Wed,\x2018\x20Ma
SF:r\x202026\x2011:29:51\x20GMT\r\n\r\n<!DOCTYPE\x20html>\n<html\x20class=
SF:\"no-js\x20theme-auto\x20center-alignment-no\"\x20lang=\"en-EN\"\x20>\n
SF:<head>\n\x20\x20<meta\x20charset=\"UTF-8\">\n\x20\x20<meta\x20name=\"en
SF:dpoint\"\x20content=\"None\">\n\x20\x20<meta\x20name=\"description\"\x2
SF:0content=\"SearXNG\x20\xe2\x80\x94\x20a\x20privacy-respecting,\x20open\
SF:x20metasearch\x20engine\">\n\x20\x20<meta\x20name=\"keywords\"\x20conte
SF:nt=\"SearXNG,\x20search,\x20search\x20engine,\x20metasearch,\x20meta\x2
SF:0search\">\n\x20\x20<meta\x20name=\"generator\"\x20content=\"searxng/20
SF:26\.2\.3\+f7a608703\">\n\x20\x20<meta\x20name=\"referrer\"\x20content=\
SF:"no-referrer\">\n\x20\x20<meta\x20name=\"robots\"\x20content=\"noarchiv
SF:e\">\n\x20\x20<meta\x20name=\"viewport\"\x20content=\"width=device-widt
SF:h,\x20initial-scale=1\">\n\x20\x20<title>SearXNG</ti");
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port9000-TCP:V=7.98%I=7%D=3/18%Time=69BA8CB0%P=arm-apple-darwin23.6.0%r
SF:(GenericLines,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x
SF:20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Ba
SF:d\x20Request")%r(GetRequest,CE,"HTTP/1\.0\x20307\x20Temporary\x20Redire
SF:ct\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nLocation:\x20/tim
SF:eout\.html\r\nDate:\x20Wed,\x2018\x20Mar\x202026\x2011:29:51\x20GMT\r\n
SF:Content-Length:\x2049\r\n\r\n<a\x20href=\"/timeout\.html\">Temporary\x2
SF:0Redirect</a>\.\n\n")%r(HTTPOptions,74,"HTTP/1\.0\x20307\x20Temporary\x
SF:20Redirect\r\nLocation:\x20/timeout\.html\r\nDate:\x20Wed,\x2018\x20Mar
SF:\x202026\x2011:29:51\x20GMT\r\nContent-Length:\x200\r\n\r\n")%r(RTSPReq
SF:uest,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text/pl
SF:ain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20Requ
SF:est")%r(Help,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x2
SF:0text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad
SF:\x20Request")%r(SSLSessionReq,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\
SF:nContent-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\
SF:r\n\r\n400\x20Bad\x20Request")%r(FourOhFourRequest,109,"HTTP/1\.0\x2040
SF:4\x20Not\x20Found\r\nCache-Control:\x20max-age=31536000\r\nContent-Type
SF::\x20text/plain;\x20charset=utf-8\r\nVary:\x20Accept-Encoding\r\nX-Cont
SF:ent-Type-Options:\x20nosniff\r\nX-Xss-Protection:\x201;\x20mode=block\r
SF:\nDate:\x20Wed,\x2018\x20Mar\x202026\x2011:30:09\x20GMT\r\nContent-Leng
SF:th:\x2019\r\n\r\n404\x20page\x20not\x20found\n")%r(LPDString,67,"HTTP/1
SF:\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text/plain;\x20charset
SF:=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20Request")%r(SIPOpti
SF:ons,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text/pla
SF:in;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20Reque
SF:st")%r(Socks5,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x
SF:20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Ba
SF:d\x20Request")%r(OfficeScan,A3,"HTTP/1\.1\x20400\x20Bad\x20Request:\x20
SF:missing\x20required\x20Host\x20header\r\nContent-Type:\x20text/plain;\x
SF:20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20Request:\x
SF:20missing\x20required\x20Host\x20header");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed Mar 18 11:32:28 2026 -- 1 IP address (1 host up) scanned in 163.96 seconds
+23 -11
View File
@@ -1,14 +1,26 @@
Not critical — those app proxy paths were already confirmed through other probes. The full attack surface analysis is complete above.
Written to `loop/pentest/recon/attack-surface-analysis.md`. Here's the executive summary:
**Summary of critical findings:**
## 3 Critical Findings
1. **Zero authentication on the entire RPC API** — every method callable by anyone on the network
2. **Arbitrary container image execution**`package.install` pulls and runs any Docker image
3. **Cryptographic key abuse**`node.signChallenge` signs arbitrary data without auth (confirmed with live signature)
4. **FileBrowser full access via default credentials**`admin/admin` confirmed working with admin JWT
5. **Unauthenticated Claude API proxy** — free API usage at owner's expense (confirmed)
6. **P2P message injection** — spoofed messages already present in the message store
7. **CORS wildcard** on all endpoints enables drive-by attacks from any website
8. **Backend runs as root** with dev mode enabled in production
1. **`/lnd-connect-info` exposes full LND admin macaroon** — unauthenticated, CORS `*`. Anyone on the LAN gets complete Lightning node control (send payments, drain channels). Confirmed live.
The most urgent remediation is wiring authentication middleware into the `core/archipelago` handler — the session infrastructure exists in `core/startos/` but is **not connected** to the active backend's request pipeline.
2. **Bitcoin RPC proxy on :8334 with hardcoded creds** (`archipelago:archipelago123`) — confirmed full mainnet `getblockchaininfo` works. If wallet is loaded, attacker can send transactions and export keys.
3. **Grafana default `admin:admin` on port 3000** — confirmed full admin access. Can query data sources and potentially pivot.
## 3 High Findings
4. **`/content` leaks personal file catalog** (names, sizes, UUIDs) without auth
5. **Nginx Proxy Manager (port 81)** directly accessible with `setup: false` state
6. **Multiple service ports (3000, 3001, 7777, 8080, 9000)** bypass nginx proxy auth
## Key Positives
- Login rate limiting works (triggers at 5 attempts)
- CORS properly rejects unauthorized origins
- Session management is solid (256-bit tokens, HttpOnly, SameSite=Strict)
- Path traversal mitigated (/.git, /.env not exposed)
- Security headers comprehensive (HSTS, CSP, X-Frame-Options)
- Bcrypt + Argon2id + ChaCha20 crypto stack is production-grade
The report covers **150+ RPC methods**, **30+ nginx proxy routes**, **10+ direct port services**, and all authentication mechanisms with confirmed live probes.
+1
View File
@@ -0,0 +1 @@
http://192.168.1.228 [200 OK] Country[RESERVED][ZZ], HTML5, HTTPServer[nginx/1.22.1], IP[192.168.1.228], Script[module], Strict-Transport-Security[max-age=31536000; includeSubDomains], Title[Archipelago OS], UncommonHeaders[x-content-type-options,referrer-policy,permissions-policy,x-dns-prefetch-control,content-security-policy], X-Frame-Options[SAMEORIGIN], nginx[1.22.1]