界: Time and State

分散型計算とは、時間と状態に関するものです。つまり、複数のコンポーネントが通信するためには、状態を共有しなければならず、そのためには時間がかかります。

ほとんどのプログラマーは、自分の仕事を人であるかのように考えています。彼らは、自分で仕事をしなければならない場合、自分がするのと同じように、1 つのスレッドのコントロールでプログラム全体を実行することを考えます。しかし、最近のコンピュータは、タスクの切り替えが非常に速く、マルチコア、マルチ CPU、分散システムなどでは、2 つのイベントが全く同時に発生することもあります。不具合は、プログラマーが考えたプログラムの実行方法のモデルと、現実に起きていることとのギャップを埋めるために押し寄せます。これらの欠陥は、スレッド、プロセス、時間、および情報の間の予期せぬ相互作用に関連しています。これらの相互作用は、セマフォ、変数、ファイル システムなど、基本的には情報を保存できるあらゆるものを含む共有状態を通じて行われます。

Insecure Temporary File

Abstract
Insecure Temporary File を作成または使用すると、アプリケーションやシステムデータが攻撃に対して脆弱になることがあります。
Explanation
アプリケーションはテンポラリファイルを非常に頻繁に必要とするため、C ライブラリと Windows(R) API にはテンポラリファイルを作成するさまざまなメカニズムが数多く存在します。これらの関数の多くは、さまざまな形態の攻撃に対して脆弱です。
例: 次のコードは、ネットワークから収集された中間データを、処理するまで格納するテンポラリファイルを使用しています。


...
if (tmpnam_r(filename)){
FILE* tmp = fopen(filename,"wb+");
while((recv(sock,recvbuf,DATA_SIZE, 0) > 0)&&(amt!=0))
amt = fwrite(recvbuf,1,DATA_SIZE,tmp);
}
...


このコードは本来、平凡なコードですが、安全でないメソッドに依存してテンポラリファイルを作成するため、さまざまな攻撃に対して脆弱です。この関数などにより導入される脆弱性について、以降で説明します。テンポラリファイルの作成と関係がある最も顕著なセキュリティ上の問題が UNIX ベースのオペレーティングシステムで発生していますが、Windows アプリケーションにも同様のリスクがあります。このセクションでは、UNIX および Windows の両方のシステムにおけるテンポラリファイルの作成について説明します。

メソッドと動作はシステムにより異なりますが、それぞれで発生する基本的なリスクはほぼ一定です。安全なコア言語関数と、テンポラリファイルの作成に関する安全な手法については「Recommendations」セクションを参照してください。

テンポラリファイルの作成を支援するよう設計された関数は、単にファイル名を提供するだけか、または実際に新しいファイルを開くかどうかによって 2 つ のグループに分類することができます。

グループ 1 - 「一意の」ファイル名:

C ライブラリや WinAPI の最初のグループは、新しいテンポラリファイルに対して一意のファイル名を生成し、テンポラリファイルの作成処理を支援します。このテンポラリファイルをプログラムが開きます。このグループに含まれるのは、tmpnam()tempnam()mktemp()などの C ライブラリ関数と、先頭に _ (アンダースコア) が付けられた、それぞれに対応する C++ 関数、および Windows API に属する GetTempFileName() 関数です。このグループの関数は、選択されたファイル名の Race Condition の脆弱性があります。関数は、ファイル名が選択されたときに一意であることを保証しますが、ファイルの選択後、アプリケーションがファイルを開こうと試みる前に別のプロセスまたは攻撃者が同一の名前を持つファイルを作成するのを阻止するメカニズムがありません。同じ関数への別のコールによって発生する正当な衝突の危険のほかに、攻撃者が悪意ある衝突を作成する可能性も十分あります。これらの関数によって生成されたファイル名が十分にランダムでなく、推測が難しくないためです。

選択された名前のファイルが作成されると、ファイルの開き方に応じて、既存のコンテンツまたはファイルのアクセス許可は変更されないままとなります。ファイルの既存のコンテンツが悪意ある性質のものである場合、アプリケーションがテンポラリファイルからデータを読み戻す際に、攻撃者がアプリケーションに危険なデータを挿入できる可能性があります。攻撃者が事前にアクセス許可を緩くしたファイルを作成した場合、アプリケーションによりテンポラリファイルに格納されたデータに対して攻撃者はアクセス、変更、破壊を行うことができます。UNIX ベースのシステムの場合、攻撃者は事前に別の重要なファイルへのリンクとしてファイルを作成しておくことで、さらに露見しにくい攻撃が可能です。この場合、アプリケーションがデータを切り詰めたりファイルに書き込んだりすると、知らずに攻撃者の意図に沿って損傷をもたらす操作を実行することになる可能性があります。昇格した許可でプログラムが動作している場合、これは特に深刻な脅威となります。

最後に、最良のケースでは、O_CREAT フラグや O_EXCL フラグを使用した open() のコールや、CREATE_NEW 属性を使用した CreateFile() のコールでファイルが開かれるのは、ファイルが既に存在する場合に失敗するため、前述のタイプの攻撃は阻止されます。ただし、攻撃者が一連のテンポラリファイル名を正確に予測できる場合、アプリケーションは必要とするテンポラリストレージを開こうとしても阻止され、Denial of Service (DoS) 攻撃が発生する可能性があります。これらの関数によって生成されたファイル名の選択に使用されているランダム度が小さければ、このタイプの攻撃を準備するのは容易です。

グループ 2 - 「一意の」ファイル:

C ライブラリ関数の 2 番目のグループは、一意のファイル名を生成するだけではなく、そのファイルを開くことによって、テンポラリファイルに関連するセキュリティ上の問題の一部を解決しようと試みます。このグループに含まれるのは、tmpfile() などの C ライブラリ関数と、先頭に _ (アンダースコア) が付けられた、それに対応する C++ 関数、および多少動作が優れている C ライブラリ関数 mkstemp() です。

tmpfile() スタイル関数は一意のファイル名を作成して、"wb+" フラグが渡された場合の fopen() と同じ方法、つまり読み書きモードでバイナリ ファイルとしてそのファイルを開きます。ファイルが既に存在する場合、tmpfile() により、サイズがゼロに切り詰められます。これは、一意であるはずのファイル名を選択してから、選択されたファイルをその後で開くまでの間に存在する Race Condition に関する、前述したセキュリティ上の懸念を緩和しようとするものです。ただし、この動作は関数のセキュリティ上の問題を明確に解決するわけではありません。まず、攻撃者は事前にアクセス許可を緩くしたファイルを作成でき、その許可が tmpfile() により開かれるファイルによって変更される可能性はあまりありません。さらに、UNIX ベースのシステムの場合、攻撃者がファイルを別の重要なファイルへのリンクとして事前に作成すると、アプリケーションは昇格した許可を使用してそのファイルを切り詰める可能性があり、結果的に攻撃者の意図した損傷を与えます。最後に、tmpfile() が実際に新しいファイルを作成する場合、そのファイルに適用されるアクセス許可はオペレーティングシステムにより異なります。つまり、攻撃者が事前にファイル名を予測できない場合も、アプリケーションデータは脆弱な状態に保たれる可能性があります。

最後に、mkstemp() は、テンポラリファイルを作成する上で十分に安全性が確保された方法です。ユーザーが提供したファイル名テンプレートに基づき、ランダムに生成した一連の文字を組み合わせて一意のファイルを作成して開こうとします。ファイルを作成できなかった場合は、失敗して -1 を戻します。最近のシステムでは、ファイルはモード 0600 で開かれます。つまり、ユーザーがアクセス許可を明示的に変更しない限り、ファイルは改竄に対して安全です。しかし、mkstemp() は予測可能なファイル名が使用されているため攻撃されやすく、攻撃者が使用されるファイル名を予測して事前に作成することで mkstemp() の失敗を引き起こした場合、アプリケーションは Denial of Service 攻撃にさらされる可能性があります。
References
[1] B. Schneier Yarrow: A secure pseudorandom number generator
[2] CryptLib
[3] Crypto++
[4] BeeCrypt
[5] OpenSSL
[6] CryptoAPI: CryptGenRandom() Microsoft
[7] RtlGenRandom() Microsoft
[8] .NET System.Security.Cryptography: Random Number Generation Microsoft
desc.semantic.cpp.insecure_temporary_file
Abstract
Insecure Temporary File を作成または使用すると、アプリケーションやシステムデータが攻撃に対して脆弱になることがあります。
Explanation
アプリケーションはテンポラリ ファイルを非常に頻繁に必要とするため、テンポラリ ファイルを作成するさまざまなメカニズムが数多く存在します。これらの関数の多くは、さまざまな形態の攻撃に対して脆弱です。
例: 次のコードは、ネットワークから収集された中間データを、処理するまで格納するテンポラリファイルを使用しています。


...
try:
tmp_filename = os.tempnam()
tmp_file = open(tmp_filename, 'w')
data = s.recv(4096)
while True:
more = s.recv(4096)
tmp_file.write(more)
if not more:
break
except socket.timeout:
errMsg = "Connection timed-out while connecting"
self.logger.exception(errMsg)
raise Exception
...


このコードは本来、平凡なコードですが、安全でないメソッドに依存してテンポラリファイルを作成するため、さまざまな攻撃に対して脆弱です。この関数などにより導入される脆弱性について、以降で説明します。テンポラリファイルの作成と関係がある最も顕著なセキュリティ上の問題が UNIX ベースのオペレーティングシステムで発生していますが、Windows アプリケーションにも同様のリスクがあります。

メソッドと動作はシステムにより異なりますが、それぞれで発生する基本的なリスクはほぼ一定です。安全なコア言語関数と、テンポラリファイルの作成に関する安全な手法については「Recommendations」セクションを参照してください。

テンポラリファイルの作成を支援するよう設計された関数は、単にファイル名を提供するだけか、または実際に新しいファイルを開くかどうかによって 2 つ のグループに分類することができます。

グループ 1 - 「一意の」ファイル名:

最初のグループは、新しいテンポラリ ファイルに対して一意のファイル名を生成し、テンポラリ ファイルの作成処理を支援します。このテンポラリ ファイルをプログラムが開きます。このグループの関数は、選択されたファイル名の Race Condition の脆弱性があります。関数は、ファイル名が選択されたときに一意であることを保証しますが、ファイルの選択後、アプリケーションがファイルを開こうと試みる前に別のプロセスまたは攻撃者が同一の名前を持つファイルを作成するのを阻止するメカニズムがありません。同じ関数への別のコールによって発生する正当な衝突の危険のほかに、攻撃者が悪意ある衝突を作成する可能性も十分あります。これらの関数によって生成されたファイル名が十分にランダムでなく、推測が難しくないためです。

選択された名前のファイルが作成されると、ファイルの開き方に応じて、既存のコンテンツまたはファイルのアクセス許可は変更されないままとなります。ファイルの既存のコンテンツが悪意ある性質のものである場合、アプリケーションがテンポラリファイルからデータを読み戻す際に、攻撃者がアプリケーションに危険なデータを挿入できる可能性があります。攻撃者が事前にアクセス許可を緩くしたファイルを作成した場合、アプリケーションによりテンポラリファイルに格納されたデータに対して攻撃者はアクセス、変更、破壊を行うことができます。UNIX ベースのシステムの場合、攻撃者は事前に別の重要なファイルへのリンクとしてファイルを作成しておくことで、さらに露見しにくい攻撃が可能です。この場合、アプリケーションがデータを切り詰めたりファイルに書き込んだりすると、知らずに攻撃者の意図に沿って損傷をもたらす操作を実行することになる可能性があります。昇格した許可でプログラムが動作している場合、これは特に深刻な脅威となります。

最後に、os.O_CREAT フラグや os.O_EXCL フラグを使用した open() のコールでファイルが開かれる最良のケースでは、ファイルがすでに存在する場合は処理が失敗するため、ここで説明したタイプの攻撃は阻止されます。ただし、攻撃者が一連のテンポラリファイル名を正確に予測できる場合、アプリケーションは必要とするテンポラリストレージを開こうとしても阻止され、Denial of Service (DoS) 攻撃が発生する可能性があります。これらの関数によって生成されたファイル名の選択に使用されているランダム度が小さければ、このタイプの攻撃を準備するのは容易です。

グループ 2 - 「一意の」ファイル:

関数の 2 番目のグループは、一意のファイル名を生成するだけではなく、そのファイルを開くことによって、テンポラリ ファイルに関連するセキュリティ上の問題の一部を解決しようと試みます。このグループには tmpfile() のような関数が含まれます。

tmpfile() スタイル関数は一意のファイル名を作成して、"wb+" フラグが渡された場合の open() と同じ方法、つまり読み書きモードでバイナリ ファイルとしてそのファイルを開きます。ファイルが既に存在する場合、tmpfile() により、サイズがゼロに切り詰められます。これは、一意であるはずのファイル名を選択してから、選択されたファイルをその後で開くまでの間に存在する Race Condition に関する、前述したセキュリティ上の懸念を緩和しようとするものです。ただし、この動作は関数のセキュリティ上の問題を明確に解決するわけではありません。まず、攻撃者は事前にアクセス許可を緩くしたファイルを作成でき、その許可が tmpfile() により開かれるファイルによって変更される可能性はあまりありません。さらに、UNIX ベースのシステムの場合、攻撃者がファイルを別の重要なファイルへのリンクとして事前に作成すると、アプリケーションは昇格した許可を使用してそのファイルを切り詰める可能性があり、結果的に攻撃者の意図した損傷を与えます。最後に、tmpfile() が実際に新しいファイルを作成する場合、そのファイルに適用されるアクセス許可はオペレーティングシステムにより異なります。つまり、攻撃者が事前にファイル名を予測できない場合も、アプリケーションデータは脆弱な状態に保たれる可能性があります。
References
[1] B. Schneier Yarrow: A secure pseudorandom number generator
[2] Python Library Reference: os Python
[3] Python Library Reference: tempfile Python
[4] Symlink race WikiPedia
[5] Time of check to time of use WikiPedia
desc.semantic.python.insecure_temporary_file