[中英对照]rm -rf 幸存者

软件测试 William 139浏览 0评论

Just for fun, I decided to launch a new Linux server and run rm -rf / as root to see what remains. As I found out, rm lives in the future with idiots like me, so you have to specify --no-preserve-root to kick this exercise off.

# rm -rf --no-preserve-root /

After committing this act of tomfoolery, great utilities like

  • /bin/ls

  • /bin/cat

  • /bin/chmod

  • /usr/bin/file

will all be gone! You should still have your connection over SSH as well as your existing bash session. This means you have all the bash builtins, like echo.

仅仅是为了娱乐,我决定登录一个新的linux服务器然后使用root用户执行一下 “rm -rf / ”这条命令,看看还会剩下什么。因为我发现,rm执行了很久,并没有任何反应,所以你必须指定–no-preserve-root这个参数才能完成这项练习。

# rm -rf --no-preserve-root /

提交这个破坏性的命令之后,一些非常有的用命令像

  • /bin/ls

  • /bin/cat

  • /bin/chmod

  • /usr/bin/file

都会消失!您应该通过SSH以及现有的bash会话保持连接。这样你就拥有所有的bash内置命令函数,比如echo命令。

Becoming Bash McGyver

root@rmrf:/# ls
-bash: /bin/ls: No such file or directory

There is no ls, but echo and fileglobs are still around. What can we do with those?

root@rmrf:/# echo *
dev proc run sys
# echo /dev/pts/*
/dev/pts/0 /dev/pts/3 /dev/pts/ptmx

Hey, we got to keep /dev/proc/run, and /sys. Now that we have ls, we might as well make it a little easier to read.

root@rmrf:/# for file in /dev/pts/*; do echo $file; done
/dev/pts/0
/dev/pts/3
/dev/pts/ptmx

Several Redditors pointed out that printf is available.

root@rmrf:/# ls() { printf '%s\n' ${1:+${1%/}/}*; }

printf will [apply] the format string until it runs out of args.” – camh-

成为Bash MacGyver

root@rmrf:/# ls
-bash: /bin/ls: No such file or directory

执行完ls命令后,发现提示没有ls命令,但echo和fileglobs仍然存在。我们能用这些命令做些什么呢?

root@rmrf:/# echo *
dev proc run sys
# echo /dev/pts/*
/dev/pts/0 /dev/pts/3 /dev/pts/ptmx

嘿,执行完以上操作后我们得到了/dev,/proc,/run和/sys目录。现在我们有了ls功能,我们同样可以让它的可读性更强。

root@rmrf:/# for file in /dev/pts/*; do echo $file; done
/dev/pts/0
/dev/pts/3
/dev/pts/ptmx

几个Redditors指出printf是可用的。

root@rmrf:/# ls() { printf '%s\n' ${1:+${1%/}/}*; }

“直到运行完args,printf将[通过应用]格式化字符串。” –  camh-

Since you can define functions in bash, we can create an ls utility, albeit very limited.

root@rmrf:/# ls() { printf '%s\n' ${1:+${1%/}/}*; }
-bash: syntax error near unexpected token `('

What? That should be completely valid. Is ls already hashed or aliased?

root@rmrf:/# type ls
ls is aliased to `ls --color=auto'

Ah, that gets expanded to ls--color=auto () { printf '%s\n' ${1:+${1%/}/}*; }. Yuck. Well, we can unalias that.

root@rmrf:/# unalias ls
root@rmrf:/# ls() { printf '%s\n' ${1:+${1%/}/}*; }
root@rmrf:/# ls
/dev
/proc
/run
/sys
root@rmrf:/# ls /dev
/dev/pts

And save our work. console root@rmrf:/# echo 'ls() { printf '%s\n' ${1:+${1%/}/}*; }' >> utils.sh root@rmrf:/# source utils.sh

因为您可以在bash中定义函数,所以我们可以创建一个ls实用程序,尽管非常有限。

root@rmrf:/# ls() { printf '%s\n' ${1:+${1%/}/}*; }
-bash: syntax error near unexpected token `('

什么?这应该是完全有效的啊。ls命令已经散列或被别名化了吗?

root@rmrf:/# type ls
ls is aliased to `ls --color=auto'

啊,它扩展到 ls–color=auto () { printf ‘%s\n’ ${1:+${1%/}/}*; } 了。讨厌!好吧,我们可以unalias 这个设置。

root@rmrf:/# unalias ls
root@rmrf:/# ls() { printf '%s\n' ${1:+${1%/}/}*; }
root@rmrf:/# ls
/dev
/proc
/run
/sys
root@rmrf:/# ls /dev
/dev/pts

然后保存我们的操作。 console root@rmrf:/# echo 'ls() { printf '%s\n' ${1:+${1%/}/}*; }' >> utils.sh root@rmrf:/# source utils.sh

How about cat? The read builtin comes in handy along with pipes and redirection, so we can piece together a rudimentary cat.

root@rmrf:/# (while read line; do echo "$line"; done) < utils.sh
ls() { printf '%s\n' ${1:+${1%/}/}*; }

With these abilities and the fact that we can write arbitrary bytes with echo, we could rebuild and then curl or wget the binaries we want directly. My first choice, echoed by others, would be to get busybox. Busybox is the Swiss Army Knife of Embedded Linux, with builtin versions of wgetddtar, and many others. Eusebe?a goes into great detail about how to get a fully escaped version of busybox on your system, so I won’t do that here.

那么cat命令呢?内置的read命令连同管还有重定向可以派上用场了,所以我们可以通过以上功能组合拼凑出一个初级的cat命令.

root@rmrf:/# (while read line; do echo "$line"; done) < utils.sh
ls() { printf '%s\n' ${1:+${1%/}/}*; }

有了这些能力,同时我们可以用echo命令输出任意字节,这样我们可以重建、然后使用curl 或者 wget命令直接执行我们想要执行的二进制文件。我的第一个选择是通过busybox(别人输出的)执行.Busybox是嵌入式Linux的瑞士军刀,内置了wget,dd,tar命令版本,以及许多其他命令。Eusebe?a详细介绍了如何在你的系统上获得完全转义的busybox版本,所以我就不在这里做过多的演示了。

There is a problem though.

Even if we echo all the bytes we need into creating entire binaries, those files won’t be executable. No way to start busybox. The easiest workaround for this is to find something which is executable and overwrite it with echo. We’ve nuked all of /usr and /bin at this point though, so that’s a bit tricky.

We can use shell globs and bash logic to find files with the executable bit set, making sure to ignore directories.

executable () { if [[ ( ! -d $1 ) && -x $1 ]] ; then echo "$1"; fi }

但是有一个问题。

即使我们echo出所有我们需要创建的完整二进制文件的所有字节,这些文件却不能执行。也没有方法启动busybox。此种情况下最简单的解决方法是找到一些可执行的文件然后使用echo命令去覆盖。在此刻我们已经摧毁了所有/usr 和 /bin,所以这有点困难。

我们可以使用shell globs和bash逻辑查找可执行位设置的文件,记得要忽略目录。

executable () { if [[ ( ! -d $1 ) && -x $1 ]] ; then echo "$1"; fi }

Find the executables!

root@rmrf:/# for file in /*; do executable $file; done
root@rmrf:/# for file in /*/*; do executable $file; done
root@rmrf:/# for file in /*/*/*; do executable $file; 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

Great! Hold on a minute though, those are all symbolic links to executables that no longer exist on disk. We’ll just update executable() to ignore symbolic links.

root@rmrf:/# executable () { if [[ ( ! -d $1 ) && ( ! -h $1 ) && -x $1 ]] ; then echo "$1"; fi }
root@rmrf:/# for file in /*/*/*; do executable $file; done
root@rmrf:/# for file in /*/*/*/*; do executable $file; done
root@rmrf:/# for file in /*/*/*/*/*; do executable $file; done
root@rmrf:/# for file in /*/*/*/*/*/*; do executable $file; done

Well now, that’s bad news bears. Perhaps there is something at the kernel level we can use. After all, we can restart the box using sysrq magic:

root@rmrf:/# echo 1 > /proc/sys/kernel/sysrq
root@rmrf:/# echo "b" > /proc/sysrq-trigger

找到可执行文件!

root@rmrf:/# for file in /*; do executable $file; done
root@rmrf:/# for file in /*/*; do executable $file; done
root@rmrf:/# for file in /*/*/*; do executable $file; 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()方法来忽略符号链接。

root@rmrf:/# executable () { if [[ ( ! -d $1 ) && ( ! -h $1 ) && -x $1 ]] ; then echo "$1"; fi }
root@rmrf:/# for file in /*/*/*; do executable $file; done
root@rmrf:/# for file in /*/*/*/*; do executable $file; done
root@rmrf:/# for file in /*/*/*/*/*; do executable $file; done
root@rmrf:/# for file in /*/*/*/*/*/*; do executable $file; done

现在看来,那是个坏消息。也许我们可以使用内核级别的东西。毕竟,我们可以使用sysrq magic重启盒子。

root@rmrf:/# echo 1 > /proc/sys/kernel/sysrq
root@rmrf:/# echo "b" > /proc/sysrq-trigger

Now we’re locked out and I should do something else on a Friday. Thanks for reading! Let me know if you figure out how to get an executable bit set.

UPDATE: Redditor throw_away5046 posted a full, beautiful, solution to this.

From a non-hosed, same architecture box:

$ 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

Back on the rmrf’ed machine

# 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

Now to create a shared object that will change permissions on busybox

$ 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

Time to enable setx as a built in and get busybox executable

# ( download > setx; enable -f ./setx setx; setx; )
# /busybox mkdir .bin
# /busybox  --install -s .bin
# PATH=/.bin

In action:

现在我们被锁定了,我应该在星期五做其他事情。谢谢阅读!如果您弄清楚如何设置可执行位,请告诉我。

更新:Redditor throw_away5046 发布了一个完整,完美的解决方案。

来自非宿主,相同的架构盒子:

$ 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

回到 rmrf’ed 机器上

# 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 上将会更改权限的共享对象

$ 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

是时候启用enable命令 将setx作为内置函数和获取busybox可执行文件了:

# ( download > setx; enable -f ./setx setx; setx; )
# /busybox mkdir .bin
# /busybox  --install -s .bin
# PATH=/.bin

动作如下:

div.column{width:49.5%;display:table-cell;border:1px solid #d4d4d5;}


via:oschina

转载请注明:AspxHtml学习分享网 » [中英对照]rm -rf 幸存者

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址