Slapdash Safeguards

にわか仕込みのセキュリティ

アンチウイルスソフトによるzip内のファイルをスキャンしづらくする「Zombie ZIP」

アンチウイルスソフトはzip,7zなどの圧縮ファイルを自動で展開して、中のファイルをスキャンする。

なので、基本的にはパスワードがかかっていなければ勝手に圧縮ファイルの中身もマルウェア検知してくれる。

しかし、圧縮ファイルのメタデータに記載されている展開方法が誤魔化されていたらどうだろうか。

圧縮ファイルのメタデータには「無圧縮です」って書いてあるけど、実際は圧縮されているようなファイルが含まれていた場合。

こういうときには、アンチウイルスソフトが無圧縮だと思ってスキャンしてしまって、マルウェアが検知回避できる。

kb.cert.org

ざっくりと理解

zipファイルって、大きく分けて「圧縮されたファイルの連なり」、格納されたファイルの情報が並ぶ「セントラルディレクトリ(Central Directory)」に分かれていて、ファイルの先頭から並ぶ格納ファイルごとにローカルファイルヘッダ(Local File Header)って言われている格納ファイルの情報が記載される場所がある。

「ローカルファイルヘッダ」と「セントラルディレクトリの格納ファイルごとの情報」のところに格納された対象のファイルがどのように圧縮されているか記載されている。(Compression Methodフィールド[2バイト])

おそらく、アンチウイルスソフトはCompression Methodフィールドを見て格納ファイルをどのような方式で解凍してからスキャンするか決めているのではないかと。

例えば、実際にはDeflate(0x0008)で圧縮されて格納されているのに、無圧縮(0x0000)であるとマルウェアのローカルファイルヘッダのCompression MethodとセントラルディレクトリのマルウェアのエントリのCompression Methodに記載したとしよう。

そうすると、そのzipファイルの中身を見たアンチウイルスソフトは「無圧縮だからそのままスキャンすれば確認できるか。」ってなる。

そうすると、マルウェアは検知されずに対象システムに持ち込まれてしまうということ。

ここら辺の仕様は、以下のZIPフォーマット仕様の「Section 4.3.7 — Local file header」、「Section 4.3.12 — Central directory file header」、「Section 4.4.5 — compression method」を見ると何となく分かる。
File: APPNOTE.TXT - .ZIP File Format Specification

日本語Wikiでも良いかも。
ja.wikipedia.org

ところで、過去にzipファイルの似たような事例としてCVE-2004-0935というのがあったらしく、こちらはCompressed Sizeフィールドという似たような別のものを書き換えて該当のファイルエントリは中身が無いように見せかけるものだったらしい。
vulners.com

PoC

PoCは既に公開されておりGithubで確認できる。
github.com

PoCではここまでの話、該当ファイルのローカルファイルヘッダ、セントラルディレクトリのエントリのCompression MethodをDeflate圧縮なのに無圧縮に書き換えてzip作成している。

    local = struct.pack('<IHHHHHIIIHH',
        0x04034b50,
        20,
        0,
        0,
        0, 0,
        crc32(payload),
        len(compressed),
        len(payload),
        len(name_bytes),
        0
    )
    
    cd = struct.pack('<IHHHHHHIIIHHHHHII',
        0x02014b50,
        20,
        20,
        0,
        0,
        0, 0,
        crc32(payload),
        len(compressed),
        len(payload),
        len(name_bytes),
        0, 0, 0, 0, 0,
        0
    )


# https://github.com/Bombadil-Systems/zombie-zip/blob/fb99f981a5dfb55ae6bc1aae9a82a1501c95263d/zombie_zip.py#L69

これでMicrosoft Defender, Avast, Bitdefender, ESET, Kaspersky, McAfee, Sophos, TrendMicroなど、Virustotalの50/51の検知を回避できたと。

検知されずにローカルにマルウェアを持ち込める、あとはファイルとして展開しないでメモリ上で実行するだけ。

ちなみに、Compression Methodを弄ることで普通のzip解析だと元通りに展開できないので、少し独自のzip展開方法が必要になる。これもPoCで実装されている。
github.com

という感じで、アンチウイルスソフトは「展開に失敗した」のではないからエラーとして記録されることはなく、Method=0(Stored)であればデータをそのまま読むのが正しい処理であり、実装としては仕様通り。

問題は、宣言と実態が意図的に乖離させられていることを検証してないってことですね。

たぶんだけどアンチウイルスソフトは、ローカルファイルヘッダ優先タイプ、セントラルディレクトリ優先タイプ、両方確認して合ってそうな方を信用するタイプがあると思っている。

でも、それだと両方誤魔化されてたら意味無いっていう状況。

CVE-2004-0935っていう似たようなことをまたやられている訳だが、zip格納ファイルのメタデータはまだ対策しきれていないいないようですな。

うーむ、大変そうだなぁ。

zipの曖昧さを悪用する

zipって皆知ってるし、結構長く使われているし。

たぶん、人生で初めて出会う圧縮ファイルぐらいにはどこでも使われていると思うんだが。

圧縮方法とか、解析方法とかはバラツキがあっても使用できるって何か変な感覚。でも、そりゃそうかぁとも思ってしまう。

こんなに有名なzipでさえ実装の違い、パースの仕方の違いがあるって面白い。

7-ZipとWinRARとWindows File Explorerで展開時の解析方法が違うからそれを悪用した「ZIP Concatenation」何てのもあったが、古いものほど昔各々独自で実装していた仕組みをずっと使い続けているから変な感じになっているんだろうか。
www.bleepingcomputer.com

古いものなら他にもあるんかなぁ。