パスワード保護Excelファイル (俗に言う暗号化Excelファイル) のパスワードをcrackする難易度ってどれくらいだろうか?
と、ある事案 (参考リンク1) からの連想で急に確認したくなった。もちろん、事案のプレスリリースで述べられている「暗号化処理」が、Excelの機能を使ってExcelファイルをファイルレベルで保護する手法 (参考リンク2) なのか、それ以外の別の手法なのかは現時点で明らかになっていないので、これは「もしも前者だったら」の一種の私的な実証実験である。
実験の際には自分に条件を課し、手元のUbuntu環境にはもちろん純正のMicrosoft Excelは無いので、一連の内容をコマンドライン (CLI) のみでやってみようと考えた。
参考リンク3によると、次の「secure-spreadsheet」というNode.js製ツールを用いてパスワード保護ExcelファイルをCLIで作成できるとわかり、やってみた。
## secure-spreadsheetをインストール
$ npm install -g secure-spreadsheet
## 簡単なCSVファイルを用意
$ cat input.csv
A,B,C
1,2,3
## パスワード「Amagasaki2022」としたパスワード保護Excelファイルを作成
$ TMP_PASSWORD='Amagasaki2022'
$ secure-spreadsheet --password ${TMP_PASSWORD} < input.csv > output.xlsx
## 作成したExcelファイルをfileコマンドでチェック
$ file ./output.xlsx
./output.xlsx: CDFV2 Encrypted
secure-spreadsheetが生成したoutput.xlsx
をLibreOffice Calcで開いてみると、パスワードを入力するダイアログがちゃんと現れて、「Amagasaki2022」を入力すればブックの内容が確認できる。CLIでのパスワード保護Excelファイルの作成に成功したようだ。
次に、定番のJohn the Ripperを用いて、
パスワード保護Excelファイルoutput.xlsx
のパスワードを解析する。参考リンク4にある手順のままに進めれば簡単だ。
## John the Ripperのソースをmake
$ git clone https://github.com/magnumripper/JohnTheRipper.git
$ cd JohnTheRipper/src
$ ./configure && make
## output.xlsxのhashを取り出す
$ cd ../run/
$ python3 ./office2john.py ../../output.xlsx > hash_output.txt
$ cat ./hash_output.txt
output.xlsx:$office$*2013*100000*256*16*c62bc00d6b5b5a2b6748e04fe64fb2d8*ee874eeeee93a1f6800ff9459cec62e7*b062d3e7cbaa3f69819eaff603fa5054973c6a97134231c2f7f8751543d6a1be
output.xlsx
のhashに対して、John the Ripperでのパスワード解析を実行すると、次のように内蔵のパスワードリストを元にした解析段階 (Proceeding with wordlist:./password.lst
) へと進み、解析終了までのかなり長い予想時間 (ETA) が表示される。
$ ./john --progress-every=5 ./hash_output.txt
Using default input encoding: UTF-8
Loaded 1 password hash (Office, 2007/2010/2013 [SHA1 256/256 AVX2 8x / SHA512 256/256 AVX2 4x AES])
Cost 1 (MS Office version) is 2013 for all loaded hashes
Cost 2 (iteration count) is 100000 for all loaded hashes
Will run 16 OpenMP threads
Proceeding with single, rules:Single
Press 'q' or Ctrl-C to abort, 'h' for help, almost any other key for status
0g 0:00:00:05 30.52% 1/3 (ETA: 01:48:23) 0g/s 638.7p/s 638.7c/s 638.7C/s 2oxlsx..Aoutput
0g 0:00:00:10 51.69% 1/3 (ETA: 01:48:27) 0g/s 636.1p/s 636.1c/s 636.1C/s ooutput26..Output.xlsxxlsx75
0g 0:00:00:15 70.87% 1/3 (ETA: 01:48:29) 0g/s 645.0p/s 645.0c/s 645.0C/s ooutput.xlsx6666..Outputxlsx5555
0g 0:00:00:20 91.74% 1/3 (ETA: 01:48:29) 0g/s 649.5p/s 649.5c/s 649.5C/s output.xlsxxlsx1909..oxlsx1900
Almost done: Processing the remaining buffered candidate passwords, if any.
0g 0:00:00:22 DONE 1/3 (2022-06-24 01:48) 0g/s 647.5p/s 647.5c/s 647.5C/s Output1906..Xoutput1900
Proceeding with wordlist:./password.lst
Enabling duplicate candidate password suppressor
0g 0:00:00:25 0.00% 2/3 (ETA: 2024-08-23 22:37) 0g/s 647.6p/s 647.6c/s 647.6C/s ilovegod..santiago
0g 0:00:00:30 0.00% 2/3 (ETA: 2023-07-16 06:28) 0g/s 649.3p/s 649.3c/s 649.3C/s vladik..just4fun
0g 0:00:00:35 0.00% 2/3 (ETA: 2023-03-27 18:17) 0g/s 648.4p/s 648.4c/s 648.4C/s dell123..giacomo
0g 0:00:00:40 0.00% 2/3 (ETA: 2023-02-03 15:44) 0g/s 649.4p/s 649.4c/s 649.4C/s alligator..reload
0g 0:00:00:45 0.00% 2/3 (ETA: 2023-01-05 17:21) 0g/s 650.6p/s 650.6c/s 650.6C/s Vladimir..megafon
0g 0:00:00:47 0.00% 2/3 (ETA: 2022-12-27 18:44) 0g/s 650.4p/s 650.4c/s 650.4C/s maynard1..breaker
Session aborted
なお、この実行例では解析終了までは待たず、1分弱で実行を中断している。クラウドのサーバの方でパスワード解析を終了まで回しとこう。いつ終わるかわからんけど……。
次に、わざと意地悪な実験を行う。解析の実行1で用いたパスワード保護Excelファイルをamagasaki.xlsx
の名前で複製し、amagasaki.xlsx
に対してJohn the Ripperでのパスワード解析を実行するとどうなるか。
## amagasaki.xlsxのhashを取り出す
$ cp -a ../../output.xlsx ../../amagasaki.xlsx
$ python3 ./office2john.py ../../amagasaki.xlsx > hash_amagasaki.txt
$ cat ./hash_amagasaki.txt
amagasaki.xlsx:$office$*2013*100000*256*16*c62bc00d6b5b5a2b6748e04fe64fb2d8*ee874eeeee93a1f6800ff9459cec62e7*b062d3e7cbaa3f69819eaff603fa5054973c6a97134231c2f7f8751543d6a1be
## John the Ripperでパスワード解析
$ time ./john --progress-every=5 ./hash_amagasaki.txt
Using default input encoding: UTF-8
Loaded 1 password hash (Office, 2007/2010/2013 [SHA1 256/256 AVX2 8x / SHA512 256/256 AVX2 4x AES])
Cost 1 (MS Office version) is 2013 for all loaded hashes
Cost 2 (iteration count) is 100000 for all loaded hashes
Will run 16 OpenMP threads
Proceeding with single, rules:Single
Press 'q' or Ctrl-C to abort, 'h' for help, almost any other key for status
0g 0:00:00:05 31.05% 1/3 (ETA: 02:00:49) 0g/s 665.6p/s 665.6c/s 665.6C/s Aamagasaki.xlsx..Jamagasaki.xlsxamagasaki
0g 0:00:00:10 52.73% 1/3 (ETA: 02:00:51) 0g/s 662.9p/s 662.9c/s 662.9C/s Axlsx84..Amagasaki23
0g 0:00:00:15 72.50% 1/3 (ETA: 02:00:53) 0g/s 662.9p/s 662.9c/s 662.9C/s xamagasaki.xlsx11111..Xlsxamagasaki00000
Amagasaki2022 (amagasaki.xlsx)
1g 0:00:00:18 DONE 1/3 (2022-06-24 02:00) 0.05434g/s 660.8p/s 660.8c/s 660.8C/s Amagasaki.xlsxamagasaki2016..Aamagasaki2025
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
real 0m19.268s
user 4m57.011s
sys 0m0.164s
するとJohn the Ripperは、シングルモード (Proceeding with single, rules:Single
) の解析段階で、なんと実験環境においては20秒弱で正しいパスワード「Amagasaki2022」を発見した。ファイル名がパスワードのヒントとして自動的に利用され、解析 (crack) を助けたわけである。
これはパスワード保護Excelファイルに限らない話となるが、パスワードに繋がる情報を持つ文字列を素のファイル名に含めてはならない、というのが今回私が得た教訓だ。
John the Ripperに組み込まれたロジックがいわば実戦的で賢すぎて、今回の実験ファイルのパスワードが速攻で暴かれたときには「えっ?」と声が出るほど驚いた。