2 ポイント 投稿者 GN⁺ 2025-04-30 | 1件のコメント | WhatsAppで共有
  • 個人ブログの運営者は、脆弱性スキャン、スパム、コンテンツスクレイピングを減らすため、悪意のあるボットに gzipベースのZip Bomb をHTTPレスポンスとして送信する
  • 正常なブラウザやクローラーが使う Accept-Encoding: gzip, deflate の流れを利用し、疑わしいリクエストには 200 OKContent-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件のコメント

 
GN⁺ 2025-04-30
Hacker News の意見
  • 2001年ごろ、自宅に専用回線を引いて、自宅の Linux ボックスでいろいろホスティングしていた時期があった
    Windows NT のアップデートのせいで、多くのシステムが特定のポートにまず接続して s/wan をネゴシエートしてから TCP トラフィックを送ろうとする楽観的暗号化機能を有効にするようになっていて、ファイアウォールでそういうトラフィックをよく見ていたので大したことではないと思っていた
    ところが、あるマシンだけが数秒おきに接続を試み続けていて、あまりにうっとうしかったので管理者に連絡しようとしたが失敗した
    結局「そのポートで新しいサービスを始めようとしているので、問題が起きないことを願っている」というような形で伝え、返事がなかったので、そのポートに /dev/urandom を読み込み TCP_NODELAY などを有効にしたサーバーを立て、ランダムデータをできるだけ速く押し込んだ
    設定を誤った NT ボックスは接続してきて、5秒ほどランダムデータを飲み込んでは消え、5分後にまた戻ってきてバッファオーバーフロー薬を飲んでまた消える、というパターンを数週間繰り返した末、インターネットから完全に姿を消した
    どこかの管理者が、なぜ NT ボックスが再起動し続けるのか首をかしげていただろう、と想像することがある

    • プログラマーなら、他人から受け取るデータ量には常に上限を設けるべき
      すべてのリクエストには、時間制限と消費するデータ量の制限の両方が必要
    • 似たような時期に、ある会社が毎週金曜日にスパムFAXを送ってきて、何度も丁寧に留守電を残しても無視された
      そこで、全ページが大きな黒い四角形になっている100ページの PDF を作り、当時新しかったメール・FAX ゲートウェイ経由で送ったところ、1時間以内に怒りの電話が来て、FAX は止まった
    • 当時、任意のクライアントの管理者連絡先は普通どうやって見つけていたのか気になる
      「ボックスの管理者に連絡しようとして、それが一般的だった」という部分が特に興味深い
    • 自宅の 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 をネストすると、もっと小さくなる
      初代 gzip で圧縮された 0 データブロック自体が低エントロピーだからで、ネストした zst は 10G ファイルを 99 バイトに縮める
    • こうした爆弾を受け取ったら、自分のブラウザがどう反応するのか気になる
      自分で試してみたいとは思わない
    • gzip はどこにでもあり、あらゆるクローラーを苦しめられる
  • 以前の職場で、ボットがWordPressの脆弱性を探してサーバーに悪性スクリプトを仕込んだという部分は少し話題から外れるものの面白い
    WordPressをインストールしてから1時間でサーバーにPHPシェルが魔法のようにデプロイされるのは、自分だけが経験しているわけではないと分かって、むしろ安心した

    • 顧客のWordPressサイトを引き継ぐと、「お、ランダムな文字列名のPHPシェルが3つあるな」となる
      3つ未満だったことはなく、常に保証されている
    • 正気を保ちたいなら、WordPressを自分でホスティングしてはいけない
      最初の1時間でなくても、いつかパッチ適用を忘れた瞬間に結局やられる
    • WordPressをホスティングしたことはないが、インターネットにHTTPサーバーを公開した瞬間に /wp-login のようなリクエストが来る
      ボットを見つける良い方法にもなるので、有名CMS関連のパスをリクエストするIPを見かけたら、すぐにiptablesの穴へ放り込む
    • WordPressは優秀なバックドアで、CMS機能まで内蔵されている
    • DevOpsを教えるときに、これを使ったことがある
      「最初のhello world nginxサーバーをデプロイしてみてください」と言うと、すぐにログに怪しいリクエストが見え始める
  • sshでも似たようなことをしたことがあり、rootパスワードを推測していたsshクライアントを殺す方法を見つけた
    その代償として、複数のスクリプトキディが私の小さなサーバーにDDoSを仕掛けてきたため、最終的には明らかに悪いことをしている行為者を識別し、ファイアウォールルールでIPをブロックする方法に変えた
    ただしIPv6では、これがより難しくなってきている
    自分でWebページを作る人なら、人間の目には見えないリンクとしてzip爆弾をページに仕込むこともできる
    白い背景に白い文字、hover/clickの強調表示がないアンカーのような形なら、ボットはダウンロードして確認し、クローラーやAIスクレイパーも同じようにする

    • 自分のfediverseサーバーのアカウント申請フォームで、この方式の変種を使った
      Webを巡回し、投稿されそうに見えるあらゆるフォームに粗雑なスパムを送信する、非常に単純なボットが問題だった
      最初は歪んだ文字の簡単なCAPTCHAを追加し、多くのボットは防げたが全部ではなかった
      サーバーログを見ると、これらのボットはフォームのあるページ、CAPTCHA画像、フォームデータのPOSTリクエストという3つのリクエストだけを素早く送り、CSSやJSはまったくロードしていなかった
      そこでフォームにフィールドをいくつか追加してCSSで隠し、そのフィールドに何か送信されたらリクエストを失敗させ、セッションをブロックするようにした
      さらにCAPTCHA画像をCSS背景にし、src は透明画像に変えたところ、スパムは完全に止まり、実ユーザーは何も気づかなかった
    • こうした行動を防ぎたいなら、これを確認してみる価値がある
      https://github.com/skeeto/endlessh
    • 人間の目に見えないリンクなら、スクリーンリーダー利用者はどうなるのか心配になる
    • IPv6でファイアウォールによるブロックがなぜより難しいのか分からない
      どちらかといえば、むしろ簡単そうに見える
    • そういうリンクは、テキストブラウザ、スクリーンリーダー、ページのリンクを一覧表示するブックマークレットなどを使う人には見える可能性がある
  • Zip爆弾は面白い
    あるセキュリティ製品で、特定サイズより大きいzipアーカイブ、またはそれを含むファイルだとマルウェア検査を正しく行わない脆弱性を見つけたことがある
    実際にはOffice XML文書の中にzip爆弾を入れると、その製品は容易に識別できるマルウェアが入っていてもOOXMLファイルを通過させることができた

    • 今でも多くの有名なEDRで、ファイルサイズの問題はそのまま残っている
  • 普段使っていたハニーポットスクリプトの代わりにこれをデプロイしてみたが、うまく動いていないようだ
    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
    • とんでもなく大きいファイルを展開しなければ済む話なのに、わざわざディスクをパーティション分けしたということ?