Initial commit: Hermes Agent Skills collection

This commit is contained in:
Debian
2026-07-12 19:02:59 +00:00
commit e9cc106625
789 changed files with 233126 additions and 0 deletions
+227
View File
@@ -0,0 +1,227 @@
---
name: network-reconnaissance
description: "Class-level skill for network reconnaissance from containerized and general environments. Covers internal subnet scanning (TCP sweep, port scan, service detection, TLS/SSH analysis), external domain/service reconnaissance (DNS, SSL, HTTP headers, API discovery), and automated recurring scan setups."
version: 1.0.0
tags: [network, reconnaissance, scanning, security, dns, ssl, ports, containers]
---
## Overview
This umbrella skill consolidates all network scanning and reconnaissance capabilities:
- **Internal Subnet Scanning** — TCP sweep, port scanning, banner grabbing, SSH/TLS analysis from containers or Python
- **External Domain Reconnaissance** — DNS, SSL certificates, HTTP headers, API/service discovery
- **Automated Recurring Scans** — Weekly cronjob-based scanning with change detection
No nmap, no root privileges required. Pure Python stdlib (`socket`, `ssl`, `concurrent.futures`) for container environments.
---
## Section 1: Internal Subnet Scanning
### 1.1 Network Layout Discovery
**Always discover the actual IP format first.** Users may describe segments as "50.x" but the real network may be `10.0.X.Y`.
```bash
ip addr show eth0 | grep inet
ip route show
ping -c 1 -W 2 10.0.50.1
ping -c 1 -W 2 50.0.50.1
```
Common formats:
- `10.0.X.Y` where X = segment index (e.g., 10.0.20.10 = Hypervisor)
- Container usually sits in one segment (e.g., 10.0.30.230)
### 1.2 Two-Phase Scan Workflow
**Phase 1 — Host Discovery (fast TCP sweep)**
```python
import socket, concurrent.futures
PROBE_PORTS = [443, 80, 22, 2222, 3306, 8080, 8443]
def host_alive(ip, ports=PROBE_PORTS, timeout=0.3):
for p in ports:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
if sock.connect_ex((ip, p)) == 0:
sock.close(); return True
sock.close()
return False
with concurrent.futures.ThreadPoolExecutor(100) as pool:
alive = [ip for ip, ok in zip(segment_ips, pool.map(host_alive, segment_ips)) if ok]
```
**Phase 2 — Deep Scan (per host)**
```python
IMPORTANT_PORTS = {
22: "SSH", 23: "Telnet", 25: "SMTP", 53: "DNS", 80: "HTTP",
443: "HTTPS/TLS", 1883: "MQTT", 2222: "SSH-alt",
2375: "Docker", 2376: "Docker-TLS", 3306: "MySQL",
5432: "PostgreSQL", 6379: "Redis", 8080: "HTTP-alt",
8443: "HTTPS-alt", 8883: "MQTT-TLS", 9090: "Prometheus/Grafana",
9200: "Elasticsearch", 11211: "Memcached", 27017: "MongoDB",
}
def deep_scan(ip):
hostname = socket.gethostbyaddr(ip)[0] # may be None
ports = scan_host_ports(ip, IMPORTANT_PORTS, workers=30)
tls = analyze_tls(ip) if any(p[0]==443 for p in ports) else None
ssh = get_ssh_banner(ip, 22) or get_ssh_banner(ip, 2222)
web = get_web_header(ip, 80)
return {"ip": ip, "hostname": hostname, "ports": ports, "tls": tls, "ssh": ssh, "web_server": web}
```
### 1.3 TLS Analysis
```python
def analyze_tls(ip, port=443, timeout=5.0):
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
try:
with socket.create_connection((ip, port), timeout=timeout) as sock:
with ctx.wrap_socket(sock, server_hostname=ip) as s:
return {
"protocol": s.version(), "cipher": s.cipher()[0],
"cert_cn": next((f[0][1] for f in s.getpeercert().get("subject",[]) if f[0][0]=="commonName"), None),
"cert_issuer": next((f[0][1] for f in s.getpeercert().get("issuer",[]) if f[0][0]=="commonName"), None),
"valid_from": s.getpeercert().get("notBefore"),
"valid_until": s.getpeercert().get("notAfter"),
}
except Exception as e:
return {"error": str(e)[:80]}
```
### 1.4 SSH Banner Grab
```python
def get_ssh_banner(ip, port=22, timeout=5.0):
sock = socket.create_connection((ip, port), timeout=timeout)
banner = sock.recv(256).decode("utf-8", errors="ignore").strip()
sock.close(); return banner
```
### 1.5 Output Format
```json
{
"scan_date": "2026-05-17T08:03:11.184435+00:00",
"total_hosts": 60,
"scan_duration_seconds": 94.4,
"segments": {
"Hypervisor": {"subnet": "10.0.20.0/24", "alive_count": 10, "hosts": [...]},
"Container": {"subnet": "10.0.30.0/24", "alive_count": 26, "hosts": [...]},
"Smart Home": {"subnet": "10.0.50.0/24", "alive_count": 24, "hosts": [...]}
}
}
```
- `hostname` is usually `null` (no reverse-DNS in internal networks)
- `vendor` and `mac` are NOT included (no MAC access from container)
---
## Section 2: External Domain & Service Reconnaissance
### 2.1 DNS Resolution
```bash
getent hosts cloud.familie-schoen.com
host cloud.familie-schoen.com
```
### 2.2 Port Scanning (Bash /dev/tcp)
```bash
bash -c 'echo >/dev/tcp/HOST/PORT 2>&1 && echo open || echo closed'
# Common ports: 22, 25, 53, 80, 443, 587, 993, 995, 3306, 5432, 8080, 8443, 9090
```
### 2.3 HTTP/HTTPS Analysis
```bash
curl -sI http://DOMAIN
curl -ksI https://DOMAIN
curl -kI -L https/DOMAIN
curl -ks https://DOMAIN/path
# Security headers:
curl -ksI https://DOMAIN | grep -iE 'strict-transport|content-security|x-frame|x-xss|cache-control'
```
### 2.4 SSL Certificate Extraction
```bash
openssl s_client -connect HOST:443 -servername HOST 2>&1 </dev/null
openssl s_client -connect HOST:443 -servername HOST 2>&1 </dev/null | \
openssl x509 -noout -subject -issuer -dates -ext subjectAltName
```
### 2.5 API/Service Discovery
```bash
for endpoint in /api/v1/version /api/health /healthz /version /status /robots.txt; do
r=$(curl -ks https://HOST$endpoint)
[ -n "$r" ] && echo "$endpoint: $r"
done
```
Common services to fingerprint:
- Seafile: `/api2/server-info/`, `/seafhttp/`
- GitLab: `/api/v4/version`
- Nextcloud: `/.well-known/caldav`
- Grafana: `/api/health`
- Prometheus: `/metrics`
### 2.6 HTML Content Analysis
```bash
curl -ks https://DOMAIN | grep -ioE '<title>[^<]+'
curl -ks https://DOMAIN | grep -ioE 'wordpress|django|flask|react|angular|nextcloud|seafile|gitea|jenkins|grafana|prometheus'
```
---
## Section 3: Automated Recurring Scanning
For SRE-style weekly network scans with change detection, set up a `no_agent` cronjob:
```bash
# 1. Write the scan script to ~/.hermes/scripts/network-scan.py
# 2. Create the cronjob:
cronjob action=create \
name="weekly-network-scan" \
script="network-scan.py" \
schedule="0 8 * * 0" \
no_agent=true \
deliver="origin"
```
**Critical rules:**
- `script` parameter accepts **filename only** (relative to `~/.hermes/scripts/`), NOT an absolute path.
- Prefer `--no-agent` for pure script execution — faster, avoids model format issues.
- After any Hermes update, verify cron job model format (see `references/cron-model-fix.md`).
### Change Detection
Load the previous scan file and diff:
- New IPs → new hosts
- Missing IPs → gone hosts
- New ports on existing hosts → new services
- Different SSH banners → version changes
---
## Pitfalls
| Pitfall | Symptom | Solution |
|---------|---------|----------|
| Using nmap | Permission denied | Use Python stdlib only |
| Using arping | Hangs forever | NEVER use arping in containers |
| Using `ip neigh` for MAC | No MACs returned | OUI vendor detection is useless from container |
| Sequential TCP scan | 14+ min for /24 | Use ThreadPoolExecutor (100 workers sweep, 30 deep scan) |
| Wrong IP format | Can't reach targets | Verify with `ip route` and `ping` first |
| `script` path absolute | Cronjob fails | Use filename only in `script` param |
| Cron model null after update | `Error code: 400` | Update with `provider/model` format |
| ShareGPT first-run delay | 25 min wait | Pre-download once before benchmark suite |
| NumPy X86_V2 crash | `RuntimeError: NumPy...X86_V2` | `pip install "numpy<2.0" --force-reinstall` |
| Prefill throughput bias | First request inflates latency | Pre-warm with throwaway run, or filter `turn_index=0` from JSONL |
---
## References
- `references/container-network-recon-session-2026-04.md` — Session notes from initial network discovery
- `references/domain-service-recon-familie-schoen.md` — External domain scan example
- `references/cron-model-fix.md` — Post-Hermes-update cron job model fix
- `scripts/network-scan.py` — Full internal scan script (copy to `~/.hermes/scripts/`)