はじめに:ディレクトリトラバーサルの基本を学ぼうとしています。
質問:2バイト文字のUnicode変換を理解しようとしているときに、ディレクトリトラバーサルの脆弱性を説明する this_SANS ARTICLE に遭遇しました。 /
は%C0%2F
として表されますが、表現%C0%AF
も機能し、攻撃の成功に役立ちます。
誰もが両方の表現が機能する理由を説明できますか?理由がバイナリレベルで説明されていると、非常に役立ちます。
まず、 RLエンコーディングはパーセントエンコーディングとしても知られています は単純なスキームで、URLでは%xx
はバイト(0〜255の数値)を表し、各x
は16進数(16進数:0-9A-F、16 * 16 = 256は異なるバイト数に注意)。
したがって、URLの%C0%AF
は、デコードされたURLにバイトC0 AF
を挿入することに対応します。つまり、バイト192(1100 0000
)とバイト175(1010 1111
)を意味し、%C0%2F
は、バイト192(1100 0000
)およびバイト47(0010 1111
)に対応します
ASCIIは、バイト0〜127のシンボルのみを定義します。ASCIIへの最も一般的な拡張は、特殊なシンボルを許可する(たとえば、英語以外のライター向け)は、Unicodeです) 。Unicodeは/
のような記号を数値で表されるコードポイントに変換します。たとえば、/
は47番目のコードポイント(16進数で0x2f
)、π
は960番目のコードポイント(0x3c0
)、および♥
は9829番目のコードポイント(0x2665
)です。ユニコードシンボルをバイトストリームに入れるには、エンコードする必要があり、現在最も一般的なエンコーディングはUTFです。 -8、UTF-8は1バイト(8ビット)でASCII文字をエンコードし続けるので、プレーンな古いASCIIドキュメントASCII定義されているのは128シンボル(0〜127の間)のみで、これらはすべて最初のビットが0です。
UTF-8の動作は正常ですASCII文字は通常どおり1バイトを使用してエンコードされます。これは、デコードアプリケーションが最初のビットが0
であることを認識することで認識されます。処理する次のバイト。最初のビットが1
で始まることがわかった場合は、次のシンボルが複数のバイトシーケンスで表されていることを示します。バイト数は、最初のバイトの形式(特に、最初のバイトの最初の1
の前にある先頭の0
の数。たとえば、マルチバイトシーケンスの最初のバイト 形式は110x xxxx
の場合同様に、次のシンボルが2バイトで表されることを示します。同様に、1110 xxxx
は、3バイトシーケンスの開始であることを意味し、1111 0xxx
は、4バイトシーケンスなどであることを意味します。 TF-8 wikipedia page 、2バイトのシーケンスが110i jklm 10no pqrs
の形式で、2進数ijk lmno pqrs
でUnicodeコードポイントを表す必要があることに気づくでしょう。原則は、000 0000 0000
(0)から111 1111 1111
(2047)までの任意の2進数です。最初のケース(C0AF
)では、ビット110があります。0 0000 1010 1111、コードポイントを表します 00000101111 = 47 = /
。 47は、単にASCII文字/
、つまりビット0010 1111
でさらに簡単に表すこともできます。2番目のバイトが開始するように定義されている理由に疑問を感じるかもしれません。 with 10
-UTF-8がこれを挿入するので、文字がマルチバイトUTF-8文字の始まりの続きであるかどうかを判別して、エラーをキャッチできます。
したがって、これはすべてのユニコード文字を表す複数の方法を可能にするようです。しかし、これはユニコード規格では許可されていません。 2バイトシーケンスは128から2047の間の値にのみ到達するはずなので、C0AF
は/
を表すべきではありませんが、エラーになります。ただし、多くの場合、Unicodeライブラリは高速になるように設計されているため、セキュリティへの影響を考慮しない場合があります。したがって、一部のライブラリは、2バイトのUnicode文字の値が有効な範囲にあることを確認しないことを選択する場合があります(Unicode標準ではこれが禁止されていますが)。または、開発者は、C0AF
が与えられた場合、ほとんどの場合、2F
を送信することを意図した不正なUTF-8アプリケーションがあり、ユーザーにとって最も便利になるように最も賢明な動作にフォールバックすることを決定しました(表示として/
は、表示する他のどの文字を選択するよりも賢明です。
同様に、Unicodeをデコードする多くのアプリケーションは2番目のバイトの最初のビットが実際には前のバイトの%C0%2F
であることを確認しないため、さらに欠陥のある1
バージョンも一部の不良Unicodeライブラリで機能します。 2バイトのコードポイントであることを示した。つまり、不正なデコーダは110i jklm ??no pqrs
を有効な2バイトコードポイントとして受け入れます。 UTF8標準の義務として10
であること。 2番目のバイトの最初の2文字は冗長であるため、高速でダーティなUnicodeデコードアプリケーションは、これらの文字が適切な値と一致することを確認しないと判断する可能性があります。
これで、%C0%AF
と%C0%2F
の両方が最終的にシンボル/
にデコードされる理由がわかったので、適切なチェックをスキップするユニコードデコーダーを使用します。
これがディレクトリトラバーサルの許可に成功する理由については、不適切な入力のフィルタリングとユニコードシンボルのデコードがアプリケーションのさまざまな段階で行われることがよくあります。 Webサーバーは、誰かがhttp://www.example.com/../../../etc/shadow
またはhttp://www.example.com/..%2f..%2f..%2fetc%2fshadow
までナビゲートできないように、不適切な記号を取り除いて十分にスマートである場合があります。ただし、Webサーバーがファイルを提供し、Unicodeのデコードがディレクトリトラバーサルを防止するチェック後に行われた場合、またはオペレーティングシステムによってわずかに異なる方法で行われた場合、この攻撃はフィルターを通過して攻撃が機能する可能性があります。
ユニコードのより詳細なアクセス可能な概要については、私はお勧めします "絶対最小値すべてのソフトウェア開発者は絶対に、Unicodeと文字セットについて積極的に知っている必要があります(言い訳なし!)" 。