
正文
rm -rf 的“幸存者”
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
原文:http://blog.jobbole.com/70971/
以 root 用户执行 rm –rf / 命令,然后观察下哪些文件或者指令会幸存下来。结果是什么也没少!因此你必须增加 —no-preserce-root 再试一遍:
1 | # rm -rf --no-preserve-root / |
当你按下 Enter 时,一些重要的工具,比如
1 2 3 4 5 6 7 | /bin/ls /bin/cat /bin/chmod /usr/bin/file |
将会应声消失!但是你当前的 SSH 连接以及 bash 终端都还在,这表明所有 bash 相关的内建指令都没有受影响,比如 echo。
成为 Bash 达人
1 2 3 | root@rmrf:/# ls -bash: /bin/ls: No such file or directory |
执行以上命令,发现已没有 ls 可用,但是 echo 和 fileglobs 还在。利用这些“幸存者”们,我们可以做点什么呢?
1 2 3 4 5 6 7 | root@rmrf:/# echo * dev proc run sys # echo /dev/pts/* /dev/pts/0 /dev/pts/3 /dev/pts/ptmx |
注意!/dev,/proc,/run,/sys还在,我们一定要保存好它们。如果有了ls指令,那么对目录下内容的读取操作将会更加简单。
1 2 3 4 5 6 7 | root@rmrf:/# for ii in /dev/pts/*; do echo $ii; done /dev/pts/0 /dev/pts/3 /dev/pts/ptmx |
许多 Reddit 用户指出,printf 仍是可用的。CAMH 说:printf 会将参数依次格式化到输出字符串中去。
1 | root@rmrf:/# ls() { printf '%s\n' ${1:+${1%/}/}*; } |
既然在bash下可以定义函数,那么我们可以自建一个ls工具,虽然功能还不是很完善。
1 | root@rmrf:/# ls() { printf '%s\n' ${1:+${1%/}/}*; } |
1 | -bash: syntax error near unexpected token `(' |
不对啊,这种操作应该完全合法才对,难道 ls 已经被映射,或者它是其他命令的别名?
1 2 3 | root@rmrf:/# type ls</code> ls is aliased to `ls --color=auto'</code> |
原来如此,我们上面的指令被扩展成了 ls--color=auto () { printf '%s\n' ${1:+${1%/}/}*; }。那么,我们可以先使用unalias 指令,去掉 ls 与 ls—color 的关联。
1 | root@rmrf:/# ls () { for ii in $1/*; do echo $ii; done } |
1 2 3 4 5 6 7 8 9 | root@rmrf:/# ls /dev /proc /run /sys |
1 2 3 | root@rmrf:/# ls /dev /dev/pts |
把函数存储到 utils.sh 文件
1 | root@rmrf:/# echo 'ls () { for ii in $1/*; do echo $ii; done }' >> utils.sh |
1 | root@rmrf:/# source utils.sh |
cat 命令怎么样实现呢?借助 read!read 是幸存者之一,使用 read 结合管道和重定向,一个基本的 cat 就基本成型了!
1 2 3 | root@rmrf:/# (while read line; do echo "$line"; done) < utils.sh ls () { for ii in $1/*; do echo $ii; done } |
结合上述通过“幸存者”逐渐恢复一些指令的方法,以及 echo 可以写入任意多字节的特性,我们可以重新构建出 linux 的工具系统,并可以通过 curl 或者 wget 直接获得我们想要的二进制文件。首先,参照 echoed by others,获取 busybox。Busybox 是嵌入式 Linux 的瑞士军刀,内嵌 wget、dd、tar等许多工具。Eusebeîa 详细介绍了如何获得一个 busybox 的 escaped 版本,我在这里就不多做赘述了。
但是,还有一个问题。
即使我们 echo 了整个二进制文件需要的所有字节,这些二进制文件仍无法执行。没法启动 busybox!针对这个问题,早期的解决方法是找到一些可执行的程序,然后用 echo 覆盖它们。我们对 /usr 和 /bin 下的文件进行了诸如此类的改造,但这确实稍显复杂。
可以利用 shell 通配符和 bash 筛选出带有可执行位组的文件,记住要把目录排除在外。
1 | executable () { if [[ ( ! -d $1 ) && -x $1 ]] ; then echo "$1"; fi } |
找到了可执行文件!
1 | root@rmrf:/# for ii in /*; do executable $ii; done |
1 | root@rmrf:/# for ii in /*/*; do executable $ii; done |
root@rmrf:/# for ii in /*/*/*; do executable $ii; done
/proc/1107/exe
/proc/1136/exe
/proc/1149/exe
/proc/1179/exe
/proc/1215/exe
/proc/1217/exe
/proc/1220/exe
/proc/1221/exe
/proc/1223/exe
/proc/1248/exe
/proc/1277/exe
/proc/1468/exe
/proc/1478/exe
/proc/1625/exe
/proc/1644/exe
/proc/1/exe
/proc/374/exe
/proc/378/exe
/proc/471/exe
/proc/616/exe
/proc/657/exe
/proc/self/exe
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | root@rmrf:/# for ii in /*/*/*; do executable $ii; done /proc/1107/exe /proc/1136/exe /proc/1149/exe /proc/1179/exe /proc/1215/exe /proc/1217/exe /proc/1220/exe /proc/1221/exe /proc/1223/exe /proc/1248/exe /proc/1277/exe /proc/1468/exe /proc/1478/exe /proc/1625/exe /proc/1644/exe /proc/1/exe /proc/374/exe /proc/378/exe /proc/471/exe /proc/616/exe /proc/657/exe /proc/self/exe |
太好了!但是别急,这些只是软链接到可执行文件的链接文件,原文件在磁盘上已经不存在了。那么现在我们要重新改写executable(),排除这些软链接。
1 | root@rmrf:/# executable () { if [[ ( ! -d $1 ) && ( ! -h $1 ) && -x $1 ]] ; then echo "$1"; fi } |
root@rmrf:/# for ii in /*/*/*; do executable $ii; done
1 | root@rmrf:/# for ii in /*/*/*; do executable $ii; done |
1 | root@rmrf:/# for ii in /*/*/*/*; do executable $ii; done |
1 | root@rmrf:/# for ii in /*/*/*/*/*; do executable $ii; done |
1 | root@rmrf:/# for ii in /*/*/*/*/*/*; do executable $ii; done |
噩耗,什么输出也没有。或许可以利用内核层面的东西,毕竟,我们可以使用Magic Sysrq组合键重启busybox。
Shell
root@rmrf:/# echo 1 > /proc/sys/kernel/sysrq
1 | root@rmrf:/# echo 1 > /proc/sys/kernel/sysrq |
1 | root@rmrf:/# echo "b" > /proc/sysrq-trigger |
我们现在已经骑虎难下了,周五的时候,我会继续研究下去。感谢关注,如果您发现了什么获取可执行位组的好方法,请及时知会我。
UPDATE: Reddit 用户 throw_away5046 提出了一种解决方法:a full solution to this。
获取一个可信任的、适用于本机架构的box
1 2 3 4 5 6 7 8 9 10 11 12 13 | $ mkdir $(xxd -p -l 16 /dev/urandom) $ cd $_ $ apt-get download busybox-static $ dpkg -x *.deb . $ alias encode='{ tr -d \\n | sed "s#\\(..\\)#\\\\x\\1#g"; echo; }' $ alias upload='{ xxd -p | encode | nc -q0 -lp 5050; }' $ upload < bin/busybox |
执行 rm –rf 之后的机器
1 2 3 4 5 6 7 | # cd / # alias decode='while read -ru9 line; do printf "$line"; done' # alias download='( exec 9<>/dev/tcp/{IP OF NON HOSED BOX}/5050; decode )' # download > busybox |
创建一个可以改变 busybox 访问权限的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | $ cat > setx.c <<EOF extern int chmod(const char *pathname, unsigned int mode); int entry(void) { return !! chmod("busybox", 0700); } char *desc[] = {0}; struct quick_hack { char *name; int (*fn)(void); int on; char **long_doc, *short_doc, *other; } setx_struct = { "setx", entry, 1, desc, "chmod 0700 busybox", 0 }; EOF $ gcc -Wall -Wextra -pedantic -nostdlib -Os -fpic -shared setx.c -o setx $ upload < setx |
以内建工具的方式使能 setx,使 busybox 可执行
1 2 3 4 5 6 7 | # ( download > setx; enable -f ./setx setx; setx; ) # /busybox mkdir .bin # /busybox --install -s .bin # PATH=/.bin |
操作如下:

加入伯乐在线专栏作者。




![【电子书】[经典小说] 《孤独的幸存者》 [马库斯·鲁特埃勒][epub+mobi] 【电子书】[经典小说] 《孤独的幸存者》 [马库斯·鲁特埃勒][epub+mobi]](https://www.04ip.com/template/qe/style/noimg/6.jpg)
![【电子书】[科学技术] 《幸存者回忆录》[多丽丝·莱辛][epub+mobi+azw3] 【电子书】[科学技术] 《幸存者回忆录》[多丽丝·莱辛][epub+mobi+azw3]](https://www.04ip.com/template/qe/style/noimg/3.jpg)
![【电子书】[人文传记] 《一个海难幸存者的故事(精制精排,弹出注释本)》[哥伦比亚][加西亚·马尔克斯][epub+mobi] 【电子书】[人文传记] 《一个海难幸存者的故事(精制精排,弹出注释本)》[哥伦比亚][加西亚·马尔克斯][epub+mobi]](https://www.04ip.com/template/qe/style/noimg/14.jpg)