Protecciones en PHP y utilidad de SandBox

Recientemente ha llegado a mis manos un script en PHP que estaba protegido.
Las protecciones típicas que se ven en los PHP son dos:

  • PHP compilado en opcodes (y para los que hay que usar un acelerador que soporte carga de archivos compilados)
  • Código PHP ofuscado de alguna forma. Mediante urldecode, base64_decode, evals…

La primera protección se puede saltar con algún decompilador de opcodes para PHP. No estoy muy puesto, pero seguro que hay alguno. Y de hecho hay extensiones que te permiten ver los opcodes para un código PHP. Por ejemplo la parsekit (aunque en este caso no estoy seguro si permite cargar PHPs ya compilados). Para lenguajes como java, .net o flash hay algunos programitas para convertir los opcodes en código de alto nivel recompilable: JD (Java Decompiler), .NET Reflector, Sothink SWF Decompiler.

La segunda protección impide que los aceleradores cacheen el código por lo que acaba ralentizando la aplicación. Hay diversas formas de obtener el código final. Posiblemente la más sencilla sea con un debugger. Sin embargo yo quería probar una que no requisiese ningún debugger y que se pudiese automatizar de alguna forma.

Hace ya varios años estuve experimentando con formas de ejecutar PHP de forma segura. Es decir, PHP tiene un montón de APIs, permite hacer llamadas a funciones dinámicas mediante $var()…

La forma de hacer eso es llamando a una función proxy que se encargase de llamar a las funciones que tocase o a funciones personalizadas, stub o mockeadas. La función call_user_func_array permite llamar a cualquier función con parámetros variables.

El caso concreto:

No me podía fiar del script que quería desproteger. Lo primero es establecer un entorno de pruebas donde no se pueda romper nada. Un script malintencionado podría borrar algún archivo importante, extraer información o hacer otras cosas si detectase que estás intentando desprotegerlo. Para hacer esto basta con montarse una máquina virtual que no esté conectada a Internet y hacer las pruebas ahí sin peligro alguno.

El segundo paso era montar el sandbox que comentaba antes. Monté poco a poco un sistema que reescribía el código haciendo que las llamadas pasasen por una función hook y limitando su uso conforme veía las funciones que utilizaba.

El script en cuestión usaba urlencode, base64_decode y eval. Además de variables con nombres parecidos para despistar.

Con el sandboxer que monté hookeé las funciones a las que llamaba estática y dinámicamente. La función eval tiene la particularidad de que se ejecuta con el mismo contexto de variables locales que el callee. Como el sistema hace que se ejecute todo en un contexto diferente, tuve que hacer que el sandboxer capturase las variables locales cuando se llamaba a un eval (con la limitación de llamadas estáticas a eval). Esto lo hago mediante la función get_defined_vars, y para reimportar el contexto basta con usar la función extract.

El script requería que estuviese el archivo sin modificaciones y leía parte de su contenido en direcciones y longitudes fijas. Además utilizaba FILE para saber el nombre y la ruta del archivo al que se quería acceder. Como el código se ejecutaba desde un eval, FILE ya no funcionaba correctamente, así que hice que el código encargado de reescribir el código en sandbox, reemplazase los FILE por el fichero original que se esperaba ejecutar.

Como el script utilizaba la función fopen y no podía saber si se iba a usar varias veces hookeé dicha función y limite su uso a read-only para evitar que escribiese en ningún sitio. Como tampoco había Internet donde mandar datos, no había peligro.

En cada llamada a funciones y ejecución de evals reescritos, iba dumpeando el contenido de los parámetros en las llamadas. En algún eval tendría que estar el código “final” encriptado que hacía lo que se esperaba.

El script tenía además una protección por dominio. Usando $_SERVER[‘HTTP_HOST’] y una expresión regular para limitar la ejecución a un dominio y subdominios. Por cierto, una forma absurda de proteger, pues se puede saltar así de fácil:

$original_host = $_SERVER['HTTP_HOST'];  
$_SERVER['HTTP_HOST'] = 'expectedhost.com';  
{  
    require_once(__DIR__ . "/file.php");  
}  
$_SERVER['HTTP_HOST'] = $original_host;  

Al final mostrando las salidas, y de forma completamente automática, en el último paso se podía observar el código que se había intentado proteger con tanto empeño.
Conclusión: Este tipo de protecciones son muy fáciles de romper y lo único que hacen son ralentizar la ejecución de los scripts.

Código fuente medio genérico del PHP Sandboxer que monté: http://code.google.com/p/phplutils/source/browse/trunk/php_sandboxer.php

Leer más...

poly2tri y búsqueda de caminos

Hace algún tiempo, para el trabajo, empecé a hacer un port a ActionScript3 de la librería opensource poly2tri.
La idea era usarla para búsqueda de caminos en flash.
La búsqueda poligonal de caminos consta de tres partes:

  1. Triangulación (en este caso mediante la librería poly2tri)
  2. Búsqueda del camino más corto en nodos. (Usando A). En este caso no ha hecho falta dividir la búsqueda en varios nivels. Es un A sencillito con un nodo para cada triángulo que puede acceder a los triángulos contiguos.
  3. Algoritmo del embudo (Funnel algorithm). Implementación Simple Stupid Funnel Algorithm (De la cual también hice un port en Javascript).

Los pasos 2 y 3 son suficientemente rápidos como para hacerlos en tiempo real, al menos con escenas sencillitas. El paso uno posiblemente también, pero en este caso no hace falta.

Se puede acceder al código fuente de mercurial desde aquí.

Aquí una demo en funcionamiento (tras el salto):

Leer más...

header_register_callback() en PHP 5.4

Hace una semana vi que añadieron al trunk de PHP una nueva función llamada header_register_callback.

La función permite procesar, mediante un callback, todos los headers (los generados por el usuario explícitamente, más los que genera PHP internamente) inmediatamente antes de que se manden. Permitiendo utilizar las funciones relacionadas con los headers: headers_list, header_remove, header.

Leer más...

Charla sobre Shaders

Hacía ya tiempo que tenía pendiente grabar en vídeo la presentación de la charla de shaders de Pixel Bender que di en Softonic allá por noviembre de 2009.
La preparé a la vez que añadía soporte de shaders a mi librería phpMedia:
http://blog.cballesterosvelasco.es/category/proyectos/phpmedia/

DESCARGAR ARCHIVOS DE LA CHARLA - 

DEMO INTERACTIVA

 (8Mb)

Leer más...

Transmisión de paquetes con estructura flexible

Hace algún tiempo estuve investigando sobre la tranmisión de paquetes cliente <-> servidor en una plataforma de juegos flash.

La forma tradicional de mandar paquetes en las conexiones de flash es mediante sockets XML. Los paquetes XML son muy grandes para un intercambio continuado entre cliente y servidor.

Algunos servidores de sockets flexibles pensados para flash utilizan también JSON. Los JSON son mucho más compactos, pero siguen enviándose muchísimas redundancias. Especialmente sobre la estructura de los paquetes.

Y tanto los XML como los JSON se mandan sin encriptación alguna. Existen programas que facilitan la intercepción de paquetes, evitando mandarlos, modificar su contenido o inyectar paquetes nuevos. Esto en plataformas de juegos P2P donde el servidor no dirige las partidas es un problema mayor. Especialmente por la facilidad de hacer esto sin conocimientos avanzados.

Me puse a investigar sobre los dos problemas: tamaño de paquete y encriptación.

Leer más...

Suscribirse via RSS