Go 主机安全面试:Linux fanotify 与 Web 后门落地检测
Web 后门落地检测看起来像“监控目录里有没有新增文件”,但面试里真正考的是:你能不能讲清楚 Linux 文件事件采集的能力边界,如何把文件变化、写入进程、Web 服务账号、脚本后缀、访问日志和后续执行串成一条可信证据链。
inotify 很轻,适合盯固定目录变化;fanotify 能覆盖更高层的文件访问通知,部分模式还能拿到文件描述符;audit/eBPF 更适合补“谁写的、谁执行的”。主机安全产品通常不会押宝单一来源,而是用最小成本组合出可解释告警。
岗位场景
Web 服务器
-> 监听站点目录、上传目录、临时目录和 include/plugin 目录
-> 捕获 create/write/rename/chmod/delete 等文件变化
-> 标准化 path、inode、owner、mode、hash、writer process、web user
-> 关联 HTTP 访问日志、Web RCE 进程链、脚本执行和外联
-> 对发布系统、CI/CD、插件升级、日志轮转和正常上传做降噪高频面试题
1. 为什么 Web 后门落地不能只靠定时扫描?
简洁答案:定时扫描能发现最终状态,但容易错过短生命周期文件、rename 过程和写入主体;实时事件能提供更完整的时间线。
关键知识点:
- 攻击者可能先写临时文件,再
rename成脚本后缀。 - 后门可能落地后很快执行、删除或改权限。
- 定时扫描适合作为兜底基线,事件采集适合补时间顺序。
- 告警价值不只是“文件存在”,还包括“谁写入、何时写入、之后做了什么”。
Go 落地思路:
- 固定 Web 根目录用 inotify/fanotify 做增量触发。
- 定时快照保存
path + inode + size + mode + mtime + sha256,补漏和重启恢复。 - 事件里保留
source字段,区分来自实时监听还是快照 diff。
2. inotify 和 fanotify 在 HIDS 里怎么取舍?
简洁答案:inotify 部署简单,适合目录级变化通知;fanotify 更适合文件访问通知和挂载点级监控,但权限、内核版本和性能成本更敏感。
关键知识点:
- inotify 关注目录和文件路径变化,事件里通常没有完整进程上下文。
- fanotify 可以按 mount 或 filesystem 维度接收事件,部分事件能拿到 fd。
- fanotify 权限事件用错会拖慢 IO,HIDS 默认应优先通知模式。
- 两者都不是“万能归因工具”,进程主体通常要靠 audit/eBPF 或临近时间窗口关联。
Go 落地思路:
- 小站点目录先用 inotify,覆盖多个挂载点或需要 fd 元数据时再考虑 fanotify。
- 本地 Agent 只做轻量归一化和采样,复杂关联放到服务端。
- 明确上报采集能力:
watch_backend=inotify|fanotify|snapshot。
3. 如何判断一个新增 PHP/JSP/ASP 文件是不是 WebShell?
简洁答案:不能只看后缀,要结合目录角色、文件内容特征、写入进程、账号、权限、访问日志和后续行为。
关键知识点:
- 上传目录出现可执行脚本比静态资源目录更可疑。
eval、assert、system、shell_exec、base64_decode是风险特征,但业务代码也可能使用。- WebShell 常伴随异常 HTTP 参数、短时间命令执行、反弹 shell 或内网探测。
- 发布系统、插件市场、CMS 升级会产生大量合法脚本变更。
Go 落地思路:
- 文件内容只做小窗口扫描,限制最大读取字节,避免拖垮 Agent。
- 规则输出 reason code,例如
script_in_upload_dir、risky_php_api、web_user_write。 - 对大文件、二进制文件和频繁变动目录做跳过或降采样。
func riskyScript(path string, data []byte) bool {
ext := strings.ToLower(filepath.Ext(path))
if ext != ".php" && ext != ".jsp" && ext != ".asp" && ext != ".aspx" {
return false
}
s := strings.ToLower(string(data))
return strings.Contains(s, "eval(") ||
strings.Contains(s, "shell_exec") ||
strings.Contains(s, "base64_decode")
}4. 没有进程上下文时,怎样补“是谁写的”?
简洁答案:用近时间窗口把文件事件和进程事件、HTTP 日志、audit/eBPF 写入事件关联;没有强证据时要降低置信度。
关键知识点:
- 文件事件只有路径变化时,不能硬说某个进程就是写入者。
- Web RCE 常见链路是
nginx/apache/php-fpm/java子进程写文件,再执行命令。 rename会让最终路径和原始写入路径不同,要保留 inode 和临时路径。- PID 会复用,关联进程必须带启动时间。
Go 落地思路:
- 维护短窗口 ring buffer,按
inode/path/time关联 exec、open/write、HTTP 请求和网络事件。 - 证据强度分层:audit/eBPF 写入主体 > fanotify fd 元数据 > Web 日志临近访问 > 纯路径变化。
- 告警字段里写明
confidence和missing_evidence。
5. 如何降低发布系统和正常上传造成的误报?
简洁答案:把业务基线纳入规则:发布窗口、发布账号、CI/CD 进程、包管理路径、允许后缀、目录角色和历史 hash 分布。
关键知识点:
- 正常发布通常批量、稳定、可追溯,并来自固定账号或部署工具。
- 攻击落地更常见于 Web 用户、临时目录、上传目录和非发布时段。
- 允许名单不能只按路径放行,否则攻击者会利用上传目录。
- 降噪要保留命中原因,方便客户调整策略。
Go 落地思路:
- 配置站点目录角色:
static、upload、template、plugin、runtime。 - 对 CI/CD 进程和发布窗口降权,不直接静默。
- 服务端按租户维护基线,Agent 不塞复杂策略。
6. fanotify 事件量太大时怎么做性能控制?
简洁答案:先缩小监控范围,再做事件合并、后缀过滤、限速、哈希延迟计算和采样;不要在 IO 热路径里做重内容分析。
关键知识点:
- Web 缓存、日志、临时文件和上传大文件会制造大量事件。
- 频繁计算全量 hash 会增加磁盘 IO。
- 权限事件可能阻塞业务 IO,默认不要启用拦截模式。
- 事件丢失和队列溢出必须显式暴露,否则检测结果不可解释。
Go 落地思路:
- 用
context.Context控制 watcher 生命周期。 - 对同一路径短时间多次写入做 debounce,稳定后再 hash。
- 上报
dropped_events、queue_lag、hash_skipped_reason等健康指标。
7. WebShell 落地后还要关联哪些后续行为?
简洁答案:重点关联脚本被访问、解释器执行命令、反弹 shell、下载二阶段载荷、提权和横向移动。
关键知识点:
- 落地文件只是攻击链前半段,后续执行更能提升置信度。
- 可疑进程包括
sh、bash、curl、wget、python、perl、nc等。 - Web 服务账号发起外联、读取敏感文件或执行系统命令都很可疑。
- 攻击链还原要保留时间顺序,不要只输出孤立 IOC。
Go 落地思路:
- 用统一
entity_id关联 file、process、network、http_request。 - 告警摘要按时间线输出:文件写入 -> HTTP 访问 -> 命令执行 -> 外联。
- 同一攻击链只生成一个主告警,避免每个子事件刷屏。
8. 面试里如何评价“用 fanotify 做实时 WebShell 检测”的方案?
简洁答案:方向可行,但不能把 fanotify 当成完整检测系统;它适合做文件事件入口,归因、降噪和攻击链关联还需要其他数据源。
关键知识点:
- 采集源负责看见变化,检测系统负责解释变化。
- 生产方案要考虑权限、内核版本、容器挂载、overlayfs、事件丢失和性能。
- 对客户有价值的是可解释证据链,而不是单个 API 名称。
- 最稳妥的架构是“实时事件 + 快照兜底 + 行为关联 + 策略降噪”。
Go 落地思路:
- 先做最小可用模型:目录监听、快照兜底、风险后缀、轻量内容扫描。
- 再按环境接入 audit/eBPF 补强写入主体和执行链路。
- 保留采集状态和降级路径,避免某个 watcher 失败后静默漏报。
学习要点
| 模块 | 要点 |
|---|---|
| 文件事件 | inotify、fanotify、rename、chmod、delete、队列溢出 |
| Web 安全 | WebShell、上传目录、解释器、Web RCE、访问日志 |
| Linux 原理 | inode、fd、权限、mount、overlayfs、PID 复用 |
| Go 实现 | watcher 生命周期、debounce、hash 限流、事件归一化 |
| 检测工程 | 证据强度、攻击链关联、误报治理、健康指标 |
小练习
- 设计一个
FileChangeEvent结构体,至少包含路径、inode、事件类型、来源、hash 和置信度。 - 如果只拿到 inotify 事件,没有 audit/eBPF,你会如何表达“疑似 Web 用户写入”的不确定性?
- 为什么上传目录里出现
.php比静态目录里出现.jpg风险更高? - 写一个 debounce 策略:同一路径 3 秒内多次写入只计算一次 hash。
- 画出 WebShell 落地到反弹 shell 的 5 个关键事件。
- 给发布系统、CMS 插件升级和攻击落地各设计 2 个区分特征。
复盘题
- fanotify 相比 inotify 的优势和代价是什么?
- 为什么文件后缀、内容关键字和路径都不能单独作为恶意结论?
- 如何把文件事件、HTTP 请求、进程执行和网络连接组织成一条告警时间线?
- 如果事件队列溢出,Agent 应该如何上报和补偿?
