❏ 站外平台:

经典的 Fork 炸弹解析

作者: Saymagic

| 2015-06-24 10:42   评论: 8 收藏: 14 分享: 1    

Jaromil 在 2002 年设计了最为精简的一个 Linux Fork 炸弹,整行代码只有 13 个字符(包括空格在内,空格不能删除),在 shell 中运行后几秒后系统就会宕机:

:(){ :|:& };:

这样看起来不是很好理解,我们可以更改下格式:

:()
{
	:|:&
};
:

更好理解一点的话就是这样:

bomb()
{
	bomb|bomb&
};
bomb

因为 shell 中函数可以省略 function 关键字,所以上面的 13 个字符的功能是定义一个函数并调用这个函数,函数的名称为 : ,主要的核心代码是 :|:&,可以看出这是一个对函数本身的递归调用,通过 & 实现在后台开启新进程运行,通过管道实现进程呈几何形式增长,最后再通过 : 来调用此函数引爆炸弹。因此,几秒钟内,系统就会因为处理不过来太多的进程而死机,解决的唯一办法就是重启。

Bomb 一下

秉着不作不死的心态,我们也来运行一下,于是我将矛头指向云主机,我使用了一个 2G 内存的云主机,首先在本地开启两个终端,在一个终端连接云主机后运行炸弹,几秒后再尝试用另外一个终端登录,效果可以看下图:

看,运行一段时间后直接报出了 -bash: fork: Cannot allocate memory,说明内存不足了。并且我在二号终端上尝试连接也没有任何反应。因为是虚拟的云主机,所以我只能通过主机服务商的后台来给主机断电重启。然后才能重新登录:

炸弹的危害

Fork 炸弹带来的后果就是耗尽服务器资源,使服务器不能正常的对外提供服务,也就是常说的 DoS。与传统 1v1、通过不断向服务器发送请求造成服务器崩溃不同,Fork 炸弹有种坐山观虎斗,不费一兵一卒斩敌人于马下的感觉。更吓人的是这个函数是不需要 root 权限就可以运行的。看到网上有帖子说某些人将个性签名改为 Fork 炸弹,结果真有好奇之人中枪,试想如果中枪的人是在公司服务器上运行的话,oh,!

预防方式

当然,Fork 炸弹没有那么可怕,用其它语言也可以分分钟写出来一个,例如,Python 版:

import os
 	while True: 
 	os.fork()

Fork 炸弹的本质无非就是靠创建进程来抢占系统资源,在 Linux 中,我们可以通过 ulimit 命令来限制用户的某些行为,运行 ulimit -a 可以查看我们能做哪些限制:

ubuntu@10-10-57-151:~$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 7782
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 7782
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

可以看到,-u 参数可以限制用户创建进程数,因此,我们可以使用 ulimit -u 20 来允许用户最多创建 20 个进程。这样就可以预防 Fork 炸弹。但这样是不彻底的,关闭终端后这个命令就失效了。我们可以通过修改 /etc/security/limits.conf 文件来进行更深层次的预防,在文件里添加如下一行(下面的 ubuntu 需更换为你的用户名):

ubuntu - nproc 20

这样,退出后重新登录,就会发现最大进程数已经更改为 20 了:

这个时候我们再次运行炸弹就不会报内存不足了,而是提示 -bash: fork: retry: No child processes,说明 Linux 限制了炸弹创建进程。

参考资料



最新评论

[1]
来自117.152.73.253的 Chrome 53.0|Windows 10 用户 发表于 2016-10-20 14:45 的评论:
最后一句犯了严重错误,fork()用于创建进程而不是线程
linux [Chrome 53.0|Mac 10.11] 2016-10-20 20:08 13 回复
谢谢指正。
[1]
来自 - 安徽合肥 的 Firefox/Linux 用户 发表于 2015-06-27 20:15 的评论:
实际上,这个fork炸弹只在bash以及兼容bash的shell上才有效,如果是csh/ksh之类话,因该是无效的,因为这些shell不允许:作为函数名。
unknow_future 2015-07-06 09:43 12 回复
b(){ b|b& };b
[1]
ryt 发表于 2015-06-24 11:45 的评论:
文章中”:|:&“是什么意思?‘:’函数没有输出,怎么用到管道了?为什么通过管道可以实现进程几何增长?我是一个新手,希望大家指点
[2]
Sephiroth 发表于 2015-06-24 14:13 的评论:
管道左右两边的进程是同时开始执行的,不是后面一个等待前面运行结束才执行,所以这种递归循环导致进程以2的指数倍的数量在增加。
ryt 2015-06-24 15:49 12 回复
谢谢!
来自 - 天津 的 Chrome/Linux 用户 2015-06-24 12:50 12 回复
不好意思,我的终端上有语法错误

返回顶部

分享到微信

打开微信,点击顶部的“╋”,
使用“扫一扫”将网页分享至微信。