# callhome **Repository Path**: tomlen/callhome ## Basic Information - **Project Name**: callhome - **Description**: 外联信标哨兵 — 谁在偷偷打电话回家? lsof 多轮采样, 信标样常驻外联自动浮顶, 基线漂移抓 first-seen。零依赖单文件, 哨兵套件外联面。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-11 - **Last Updated**: 2026-10-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # callhome 📡 **外联信标哨兵** —— 哨兵套件的「外联面」一环:[porteye](https://github.com/tomlen045/porteye) 管「谁在听」,[suidhunt](https://github.com/tomlen045/suidhunt) 管「谁能提权」,[authguard](https://github.com/tomlen045/authguard) 管「谁想进来」,**callhome 管「谁在偷偷打电话回家」**。 半夜三点你的服务器往外发 TCP 包,你知道是谁吗?callhome 用 `lsof` 多轮采样,把每个进程的每条外联流按「进程 → 目标 → 出现轮次」聚合,**信标样常驻外联自动浮顶**:临时目录里的进程在对外通信直接 CRIT(exit 3),公网常驻信标 HIGH,本地链路噪音自动降噪 INFO。 [![tests](https://img.shields.io/badge/self--tests-22%2F22-green)]() [![beacon-drill](https://img.shields.io/badge/beacon--drill-live--caught-green)]() [![deps](https://img.shields.io/badge/deps-zero-yellow)]() [![license](https://img.shields.io/badge/license-MIT-blue)]() [English](README_EN.md) | 简体中文 --- ## 解决什么问题 * 反弹 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/日志平台直接吃 ## 30 秒上手 ```bash # 多轮采样 + 信标判定 (默认 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 是第一次盘点和应急用的。 ## 与哨兵套件配合 ```bash # 每天一条 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 通用 ## 自测 ```bash python3 selftest.py # 22/22 全绿 (离线 fixture, 不依赖真实网络) ``` MIT License · 零依赖单文件 · Python 3.8+