2P by GN⁺ | ★ favorite | 댓글 1개
  • 개인 블로그 운영자는 취약점 스캔, 스팸, 콘텐츠 스크래핑을 줄이기 위해 악성 봇에게 gzip 기반 Zip Bomb을 HTTP 응답으로 보냄
  • 정상 브라우저와 크롤러가 쓰는 Accept-Encoding: gzip, deflate 흐름을 이용해, 의심 요청에는 200 OKContent-Encoding: gzip을 반환함
  • 1MB gzip 파일은 압축 해제 시 약 1GB, 10MB 파일은 약 10GB로 커져 많은 봇이 메모리를 소진하거나 요청을 중단함
  • 서버 미들웨어는 블랙리스트 IP와 스팸 패턴을 확인하고, 조건에 걸리면 사전 생성한 Zip Bomb 파일을 전송한 뒤 요청 처리를 끝냄
  • 쉽게 탐지·우회될 수 있어 완전한 방어책은 아니지만, 무차별 크롤링으로 서버를 방해하는 단순한 봇을 막는 용도로는 충분함

봇 트래픽과 Zip Bomb 사용 배경

  • 웹 트래픽의 대부분은 에서 오며, RSS 리더, 검색엔진 크롤러, AI 봇처럼 새 콘텐츠를 찾는 정상적인 용도도 있음
  • 문제는 스패머, 콘텐츠 스크래퍼, 해커가 운영하는 악성 봇
    • 과거 직장에서 봇이 WordPress 취약점을 찾아 서버에 악성 스크립트를 삽입함
    • 해당 서버는 이후 DDoS에 쓰이는 봇넷의 일부가 됨
    • 초기 웹사이트 중 하나는 봇이 만든 스팸 때문에 Google 검색에서 완전히 제외됨
  • 이런 경험 이후 악성 봇으로부터 서버를 보호하기 위해 Zip Bomb을 사용하기 시작함

gzip 압축을 방어 수단으로 바꾸는 방식

  • Zip Bomb은 작은 압축 파일이 압축 해제 과정에서 매우 큰 파일로 확장되어 머신에 부담을 주는 파일임
  • 웹 초기에 gzip 압축은 느린 인터넷 환경에서 전송량을 줄이기 위해 도입됨
    • 50KB HTML 파일을 10KB로 줄이면 40KB 전송량을 아낄 수 있음
    • 전화 접속 인터넷에서는 페이지 다운로드 시간이 12초에서 3초로 줄어드는 효과가 있었음
  • 브라우저는 요청 시 자신이 지원하는 압축 방식을 헤더로 알림
Accept-Encoding: gzip, deflate
  • 서버도 압축을 지원하면 기대한 데이터의 압축 버전을 반환함
  • 웹 크롤링 봇 역시 대량 데이터를 수집하기 위해 gzip 같은 압축을 지원하며, 이 특성을 방어에 활용함

악성 요청에 보내는 응답

  • 블로그에는 보안 취약점을 스캔하는 봇이 자주 나타나며, 대부분은 무시함
  • 악성 입력을 주입하려 하거나 응답을 탐색하는 요청으로 판단되면 200 OK와 함께 gzip 응답을 보냄
Content-Encoding: gzip
  • 전송하는 파일 크기는 상황에 따라 1MB~10MB
    • 1MB 파일은 압축 해제 시 약 1GB로 커짐
    • 10MB 파일은 압축 해제 시 약 10GB로 커짐
  • 봇은 헤더를 보고 압축 파일이라고 판단한 뒤 내용을 찾기 위해 압축 해제를 시도함
  • 파일이 계속 확장되면서 메모리를 소진하고 서버나 스크립트가 크래시할 수 있음
  • 1MB 파일로 충분하지 않은 끈질긴 스크립트에는 10MB 파일을 보내며, 이 경우 스크립트가 즉시 종료된다고 함

Zip Bomb 생성과 서버 적용 예

  • Zip Bomb을 만들 때는 자신의 장치를 크래시시키거나 망가뜨릴 수 있으므로 위험 부담을 감수해야 함
  • 10GB로 풀리는 gzip 파일은 다음 명령으로 생성함
dd if=/dev/zero bs=1G count=10 | gzip -c > 10GB.gz
  • 명령 구성은 다음과 같음
    • dd: 데이터를 복사하거나 변환하는 명령
    • if=/dev/zero: 무한한 0 바이트 스트림을 생성하는 특수 파일을 입력으로 사용
    • bs=1G: 블록 크기를 1GB로 설정
    • count=10: 1GB 블록 10개를 처리해 10GB의 0 데이터 생성
    • gzip -c > 10GB.gz: 출력 데이터를 gzip으로 압축해 10GB.gz 파일로 저장
  • 이 경우 결과 파일 크기는 약 10MB
  • 서버에는 현재 요청이 악성인지 확인하는 미들웨어를 추가함
    • 사이트 전체를 반복적으로 스캔하는 IP의 블랙리스트를 유지함
    • 스팸을 남긴 뒤 해당 스팸이 페이지에 반영됐는지 다시 확인하러 오는 패턴도 탐지에 사용함
if (ipIsBlackListed() || isMalicious()) {
    header("Content-Encoding: gzip");
    header("Content-Length: ". filesize(ZIP_BOMB_FILE_10G)); // 10 MB
    readfile(ZIP_BOMB_FILE_10G);
    exit;
}
  • 비용은 특정 상황에서 서버가 10MB 파일을 전송해야 한다는 점임
  • 글이 바이럴되는 상황에서는 1MB 파일로 낮추며, 이 파일도 효과가 있다고 함

한계와 사용 범위

  • Zip Bomb은 완전한 방어책이 아님
    • 쉽게 탐지될 수 있음
    • 우회도 가능함
    • 클라이언트가 내용을 부분적으로만 읽을 수도 있음
  • 그래도 웹을 무작정 크롤링하며 서버를 방해하는 정교하지 않은 봇을 막는 도구로는 충분함
  • 동작 예시는 서버 로그 리플레이에서 확인할 수 있음: this replay of my server logs

댓글과 토론

Hacker News 의견들
  • 2001년쯤 집에 고정 회선을 두고 집 Linux 박스에서 이것저것 호스팅하던 때가 있었음
    Windows NT 업데이트 때문에 많은 시스템이 특정 포트에 먼저 접속해 s/wan을 협상한 뒤 TCP 트래픽을 보내려는 낙관적 암호화 기능을 켜게 됐고, 방화벽에서 그런 트래픽을 자주 봐서 대수롭지 않았음
    그런데 유독 한 머신이 몇 초마다 계속 접속을 시도해서 너무 성가셨고, 관리자에게 연락하려 했지만 실패함
    결국 “그 포트에서 새 서비스를 시작하려는데 문제가 생기지 않길 바란다”는 식으로 알렸고, 답이 없자 그 포트에 /dev/urandom을 읽고 TCP_NODELAY 등을 켠 서버를 띄워 무작위 데이터를 최대한 빠르게 밀어 넣었음
    잘못 설정된 NT 박스는 접속해서 5초쯤 랜덤 데이터를 마시고 사라졌다가, 5분 뒤 다시 와서 버퍼 오버플로 약을 먹고 또 사라지는 패턴을 몇 주 반복하다가 인터넷에서 완전히 사라짐
    어떤 관리자가 왜 NT 박스가 계속 재부팅되는지 머리를 긁적였을 거라고 상상하곤 함

    • 프로그래머라면 남에게서 받는 데이터 양에 항상 상한선을 둬야 함
      모든 요청에는 시간 제한과 소비할 데이터 양 제한이 둘 다 있어야 함
    • 비슷한 시기에 어떤 회사가 매주 금요일마다 스팸 팩스를 보냈고, 여러 번 정중히 음성 메시지를 남겨도 무시했음
      그래서 모든 페이지가 큰 검은 사각형인 100쪽짜리 PDF를 만들고 당시 새로웠던 이메일-팩스 게이트웨이로 보냈더니 한 시간 안에 화난 전화가 왔고, 팩스는 멈춤
    • 그 시절엔 임의의 클라이언트 관리자 연락처를 보통 어떻게 찾았는지 궁금함
      “박스 관리자에게 연락하려 했고 그게 흔했다”는 부분이 특히 흥미로움
    • 집 RPi 서버의 다운 감지를 대충 고친 적이 있는데, 소유한 도메인에 ping을 보내고 실패하면 네트워크가 끊겼다고 보고 재부팅하게 했음
      도메인을 만료시킨 뒤 이 RPi가 5분마다 죽어서 전원 문제인 줄 알았는데, 나중에 그 CRON 작업이 떠올랐음
    • 그 시대에 서비스를 제공하던 NT 설치 대부분에는 무슨 일이 벌어지는지 알아차릴 관리자가 거의 없었다는 걸 알면 놀랄 수도 있음
      NT 박스에서 이런 서비스를 돌린 이유 자체가 “관리자가 필요 없게 하려고”인 경우가 수천 건은 됐고, 과소평가하면 안 됨
      90년대와 2000년대 초에 많은 서버를 인터넷에 올렸는데, 업계 전반의 표준 관행이 관리자 없이 쓰려고 NT를 쓴다였음
  • 어릴 때 멍청하게 장난삼아 내 홈페이지에 ln -s /dev/zero index.html을 해둔 적이 있음
    당시 브라우저들은 이걸 잘 처리하지 못해서 거의 멈췄고, 가끔은 클라이언트 시스템까지 같이 죽였음
    나중에는 브라우저들이 실제 콘텐츠를 확인하고 그런 요청을 중단하기 시작한 것 같음

    • 한 번은 인코더에 같은 매크로블록 줄을 계속 먹여서 64k×64k JPEG를 만든 적이 있음
      몇 년 뒤에야 마침내 열 수 있었음
    • squashfs 위에 적절한 헤더가 있는 500TB HTML 파일을 만들고, 닫는 태그 없는 끝없는 내용을 넣은 뒤 서버가 다운로드 전에 파일 크기를 보고하지 않게 할 수 있을지 궁금함
      아이디어가 있을까?
    • 브라우저를 죽이던 favicon.ico가 떠오름
      아마 이거였던 것 같음: https://freedomhacker.net/annoying-favicon-crash-bug-firefox...
    • KiB 단위로 대역폭 요금을 내던 상황은 아니었길 바람
    • 이제 /dev/zipbomb 장치를 만들 때가 된 건지도 모름
  • 요즘은 거의 모든 브라우저가 zstdbrotli를 받아들이니, 이런 폭탄은 지금 더 효과적일 수도 있음
    This 예전 댓글은 인상적인 1.2M:1 압축률을 보여줬고, zstd seems to be doing even better
    다만 봇은 현대적인 압축 표준을 지원하지 않을 수 있음
    반대로 그게 봇 차단에 좋은 방법일 수도 있는데, 모든 현대 브라우저는 zstd를 지원하니 허용 목록에 없는 브라우저 에이전트에 강제로 적용하면 스크레이퍼를 자동으로 혼란스럽게 만들 수 있음

    • 실제로 내 one million checkboxes Datastar 데모[1]에서 압축으로 봇을 걸러내고 있음
      모든 상호작용마다 전체 사용자 보기를 스트리밍하는 데 크게 의존하는데, SSE 위에 brotli를 쓰면 200:1 압축률[2]도 쉽게 나옴
      문제는 악의적인 행위자가 압축 없는 스트림을 요청할 수 있다는 점임
      brotli는 브라우저의 98%가 지원하므로 brotli 압축을 지원하지 않는 클라이언트에는 데이터를 보내지 않고, 많은 스크레이퍼와 봇도 이를 지원하지 않아서 꽤 잘 작동함
      [1] checkboxes demo
      https://checkboxes.andersmurphy.com
      [2] article on brotli SSE
      https://andersmurphy.com/2025/04/15/why-you-should-use-brotl...
    • gzip 안에 또 gzip을 중첩하면 더 작아짐
      1세대 gzip에서 압축된 0 데이터 블록 자체가 낮은 엔트로피라서 그렇고, 중첩 zst는 10G 파일을 99바이트로 줄임
    • 이런 폭탄을 받으면 내 브라우저가 어떻게 반응할지 궁금함
      직접 시험해보고 싶지는 않음
    • gzip은 어디에나 있고, 모든 크롤러를 괴롭힐 수 있음
  • 예전 직장에서 봇이 WordPress 취약점을 찾아 서버에 악성 스크립트를 넣었다는 부분이 살짝 주제에서 벗어나긴 해도 재미있음
    WordPress를 설치한 지 1시간 만에 서버에 PHP 셸이 마법처럼 배포되는 일이 나만 겪는 게 아니라는 걸 알게 돼서 오히려 안심됨

    • 고객의 WordPress 사이트를 넘겨받으면 “오, 임의 문자열 이름의 PHP 셸 3개가 있네”가 됨
      3개보다 적은 적은 없고, 항상 보장됨
    • 제정신을 지키고 싶다면 WordPress를 직접 호스팅하면 안 됨
      첫 한 시간이 아니더라도 언젠가 패치를 잊는 순간 결국 터짐
    • WordPress를 호스팅한 적은 없지만, 인터넷에 HTTP 서버를 노출하는 순간 /wp-login 같은 요청이 들어옴
      봇을 찾는 좋은 방법이 되기도 해서, 유명 CMS 관련 경로를 요청하는 IP가 보이면 바로 iptables 구멍으로 넣어버림
    • WordPress는 훌륭한 백도어이고, CMS 기능까지 내장돼 있음
    • DevOps를 가르칠 때 이걸 써먹은 적이 있음
      “첫 hello world nginx 서버를 배포해보세요”라고 하면 곧바로 로그에 이상한 요청들이 보이기 시작함
  • ssh에서도 비슷한 일을 한 적이 있는데, root 비밀번호를 추측하던 ssh 클라이언트를 죽이는 방법을 알아냈음
    그 대가로 여러 스크립트 키디들이 내 작은 서버에 DDoS를 날렸고, 결국 명백히 나쁜 짓을 하는 행위자를 식별해 방화벽 규칙으로 IP를 차단하는 방식으로 바꿈
    다만 IPv6에서는 이게 더 어려워지고 있음
    직접 웹페이지를 만드는 사람이라면, 사람 눈에는 보이지 않는 링크로 zip 폭탄을 페이지에 넣을 수도 있음
    흰 배경에 흰 글자, hover/click 강조 없는 앵커 같은 식이면 봇은 내려받아 확인하고, 크롤러와 AI 스크레이퍼도 마찬가지임

    • 내 fediverse 서버의 계정 요청 폼에서 이 방식의 변형을 썼음
      웹을 돌아다니며 게시될 것처럼 보이는 모든 폼에 조잡한 스팸을 제출하는 아주 단순한 봇들이 문제였음
      처음에는 왜곡된 문자로 된 간단한 CAPTCHA를 추가했고 많은 봇은 막았지만 전부는 아니었음
      서버 로그를 보니 이 봇들은 폼이 있는 페이지, CAPTCHA 이미지, 폼 데이터 POST 요청 이렇게 세 요청만 빠르게 보내고 CSS나 JS는 전혀 로드하지 않았음
      그래서 폼에 필드를 몇 개 더 넣고 CSS로 숨긴 뒤, 그 필드에 뭐라도 제출하면 요청을 실패시키고 세션을 차단하게 했음
      또한 CAPTCHA 이미지는 CSS 배경으로 만들고 src는 투명 이미지로 바꿨더니, 스팸은 완전히 멈췄고 실제 사용자는 아무것도 눈치채지 못함
    • 이런 행동을 막고 싶다면 이걸 확인해볼 만함
      https://github.com/skeeto/endlessh
    • 사람 눈에 안 보이는 링크라면 스크린 리더 사용자는 어떻게 되는지 걱정됨
    • IPv6에서 방화벽 차단이 왜 더 어려운지 모르겠음
      둘 중에는 오히려 더 쉬워 보임
    • 그런 링크는 텍스트 브라우저, 스크린 리더, 페이지 링크를 나열하는 북마클릿 등을 쓰는 사람에게는 보일 수 있음
  • Zip 폭탄은 재미있음
    한 보안 제품에서 특정 크기보다 큰 zip 아카이브이거나 그걸 포함한 파일이면 악성코드 검사를 제대로 하지 않는 취약점을 발견한 적이 있음
    실제로는 Office XML 문서 안에 zip 폭탄을 넣으면, 그 제품은 쉽게 식별 가능한 악성코드가 들어 있어도 OOXML 파일을 통과시킬 수 있었음

    • 아직도 많은 유명 EDR에서 파일 크기 문제는 그대로 남아 있음
  • 평소 쓰던 허니팟 스크립트 대신 이걸 배포해봤는데 잘 작동하지 않는 것 같음
    웹 서버 로그를 보면 봇들이 10MB짜리 독약을 전부 내려받지 않고, 여러 길이에서 끊고 있음
    지금까지는 약 1.5MB보다 많이 가져간 걸 못 봄
    아니면 작동 중인 걸까? 스트림으로 즉석에서 디코딩하다가 죽는 걸 수도 있음
    예를 들어 1.5MB를 읽은 것으로 기록됐다면, 메모리에서 즉석으로 1.5GB로 디코딩하다가 크래시났을 수도 있음
    확인할 방법은 없음

    • 콘텐츠 미로를 시도해볼 만함
      다른 생성 페이지로 가는 참조가 잔뜩 달린 무한 생성 콘텐츠 같은 방식임
      단순한 wget과 봇이 적응하기 전까지는 도움이 될 수 있음
      덧붙이면 나는 봇 쪽 편이지만, 돕는 건 상관없음
    • 파일 크기를 반쯤 무작위화해야 할지도 모름
      어떤 봇들은 내려받을 리소스 크기에 하드 리밋이 있을 것 같음
      상당수가 성가신 LLM 학습/스크레이핑 봇이라서, 800KB짜리 zip 폭탄을 내보내도 죽이지는 못하더라도 저쪽의 컴퓨팅 자원은 낭비시킬 수 있음
    • 다시 돌아오면 감지하고 피하는 것이고, 돌아오지 않으면 크래시난 것이니 임무 완수임
  • 이건 고전적인 zip 파일이 아니라 gzip 폭탄이라는 점을 짚어둘 만함
    중첩 zip으로 백신을 쓰러뜨리는 방식이 아니라, 일반 압축 웹페이지처럼 동작함

  • 얼마 전 Tor Project의 검열 우회 인프라 일부가 zip 폭탄 관련 블로그 글과 같은 사이트에서 운영되던 일이 있었음[0]
    그 zip 파일 중 하나가 Google에 크롤링되어 악성 도메인 목록에 들어갔고, Tor의 Snowflake 도구에서 꽤 중요한 부분이 깨졌음
    해결하는 데 몇 주가 걸림[1]
    [0] https://www.bamsoftware.com/hacks/zipbomb/
    [1] https://www.bamsoftware.com/hacks/zipbomb/#safebrowsing

  • 내 애플리케이션의 업로드를 보호하려고 각각 10MB 정도의 고정 크기 임시 디스크 파티션을 만들고 거기에 압축을 풀었음
    누가 너무 큰 걸 업로드해도 피해가 그 안에 갇히게 됨

    • unzip -p | head -c 10MB
    • 말도 안 되게 큰 파일을 압축 해제하지 않으면 될 일을, 굳이 디스크를 파티션으로 나눈 건가?