ciliのブログ

差し障りない範囲で思い出の形作りのために既知の脆弱性とか、脆弱性じゃないと強く信じられているものについて語ります。脆弱性と分かってると問題ですからね!

VBAのExcelでDDEの罠

はじめに

前回はExcelでDDEの罠を紹介しましたが、その応用編です。あんまり書くことないのでショートです。

Excel VBAの世界でGO

Excel VBAって書いてますけど、Visual Basicで書いたアプリケーションでも同様です。

警告ダイアログってウザいよね?

Excel VBAを使っていると、警告ダイアログが表示さえるのがウザかったり、選択で「はい」「いいえ」「キャンセル」を選ばれたくない場合があります。

  • Excelで編集したファイルを(表示なしに)上書き保存したい場合
  • Excelでファイルオープン時にマクロ実行を操作させたくない場合

どっちの場合も、Application.DisplayAlertsプロパティをFalseにすると

保存処理の場合

こんな感じですね。これは(多分)安全です。

Application.DisplayAlerts = False

' 保存処理

Application.DisplayAlerts = True

保存処理が終わったらDisplayAlertsをTrueに戻すのはお作法です。

ファイルオープン時の警告抑止

こんなコード、それってマナー違反です!?

Application.DisplayAlerts = False

Workbooks.Open("hoge.xls")

Application.DisplayAlerts = True 

 Workbooks.Openはわりと柔軟で、xlsじゃなくてもCSVやTXTも読み込めます(多分)。参考までにファイルオープンの機能はいくつかあります。

  • Workbooks.Open
  • Workbooks.OpenText
  • QueryTables.Add

サーセン、それぞれの動作までは調べてません。

なんかヤバいの?

ExcelでDDEの罠で紹介した仕様を組み合わせると、怖い動きをします。多分、仕様です。試した感じだと、警告ダイアログをOFFにしてマクロ有効で開きます。マクロ有効?DDEで頓死ですね。Excel側設定でOFFにすることも可能なので、マクロ自動実行されるのは利便性のための仕様です。

なお、Application.DisplayAlertsプロパティは警告メッセージを抑止する機能なので、警告がでないのは仕様通りと思われます。

docs.microsoft.com

どうすればいいんでしょうか?

OpenのときはApplication.DisplayAlerts = Trueにしましょう。SaveAsなんかで真に必要な場合はApplication.DisplayAlerts = Falseして処理してTrueに戻しましょう。

あるいは試してないけど、OpenTextだと大丈夫かもしれません。

魔法の呪文

大人の事情により、詠唱破棄!

ExcelでDDEの罠

はじめに 

友達から教えてもらったお話です。対象はExcel2013です。友達は日本のMicrosoft脆弱性届出窓口に脆弱性じゃないの?ってメール投げたところ、利便性からそういう仕様なんですし、この動作説明も公開OKですって返事来たそうです。

とにかく、脆弱性ではないってことを最初に強調しておきます。

まずはDDEを悪用した攻撃について

どんな攻撃方法なの?

有名なので詳しく説明するまでもないですよね。

DDEコマンドが書かれたファイルを開くと実行されてしまうという、かつての脆弱性です。マクロ自動実行とかガクブルですね。

対策は?

いまのExcelではファイル開いたときにセキュリティ警告がでるようになりました。ここで間違って実行を許さなければ、かなり安全です。

一般に推奨されている方法

Excelで開いたファイルにマクロやDDEコマンドが入っていると「コンテンツの有効化」の警告が出ます。ここで「無効にする」を選びましょう。

たとえばJ-CSIPの公開レポートを読むと、ここで「無効にする」を選ぶと安全ってなってます。

www.ipa.go.jp

ただし、無効にすると、Excelのシート間参照ができなくて困るのが難点。不便ですね。

そこまでやんなくても!?な方法

マイクロソフトはセキュリティにとてもとても気を遣うので、そもそもDDE機能を無効化することができます。 ちょっと罠っぽいのは、ExcelGUIで設定する項目なので、GUIのデフォルトではDDE機能をOFFって意味のようです。後述しますがGUIの操作で回避できます...。

docs.microsoft.com

さあ、試したまえ

これで背景知識が習得できましたね。いかにDDEの悪用対策がパーペキか試して確かめてみましょう。

あなたの対策、大丈夫ですか?レッツトライ

  • 被験者はこんな内容が書かれたCSVファイルをメール(たとえばoutlook)で受け取ります。一目瞭然DDEを悪用した公知なアレです。

=calc|' '!A0

  • OutlookでそのCSVファイルをクリックして、Excelで開くと警告が出ます。もちろん「無効にする」でマクロを無効化します。
  • ツールバーの「データ」の「リンクの編集」をクリックしましょう。
  • 右上にある「値の更新」をクリックしてみましょう!

どうですか?電卓が立ち上がりますよね。

ほんとは怖い、DDE無効化

さて、前述のマイクロソフトセキュリティアドバイザリ4053440に従って、DDEを無効化してから、さっきのCSVファイルを開いてみましょう。

 

違いがわかりますか?

 

なんと、最初の「コンテンツの有効化」の警告が出ません。選ぶまでもなく「無効にする」を選んだのと同じ扱いになります。気分としては安全ですよね。

 

では、ついでなので、先ほど紹介した「リンクの更新」をやってみましょう!

あれ?

あれれ??

面白いと思うのは、この操作はマウスだけで出来ることです。便利ですよね

これって脆弱性じゃないの?

いいえ、脆弱性ではなく仕様です。マイクロソフト的にはPros/Consで判断して利便性が勝るからそうなってるそうです。

対策はどないすりゃええんの?

いくつか対策があります。

  • Excelの設定でCSVやTXTを読めなくする(根本的対策!?)
  • マイクロソフトセキュリティアドバイザリ4053440に従ってDDE機能無効化するから警告がでなくて危なくなるのです。このアドバイザリは無視して、ファイル読み込み時に「無効化する」を選ぶようにしましょう。これで危険性が把握できます。その上で「リンクの更新」はダメ、絶対。
  • まあ、DDE機能無効化してても、警告が出なくて1ステップ安全策が消えるだけでそれなりに安全です。「リンクの更新」はダメ、絶対。を心がければ問題ありません。
  • 「リンクの更新」の先で、「値の更新」以外のあるボタンを押して見るものも手です。なぜかExcelがクラッシュするので、電卓が立ち上がるのは阻止できます:)

なお、ここではユーザ教育コストってものはプレイスレスゼロエンとしています。

おまけ。しつこいですが、これって脆弱性じゃないの?(2019/11/07)

より安全と思えるオプション設定すると警告がでないので却って危険ってのは、すげー脆弱性っぽいですが、いとやんごとなきマイクロソフトさまによるとPros/Consの評価でProsが明らかに上回ると判断できる場合には脆弱性じゃなくて仕様なんだそうです。この脆弱性判定(MS的には脆弱性じゃないと思うよ)のJVNVU#98504876も同様。

jvn.jp

これって、元ネタのCERT/CC #125336ではプロンプト無効にすると実行されちゃうってのが問題らしいですが、Mac用の新しいOfficeで本当にそんな動作するのでしょうかね??

kb.cert.org

 

魔法の呪文

なし

CMD.EXEの罠

はじめに

ありきたりなお話です。これも昔話ぐらいによく知られている話なので、よもや脆弱性と思う人はないでしょう。マイクロソフトWindowsNHK風に言えば「窓」)世界における仕様です。今回は外部プログラム呼び出しです。

プログラムからCMDって使ってますか?

ええ、使ってますよ。そうじゃないとこのコラムの話はじまらないじゃないですか。UNIX系とのマルチプラットフォームでシェルっぽい扱いといえば当然、CMD使うでしょ。

それってマナー違反です!

なんだって!?

いきなり結論になってしまいました。ShellExecute(Ex)とかCreateProcessで実行コマンドに"CMD"なんて書いちゃいけません。そういうことなんですよね。

そうそう、拡張子なしってのがダメなんですよね

何言ってるのですか!

CMDをCMD.EXEにしても、カレントディレクトリの実行ファイルが優先される仕様は変わらないので、ほぼノーガードです。まさに100-1=0です。

じゃ、絶対パスで書くの?C:\Windows\Sytem32\cmd.exeなの?

あなたのWindowsシステム領域のドライブはCですか?Dじゃダメなんですか?*1

正解言えやー

何を信頼すれば安全かって悩む所ですが*2、いとやんごとなきマイクロソフトの啓示によれば、環境変数は信じてよいです。

ということで、WindowsのプログラミングでCMD.EXEを呼び出したい場合、CMD.EXEの絶対パスがセットされている環境変数のCOMSPECを展開して使いましょう。COMSPECを使うのが望ましい実装と思いますが、カレント探すのは仕様なのでバグではありません*3

あるいは面倒ですが、レジストリから探しましょう。といってもこっちの仕様は良く知らない。

当たり前すぎてドキュメントに出てこないですが、カレントディレクトリのバイナリプランティングを阻止するには定石です。

魔法の呪文

いかがでしたか、いかがでしょうか、いかがでしたでしょうか、調べてみました。

 

*1:ほとんどダメな気がするが気のせいとしましょう

*2:脆弱じゃないといってるのに!?

*3:ちなみに、PostgreSQLのv12の後に修正が入りましたが、バグでも仕様変更でもないのでバックポートしないって表明がありました。。

ShellExecuteの罠

罠大杉ですね。

先日WinFileのWinExecの話にちらっと触れたので、GUIからの行儀良いプログラムの実行方法のお話です。IssuesにLoadLibraryのセキュリティ取り扱いに注意とか書かれているけど、ガン無視なのでWinFile3.0時代のセキュリティなのでしょう。

まず歴史

ファイラーってご存知ですか?PC-88/98時代のプロテクトを外すカタログファイルのことではありません。

DOS系のコマンドライン

CUIです。指定したファイルの拡張子は勝手に付与。

ファイラー

コマンドラインGUI化したものです。指定したファイルの拡張子は勝手に付与します。ちなみに、欧米ではマイナーですが日本やロシアではメジャーでした。

Explorer

GUIで指定したファイルを実行するものです。指定したファイルの拡張子を勝手に付与したりしません。NTや2000までは良くわかりませんが、Windows XPはこれ。多分、Windows95 OSR2あたりからこれなのじゃないかな。

そんなShellExecuteで大丈夫か?問題あり

UACの導入以来、プログラム実行はCreateProcessから権限昇格可能なShellExecuteに移ってきました。ShellExecute便利ですよね。けど、使い方のお作法ご存知ですか?というか、はっきり言えばShellExecuteの引数で許されるプログラムは固定の絶対パスです。UIから指定されたファイルをShellExecuteで実行するなんて論外です、蛮勇です、死にたいんでうかワレです。ShellExecuteExを使いましょう

よくあるShellExecuteのよろしくない使い方

このコード片はWinFileからもってきたものです。繰り返しますが懐古主義で過去の仕様を再現したプログラムなのでこれによる動作は仕様です。脆弱性ではないはずです。

よくあるコード片

DWOR ret = (DWORD)ShellExecute(hwnd, bRunAs? L"runas" : NULL, lPath, lpParams, lpDir, bLoadIt ? SW_SHORWINNOACTIVE : SW_SHOWNORMAL); 

実はこれって、怖いんです。これってファイラーなのです。

lPathが"hoge"だとすると、"hoge.exe"みたいな実行可能ファイル(拡張子はEXTPATHのもの。他にBATやCMDなども検索対象)があるとそちらを実行してしまいます。これはCreateProcessと一緒です。

そこでShellExecuteExさん登場

エクストラはすごいんです。先の例だとこんな書き方ができます。

#define STRICT_TYPED_ITEMIDS

#include <shlobj.h>

 

DWORD ret;

SHELLINFO info;

ZeroMemory(&info, sizeof(info));

info.cbSize = sizeof(info);

info.hwnd = hwnd;

info.lpVerb = bRunAs ? L"runas" : NULL;

info.lpFile = lpPath

info.lpParameters = lpParms;

info.lpDirectory = lpDir;

info.nShow = bLoadIt  ? SW_SHOWINNOACTIVE : SW_SHOWNORMAL;

info.lpIDList = SHSimpleIDListFromPath(lpPath)

info.fMask = SEE_MASK_INVOKEIDLIST; // includes SEE_MASK_IDLIST

if (ShellExecuteEx(&info)) {

  ret = (DWORD)info.hInstApp;

}

else {

  ret = GetLastError();

}

ちょっと長ったらしいですね。エラーハンドリングは手抜きしてます*1。重要なのは、fMaskとlpIDListの指定。この組み合わせならlpFileより優先されます。この書き方では"hoge"に対応するファイルのITEMIDLISTを取得してセットしているのがミソ。こうすれば別のITEMIDを持った"hoge"と"hoge.exe"を同一視するような情弱なことにはなりません。もちろん?info.lpIDListの指定を忘れるとShellExecuteと同じような情弱な動きをするので注意。そんなミスしないでしょうけどね。

みんな使ってねーだろ

そう思うでしょ。そう思っていた時代もありましたが、人気ソフトのExpLzhの更新履歴にはなぜか

  • ShellExecuteEx() の実行では実行ファイルの ITEMIDLIST を指定して実行するように変更。

という項目があります。脆弱性対策の意識がとてもとても高くて気付いたのでしょう。拡張子なしファイル選んだら拡張子補完はWindowsの仕様だ、そんなことも知らんのか。なんて言いたくなるところですが、こんなのまで対応しているOSSは偉いですね。

ほ・そ・く

ここではShellExecuteExによる実行だけを書きましたが、もう一つメジャーな使い道としてファイルプロパティの表示があります。その場合はlpVerbに"properties"をセットします。

やっぱり同じような問題があって、ITEMIDLISTを使わないと、"hoge"を指定しても勝手に"hoge.exe"のプロパティが出てきたりします。ShellExecuteやShellExecuteExでlpFileだけ指定してプロパティ表示しようとせずに、ちゃんとITEMIDLISTを使いましょうね。

魔法の呪文

いかがでしたか、いかがでしょうか、いかがでしたでしょうか、調べてみました。

*1:SHSimpleIDListFromPathで拾えない場合など

広い意味でのバイナリプランティング

バイナリプランティングって、宇宙人のインプランティングみたいで怖いですよね!?

バイナリプランティング概説

現代的にはDLLによるバイナリプランティングを指すようです。

DLLのバイナリプランティング

Windowsでは昔はカレントディレクトリを優先的に読み込んでいましたが、ファイルダブルクリックでアプリ起動すると嵌められるってことで、比較的最近に仕様変更になりました。現在のDLL読み込みの仕様として、順序はこんな感じ。LoadLibraryせずに依存関係で読み込むとこんな順序です。

  1. Known DLLsは登録済み絶対パスで参照
  2. アプリケーションモジュールのあるディレクトリから検索
  3. システムディレクトリ(ようするにC:\Windows\System32)から検索
  4. 16ビットシステムディレクトリ。今もあるかは不明。
  5. Windowsディレクトリ(ようするにC:\Windows)から検索
  6. 現在の作業ディレクトリ(カレントディレクトリ)から検索
  7. PATHで指定されたディレクトリから検索

なお、Windows7の問題は、システム or WindowsディレクトリのDLLが依存関係で読み込むDLLの中に、カレントディレクトリのDLLを読み込んで使う古い実装のものが混じっているのでしょう。特に16ビットとかはあっても不思議ではない。

WindowsにおいてはDLLとEXEはほとんど同じですが、EXEは大人の事情で、現在の作業ディレクトリがトップの最古の仕様のようです。

問題になるのはなになの?

数年ごとに大量に報告されるマイクロソフトはうんざりしたのか、「サーセン基準標準がありませんでした。パイセンこれでどうっすか?」と

DLL の植え付けの脆弱性のトリアージ – 日本のセキュリティチーム

っていう分かりやすい解説を出してます。

要約すると、カレントディレクトリにあるのを読み込む場合はCWEとして「修正してやる!」となるようです。

EXEだとどうなの?

多分ですが、パス省略してEXEを呼び出してカレントディレクトリのファイルが実行されるのは仕様。ただし、アプリケーションレベルでそれやるのはCWEになるかもしんないです*1

Windowsでのプログラム実行

いろんな関数があります。これだけでなく派生もあります。

  • system
  • WinExec
  • popen
  • CreateProcess
  • ShellExecute

この中でWinExecは太古のWindowsなので忘れてあげることにしましょう。systemみたいな危険な代物で、使うべきではありません。脆弱性とか考えられていない仕様なので。情弱にも無検証にCreateProcessやShellExecuteで置き換えた懐古趣味のプログラムもありますが、使う人は当時の安全性基準適用している自業自得ってことで。テキトーに解説すると。

system

シェルを呼び出します。Windows10の時点ではシェルプロンプトのCMD.EXEに引数渡して実行する感じです。シェルの拡張子補完をするので、拡張子なしだと環境変数EXTPATHの順で補完するっぽいです。

CreateProcess

プロセスを起動します。拡張子を省略するとEXEを補完するようです。カレントディレクトリや環境変数を指定できるし、プロセスの権限も指定できます。

ShellExecute

シェルを呼び出すのでsystem同様に拡張子補完するところが似てますが、あとはCreateProcessに準拠してて、さらにUACをサポートするとこがちゃうかな?

伝統がおりなすアレとマルチプラットフォーム

OSSなんかだと、つい伝統あるものなら大丈夫かなって気にしなってしまいますよね。

脆弱性の問題なんかが起きると、リファクタリングでソースが綺麗になるのも嬉しいところです。古くから*2UNIX系とWindows系にマルチプラットフォームで対応している場合は、まあうまくやっているんでしょう。しかし、なぜかWindows系のコードメンテナンスって脆弱性対策が不徹底なことがあるので、コミッターやレビューアの関心度の差でしょうか?不思議ですね。

ようやく本題

マルチプラットフォームと謳っているOSSの場合、Windowsのコードは注意深く読んだ方が良いです。UNIX系から派生した場合にありがちな僕たちの失敗。

それってシェル組み込みコマンド?

UNIX系から派生していると、いろいろと勇気ある行動のコードを見ることがあります。

  • なぜか、いまだにsystemコマンド使っている(正しく使えばいんだろうけど)
  • なぜか、拡張子なしでコマンド記述してわざわざEXEを補完している
  • なぜか、コマンドを絶対パスで書かない(カレントにプラントされたらどうすんですか!?)

コマンドのパス省略は一見問題ないですが、実行ファイル(DLL除く)の場合はカレントディレクトリが優先されるWindowsの伝統仕様に注意が必要です。これがUNIXだとcpは組み込み(ビルトイン)なので、同じノリでWindowsでファイルコピーにCOPYを使うのは問題ないのですが、ディレクトリコピーしたいからXCOPYなんて使うと、外部コマンドです。カレントに実行ファイルがあると詰みます。きーつけましょう。

Windowsでシェルってどうやって呼ぶの?

多分、ShellExecuteを呼ぶのが正解です。systemコマンドでCMDを呼んだりすると、EXE以外も補完するので、カレントディレクトリのCMD.exeどころかCMD.batやCMD.cmdが呼び出されたりするので、すげー困ります。どうせ使うのはEXEなんだし、#ifdef WIN32してるのだから、横着せずに拡張子付きで指定しましょう。とにかくきーつけましょう。以上

脆弱性なの?

とあるサーバで使うOSSでメンテナンスコマンドを実行すると、カレントディレクトリのコマンドを実行する困った仕様がありました。これって脆弱性なの?というと微妙です。サーバでメンテナンスコマンドを実行する時点で特権もってて、おそらく自由にコマンド実行できるので、問題じゃないはず。あと、注意深い管理者は良く問題になるCMDとかXCOPYがないかチェックするものです。これは常識ですよね!?

魔法の呪文

いかがでしたか、いかがでしょうか、いかがでしたでしょうか、調べてみました。

 

*1:使い方を勘案するようで、それでもOKな場合があるようです。雰囲気ですが。

*2:ソースにWindows2000やXP用の動作が書いてあるのがそれ

次回ネタ予告

前回はZip Slipでしたが、次回はExcelのDDEについて。

 

CSVでマクロ実行って怖い」って言うと「マクロ警告を無視するのが悪い」って言う。

「セキュリティ警告が分かりにくい」って言うと「セキュリティ設定しておけば大丈夫です」って言う。

脆弱性でしょうか」って言うと、「脆弱性として無効化すると既存ユーザの利便性を損ないます」って言う。

こだまでしょう?いいえ、仕様です。

 

友達から聞いた公開情報です。公開時期未定。

なんとなくZip Slipについて語る

この記事はZip Slipが公開されてから3ヶ月近くも後に書かれたお話です。

そうだ、旅に出よう

ディレクトリトラバーサルパストラバーサル)は、格式張って語ると、ユーザ入力のバリデーションが不十分で親ディレクトリにトラバースするってことです。

トラバースって横断って訳されるけど、マウントな隣の山に移るみたいな意味もあるような無いような。とりあえず意識高く語るなら、このディレクトリはリスペクトできなかった、俺はビッグになるためにパレントディレクトリへのトラバースにチャレンジした。です。

名前付き脆弱性(Branded Vulnerabilities)

脆弱性だろうがなんだろうが、名前を付けるってのは悪くないアイデアです。脆弱性の原因が〇〇だった場合、それが初めてって劇レアケースならいいんだけど、多くは原因と影響を説明しても「で?なに?」って言われちゃいます。それって美味しいの?ぐらいの反応すら返ってきません。 

そこで、2014年の命名Heartbleedさんはうまい方法をとりました。①影響がイメージできるペットネームをとる②ドメインとる③アイコンをつくる。これで勝利です!

そう、商品ではなくストーリーごと売り込めです。こういった感じに、印象的なお名前の付いたバグ(Bug With An Impressive Name)はBWAINって呼ばれます。

Zip Slipのご紹介

Zip Slipはぶっちゃけ前述の名前付き脆弱性の一つでBWAINです。Zipがズレちゃった、てへぺろって感じですね。Zip Slipでは、Zipファイルを展開するときにディレクトリトラバーサルが起きるライブラリを一斉摘発しました。github検挙者リストと対策状況を公開しています。ライブラリの脆弱性じゃなくて仕様で、呼び出し側ツールの脆弱性なんじゃね?って意見もありますが、その議論はスルー。 

※Zipper(チャック)を開き閉めするとき噛んだりズレたり引っかかったりすると困りますが、そんな不具合をまず起こさないYKKの高性能なジッパーが普及して、昭和末期には一度は幸せになったんですが、最近は安いジッパーが服に使われていることもあって、それ原因で服が寿命に…。残念。 

そんな対策で大丈夫か?

Zip Slipの脆弱性説明文

脆弱性の説明はこうなってます。 

The vulnerability is exploited using a specially crafted archive that holds directory traversal filenames (e.g. ../../evil.sh). The Zip Slip vulnerability can affect numerous archive formats, including tar, jar, war, cpio, apk, rar and 7z. If you’d like the information on this page in a downloadable technical white paper, click the button below. 

説明文から受ける印象

ああ、".."に起因するディレクトリトラバーサルのBWAINね。そう思うと生き残れないかもしれません、あなたは頓死に一歩近づいています。脆弱性があるって指摘されたからには対策すると良いわけですが、そこで原因をどう思うかが重要。

ディレクトリトラバーサル

× ".."に起因する

です。".."だと思うと、なんと情弱だったのでしょう!と自己批判に迫られる事態に陥ります。

推奨している対策(.NET編)

snykは、親切にも脆弱性のあるコードの例とその対策を公開しています。以下のコードは.NETのサンプルです。どのコードも引用です。

脆弱性のあるコード:

ヤバいコードの例です。destDirectoryがなんだろうが、fileが相対パスだったら親ディレクトリにさかのぼることも可能だし、ましては絶対パスだったりすると、どこでもフリーアクセスです。豪快ですね。 

.NETの脆弱性サンプル

ちなみに、Path.Combineは第二引数(の正規化評価結果)が絶対パスだと、第一引数は無視して第二引数を使う仕様です。第三引数があるパターンもやっぱり後ろが優先されます。言われてみると「そういう仕様はあり得るな」でしょうが、単純に引数を連結してから正規化だと思ってると大変なことになります。

正しいコード:

対策も公開しています。「まったく簡単だ」です。標準ライブラリにパスを正規化するAPIがあるので、正規化した後のものが期待したパスから始まっているかチェックすればいいんです。簡単なお仕事です。

.NETの推奨対策サンプル

 さて、本題

対策済みリストが出ているからといって、信じていいんでしょうか?

友達は疑い深いのでリストをチェックしたそうです。前述のように.NETでは単純明快な対策がでているので、まずは.NETのライブラリを見てみると良さそうってこともあり、

DotNetZip.Semverdってのを見てみたんだそうです。ほら、対策済みになってますよね。 

Zip Slipのリスト

親切にgithubの修正差分へのリンクもついてます。便利ですねー。コメント文にきちんと対策内容も書いてます。ご立派。

けど、あれ? if (dir == "..") って呪文が!?

修正内容うーん。もちろん、ディレクトリデリミタを"\"を"/"で正規化するときに、Linuxでは有効だとしてもWindowsでは無視される余分なスペース省いているんですよね。知らないけど絶対そう。

.NETのWindows世界の常識というか定説というか

さて、.NETのWindows世界の高校の屋上で以下の会話があったとしましょう。

A「親ディレクトリって".."だけですよね? 」

B「えっ、なんだって」

別にラノベ突発性難聴主人公ではありません。そうです。.NETのWindows世界ではDotDotこと".."だけが親ディレクトリではありません。DotDotの後ろにいくつかスペースを加わってても、親切なWindowsは華麗にスルーしてくれます。そうです。DotDotSpacesはDotDotと等価なのです。

※下位フレームワークというか言語のランタイムによっては、WindowであってもDotDotとDotDotSpacesが異なる可能性もゼロではないです(SE的危険表現)。 

推奨している対策(Java編)

たまたま見たライブラリが.NETのWindowsの有名な地雷を踏んでいるように見えるので(呼び出し元でチェック済みな可能性も微レ存)、ついでに疑り深くJavaも見てみましょう。同じく、どのコードも引用元です。

脆弱性のあるコード:

これまた分かりやすい例ですね。destnationDirがなんだろうと、Enumerationキーに相対パス絶対パスが入っていると困ったことになります。

Javaの脆弱性サンプル

正しいコード:

これの対策の例示も明快ですね。標準ライブラリのAPIを信頼してgetCanonicalPathで正規化した後のものが期待したパスから始まっているか確かめます。

Javaの推奨対策サンプル

サンプルはサンプルであって(以下略)

getCanonicalPathはシンボリックリンクをフォローする仕様だけど、destinationfileもgetCanonicalPathしているから比較しているので、展開先ディレクトリがシンボリックリンクであってもうまく動作するサンプルコードになっていて素晴らしいです。

なお、存在しないパスを指定するとIOExceptionが出て、そのままメッセージを表示すると原因パスが懇切丁寧に表示される事があるので、必要に応じてキャッチしましょう。作業ディレクトリにあたるdestinationfileが漏れた場合は脆弱性とみなされるシチュエーションプレイがあります。この辺りは常識の範囲だし、問題ないこともあるのでサンプルでは省略してるのでしょう。 

おまけ

アタッシェケースという暗号ソフトはv3.3.0で、ATCファイル(独自の暗号化ファイルフォーマット)のディレクトリトラバーサル対策が強化されました。けど不十分だったということで2018年8月末にv3.4.0が公開され、対策をブラックリスト方式から、展開先パスを確認するホワイトリストっぽい方式に変更したそうです。これって、ZipSlipの対策でも紹介されている定番のアプローチです。一方、ブラックリスト方式ってのはDotNetZip.Semverdの例で紹介したような、これが入ってるとダメのアプローチです。完全に使いこなせば問題ないですが、ブラックリストアプローチはなかなか難しいものです。脆弱性追加修正の謝辞にでてくる、対処方法を指導したJPCERT/CCさんグッジョブですね。

魔法の呪文

いかがでしたか、いかがでしょうか、いかがでしたでしょうか、調べてみました。