- 個人ブログの運営者は、脆弱性スキャン、スパム、コンテンツスクレイピングを減らすため、悪意のあるボットに gzipベースのZip Bomb をHTTPレスポンスとして送信する
- 正常なブラウザやクローラーが使う Accept-Encoding: gzip, deflate の流れを利用し、疑わしいリクエストには
200 OK と Content-Encoding: gzip を返す
- 1MBのgzipファイルは展開時に約 1GB、10MBのファイルは約 10GB に膨らみ、多くのボットがメモリを使い果たすかリクエストを中断する
- サーバーミドルウェアはブラックリストIPとスパムパターンを確認し、条件に一致した場合は事前生成したZip Bombファイルを送信してリクエスト処理を終了する
- 簡単に検知・回避され得るため完全な防御策ではないが、無差別クロールでサーバーを妨害する 単純なボット を防ぐ用途としては十分である
ボットトラフィックとZip Bomb利用の背景
- Webトラフィックの大半は ボット から来ており、RSSリーダー、検索エンジンクローラー、AIボットのように新しいコンテンツを見つける正当な用途もある
- 問題は、スパマー、コンテンツスクレイパー、ハッカーが運用する 悪意のあるボット である
- 過去の職場では、ボットがWordPressの脆弱性を探してサーバーに悪性スクリプトを挿入した
- そのサーバーはその後、DDoSに使われるボットネットの一部になった
- 初期に運営していたWebサイトの1つは、ボットが作ったスパムのせいでGoogle検索から完全に除外された
- こうした経験の後、悪意のあるボットからサーバーを守るために Zip Bomb を使い始めた
gzip圧縮を防御手段に変える方法
- Zip Bombとは、小さな 圧縮ファイル が展開過程で非常に大きなファイルに拡張され、マシンに負荷をかけるファイルである
- Web初期のgzip圧縮は、低速なインターネット環境で転送量を減らすために導入された
- 50KBのHTMLファイルを10KBに縮めれば、40KBの転送量を節約できる
- ダイヤルアップ接続では、ページのダウンロード時間が12秒から3秒に短縮される効果があった
- ブラウザはリクエスト時に、自分が対応する圧縮方式をヘッダーで通知する
Accept-Encoding: gzip, deflate
- サーバー側も圧縮をサポートしていれば、期待されるデータの 圧縮版 を返す
- Webクローリングボットも大量のデータを収集するために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は 完全な防御策 ではない
- 簡単に検知され得る
- 回避も可能である
- クライアントが内容を部分的にしか読まない場合もある
- それでも、Webを無差別にクロールしてサーバーを妨害する 高度ではないボット を防ぐ道具としては十分である
- 動作例はサーバーログのリプレイで確認できる: this replay of my server logs
1件のコメント
Hacker News の意見
2001年ごろ、自宅に専用回線を引いて、自宅の Linux ボックスでいろいろホスティングしていた時期があった
Windows NT のアップデートのせいで、多くのシステムが特定のポートにまず接続して s/wan をネゴシエートしてから TCP トラフィックを送ろうとする楽観的暗号化機能を有効にするようになっていて、ファイアウォールでそういうトラフィックをよく見ていたので大したことではないと思っていた
ところが、あるマシンだけが数秒おきに接続を試み続けていて、あまりにうっとうしかったので管理者に連絡しようとしたが失敗した
結局「そのポートで新しいサービスを始めようとしているので、問題が起きないことを願っている」というような形で伝え、返事がなかったので、そのポートに
/dev/urandomを読み込みTCP_NODELAYなどを有効にしたサーバーを立て、ランダムデータをできるだけ速く押し込んだ設定を誤った NT ボックスは接続してきて、5秒ほどランダムデータを飲み込んでは消え、5分後にまた戻ってきてバッファオーバーフロー薬を飲んでまた消える、というパターンを数週間繰り返した末、インターネットから完全に姿を消した
どこかの管理者が、なぜ NT ボックスが再起動し続けるのか首をかしげていただろう、と想像することがある
すべてのリクエストには、時間制限と消費するデータ量の制限の両方が必要
そこで、全ページが大きな黒い四角形になっている100ページの PDF を作り、当時新しかったメール・FAX ゲートウェイ経由で送ったところ、1時間以内に怒りの電話が来て、FAX は止まった
「ボックスの管理者に連絡しようとして、それが一般的だった」という部分が特に興味深い
ドメインを失効させた後、この RPi が5分おきに落ちるので電源問題だと思っていたが、後になってそのCRON ジョブを思い出した
NT ボックスでこうしたサービスを動かした理由そのものが「管理者を不要にするため」だったケースは何千件もあり、過小評価してはいけない
90年代と2000年代初頭に多くのサーバーをインターネットに公開したが、業界全体の標準的な慣行は管理者なしで使うために NT を使うことだった
子どものころ、愚かな悪ふざけで自分のホームページに
ln -s /dev/zero index.htmlを仕込んだことがある当時のブラウザはこれをうまく処理できず、ほとんど固まってしまい、ときにはクライアントシステムごと落とすこともあった
後には、ブラウザが実際のコンテンツを確認して、そうしたリクエストを中断するようになったようだ
数年後になって、ようやく開けるようになった
squashfs上に適切なヘッダーを持つ500TB の HTML ファイルを作り、閉じタグのない終わりのない内容を入れたうえで、サーバーがダウンロード前にファイルサイズを報告しないようにできるのか気になる何かアイデアはある?
favicon.icoを思い出すたぶんこれだったと思う: https://freedomhacker.net/annoying-favicon-crash-bug-firefox...
/dev/zipbombデバイスを作る時期なのかもしれない最近はほぼすべてのブラウザが zstd と brotli を受け入れるので、こうした爆弾はいまのほうがさらに効果的かもしれない
This という昔のコメントは印象的な 1.2M:1 の圧縮率を示しており、zstd seems to be doing even better
ただし、ボットは現代的な圧縮標準をサポートしていない可能性がある
逆にそれはボット遮断に有効な方法かもしれない。現代のブラウザはすべて zstd をサポートしているので、許可リストにないブラウザエージェントに強制適用すれば、スクレイパーを自動的に混乱させられる
すべてのインタラクションごとにユーザー表示全体をストリーミングすることに大きく依存しているが、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 で圧縮された
0データブロック自体が低エントロピーだからで、ネストした zst は 10G ファイルを 99 バイトに縮める自分で試してみたいとは思わない
以前の職場で、ボットがWordPressの脆弱性を探してサーバーに悪性スクリプトを仕込んだという部分は少し話題から外れるものの面白い
WordPressをインストールしてから1時間でサーバーにPHPシェルが魔法のようにデプロイされるのは、自分だけが経験しているわけではないと分かって、むしろ安心した
3つ未満だったことはなく、常に保証されている
最初の1時間でなくても、いつかパッチ適用を忘れた瞬間に結局やられる
/wp-loginのようなリクエストが来るボットを見つける良い方法にもなるので、有名CMS関連のパスをリクエストするIPを見かけたら、すぐにiptablesの穴へ放り込む
「最初のhello world nginxサーバーをデプロイしてみてください」と言うと、すぐにログに怪しいリクエストが見え始める
sshでも似たようなことをしたことがあり、rootパスワードを推測していたsshクライアントを殺す方法を見つけた
その代償として、複数のスクリプトキディが私の小さなサーバーにDDoSを仕掛けてきたため、最終的には明らかに悪いことをしている行為者を識別し、ファイアウォールルールでIPをブロックする方法に変えた
ただしIPv6では、これがより難しくなってきている
自分でWebページを作る人なら、人間の目には見えないリンクとしてzip爆弾をページに仕込むこともできる
白い背景に白い文字、hover/clickの強調表示がないアンカーのような形なら、ボットはダウンロードして確認し、クローラーやAIスクレイパーも同じようにする
Webを巡回し、投稿されそうに見えるあらゆるフォームに粗雑なスパムを送信する、非常に単純なボットが問題だった
最初は歪んだ文字の簡単なCAPTCHAを追加し、多くのボットは防げたが全部ではなかった
サーバーログを見ると、これらのボットはフォームのあるページ、CAPTCHA画像、フォームデータのPOSTリクエストという3つのリクエストだけを素早く送り、CSSやJSはまったくロードしていなかった
そこでフォームにフィールドをいくつか追加してCSSで隠し、そのフィールドに何か送信されたらリクエストを失敗させ、セッションをブロックするようにした
さらにCAPTCHA画像をCSS背景にし、
srcは透明画像に変えたところ、スパムは完全に止まり、実ユーザーは何も気づかなかったhttps://github.com/skeeto/endlessh
どちらかといえば、むしろ簡単そうに見える
Zip爆弾は面白い
あるセキュリティ製品で、特定サイズより大きいzipアーカイブ、またはそれを含むファイルだとマルウェア検査を正しく行わない脆弱性を見つけたことがある
実際にはOffice XML文書の中にzip爆弾を入れると、その製品は容易に識別できるマルウェアが入っていてもOOXMLファイルを通過させることができた
普段使っていたハニーポットスクリプトの代わりにこれをデプロイしてみたが、うまく動いていないようだ
Webサーバーのログを見ると、ボットは10MBの毒を全部ダウンロードせず、さまざまな長さで切っている
これまでのところ、約1.5MBより多く取得したものは見ていない
あるいは動作しているのだろうか? ストリームでその場でデコードしていて死んでいるのかもしれない
例えば1.5MBを読んだと記録されているなら、メモリ上でその場で1.5GBにデコードしていてクラッシュした可能性もある
確認する方法はない
別の生成ページへの参照が大量に付いた、無限生成コンテンツのような方式だ
単純な
wgetやボットが適応するまでは役に立つかもしれないちなみに私はボット側の立場だが、手助けするのは構わない
ボットの中には、ダウンロードするリソースサイズにハードリミットを設けているものがありそうだ
多くは厄介なLLM学習・スクレイピングボットなので、800KBのzip爆弾を返しても殺せはしないとしても、相手の計算資源は浪費させられる
これは古典的なzipファイルではなく、gzip爆弾だという点は指摘しておく価値がある
入れ子のzipでアンチウイルスを倒す方式ではなく、通常の圧縮Webページのように動作する
少し前、Tor Projectの検閲回避インフラの一部が、zip爆弾関連のブログ記事と同じサイトで運用されていたことがあった[0]
そのzipファイルの1つが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