文章总结: Whoamifuck应急响应工具从4867行Bash脚本重构为Rust并发布v8.0.0。重构核心在于利用Rust的类型安全、模块化结构和静态编译特性解决Shell脚本维护难题,同时保留系统命令调用与原有命令行接口,确保老用户无感升级。工具内置DirtyCow等漏洞自查功能,支持多架构静态分发,建议应急场景直接使用musl版本。
综合评分: 88
文章分类: 应急响应,安全工具,安全开发,漏洞分析
who -> who-rs ; v8.0.0 Rust重构已发布
永恒之锋实验室
永恒之锋实验室
Eonian Sharp
2026年9月22日 11:07
上海
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
从 4867 行 Bash 到一颗静态二进制:司稽 Whoamifuck 的 Rust 重构之路
「司稽,察留连不时去者。」——《周礼·司稽》
2021 年写第一版 Whoamifuck 的时候,我没想过这个脚本最后会长到 4867 行。
那时候的想法很直接。
应急的时候经常要看进程、端口、登录记录、计划任务、WebShell、系统版本,来来回回敲的命令其实就那些。既然每天都要敲,不如把它们收进一个脚本里。
于是有了 who.sh。
后来功能一点点往里面加。
基线检查加进去,漏洞检查加进去,HTML 报告加进去,内核漏洞版本表也塞进去。版本一路从最开始跑到了 v7。
直到有一天再打开那个文件,已经很难一眼看明白某一段代码到底会影响哪里。
4867 行。
这个数字差不多就是这次重构真正开始的原因。
现在,司稽 Whoamifuck v8.0.0 发布了。
这一版最明显的变化只有一个:
整个项目从 Bash 搬到了 Rust。
一个脚本什么时候开始变得不好维护
Shell 本身没有什么问题。
甚至直到现在,我依然觉得应急响应工具用 Shell 起步非常合适。
ps、ss、last、find、systemctl 都在那里,脚本直接调就行。写完之后扔到机器上,也不用想太多。
Whoamifuck 最早能快速做起来,很大一部分原因就是 Bash 足够方便。
问题是,这种方便是有边界的。
当文件越来越大,很多当初无所谓的问题会慢慢变得麻烦。
比如变量。
Shell 里:
$FILE
"$FILE"
${FILE}
看起来差不了多少,实际行为却可能完全不同。
原来的代码里甚至还能翻到这样的历史痕迹:
rm -f /tmp/valid.$$.log/tmp/$$.log
两段路径粘在了一起。
这种东西在一个几百行的小脚本里,很容易发现。
放到将近 5000 行的脚本里,就不一定了。
另一个问题是,函数越来越多以后,很多数据是靠大家心照不宣地传下去的。
这个变量是谁定义的?
哪个函数会改它?
改完之后还有谁依赖它?
Shell 不会告诉你。
你只能搜。
再往后,就是不同机器上的兼容性问题。
正常的 Debian、Ubuntu、CentOS 通常没什么问题,但应急现场从来不会只遇到这些。
有些机器 Bash 版本很老。
有些发行版裁掉了一部分命令。
有些国产系统的行为和你预想的不一样。
脚本写得越大,这种环境差异越容易冒出来。
所以这次决定做一件拖了很久的事情:
把它拆开。
为什么最后选了 Rust
其实这几年也想过别的方案。
Python 写起来更快,生态也成熟。
Go 做单文件分发也很好。
最后还是选了 Rust。
原因和“性能”关系没有很多。
Whoamifuck 又不是在做高并发服务,很多时候真正耗时间的是系统命令本身。
我更在意的是另外几件事。
首先是类型。
很多 Shell 里的问题,本质上不是逻辑复杂,而是变量状态太自由。
Rust 会逼着你在编译阶段把很多问题解决掉。
其次是项目结构。
以前所有东西都挤在 who.sh 里。
现在一个功能对应一个模块:
src/
├── main.rs
├── color.rs
├── ui.rs
├── env.rs
├── sys.rs
├── util.rs
├── version.rs
└── modules/
├── baseinfo.rs
├── userlogin.rs
├── vulncheck.rs
├── baseline.rs
├── webshell.rs
├── report_html.rs
├── kernel_cve_data.rs
└── ...
现在如果要改登录日志,就去 userlogin.rs。
改漏洞检测,就去 vulncheck.rs。
至少不用先在一个 4867 行的文件里翻半天。
还有一点很实际:
静态编译。
这一点对于这种需要扔到各种陌生 Linux 环境里的工具来说,挺重要。
编译好一个 musl 版本,上传到目标机器:
scp who root@target:/tmp/
sudo /tmp/who -r
能跑就行。
不需要先确认 Python 在不在,也不用再猜目标机器上的 Bash 到底是哪一版。
我们没有把系统命令重新造一遍
这次重构有一个原则一直没变:
原来该调系统命令的地方,继续调。
有时候看到“某某工具用 Rust 重写”,很容易理解成什么东西都要自己实现。
其实没这个必要。
比如:
ps
ss
last
find
systemctl
这些工具已经在 Linux 上跑了很多年。
为了追求“纯 Rust”,重新实现一套进程枚举、Socket 获取、systemd 查询,意义不大。
甚至还有可能让结果和原版出现差异。
所以现在 Rust 主要负责这些事情:
参数处理、执行流程、数据组织、版本比较、漏洞表匹配、输出和报告生成。
真正采集系统信息的地方,还是尽量沿用 Linux 本身的命令。
这样做还有一个好处。
v8 和旧版的结果更容易对得上。
对于应急工具来说,我觉得这个比“纯不纯”重要。
有些东西则很适合搬进 Rust
另外一类代码就不一样了。
比如版本比较。
原来 Bash 里是这样的:
version_lt() {
[ "$1" = "$(printf '%s\n' "$1" "$2" | sort -V | head -n1)" ] && [ "$1" != "$2" ]
}
它能用。
而且用了很多年。
但第一次看到这段的人,大概率得停一下。
现在对应的代码变成了:
/// a < b
pub fn version_lt(a: &str, b: &str) -> bool {
a == min_version(a, b) && a != b
}
版本比较的语义没有改,还是按原来的 sort -V 行为处理。
只是终于变成了一个可以单独测试的函数。
漏洞版本表也是类似的情况。
Whoamifuck 里面一直保留着一份 Dirty Cow 的受影响内核版本表。
1217 条。
以前这些数据直接塞在 Shell 里。
现在它们单独放进:
kernel_cve_data.rs
需要改数据的时候,不会再碰到其他检测逻辑。
目前 v8 里的漏洞自查包括:
• CVE-2016-5195 Dirty Cow
• CVE-2022-0847 Dirty Pipe
• CVE-2026-31431 Copy Fail
• OpenSSH CVE-2018-15473、CVE-2024-6387
• Sudo CVE-2019-18634、CVE-2021-3156、CVE-2023-22809
• XZ Utils CVE-2024-3094
这些判断逻辑以后继续扩展,也比原来轻松很多。
老用户应该基本感觉不到变化
重构的时候有一个比较麻烦的问题:
如果新版本更“先进”,但老用户要重新学一遍怎么用,那这次升级其实挺失败的。
所以命令行接口基本没有动。
以前怎么跑,现在还是怎么跑。
比如:
sudo ./who -n
sudo ./who -a
sudo ./who -r
sudo ./who -m report.html
LOGO 也没动。
配色也尽量保留。
甚至一些看起来没那么“现代”的输出方式,我都没有急着改。
因为司稽用了这么多年以后,它已经有自己的使用习惯了。
v8 更像是把发动机和底盘换掉。
驾驶方式先别动。
下载和使用
如果只是想用,可以直接去 Releases 下载。
常规 x86_64 Linux 可以用:
whoamifuck-v8.0.0-x86_64-unknown-linux-gnu.tar.gz
如果不想管目标机器是什么发行版,我更建议:
whoamifuck-v8.0.0-x86_64-unknown-linux-musl.tar.gz
ARM64 则用:
whoamifuck-v8.0.0-aarch64-unknown-linux-musl.tar.gz
解压之后:
tar xzf whoamifuck-v8.0.0-x86_64-unknown-linux-musl.tar.gz
cd whoamifuck-v8.0.0-x86_64-unknown-linux-musl
sudo ./who -h
sudo ./who -n
sudo ./who -r
sudo ./who -m report.html
因为涉及不少系统级信息,建议直接使用 root 权限运行。
如果想自己编:
git clone https://github.com/enomothem/Whoamifuck.git
cd Whoamifuck
cargo build --release
产物在:
target/release/who
五年以后,再看这个工具
老的 who.sh 我没有删。
它还在仓库里。
一方面方便对照结果,另一方面我也不太想删。
毕竟从 2021 年一直改到现在,里面留下了很多很明显的时代痕迹。
有些写法现在看起来挺笨。
有些代码如果今天重新写,肯定不会那么处理。
但当时它确实解决了问题。
这次迁移到 Rust 以后,司稽本身没有突然变成一个完全不同的工具。
平时应急时关心的东西还是那些:
端口对应哪个服务。
服务后面是什么进程。
进程什么时候起来的。
它连过哪里。
谁登录过机器。
什么文件在那个时间点发生了变化。
最后还是要把这些东西串起来。
我一直很喜欢原来留下的这句话:
端口 → 服务,服务 → 进程,进程 → 网络。 时间线、轨迹、日志,最后都要对得上。
工具能帮你少敲一些命令。
至于异常到底藏在哪里,很多时候还是得靠经验。
有时候甚至真的是感觉。
”虽然现在AI能快速制造一些东西,但是这个是我一步一步累积出来的经验,每一次排查,每一个想法,每一个思路,每一个发现,改了无数次代码,微调,实战验证。“
”这次重构,借助AI的能力进行快速使用Rust重构,结构化,其实自己重构的版本早就写好了,只不过代码太乱了,虽然能跑起来,不利于后面的迭代,所以才使用AI全部重构“
”AI虽然能快速搞出炫酷的东西,但我们不需要,我们仍然保留原有功能和格式,实现如果rust能替换的直接用rust,更快一点,不能的,就原生命令,还是熟悉的whoamifuck。“
项目地址:
https://github.com/enomothem/Whoamifuck
如果你以前用过 who.sh,可以直接试试 v8。
遇到 Bug 就提 Issue。
WHOK-ID 还在。
—— 永恒之锋 · Enomothem
工具仅用于授权范围内的安全测试、应急响应与技术研究。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:Eonian Sharp 永恒之锋实验室
永恒之锋实验室《who -> who-rs ; v8.0.0 Rust重构已发布》