Archivo

Posts Tagged ‘seguridad python’

Monitorizar conexiones y desconexiones contra un servidor OpenVPN con Python.

agosto 10, 2019 Deja un comentario

Hola a todos. He vuelto. 🙂

Las próximas semanas tendré algo de tiempo libre y he decidido dedicarlo a este espacio, escribiré algunos artículos sobre seguridad que tengo pendientes desde hace mucho tiempo y que ahora, me dispongo a compartir con todos vosotros. Vamos a por uno sencillo primero!

Una de las características más interesantes que tiene OpenVPN es precisamente la posibilidad de ejecutar scripts ante determinados eventos, por ejemplo, es posible indicar en el fichero de configuración que se ejecute un programa determinado cuando un usuario se conecta o desconecta. Dicho programa puede ser un script escrito en Python, por ejemplo, que se encargará de recopilar la información de la conexión que ha establecido el cliente. Esto puede tener varios usos, entre los que se incluyen la monitorización de las conexiones de los usuarios, forzar a que los clientes se conecten únicamente desde ubicaciones concretas, limitar el número de conexiones con el mismo certificado o OVPN, etc. En resumen, permite un buen nivel de control sobre los usuarios y las conexiones realizadas contra el servidor. Ahora, esto cómo se hace?

Configuración de OpenVPN con “script-security”

La directiva de configuración “script-security” es precisamente la que permite la ejecución de scripts y otros programas externos desde el proceso en ejecución de OpenVPN. Sin embargo, está opción no está exenta de riesgos y problemas de seguridad potenciales, tal como se puede leer en la documentación oficial de OpenVPN:

–script-security level [method]

This directive offers policy-level control over OpenVPN’s usage of external programs and scripts. Lower level values are more restrictive, higher values are more permissive. Settings for level:0 — Strictly no calling of external programs.
1 — (Default) Only call built-in executables such as ifconfig, ip, route, or netsh.
2 — Allow calling of built-in executables and user-defined scripts.
3 —Allow passwords to be passed to scripts via environmental variables (potentially unsafe).The method parameter indicates how OpenVPN should call external commands and scripts. Settings for method:

execve — (default) Use execve() function on Unix family OSes and CreateProcess() on Windows.
system —Use system() function (deprecated and less safe since the external program command line is subject to shell expansion).

The –script-security option was introduced in OpenVPN 2.1_rc9. For configuration file compatibility with previous OpenVPN versions, use: –script-security 3 system”

Evidentemente, si se utiliza ésta opción en el fichero de configuración o como argumento a la hora de levantar el servicio hay que tener en cuenta, como mínimo lo siguiente:

1. Si se establece el método “2”, sería recomendable eliminar los permisos de lectura y escritura en los scripts que se ejecutarán por medio de OpenVPN, ya que si un atacante consigue acceso local y dichos scripts permiten su edición por parte de usuarios con permisos bajos, existe la posibilidad de que elevar privilegios en el sistema.

2. Evitar usar el método “3” ya que se pueden producir fugas de información sensible a la hora de establecer credenciales en variables de entorno.

Es una opción de configuración con la que hay que tener cuidado, sin embargo cuando se siguen los criterios anteriores es posible utilizarla sin riesgo. Esta opción únicamente le indica a OpenVPN que desde el proceso se podrán lanzar scripts o comandos externos, sin embargo con esto no es suficiente para indicar cuáles serán dichos scripts y cómo se deben ejecutar. Para ello existen otras opciones de configuración en las que se especifican precisamente estos detalles, tales como “up”, “client-connect” o “client-disconnect”. Dichas opciones se pueden incluir en el fichero de configuración utilizado para levantar el proceso de OpenVPN, por ejemplo:

script-security 2
client-connect "/usr/bin/python /home/adastra/connection.py"
client-disconnect "/usr/bin/python /home/adastra/disconnection.py"

Tal como el nombre de la opción indica, estos scripts se van a ejecutar en el momento en el que un cliente se conecte o desconecte, lo que nos permite hacer cosas simples pero interesantes, como por ejemplo registrar en una base de datos los detalles relacionados con las conexiones de los usuarios (fecha, ubicación, duración de la conexión, etc.). Se trata de información que se almacena en el momento en el que el evento ocurre en forma de variables de entorno, por lo tanto, lo que se debe de hacer en estos scripts es simplemente leer el valor de dichas variables de entorno antes de que dejen de estar disponibles. El siguiente script en Python nos permite hacer precisamente esto, con muy pocas líneas y prácticamente ningún esfuerzo.

connection.py:

import posix,time;
with open('/tmp/conn.out','w') as fd:
    fd.write(posix.environ['trusted_ip'])
    fd.write(posix.environ['common_name'])

Con esto simplemente se escriben los valores de las variales “trusted_ip” y “common_name” en un fichero de texto en el directorio “/tmp”. Evidentemente existen otras variables de entorno que se pueden consultar, como por ejemplo la IP dentro de la VPN que se le ha asignado al cliente (ifconfig_pool_remote_ip).

No obstante, lo más normal es que esta información se almacene en una base de datos, para demostrar esto, el siguiente script se encargará del registro de las conexiones en una base de datos PostgreSQL, por lo tanto será necesario utilizar una librería como “psycopg2”.

import psycopg2
import posix
common_name = posix.environ['common_name']
trusted_ip = posix.environ['trusted_ip']


class Database():
	def __init__(self, dbName="database_openvpn", dbUser="postgres", dbServer="127.0.0.1", dbPort=5432, dbPass="postgres"):
		self.connection = psycopg2.connect("dbname='%s' user='%s' host='%s' port='%s'  password='%s'" %(dbName, dbUser, dbServer, dbPort, dbPass))
		self.cursor = self.connection.cursor()

	def execute(self, createInstruction, params=None):
		self.cursor.execute(createInstruction, params)
		self.connection.commit()
		id = self.cursor.fetchone()[0]
		return id

	def create(self, createInstruction, params=None):
		self.cursor.execute(createInstruction, params)
		self.connection.commit()

	def select(self, selectInstruction, params=None):
		self.cursor.execute(selectInstruction,params)
		return self.cursor.fetchall()

	def close(self):
		self.cursor.close()
		self.connection.close()

if __name__ == "__main__":
	db = None
	try:
		db = Database()
		db.create("CREATE TABLE IF NOT EXISTS user(id serial primary key, common_name varchar NOT NULL);")	
		db.create("CREATE TABLE IF NOT EXISTS addresses(id SERIAL PRIMARY KEY, address varchar(255) NOT NULL,user_id integer REFERENCES user(id));")
		db.create("CREATE TABLE IF NOT EXISTS connections(id SERIAL PRIMARY KEY, date_connection TIMESTAMP NOT NULL, date_disconnection TIMESTAMP, address_id integer REFERENCES addresses(id));")

		from datetime import datetime
		fechaActual = datetime.now()
		timeStampActual = psycopg2.Timestamp(fechaActual.year, fechaActual.month, fechaActual.day, fechaActual.hour, fechaActual.minute, fechaActual.second)
		with open('/tmp/trazas-connect','w') as fd:
			fd.write("Conexion de cliente %s desde %s \n" %(common_name, trusted_ip))
			users = db.select("select id from user where common_name = %s", (common_name,))
			userid = 0
			if len(users) < 0:
				fd.write("\nUsuario registrado previamente en la base de datos")
				userid = users[0][0]
				fd.write("\nIdentificador de usuario: %s " %(str(userid)))

			else:
				fd.write("\nUsuario NO registrado previamente en la base de datos")
				userid = db.execute("insert into user(common_name) values(%s) RETURNING id", (common_name,))
				fd.write("\nUsuario insertado en BD con identificador: %s" %(str(userid)))
				addressid = db.execute("insert into addresses(address, user_id) values(%s, %s) RETURNING id", (trusted_ip, userid,))
				fd.write("\nDirección insertada en BD con identificador: %s" %(str(addressid)))
				connid = db.execute("insert into connections(date_connection, address_id) values(%s, %s) RETURNING id", (timeStampActual, addressid,))
				fd.write("\nConexion insertada en BD con identificador: %s" %(str(connid)))
				fd.write("\nProceso de registro finalizado correctamente.")
				fd.write("\n-----------------------------------------\n\n")

	finally:
		if db is not None:
			db.close()

Este sería el script de registro, en donde se almacenan las conexiones de los usuarios y un par de detalles básicos. En este programa se verifica si el usuario se encuentra almacenado en base de datos y si está, no se procede a almacenar nada en la base de datos. El script en realidad es bastante simple, sin embargo tiene bastantes líneas de código, las cuales como se puede apreciar, en su mayoría sirven para depurar. El motivo de esto es que a día de hoy (o mejor, hasta donde llegan mis conocimientos en OpenVPN) no hay manera de depurar los programas externos que se lanzan desde el proceso de OpenVPN y si por lo que sea, dichos programas, como por ejemplo este script, lanza una excepción no controlada, el servidor rechazará la conexión con el cliente, este es otro de los motivos por los que hay que tener mucho cuidado a la hora de utilizar esta característica. Por ejemplo, suponiendo que la base de datos “database_openvpn” no se encuentre creada o que directamente el servicio de PostgreSQL se encuentre detenido, en tales casos el script lanzará una excepción y si no se controla adecuadamente, supondrá que ningún cliente se va a poder conectar a la VPN.
Ahora bien, si la opción “client-connect” permite indicar un script que se lanzará justo en el momento en el que un usuario se conecta, la opción “client-disconnect” hace lo mismo pero al reves, cuando el cliente envia la señal de cierre de conexión. Siguiendo la lógica del script anterior, el script de desconexión se encargará de realizar una operación DELETE/UPDATE sobre cada una de las tablas relacionadas. Este sería el contenido de dicho script:

import posix
import psycopg2

common_name = posix.environ['common_name']
trusted_ip  = posix.environ['trusted_ip']

class Database():
    def __init__(self, dbName="database_openvpn", dbUser="postgres", dbServer="127.0.0.1", dbPort=5432, dbPass="postgres"):
        self.connection = psycopg2.connect("dbname='%s' user='%s' host='%s' port='%s' password='%s'" %(dbName, dbUser, dbServer, dbPort, dbPass))
        self.cursor = self.connection.cursor()
        
    def execute(self, createInstruction, params=None):
        self.cursor.execute(createInstruction, params)
        self.connection.commit()

    def select(self, selectInstruction, params=None):
        self.cursor.execute(selectInstruction,params)
        return self.cursor.fetchall()

    def close(self):
        self.cursor.close()
        self.connection.close()
    
        
if __name__ == "__main__":
	db = None
	try:
		db = Database()
		from datetime import datetime
		fechaActual = datetime.now()
		timeStampActual = psycopg2.Timestamp(fechaActual.year, fechaActual.month, fechaActual.day, fechaActual.hour, fechaActual.minute, fechaActual.second)
		with open('/tmp/trazas-disconnect','w') as fd:			
			conn = db.select("select c.id from user u, addresses a, connections c where (u.id = a.user_id and c.address_id = a.id) and u.common_name = %s and a.address = %s and c.date_disconnection IS NULL", (common_name, trusted_ip,) )
			connid = 0
			fd.write("\nProceso de desconexion iniciado para el usuario %s " %(common_name))
			if len(conn) > 0:
				connid = conn[0][0]
				fd.write("\nIdentificador de conexion a actualizar %s " %(str(connid)))
				db.execute("UPDATE connections SET date_disconnection = %s where id = %s", (timeStampActual, connid,))
			fd.write("\nProceso de desconexion del usuario %s finalizado correctamente" %(common_name))
			fd.write("\n-----------------------------------------------\n\n")
	except:
		fd.write("\nSe ha producido una excepción\n")
	finally:
		if db is not None:
			db.close()

Con esto ya se tendría un sistema para la gestión de conexiones en VPN, algo que serviría para monitorizar la actividad del servidor y las conexiones/desconexiones que realizan los usuarios.
Eres libre de utilizar estos scripts y modificarlos a tu gusto para realizar pruebas o incluso para implementarlos en tu propio servicio de OpenVPN

Un saludo y Happy Hack.

Adastra.

Hoy vengo a hablar de mi libro. Python para Pentesters.

septiembre 22, 2014 26 comentarios

A partir del día de hoy, se encuentra disponible al público mi libro sobre Pentesting con Python :-). Se trata de un documento que he escrito basándome en lo que he aprendido en los años que llevo dedicándome a la seguridad informática y al desarrollo de software. Me ha llevado varios meses escribir un documento con el me que sintiera a gusto, un documento en el que pudiera recopilar algunos de los tópicos que considero los más importantes cuando se habla de pentesting y hacking. Los contenidos del libro no son los mismos que has visto en la serie de vídeos que he desarrollado sobre “Hacking con Python”, el libro incluye temas más avanzados y completos, además se explica cómo usar librerías y herramientas que no se han mencionado en los vídeos. Lo he hecho con la idea que siempre he tenido en mente cuando de informática se trata: Cualquier profesional que se dedique a esto tiene que tener unos conocimientos mínimos en programación (que no consiste simplemente en dominar un único lenguaje), tiene que tener la capacidad suficiente para afrontar problemas de manera creativa y utilizando la inmensa cantidad de recursos que se encuentran a su disposición y creo, que es algo que las nuevas generaciones de hackers y pentesters lo suelen olvidar (o mejor, solemos olvidar porque no soy tan mayor. 🙂 ). He intentado ponerme en el lugar del lector y he enfocado el documento en aquellos temas que a cualquier persona dedicada a temas relacionados con el hacking le gustaría leer. Por otro lado, aquellos que me conocéis (y los que me soportáis :-p ) sabéis que no me siento a gusto “vendiendo humo”, hablando de cosas de las que no controlo plenamente o sobre “teorías” demasiado abstractas que en muchos casos se alejan tanto del mundo real/practico, que en raras ocasiones las vemos reflejadas en herramientas funcionales. Con todo esto, mi idea es que el lector tenga un documento en el que se mezcle la teoría y la practica con muchos ejemplos y casos prácticos.

No es precisamente un documento introductorio a técnicas de pentesting, hacking o programación en general, pero creo que es una buena guía para el “público de todas las edades”, incluso si no sabes programar, solamente necesitas ser curioso, tener ganas de aprender y dedicar algo de tiempo.

Dado que se trataba de mi primera obra y tenía muchísimas dudas sobre cómo debía editar y publicar mi libro, decidí contactar directamente con Chema Alonso para que me diese consejos sobre todos esos temas y me hablase sobre 0xWORD, que es la editorial que él lleva desde hace algunos años. Chema es una persona que se ha ganado mi respeto no solamente por su nivel técnico, sino también porque es una persona con carisma, amable y que siempre esta dispuesto a compartir sus conocimientos y colaborar en lo que pueda, eso si, no le pidas que te consiga una cuenta de Facebook o Hotmail que ahí ya no es tan amable XD. Toda mi vida he pensado que el respeto es algo que hay que ganarse, ya que tus méritos, habilidades y dedicación es lo que realmente cuenta y la gente puede ver el “brillo” de tu labor.

Por otro lado, después de valorar las otras opciones que tenia a mi disposición, he confiado mi obra a 0xWORD y creo que ha sido la decisión correcta ya que me han asesorado y apoyado durante todo el proceso, la verdad es que he quedado muy satisfecho con su trabajo y desde ya os adelanto, que hay otro libro en marcha sobre Python, pero centrado en Maleware, anonimato, Exploiting, Cyberwarfare y todo lo relacionado con la seguridad puramente ofensiva, a lo que se dedican “los chicos malos” de Internet. Seguro que os va a encantar, pero de momento no puedo decir mucho más. 🙂

La verdad es que llevaba mucho tiempo pensando en escribir un libro sobre Hacking, ese era uno de los objetivos que tenía previstos para este año y desde el mes de enero comencé a dar pinceladas y a estructurar lo que quería escribir. Todos los días estuve volcando las cosas que tenia en mi cabeza y página tras página iba dando forma al documento. Ha sido una actividad muy estimulante para mí, ya que movía de un lado al otro aquellas cosas que llevo aprendiendo desde que comencé a “jugar” con ordenadores. Mientras escribía, me venían muchos recuerdos de aquellas épocas en las me pasaba horas y horas delante del monitor y mis padres se enfadaban conmigo por ello. Épocas en las que iba a la facultad de informática de mi universidad y me sentía a gusto en las salas de ordenadores programando algo en C, jugando con alguna distro de Linux, o en la biblioteca leyendo algún libro. También recuerdo la forma en la que me miraban algunas personas y con su lenguaje corporal (o a veces directamente) me decían: “¿A dónde vas con esos pelos? ¿Qué haces? Las personas de bien llevan el cabello corto y no se visten así”, recuerdo que me importaba una soberana .…. y de hecho, me divertia mucho ver sus reacciones XD. Los ordenadores y mi conocimiento sobre ellos ha cambiado muchísimo desde aquel entonces, pero prácticamente todo lo demás sigue igual, sin importar los años ni las circunstancias. Solamente espero tener la oportunidad de poder seguir así, de poder seguir aprendiendo cosas, mejorando mis habilidades y compartiendo lo aprendido. Aun hay un largo camino por recorrer.

Si compras el libro, solamente espero que superes con creces lo que has invertido, que te sirva para ampliar tus conocimientos o simplemente recordar cosas que a lo mejor tenias olvidadas y como siempre, si tienes cualquier duda, comentario o sugerencia para una futura edición, no dudes en ponerte en contacto conmigo. Con esta entrada no intento venderte nada, simplemente voy dejar que los contenidos del documento hablen por si solos. Fíjate en el índice del libro y si después de leerlo crees que te puede aportar algo, no dudes en comprarlo, eso es justo lo que yo hago con los libros que realmente despiertan mi interés y creo que es el mejor consejo que se le puede dar a cualquier lector.

Saludos y Happy Hack!

A %d blogueros les gusta esto: