外联信标哨兵 —— 哨兵套件的「外联面」一环:porteye 管「谁在听」,suidhunt 管「谁能提权」,authguard 管「谁想进来」,callhome 管「谁在偷偷打电话回家」。
半夜三点你的服务器往外发 TCP 包,你知道是谁吗?callhome 用 lsof 多轮采样,把每个进程的每条外联流按「进程 → 目标 → 出现轮次」聚合,信标样常驻外联自动浮顶:临时目录里的进程在对外通信直接 CRIT(exit 3),公网常驻信标 HIGH,本地链路噪音自动降噪 INFO。
English | 简体中文
- 反弹 shell / C2 信标的第一特征是**「进程位置不对 + 目标固定 + 长期在场」**——
netstat看一眼就过去,没人天天盯。callhome 多轮采样聚合,常驻外联按「在场轮次占比」排序,信标自己浮到第一行 - 传统「看连接」工具把 fe80:: 本地链路、127.0.0.1 回环、推送心跳全端出来报警,狼来了三次你就再也不看了。callhome 分域降噪:本地链路恒 INFO,推送/浏览器类平台常客标注降级,报出来的都是真该看的
- 进程在 /tmp、/private/var/folders(macOS 临时区)、Downloads、/dev/shm 里还敢对外连——这是比「目标 IP 是谁」更强的信号,callhome 直接 CRIT
- 昨天还没的外联目标今天出现了 → snapshot 拍基线 + compare 找新增:基线只收「出现 ≥2 轮」的稳定目标,瞬时连接不污染;新增目标按 CRIT/HIGH/MED 分级,退出码直接接监控管道
- 盯外联不想盯细节 →
--json全量导出,SIEM/日志平台直接吃
# 多轮采样 + 信标判定 (默认 10 轮 x 3s, 约 30 秒)
python3 callhome.py watch
# 快速看一眼 (2 轮)
python3 callhome.py watch --rounds 2 --interval 1
# 信标阈值放宽: 在场 60% 即算常驻 (抓断续信标)
python3 callhome.py watch --hits 0.6
# 拍外联基线 (稳定目标才入库)
python3 callhome.py snapshot callhome_base.json --rounds 8 --interval 3
# 以后每天 cron 一跑: 只报基线外新增
python3 callhome.py compare callhome_base.json
# 全量盘点含平台心跳类 + JSON 导出
python3 callhome.py watch --show-all --json callhome_flows.json退出码即结论:0=clean · 1=MED+ · 2=HIGH+ · 3=CRIT。挂 cron/监控管道不用解析文本。
| 场景 | 判定 |
|---|---|
| 临时目录/下载区/内存盘进程 + 任何外联 | CRIT (exit 3) |
| 非白名单进程 + 公网目标常驻(≥80% 轮在场) | HIGH (exit 2) |
| 基线外新增公网目标(常驻) | HIGH (exit 2) |
| 私网目标常驻 / 公网断续外联 / 基线外新增(断续) | MED (exit 1) |
| 本地链路 fe80::/127. 回环目标 | INFO(降噪) |
| 推送/浏览器类平台常客(Chrome/apsd/identityservicesd…) | INFO(标注降级) |
白名单是「平台常客」进程名模糊匹配(chrome/apsd/push/mdns…30+ 条),只影响降噪不影响盘点——--show-all 一条不少全部列出。
开发时跑过一轮实弹:后台起一个 Python 进程对 93.184.216.34:443 每 0.8s 重连一次——
$ python3 callhome.py compare demo_base.json --rounds 4 --interval 2
基线: 2026-10-11 10:20:49 (54 条) → 现状: 73 条外联流
------------------------------------------------------------------------
[MED] 93.184.216.34:443 (tcp)
↑ Python
/Library/.../Python.app/Contents/MacOS/Python
· 基线外新增 (基线 2026-10-11 10:20:49 建立, 54 条)
· 在场 3/4 轮
------------------------------------------------------------------------
结论: HIGH — 3 条信标样新目标, 建议核对归属
信标进程第一次出现就被拎出:目标、进程、路径、在场轮次,一行不缺。
在本机(开着一堆应用的 macOS)跑 watch --rounds 8:116 条外联流里 CRIT 0 / HIGH 42 / MED 6 / INFO 68——WPS 云服务 8 个目标、企业微信 9 个、ClassIn 4 个、xray 2 个全部在列。这些不是入侵,但你被问「这台机器都在跟谁通信」时,答案 30 秒就有。
callhome 只看「谁在往外连」,看不到连接里传了什么内容——那要抓包(tcpdump/Wireshark)。它定位的是「该看哪条」:先用它把 116 条收到 6 条,再对这 6 条上抓包。另外 watch 模式对「应用正常联网」也会标 HIGH(它不认识你的应用),所以才有 snapshot/compare——基线法才是日常姿势,watch 是第一次盘点和应急用的。
# 每天一条 cron, 四个哨兵各守一面:
python3 cronguard.py doctor # 定时任务面
python3 authguard.py check # 登录面
python3 suidhunt.py --compare suid_baseline.json # 特权面
python3 callhome.py compare callhome_base.json # 外联面- 采样靠
lsof -i,只能看到采样瞬间的连接;只连一次就断的闪连可能错过(--rounds加大窗口可缓解) - macOS 上看其他用户进程的完整信息可能需要 sudo;不加 sudo 盘点自己会话内的外联已够用
- Windows 不支持(lsof 依赖);macOS / Linux 通用
python3 selftest.py # 22/22 全绿 (离线 fixture, 不依赖真实网络)MIT License · 零依赖单文件 · Python 3.8+