Skip to content

Go 主机安全面试:Linux 进程伪装与命令行欺骗检测

攻击者拿到主机执行权限后,经常不急着做高噪声动作,而是先把进程伪装成系统服务、业务组件或内核线程样式,降低巡检和人工排查时的可见性。面试官通常会追问:进程名为什么不可信?commcmdlineexe 和启动路径有什么区别?Go Agent 如何用低成本字段发现伪装,同时避免把正常 supervisor、容器进程和脚本包装器误报成攻击?

岗位场景

text
Linux 主机
  -> 采集进程启动、procfs 快照、父子关系、用户、路径和文件元数据
  -> 识别 argv[0] 改名、prctl 改 comm、删除落地文件、系统进程名伪装
  -> 关联 Web RCE、临时目录执行、外联、提权和持久化动作
  -> 区分正常守护进程、容器入口、软链接启动、发布脚本和恶意伪装
  -> 输出可解释证据,而不是只告警“进程名可疑”

这类题考的是 Linux 进程模型、procfs 字段可信度、父子进程关联、文件身份、误报治理,以及 Go 侧事件标准化和轻量规则设计能力。

高频面试题

1. 什么是进程伪装,为什么主机侧要检测?

简洁答案:进程伪装是攻击者通过改进程名、命令行、文件名、路径或父进程表现,让恶意程序看起来像正常系统进程或业务进程。主机侧要检测它,因为网络或文件单点证据可能正常,只有把“谁在运行、从哪运行、以什么身份运行”串起来,才能发现伪装。

关键知识点:

  • Linux 进程展示名可能来自 /proc/<pid>/comm/proc/<pid>/cmdlineargv[0] 或工具自己的解析逻辑。
  • 攻击者可以把文件命名为 kworkersystemdsshdcron 等,制造人工排查误导。
  • argv[0] 可以和真实可执行文件路径不一致,comm 也可能被 prctl(PR_SET_NAME) 修改。
  • 内核线程通常没有普通用户态可执行文件路径,伪装成 [kworker/u8:2] 但有真实 exe 路径就很可疑。
  • 进程伪装本身不一定等于入侵,要结合落地路径、父进程、用户、网络和文件行为判断。

Go 落地思路:

  • 标准化进程事件时同时保存 commargv0cmdlineexe_pathpidppidstart_time
  • 检测逻辑不要只匹配进程名,要输出“不一致在哪里”和“为什么可疑”。
  • 对命中伪装候选的进程,再补充 hash、文件属主、权限、父进程链和网络连接。

2. /proc/<pid>/commcmdlineexe 有什么区别?

简洁答案:comm 是短进程名,cmdline 是启动参数,exe 是当前可执行文件软链接。三者来源不同、可信度不同,安全检测要比较它们的一致性,而不是只相信其中一个。

关键知识点:

字段作用风险点
/proc/<pid>/comm进程短名,通常最多 15 字节可被程序修改,容易截断
/proc/<pid>/cmdline启动命令行,NUL 分隔argv[0] 可伪造,也可能被覆盖或为空
/proc/<pid>/exe可执行文件软链接进程退出、权限不足或 deleted exe 会读取失败
/proc/<pid>/stat包含 comm、ppid、状态、启动时间comm 带括号,解析要处理空格和括号
文件元数据inode、mode、uid、mtime、hash文件可能被删除、替换或通过软链接启动

Go 落地思路:

go
type ProcessIdentity struct {
	PID       int
	PPID      int
	StartTime uint64
	Comm      string
	Argv0     string
	ExePath   string
	UID       uint32
}
  • pid + start_time 作为进程键,避免 PID 复用导致关联错人。
  • cmdline 解析要按 \x00 分隔;空命令行不能直接当作恶意。
  • exe 读取失败要区分 ENOENTEACCES(deleted),分别用于生命周期、权限和可疑落地判断。

3. 如何识别伪装成内核线程的用户态进程?

简洁答案:真正的内核线程通常没有用户态 cmdline 和常规可执行文件路径;如果一个普通用户态进程把名字伪装成 [kworker][migration][rcu_sched] 这类样式,但它有 exe、用户 ID、父进程和外联行为,就应该提高风险。

关键知识点:

  • 方括号样式常见于内核线程展示,但不能只凭名字判断。
  • 用户态进程可以把 argv[0] 设置成 [kworker/u8:2]
  • 真实内核线程的父进程、状态、地址空间和可执行文件表现与普通进程不同。
  • 容器或精简系统里展示方式可能有差异,规则要保留“候选”状态。
  • 伪装成内核线程后又发起公网连接、读取凭据或写启动项,可信度会明显上升。

Go 落地思路:

  • 建立一组“内核线程样式名”模式,但只作为候选条件。
  • 候选命中后检查 exe_path 是否存在、uid 是否为普通用户、是否有 cmdline 和网络连接。
  • 告警证据写清楚:comm="[kworker/...]",但 exe="/tmp/.cache/kworker",父进程为 Web 服务或 shell。

4. 如何识别 argv[0] 和真实可执行文件不一致?

简洁答案:把 cmdline 第一个参数、commexe basename 做归一化比较。如果 argv[0] 显示为 sshd,但 exe 指向 /tmp/.x,并且父进程、用户或路径也异常,就可能是命令行欺骗。

关键知识点:

  • execve 允许调用者传入自定义 argv[0]
  • BusyBox、Python、Java、Node、supervisor 和软链接启动会天然出现名字差异。
  • 只比较字符串会有误报,需要结合解释器脚本、软链接解析和文件 hash。
  • comm 最多 15 字节,长名称会被截断,不适合做严格等值判断。
  • 路径 basename 要做归一化,例如去掉路径、空白、方括号和常见版本后缀。

Go 落地思路:

go
func nameMismatch(argv0, exePath string) bool {
	a := filepath.Base(strings.TrimSpace(argv0))
	e := filepath.Base(exePath)
	if a == "" || e == "" {
		return false
	}
	return a != e
}
  • 这个函数只能产出风险线索,不能单独生成高危告警。
  • 对解释器类进程要额外看脚本路径和父进程,而不是要求 argv0 == exe basename
  • /usr/bin/python3pythonpython3.11 这类版本名做白名单归一化。

5. 进程名伪装和正常软链接启动怎么区分?

简洁答案:正常软链接启动通常路径稳定、包管理可追溯、父进程合理、hash 可基线;恶意伪装更常位于临时目录、隐藏目录、Web 上传目录或用户 home 下,并伴随异常父进程、外联和权限变化。

关键知识点:

  • /bin/sh -> dash/usr/bin/awk -> alternatives、BusyBox applet 都可能让名字和真实文件不同。
  • systemd、supervisor、容器 entrypoint 可能包装业务进程,不能简单按父进程异常判定。
  • 恶意样本常用近似名:sshd/sshd2systemd/systemd-udevdkthreadd/kthread
  • 隐藏目录如 /tmp/.cache//var/tmp/.x//dev/shm/. 结合系统进程名更可疑。
  • 降噪要绑定路径、签名或 hash、包来源、用户和主机角色,不能只对白名单进程名放行。

Go 落地思路:

  • 维护“可信启动路径 + 文件身份”基线,而不是维护“可信进程名”基线。
  • 对软链接读取 EvalSymlinks 或保留 link_path -> target_path 证据。
  • 规则输出中区分 symlink_expectedname_mismatchsystem_name_from_tmp 等原因。

6. 如何把进程伪装和攻击链关联起来?

简洁答案:进程伪装只是隐藏阶段的线索,真正高置信要看前后行为:是否由 Web 服务、异常 shell、定时任务或账号登录拉起,是否在临时目录落地,是否外联、读取凭据、修改启动项或清理日志。

关键知识点:

  • 常见链路:php-fpm -> sh -> wget/curl -> /tmp/.systemd,随后伪装成系统进程外联。
  • 伪装二进制如果写入 systemd service、cron 或 shell profile,说明有持久化意图。
  • 伪装进程读取 /etc/shadow、SSH key、云元数据凭据,说明风险升级。
  • 如果只看到名字不一致,没有其他行为,应先作为中低危候选。
  • 攻击链关联要允许乱序和迟到事件,不能因为网络事件先到就丢掉后续补证。

Go 落地思路:

  • host_id + pid + start_time 缓存短期进程画像,按 file_inode 关联落地文件。
  • 规则引擎输出分层状态:candidatesuspicioushigh_confidence
  • 服务端可在更长窗口合并 Web RCE、文件落地、进程伪装、外联和持久化事件。

7. 客户现场误报“业务进程名不一致”,你怎么处理?

简洁答案:先确认它是否属于正常启动机制,再看路径、包来源、父进程、hash、用户和主机角色是否稳定。如果稳定且可解释,就把它沉淀成条件化基线;如果只是为了消除告警而按名称白名单,会留下绕过空间。

关键知识点:

  • Java、Python、Node、Go wrapper、supervisor、容器 entrypoint 都可能造成展示名不一致。
  • 发布系统可能生成临时路径,但通常有固定用户、固定父进程和可追溯 hash。
  • 客户主机角色不同,基线也不同;数据库主机和 Web 主机的进程画像不能混用。
  • 白名单要有失效条件,例如 hash 变化、路径漂移、父进程异常、开始外联陌生目标。
  • 降噪结果要可审计,避免规则越调越宽。

Go 落地思路:

  • 基线 key 使用 host_role + user + real_path + hash/signature + parent_path
  • 告警降级时保留 suppressed_reason 和命中基线版本。
  • 对同名不同路径、同路径 hash 变化、普通用户运行系统名进程保留低成本审计事件。

8. Go Agent 做这类检测时如何控制性能?

简洁答案:进程伪装检测主要依赖轻量字段,可以在 exec 事件到达时实时判断,在周期扫描时补漏。高成本操作如 hash、签名、完整父进程树和 fd/network 关联,应放在候选命中后异步补证。

关键知识点:

  • 全量扫描 /proc 的成本和进程数相关,频率不能太高。
  • commcmdlineexestatus 成本较低,fdmaps、hash 成本更高。
  • 短生命周期进程只靠定时扫描容易漏,最好结合 eBPF、auditd 或 exec 事件。
  • 候选缓存要设置 TTL,避免长期保存大量进程画像。
  • 资源指标要能解释“为什么没有补到 hash 或网络证据”。

Go 落地思路:

  • 热路径只做字段归一化和候选打分。
  • 命中候选后进入异步 enrich worker,按限速补充 hash、父进程、网络连接。
  • 暴露 process_masquerade_candidates_totalenrich_failed_totalproc_read_denied_total 等指标。

通俗答案

可以把进程伪装理解成“穿制服冒充工作人员”。只看衣服上的名字,攻击者可以写成 systemdsshd[kworker];但如果再看工牌、来路、办公地点、行为记录,就容易发现破绽。主机安全检测也是一样:进程名只是入口,真正可信的是多字段一致性和行为链路。

Go 落地设计要点

进程身份模型

go
type ProcessEvent struct {
	HostID    string
	PID       int
	PPID      int
	StartTime uint64
	UID       uint32
	Comm      string
	Argv      []string
	ExePath   string
	Cwd       string
	Source    string
	At        int64
}

检测策略

  • 第一层:比较 commargv[0]exe basename,识别名字不一致和系统名伪装。
  • 第二层:检查路径画像,例如临时目录、隐藏目录、Web 上传目录、用户 home 下的系统进程名。
  • 第三层:关联父进程、用户、网络连接、文件落地和持久化行为,决定告警等级。
  • 第四层:命中可信基线时降级,但保留低成本审计和基线命中原因。

告警证据

text
process_name="[kworker/u8:2]"
exe_path="/tmp/.cache/kworker"
parent="php-fpm -> sh"
uid=33
reasons=["kernel_thread_name_with_user_exe", "tmp_hidden_path", "web_parent_chain", "public_egress"]

这类输出比“发现可疑进程”更适合面试和真实客户沟通,因为它回答了三个问题:哪里伪装、为什么可疑、还关联了哪些行为。

学习要点

  • Linux 进程字段:commcmdlineexestatstatusstart_time
  • 伪装手法:argv[0] 欺骗、prctl 改名、系统进程名仿冒、隐藏路径、deleted exe。
  • 检测方法:字段一致性校验、路径画像、父子链路、文件身份、网络和持久化关联。
  • 工程重点:轻量热路径、异步补证、TTL 缓存、基线降噪、可解释告警。
  • 排障边界:权限不足、进程退出、容器命名空间、软链接启动和 supervisor 包装都可能影响判断。

小练习/复盘题

  1. 写一个 Go 函数,读取 /proc/<pid>/cmdline/proc/<pid>/exe,输出 argv0exe basename 是否一致。
  2. 设计一条规则:普通用户启动名为 [kworker] 的进程,真实路径在 /tmp/.cache/,并发起公网连接,应该输出哪些证据字段?
  3. 给 Java、Python、BusyBox 和 supervisor 各举一个正常名字不一致的例子,并说明如何降噪。
  4. 如果客户反馈“误报了业务发布脚本”,你会要求提供哪些字段来判断是基线问题还是规则过宽?
  5. 思考为什么 pid 不能单独作为进程唯一键,start_timeboot_id 和容器 namespace 分别解决什么问题?
最近更新