web3-ai-game/oece-x-blue-sh
GitHub: web3-ai-game/oece-x-blue-sh
一款单文件 Bash 编写的 VPS 蓝队安全加固面板,提供从加固评分到蜜罐、监控和应急响应的完整防御闭环,所有变更均可回滚。
Stars: 0 | Forks: 0
### 🔗 姊妹项目 / Sister Project
| 项目 | 回答的问题 | 短命令 |
|:-----|:-----------|:-------|
| [**oece-x.sh**](https://github.com/web3-ai-game/oece-x-sh) | 这台机器**值不值**? | `bash <(curl -sL oece-x.com/x)` |
| **oece-x-blue.sh** ← 你在这里 | 这台机器**守不守得住**? | `bash <(curl -sL oece-x.com/b)` |
## ⚡ 快速开始 / Quick Start
| 方式 / Method | 命令 / Command |
|:----:|:-----|
| 🌐 **官网一键** | `bash <(curl -sL oece-x.com/b)` |
| 🐙 **GitHub raw** | `bash <(curl -sSL https://raw.githubusercontent.com/web3-ai-game/oece-x-blue-sh/main/oece-x-blue.sh)` |
| 📊 **只跑评分** | `bash oece-x-blue.sh --audit` |
| 📡 **直接进面板** | `bash oece-x-blue.sh --panel` |
| 🔇 **跳过动画** | `OECE_NO_ANIM=1 bash <(curl -sL oece-x.com/b)` |
```
# 推薦 / Recommended
bash <(curl -sL oece-x.com/b)
```
## 💡 为什么需要这个 / Why This Exists
**大多数 VPS 教程停在“改个 SSH 端口、装个 fail2ban”就结束了。**
*Most VPS tutorials stop at "change the SSH port, install fail2ban."*
真正的蓝队工作是一个闭环,而且有一个所有教程都轻描淡写的风险:
```
flowchart LR
A["👁️ 看得見Visibility"] --> B["🛡️ 守得住
Hardening"] B --> C["🪤 有陷阱
Deception"] C --> D["🔔 有告警
Alerting"] D --> E["🔍 查得清
Forensics"] E --> A style A fill:#0EA5E9,color:#fff,stroke:none style B fill:#8B5CF6,color:#fff,stroke:none style C fill:#F59E0B,color:#fff,stroke:none style D fill:#10B981,color:#fff,stroke:none style E fill:#EF4444,color:#fff,stroke:none ```
### ⚠️ 加固 SSH 最大的风险不是被入侵,是把自己关在门外
### *SSH 加固的头号风险不是入侵——而是把自己锁定在外*
一个“一键加固”脚本如果没有逃生机制,就是一键自杀。所以本项目的**第一个**功能不是加固,而是防锁门:
```
flowchart TD
S["開始加固Start"] --> P{"preflight
留存帳戶真的有可用公鑰?
Valid pubkey exists?"} P -->|"❌ 沒有 / None"| R["拒絕執行
Refuse — no lockout possible"] P -->|"✅ 有 / Yes"| BK["備份設定
Backup to /var/backups/oece-x/"] BK --> T["⏱️ 排定 N 分鐘後自動還原
Arm auto-rollback timer"] T --> AP["套用變更 + sshd -t 驗證
Apply + validate"] AP --> U{"你另開終端登入
並執行 xb --confirm ?"} U -->|"✅ 有 / Confirmed"| OK["取消定時器 · 寫入 manifest
Timer cancelled"] U -->|"❌ 沒有 / Timeout"| RB["⏮️ 自動還原到加固前
Auto-restored"] style R fill:#EF4444,color:#fff,stroke:none style OK fill:#10B981,color:#fff,stroke:none style RB fill:#F59E0B,color:#fff,stroke:none style T fill:#0EA5E9,color:#fff,stroke:none ``` **没登上去 = 没确认 = 自动还原。** 这是整个脚本最重要的设计。 *Didn't get back in? Then you never confirmed, and it rolls itself back.* ## 📸 界面预览 / UI Preview ### 蓝队态势面板 · Live Threat Panel 实测输出,来自一台全新的 DigitalOcean Debian 13 机器: *Real output from a freshly provisioned DigitalOcean Debian 13 droplet:* ``` ╔══════════════════════════════════════════════════════════════╗ ║ OECE-X BLUE · 藍隊態勢面板 07-23 12:38 oece-blue-testbo ║ ╚══════════════════════════════════════════════════════════════╝ 加固評分 ▊▊▊▊▊▊▊▊▊▊▊░░░░░░░░░ 56/100 偏弱 ──────────────────────────────────────────────────────── 防火牆 iptables open 入侵防禦 未安裝 24h 失敗登入 34 蜜罐命中 39 root 30 / admin 9 Top 攻擊源 45.61.188.7 (24 次) 194.26.29.3 (9 次) 162.214.22.174 (1 次) ──────────────────────────────────────────────────────── 當前會話 root@27.34.111.135 監聽埠 5355(systemd-resolve) 22(sshd) 25(exim4) 53(systemd-resolve) 安全更新 4 個待裝 重啟需求 否 負載 / 磁碟 1.73, 0.60, 0.22 5% 已用 / 25G ──────────────────────────────────────────────────────── [r] 重新整理 [w] 每 10 秒自動刷新 [a] 完整評分明細 [Enter] 返回 ``` ### 加固评分体检 · Hardening Audit ``` ── 身份與存取 ── ✘ root SSH 登入 允許 root 直接登入 ↳ 修復:選單 10 · root 蜜罐 ✔ 密碼認證 已關閉,僅金鑰登入 ✔ 空密碼登入 已禁止 ✔ uid=0 帳戶 僅 root(正常) ✔ 空密碼帳戶 無 ▲ sudo 免密規則 1 條 NOPASSWD(雲鏡像常見預設,確認是你要的) ✔ 公鑰盤點 共 1 把:root:1 — 逐一確認都是你自己的 ▲ MaxAuthTries 6(建議 ≤3) ▲ LoginGraceTime 120s(建議 20-30s,降低半開連線耗用) ── 內核與掛載 ── ✘ 網路層 sysctl 4 項未達標:rp_filter accept_redirects send_redirects log_martians ✘ /dev/shm 掛載 缺 noexec/nosuid — 攻擊者常在此落地執行檔 ── 完整性 ── ✔ ld.so.preload 空或不存在(正常) ✔ 已刪除二進制進程 無 ▲ SUID 檔案 12 個,已建立首次基線(下次即可比對變化) ──────────────────────────────────────────────────────── 加固評分 ▊▊▊▊▊▊▊▊▊▊▊░░░░░░░░░ 57/100 · 偏弱 得分 110 / 滿分 191(不適用項目已排除在分母外) ──────────────────────────────────────────────────────── ```
**一台刚开机、你什么都还没做的 VPS —— 57 分。**
*A brand-new VPS you haven't touched yet: 57/100.*
## 🧰 功能总览 / Feature Matrix
| # | 模块 ZH | EN | 说明 | 状态 |
|:-:|:--------|:---|:-----|:----:|
| **1** | **蓝队面板** ★ | Live panel | 评分趋势 · 封禁 · Top 攻击源 · 蜜罐命中 · 10s 自动刷新 | ✅ |
| **2** | **加固评分体检** ★ | Hardening score | 32 项只读检查 · 6 组 · 附修复指引 | ✅ |
| 3 | Lynis 深度审计 | Third-party audit | 业界标准工具的独立第二意见 | ✅ |
| **4** | **一键加固 · 基础** ★ | Harden: basic | 补丁 · sysctl · 挂载选项(**零锁门风险**) | 🚧 |
| **5** | **一键加固 · 标准** ★★ | Harden: standard | SSH 收紧 · 防火墙 · 入侵防御(挂自动回滚) | 🚧 |
| 6 | 一键加固 · 硬核 | Harden: hardcore | 管理员换人 · root 蜜罐 · 改端口 | 🚧 |
| 7 | 逐项加固 | Cherry-pick | 手动挑选单项 | 🚧 |
| **8** | **CrowdSec** ★ | Community IPS | 社群威胁情报(**共享预设关闭**) | 📋 |
| 9 | fail2ban | Lightweight IPS | 轻量封禁,适合 <512MB | 📋 |
| **10** | **root 蜜罐** ★ | Root honeypot | 诱饵帐户 · 诱饵用户名秒封 · 本地命中统计 | 📋 |
| **11** | **endlessh 焦油坑** ★ | SSH tarpit | 22 埠每 10s 吐一字符,把扫描器挂住数小时 | 📋 |
| **12** | **防火墙** ★ | Firewall | UFW + **Docker 绕过修复** + Cloudflare-only 入口 | 📋 |
| 13 | 告警通道配置 | Alert channels | Telegram / 邮件(`/etc/oece-x/blue.env`) | 📋 |
| **14** | **登入即时告警** ★ | Login alerts | PAM 钩子,登入成功 1 秒推送 | 📋 |
| 15 | 每日巡检报告 | Daily report | cron 日报 + **配置漂移侦测** | 📋 |
| **16** | **IOC 快检** ★ | IOC scan | 入侵指标扫描(只读) | 📋 |
| 17 | 一键取证包 | Forensics bundle | 打包全部证据 + REPORT.md | 📋 |
| 18 | 封禁 / 解封 / 踢人 | Ban & kick | IP 黑名单 + 强制下线 | 📋 |
| **19** | **紧急锁定** ★ | Emergency lockdown | 只放行当前 IP,其余全封 | 📋 |
| 20 | 回滚与还原 | Rollback | 逐项撤销 / 全部还原 | 🚧 |
| 21 | 检查更新 | Self-update | 对比远程版本 | 📋 |
*Identity & Access* | root SSH 登入 · 密码认证 · 空密码登入 · uid=0 帐户 · 空密码帐户 · sudo 免密 · **全系统公钥盘点** · MaxAuthTries · LoginGraceTime | | **网络暴露**
*Network Exposure* | 防火墙状态 · 公网监听埠 · **Docker 绕过防火墙侦测** · IPv6 同步防护 | | **补丁**
*Patching* | 待装安全更新 · 自动安全更新 · 重启需求 | | **内核与挂载**
*Kernel & Mounts* | 13 项 sysctl · `/dev/shm` 与 `/tmp` 的 noexec/nosuid · core dump | | **侦测能力**
*Detection* | 入侵防御引擎 · auditd · AIDE 基线 · 登入告警 · 日志保留 | | **完整性**
*Integrity* | `ld.so.preload` · **执行档已被删除的进程** · SUID 基线比对 · **计划任务中的“下载即执行”** · 临时目录可执行档 · 全域可写目录 |
| 分数 | 评级 | Grade |
|:----:|:----:|:------|
| 90-100 | 优秀 | Excellent |
| 75-89 | 良好 | Good |
| 60-74 | 及格 | Passing |
| 40-59 | 偏弱 | Weak |
| 0-39 | 危险 | Critical |
## 🏗️ 架构:三条降级链 / Architecture: Three Degradation Chains
**设计原则:任何资料源取不到就降级,绝不中断、绝不假装没问题。**
*Design rule: every data source degrades gracefully — never crash, never silently under-report.*
```
flowchart TD
subgraph SSHD["sshd 設定 / SSH config"]
A1["sshd -T(權威)"] -->|失敗| A2["解析 sshd_config.d/*.conf+ sshd_config"] A2 -->|沒寫該項| A3["OpenSSH 官方預設值
標註「推定」"] A1 -.->|無 SSH 服務| A4["整組 SKIP"] end subgraph LOG["auth 日誌 / Auth log"] B1["journalctl -t sshd -t sshd-session"] -->|濾掉 meta 行後為空| B2["/var/log/auth.log
或 /var/log/secure"] end subgraph FW["防火牆 · IPS"] C1["ufw"] --> C2["nftables"] --> C3["iptables"] D1["CrowdSec"] --> D2["fail2ban"] end style A1 fill:#0EA5E9,color:#fff,stroke:none style B1 fill:#0EA5E9,color:#fff,stroke:none style A3 fill:#F59E0B,color:#fff,stroke:none ```
🐛 为什么这三条链是必要的 —— 三个真实踩过的坑 / Three real bugs that shaped this design
**1. 配置档没写,不代表没开** `sshd -T` 会因为配置有误、缺 privsep 目录、或旧版不支持而失败。早期版本遇到这种情况只显示“无法读取”—— 但配置档里没有 `PasswordAuthentication` 这一行,**不代表密码登入是关的,OpenSSH 预设就是 `yes`**。 不套用官方预设值会严重**低报**真实风险。现在会降级推导并明确标注“推定”。 *A missing `PasswordAuthentication` line doesn't mean password auth is off — OpenSSH defaults it to `yes`. Reporting "unknown" here would materially under-report risk.* **2. `journalctl` 的空输出不是空字符串** 无资料时 `journalctl` 会印 `-- No entries --`(16 字符,**非空**)。 早期版本用“输出非空”判断有资料,于是永远不降级到 `/var/log/auth.log`, 导致**所有统计恒为 0** —— 面板上的数字全是假的。纯看代码看不出来,是容器测试才暴露的。 *`journalctl` prints `-- No entries --` when empty. Treating that as "has data" meant the log-file fallback never fired and every stat silently read zero.* **3. OpenSSH 10 改了 syslog 识别码** OpenSSH 9.8+ 把工作进程拆成 `sshd-session`。在 Debian 13(OpenSSH 10.0)上, 只查 `journalctl -t sshd` 会**一条日志都找不到**。本项目两个识别码都带。 *OpenSSH 9.8+ split the worker into `sshd-session`. On Debian 13 a `-t sshd`-only query returns nothing at all.*
**开始加固前,请先确认你知道自己云商的控制台在哪里。**
*Before hardening: know where your provider's console is.*
三道防线 / *Three layers of protection*:
| # | 机制 / Mechanism | 做什么 / What it does |
|:-:|:-----------------|:----------------------|
| **1** | **preflight 守门员** | 逐行跑 `ssh-keygen -l` 验证留存帐户**真的有可用公钥**(不是看档案存不存在);印出完整配置 diff;问你有没有 VNC / 救援模式。**没有任何有效公钥时直接拒绝执行禁用密码登入。** |
| **2** | **arm_rollback 定时器** | 备份原配置 → 排定 N 分钟后自动还原 → 要求你**另开终端**登入并执行 `xb --confirm`。逾时未确认即自动还原。 |
| **3** | **manifest 变更清单** | 每个动作把“做了什么 / 怎么撤销”写进 `/var/lib/oece-x/manifest.tsv`,可逐项或全部撤销。 |
### 真的被锁在外面了怎么办 / If you do get locked out
```
# 1. 用雲商的 VNC / 序列埠控制台登入
# DigitalOcean · Vultr · Linode · Hetzner · 阿里雲 都有
# 2. 還原備份
cp /var/backups/oece-x/<最新時間戳>/* /etc/ssh/sshd_config.d/
# 3. 重啟 sshd
systemctl restart sshd
```
## 🪤 主动防御设计 / Active Defense Design
### root 蜜罐 / Root Honeyp
机器人 99% 的暴破都打 `root`、`admin`、`ubuntu`、`test` 这几个名字。
把它们全部变成**诱饵**:真管理员换一个名字,诱饵帐户锁死并在**第一次尝试就封禁**。
*Bots overwhelmingly target `root`, `admin`, `ubuntu`, `test`. Turn all of them into tripwires: move the real admin elsewhere, lock the decoys, and ban on the **first** attempt.*
```
flowchart LR
BOT["🤖 掃描器Scanner"] -->|"ssh root@..."| SSHD["sshd"] SSHD -->|"DenyUsers root"| DENY["❌ 立即拒絕"] DENY --> BAN["🚫 maxretry=1 秒封
Instant ban"] DENY --> ALERT["🔔 告警 + 本地統計
Alert + local stats"] YOU["👤 你
You"] -->|"ssh <真管理員>@... :2222"| SSHD SSHD -->|"AllowUsers + 公鑰"| OK["✅ 放行"] style DENY fill:#EF4444,color:#fff,stroke:none style BAN fill:#F59E0B,color:#fff,stroke:none style OK fill:#10B981,color:#fff,stroke:none ``` ### endlessh 焦油坑 / SSH Tarpit 真 SSH 搬走后,让 22 埠**每 10 秒吐一个字符**的假 banner。扫描器会傻等好几个小时。 *Once real SSH has moved, serve an endless banner on port 22 — one character every 10 seconds. Scanners hang for hours.* ``` endlessh 已困住 41 個掃描器 · 累計浪費 63.2 小時 ``` ## 🔒 合规与隐私 / Compliance & Privacy
🌍 English Summary — click to expand
### 这是什么? `oece-x-blue.sh` is a single-file Bash blue-team panel for VPS hardening. It closes the loop that most tutorials leave open: **see → harden → deceive → alert → investigate**. ### 为什么还要另一个加固脚本? Because "one-click hardening" without an escape hatch is one-click suicide. The single most important feature here is not any hardening step — it's the **auto-rollback timer**: 1. Preflight verifies the account you're keeping has a **genuinely valid public key** (parsed with `ssh-keygen -l`, not just "the file exists"). No valid key → the script refuses. 2. Config is backed up and a timed restore job is armed. 3. Changes are applied and validated with `sshd -t`. 4. You must open a **second terminal**, log in with the new config, and confirm. 5. No confirmation within the window → everything is automatically restored. ### 亮点 - **32-point hardening score** across identity, exposure, patching, kernel, detection, and integrity. `SKIP` items are excluded from the denominator, so absent subsystems don't distort your score. - **Live threat panel** — bans, 24h failed logins, top attacking IPs, honeypot hits, tarpit stats. - **Root honeypot** — the usernames bots actually target (`root`, `admin`, `ubuntu`, `test`) become tripwires that ban on the *first* attempt. All captured data stays local. - **endlessh tarpit** — one banner character every 10 seconds on port 22; scanners hang for hours. - **Docker/UFW bypass fix** — Docker writes FORWARD-chain rules that `ufw deny` never sees. The audit cross-references published container ports against actual firewall rules. - **Graceful degradation everywhere** — three fallback chains (sshd config, auth logs, firewall/IPS) so the tool produces correct output on stock images, minimal containers, and OpenSSH 8 through 10. ### 隐私 Zero telemetry. Honeypot captures never leave the machine. CrowdSec's community signal sharing — which is normally on by default — is **opt-in** in this script. No proxy or circumvention features. Third-party binaries are pinned and SHA256-verified over HTTPS. ### 要求 Root. Debian 11+ / Ubuntu 20.04+ / RHEL-family 8+, amd64 or arm64. Menu items 1–3 are strictly read-only — safe to run before committing to anything. ``` bash <(curl -sL oece-x.com/b) ```