SUID 自定义二进制静态分析
靶场里异常 SUID 程序通常是本地提权入口。它们可能检查某些触发文件、调用系统命令、拼接路径、执行备份或隐藏硬编码密钥。分析时不必一开始就上反编译器,file + strings + objdump + strace/ltrace 往往足够恢复主线。
枚举异常 SUID
find / -perm -4000 -type f 2>/dev/null
重点关注:
- 不属于常见系统组件的名字。
- 位于
/usr/local/bin、/opt、/home的 SUID。 - 名称暗示 root、backup、reset、admin、check。
基础信息
ls -l /usr/bin/reset_root
file /usr/bin/reset_root
strings -a /usr/bin/reset_root | head -n 100
strings 里如果出现这些内容,基本就有方向:
RESETTING ROOT PASSWORD TO:
/usr/sbin/chpasswd
access
/tmp/...
/dev/shm/...
动态观察
strace -f -o /tmp/trace.txt /usr/bin/reset_root
rg -n 'access|open|execve|stat|chpasswd|/tmp|/dev/shm' /tmp/trace.txt
如果系统有 ltrace:
ltrace -o /tmp/ltrace.txt /usr/bin/reset_root
动态观察能直接暴露文件检查、命令执行和库函数调用。
反汇编主函数
objdump -d -Mintel /usr/bin/reset_root | sed -n '/<main>:/,/^$/p'
继续定位可疑函数:
objdump -d -Mintel /usr/bin/reset_root | sed -n '/<magic_cipher>:/,/^$/p'
常见模式:
- 硬编码字节数组。
- 固定字符串作为 key。
- 循环 XOR 解码。
- 解码结果传给
access()、stat()、system()。
XOR 解码模板
python3 - <<'PY'
key = b'palebluedot'
ct = bytes.fromhex('040909070e191008051d161c045d5c555e')
pt = bytes(c ^ key[i % len(key)] for i, c in enumerate(ct))
print(pt)
PY
如果第一层解出中间 key,再用它解路径:
python3 - <<'PY'
mid = b'thebluemarble1972'
cts = [
bytes.fromhex('5b0c001443060d004e192a0b3177700275'),
bytes.fromhex('5b0c001443060d004e28155b0767006207'),
bytes.fromhex('5b1c0812431e06205125071b00'),
]
for ct in cts:
print(bytes(c ^ mid[i % len(mid)] for i, c in enumerate(ct)))
PY
构造触发条件
如果程序检查文件是否存在:
touch /dev/shm/file1 /dev/shm/file2 /tmp/file3
/usr/bin/reset_root
执行后立即验证:
id
su - root
防坑点
- SUID 程序运行时有效 UID 是 root,但环境变量可能被清理。
/tmp可能有nosuid,生成 SUID 副本时要看挂载选项。strings看不到所有内容,简单 XOR 或编码会隐藏路径。strace在某些 SUID 程序上可能受限制,静态分析仍要会。
防御建议
- 避免自定义 SUID 程序,优先用最小 sudo 规则或专门服务。
- SUID 程序不要调用 shell,不要使用相对路径,不要依赖可写目录触发条件。
- 定期审计异常 SUID:
find / -perm -4000 -type f。 - 对 SUID 程序做代码审计和完整性监控。
来源案例
- The Planets: Earth:
/usr/bin/reset_root是自定义 SUID 程序,静态分析恢复触发文件路径后可重置 root 密码。