NFLabs. エンジニアブログ

セキュリティやソフトウェア開発に関する情報を発信する技術者向けのブログです。

macOSの暗号化zipファイルはパスワード無しで解凍できる

はじめに

こんにちは。事業推進部でOffensive Teamを担当する永井です。

先日のApple発表会では新型のiPhoneApple Watchなど心躍る製品が色々と発表されましたね。筆者は特に新型iPad miniが心に刺さっています。

さて、今回はApple関連の話としてmacOSの暗号化zipファイルはパスワード無しで解凍できる」というネタについて書いていきます。

解凍できる条件

何を言っているんだと思われるかもしれませんが、macOSで作られた暗号化zipファイルは以下の2つの条件を満たす場合にパスワード無しで容易に解凍が可能です。

  1. zipの暗号化方式がzipcryptoである (通常の暗号化zipファイルは基本的にzipcryptoが利用されています)
  2. zip内のいずれかのディレクトリの中身が.DS_Storeファイルおよび何らかのファイル1つである

このうち1.は基本的に満たしているので、2.の条件についてもう少し詳しく説明します。
2.の条件を満たすzipファイルとは、例えば以下のような構成です。

.
├── .DS_Store
├── abc.txt
└── sample
    ├── .DS_Store
    └── secret.txt

上記はsampleディレクトリの中身が.DS_Storeファイルとsecret.txtのみであるため、2. の条件を満たしています。

もしzipファイルの中身にディレクトリが存在しない場合は、ルートディレクトリが.DS_Storeおよび1つのファイルのみであれば条件を満たします。

.DS_Storeファイルとは?

ここで、macOSユーザではない方向けに.DS_Storeファイルについて簡単に解説しておきます。

簡単に言えば、.DS_StoreファイルとはWindowsのdesktop.iniに相当するファイルであり、ディレクトリ内のどこにファイルが置かれているのか、どのような順番で表示するべきか、といった情報が格納されているファイルです。

この.DS_StoreファイルはOS側で自動的に作成され、かつ隠しファイルになっているため、macOSディレクトリごとzipにしたり、zip -er output.zip .のようなコマンドでzipを作成した場合には、.DS_Storeファイルが気づかないうちに自動的に同梱されることになります。

.DS_Storeファイルがzipファイルに同梱されていても、単純に邪魔なだけで基本的に問題は無いのですが、.DS_Storeファイルには「ディレクトリ内にファイルが自分を除いて1つしか無い場合、そのファイル名が判明していれば、65536 (216) パターンしかバイナリとしての組み合わせが存在しない」という仕様があります。

これはどういうことかというと、「mac端末Aで作られた.DS_Storeファイルとmac端末Bで作られた.DS_Storeファイルは、.DS_Storeファイルが管理するファイルが1つであり、かつファイル名が一致している場合、ディレクトリのどこにファイルがあるのか、という情報を表す箇所以外は完全に一致する」ということです。

f:id:nfl_n2:20210920195549p:plain
.DS_Storeファイルの比較

.DS_Storeの中で位置情報を表す領域はX座標用とY座標用にそれぞれ4バイトずつあるため、最大では264パターンまで表すことが可能ですが、通常用途では意図的にディレクトリの右下にファイルを置かない限りは、X座標1バイト、Y座標1バイトの範囲に収まるため、基本的には65536 (216) 通りしか無いことになります。ディレクトリの右下にファイルを置くようなパターンを想定したとしても220通りで収まります。

これが、パスワード無しで暗号化zipを解凍する際の肝となります。

パスワード無しでの解凍手法

さて、ここまでの話で察している読者の方もいるかもしれませんが、
パスワード無しで解凍を行うための手法を一言で表すと以下になります。
「zipファイル内の.DS_Storeを既知平文として利用する既知平文攻撃」

既知平文攻撃とは「暗号化される前の平文の一部をあらかじめ知っている場合、その平文を利用して暗号化を解除することができる攻撃手法」のことで、zipの暗号化に使用されているzipcryptoは、この既知平文攻撃に脆弱であるということが広く知られています。

また、先ほど.DS_Storeファイルはフォルダの中にファイルが1つしか存在しない場合、ファイル名を揃えれば基本的に65536通りしか無い、ということを述べました。

はい、後は簡単ですね。
全パターンの.DS_Storeファイルを用いて既知平文攻撃を行えば、zipファイル内の.DS_Storeファイルと一致したタイミングで暗号化zipファイルの解凍に成功します。

パスワード無しで解凍してみる

既知平文攻撃を行うためのツールとしてはpkcrackやbkcrackが有名です。
今回はbkcrackを使用し、実際に.DS_Storeを使って解凍をしてみます。
(GitHub: https://github.com/kimci86/bkcrack )

検証では「解凍できる条件」の項目に記載した例と同じ以下の構成のディレクトリをpoc.zipとして暗号化zipにしたものを使用し、手元にsampleディレクトリ内の.DS_Storeがある前提で解凍を試みます。

.
├── .DS_Store
├── abc.txt
└── sample
    ├── .DS_Store
    └── secret.txt

bkcrackの使い方は簡単で、以下のように使います。

bkcrack -C <解凍したい暗号化zip> -c <暗号化zip内の既知平文のフルパス> -P <既知平文ファイルが含まれる平文zip> -p <平文zip内の既知平文ファイルのフルパス> -U <出力先zip名> <出力されるzipを暗号化するためのパスワード>

暗号化を解除した平文のzipが手に入るのではなく、新しいパスワードで暗号化されたzipが手に入るというのが少し特殊です。

手元で実際に動かしてみた際の画面が以下になります。

f:id:nfl_n2:20210920201025p:plain
bkcrackを用いた解凍の様子

このようにpoc.zipのパスワードを入力することなく、.DS_Storeファイルを使って既知平文攻撃を行い、中身のsecret.txtのメッセージを読み取ることができました。

今回は最初から正解の.DS_Storeファイルを使ってbkcrackを実行しましたが、実際には.DS_Storeファイルが正解するまでX座標とY座標の値を変えながらbkcrackを実行していくことになります。

パスワードブルートフォースとの比較

さて、実際にmacOSで作成された暗号化zipをパスワード無しで解凍できることがわかりましたが、この手法では.DS_Storeの総当たりが必要であり、かつ既知平文攻撃にも時間がかかります。そのため、パスワードを単純にブルートフォースするのと比べて有効なのかが気になります。

今回の手法で全パターン(65536通り) を総当たりするのにかかる時間は、以下のようになります。 (先程のスクショを取得したのと同じ端末の場合)

.DS_Store 1パターンあたりにかかる時間 (85秒) * 65536 = 5570560秒 = 92842分 = 1547時間 = 64日

また、同端末のhashcatのベンチマーク結果 (m=17200) は85915.0 kH/sでした。
この結果から、英数字+記号の8文字のパスワードをブルートフォースするためにはおよそ以下の時間がかかることがわかります。

948 / 85915000 = 70950234秒 = 1182503分 = 19708時間 = 821日

つまり、単純なパスワードの総当たりと比べ、今回の手法は8文字の段階で10倍以上高速であることがわかります。
また、今回の手法はパスワードの長さに解凍時間が依存しないことから、パスワードが10文字でも15文字でも解凍までに要する時間は変わりません。パスワードブルートフォースでは、パスワードが1文字増えるたびに94倍ずつ時間が増えていくため、今回の手法の方がより優位になっていきます。

手元のへっぽこ端末では本手法を使用して解凍までに最大64日かかってしまいますが、クラウド上に複数台のインスタンスを立ててbkcrackを回せば1日足らずで解凍することは容易でしょう。

パスワードの取得

話の主旨からは少し逸れますが、bkcrackを使用して暗号化zipを解凍した場合、暗号化に使用されていたパスワードを直接取得することはできません。
その代わり、パスワードを元に生成される、暗号化用の鍵 (Master Key) を取得することができます。

このMaster Keyがあれば、通常のパスワードブルートフォースよりも50倍程度高速にパスワードの総当たりが可能です。
(先ほどのbkcrackの実行画面では、0917ed61 cfc8f696 5d3e9072と表示されているものがMaster Keyになります)

hashcatの公式Twitterでは2019年5月に、GPU (RTX2080Ti) が4枚あればMaster Keyを用いて15時間以内に15文字以内のパスワードの総当たりが可能であることをアナウンスしています。
(参考: https://twitter.com/hashcat/status/1129441728761610242 )

まとめ

今回の記事では、macOSで作られた暗号化zipが特定条件を満たす場合にパスワード無しで解凍できることを示しました。
また、その際に得られるMaster Keyを用いてパスワードの復元も短時間で可能であることを述べました。

解凍条件を満たさないようにするためには、以下のいずれかの方法が考えられます。

  • .DS_Storeファイルがzip内に含まれないように気をつける
  • ファイルが1つだけのフォルダを含めないように気をつける
  • .DS_Storeファイルが生成されないように設定する (副作用あり)
  • 暗号化方式でzipcryptoではなくAESを使用する (Windowsの標準機能では解凍できなくなります)

そもそも共有すべき相手以外に暗号化zipが渡らなければ気にする必要はありませんが、
万が一の誤送付に備え、macOSをお使いの方はくれぐれもご注意ください。