Anteriormente he hablado sobre el uso de Stem para controlar instancias de TOR, una potente librería que no solamente se aprovecha del protocolo de control de TOR para la administración remota de una instancia en ejecución, sino que también cuenta con algunas utilidades para arrancar una nueva instancia con configuración personalizada, descargar y parsear los descriptores emitidos por las autoridades de directorio, entre muchas otras funcionalidades útiles. Es una librería que se explota bastante bien en Tortazo, una de las herramientas que he escrito para realizar pruebas de penetración contra repetidores de salida y servicios ocultos en la red de TOR.
Aunque Stem es una librería muy potente, existen otras alternativas que cuentan con las mismas capacidades y en esta ocasión, voy a hablar sobre TXTORCON.
¿Por qué TxTorCon? Porqué se trata de una implementación del protocolo de control de TOR basada en Twisted y a diferencia de Stem, TxTorCon es una implementación asíncrona. Una librería como TxTorCon permitirá crear programas reactivos que se encargarán de ejecutar acciones sobre una o varias instancias de TOR ante una lista de eventos predefinidos.
En esta entrada se verá cómo se puede utilizar TxTorCon para crear servicios ocultos en TOR de forma programática y aunque lo que se verá a continuación también se puede hacer con Stem, se trata de un ejercicio practico muy interesante que servirá para conocer los elementos básicos y la “metodología” que se debe seguir cuando se programa con esta librería.
Antes de continuar, se recomienda al lector tener claros los conceptos básicos sobre la configuración de una instancia de TOR y conocer bastante bien las propiedades admitidas en el fichero “torrc”, aunque crear un servicio oculto no es una tarea compleja ya que solamente es necesario definir la opción de configuración “HiddenService” en el fichero de configuración “torrc” tantas veces como servicios ocultos se desee crear, lo que si que puede ser complicado es mantener el servicio oculto correctamente securizado, pero eso es un tema del que se hablará en un próximo artículo.
En primer lugar, es importante conocer el uso de la clase “txtorcon.TorConfig” ya que en dicha clase es donde definen todos los elementos de configuración de una instancia de TOR y dicho elemento puede ser utilizado para levantar la instancia de forma programática utilizando TxTorCon.
import txtorcon config = txtorcon.TorConfig() config.SOCKSPort = 9051 config.ORPort = 4443 ….. config.save()
La clase “txtorcon.TorConfig” maneja un diccionario interno con las propiedades que se pueden definir en un fichero de configuración de TOR, con lo cual el programador debe definir cada propiedad como un atributo de instancia.
Ahora bien, para definir uno o varios servicios ocultos, es necesario crear un listado de instancias de la clase “txtorcon.HiddenService”. Dicho listado se almacenará en la variable “HiddenServices” de la instancia de “txtorcon.TorConfig” creada previamente.
La siguiente función servirá para definir los detalles de configuración básicos para iniciar una instancia de TOR con un servicio oculto.
import txtorcon import functools import tempfile import os from twisted.internet import reactor def createTemporal(): tempDir = tempfile.mkdtemp(prefix='torhiddenservice') reactor.addSystemEventTrigger('before', 'shutdown', functools.partial(txtorcon.util.delete_file_or_tree, tempDir)) return tempDir def configuration(hiddenserviceDir, serviceInterface, servicePort=8080, hiddenservicePort=80): if hiddenserviceDir is None: print "[+] HiddenServiceDir not specified... Generating a temporal file." hiddenserviceDir = createTemporal() if os.path.exists(hiddenserviceDir) == False: print "[+] The HiddenServiceDir specified does not exists... Generating a temporal file." hiddenserviceDir = createTemporal() config = txtorcon.TorConfig() config.SOCKSPort = 9051 config.ORPort = 4443 config.HiddenServices = [txtorcon.HiddenService(config, hiddenserviceDir, ["%s %s:%s" %(str(hiddenservicePort), serviceInterface, str(servicePort))] )] config.save() return config configuration('/home/adastra/Escritorio/django-hiddenservice', '127.0.0.1')
La función “configuration” se encarga de recibir como argumento todos los elementos necesarios para establecer un servicio oculto en la configuración definida en el objeto “txtorcon.TorConfig” y posteriormente dicho objeto es retornado. Por otro lado, la función “createTemporal” es invocada internamente por la función “configuration” con el fin de devolver un directorio temporal para el servicio oculto en el caso de que el directorio indicado por parámetro sea invalido.
Ahora que la configuración se encuentra preparada, el siguiente paso consiste en utilizarla para iniciar la instancia de TOR en cuestión.
import txtorcon import functools import tempfile import os from twisted.internet import reactor def createTemporal(): tempDir = tempfile.mkdtemp(prefix='torhiddenservice') reactor.addSystemEventTrigger('before', 'shutdown', functools.partial(txtorcon.util.delete_file_or_tree, tempDir)) return tempDir def configuration(hiddenserviceDir, serviceInterface, servicePort=8080, hiddenservicePort=80): if hiddenserviceDir is None: print "[+] HiddenServiceDir not specified... Generating a temporal file." hiddenserviceDir = createTemporal() if os.path.exists(hiddenserviceDir) == False: print "[+] The HiddenServiceDir specified does not exists... Generating a temporal file." hiddenserviceDir = createTemporal() config = txtorcon.TorConfig() config.SOCKSPort = 9051 config.ORPort = 4443 config.HiddenServices = [txtorcon.HiddenService(config,hiddenserviceDir, ["%s %s:%s" %(str(hiddenservicePort),serviceInterface, str(servicePort))] )] config.save() return config def updates(prog, tag, summary): print "%d%%: %s" % (prog, summary) def setup_complete(config, proto): print "TOR Instance started!" def setup_failed(arg): print "SETUP FAILED", arg reactor.stop() def startTor(config): d = txtorcon.launch_tor(config, reactor,progress_updates=updates) d.addCallback(functools.partial(setup_complete, config)) d.addErrback(setup_failed) reactor.run() torrc = configuration('/home/adastra/Escritorio/hidden_service_django','127.0.0.1') startTor(torrc)
En esta nueva versión del script se ha incorporado la función “startTor”, la cual se encarga de utilizar la configuración retornada por la función “configuration” para iniciar TOR. Como se puede apreciar, dicha función emplea la utilidad “txtorcon.launch_tor” enviando como argumentos, la configuración de TOR, el reactor de Twisted y una función de callback para procesar cada uno de los eventos producidos durante proceso de inicio. Finalmente, se adicionan dos funciones más en el caso de que el proceso de arranque haya ido bien o en el caso de fallo.
Después de ejecutar el script anterior, se podrá ver por consola algo muy similar a lo que se enseña en la siguiente imagen.
El script puede parecer complejo pero tal como se ha explicado anteriormente, si se conoce el funcionamiento de Twisted y las funcionalidades básicas de TxTorCon, no resulta tan complicado de comprender.
Hasta este punto se asume que en la máquina local se encuentra un servicio levantado y esperando conexiones, más concretamente en el puerto “8080”. Evidentemente, dado el escenario anterior es necesario levantar un servidor web con Tomcat, una aplicación con Django o cualquier otro servicio en dicho puerto, pero dadas las características de Twisted, también es posible crear un servidor web simple directamente desde el script y de esta forma, se contará con una herramienta completamente funcional que puede levantar un servicio oculto sin depender de ningún programa externo (excepto el propio ejecutable de TOR).
import txtorcon import functools import tempfile import os from twisted.web import static, resource, server from twisted.internet import reactor from twisted.internet.endpoints import TCP4ServerEndpoint def createTemporal(): tempDir = tempfile.mkdtemp(prefix='torhiddenservice') reactor.addSystemEventTrigger('before', 'shutdown', functools.partial(txtorcon.util.delete_file_or_tree, tempDir)) return tempDir def configuration(hiddenserviceDir, serviceInterface, servicePort=8080, hiddenservicePort=80): if hiddenserviceDir is None: print "[+] HiddenServiceDir not specified... Generating a temporal file." hiddenserviceDir = createTemporal() if os.path.exists(hiddenserviceDir) == False: print "[+] The HiddenServiceDir specified does not exists... Generating a temporal file." hiddenserviceDir = createTemporal() config = txtorcon.TorConfig() config.SOCKSPort = 9051 config.ORPort = 4443 config.HiddenServices = [txtorcon.HiddenService(config,hiddenserviceDir, ["%s %s:%s" %(str(hiddenservicePort),serviceInterface, str(servicePort))] )] config.save() return config def updates(prog, tag, summary): print "%d%%: %s" % (prog, summary) def setup_complete(config, proto): print "TOR Instance started!" def setup_failed(arg): print "SETUP FAILED", arg reactor.stop() def startTor(config): #Starting a simple web site. root = static.File('/opt/WebSite') site = server.Site(root) hs_endpoint = TCP4ServerEndpoint(reactor, 8080,interface='127.0.0.1') hs_endpoint.listen(site) d = txtorcon.launch_tor(config, reactor,progress_updates=updates) d.addCallback(functools.partial(setup_complete, config)) d.addErrback(setup_failed) reactor.run() torrc =configuration('/home/adastra/Escritorio/django-hiddenservice','127.0.0.1') startTor(torrc)
El programa anterior solamente añade los elementos necesarios para declarar un servidor web cuyo directorio raíz es “/opt/WebSite”. Dicho servidor web se levantará en el puerto 8080 en la interfaz de red local, tal como se ha definido en la configuración del servicio oculto. Con todo esto, después de que la instancia de TOR se levante y se creen los ficheros correspondientes al dominio “onion” y a las claves del servicio, cualquier cliente que intente ingresar por dicha la dirección onion del servicio oculto, podrá ver los contenidos del servidor web que se ha iniciado utilizando Twisted. La siguiente imagen enseña algo muy similar a lo que el usuario final verá en su navegador.
Como se puede apreciar, al acceder a la dirección onion del servicio oculto, se pueden visualizar los contenidos del directorio “/opt/WebSite”, que es el directorio que se ha indicado como raíz del servidor web.
Aunque aquí se ha enseñado como crear un servicio web en la red de TOR, también es posible crear cualquier otro tipo de servicio siguiendo exactamente la misma dinámica que se ha explicado aquí, como por ejemplo por un servidor SSH/SFTP con Paramiko, un servidor FTP o incluso un servidor SMB. Tienes a tu disposición muchas alternativas a la hora de automatizar la creación de servicios ocultos en la web profunda de TOR.
Un Saludo y Happy Hack!