Python para el Pentest. OSINT: Twitter (3): Streaming, ríos de datos, y para merendar Tweets.

Repasemos lo visto hasta ahora. En la primera entrada de la serie vimos algunos conceptos básicos para comenzar a trabajar con Python desde el pentesting, que vamos a necesitar durante todo el camino. Tras la introducción, nuestro primer caso práctico ha sido la aplicación de Python para OSINT (“Open Source Intelligence”), en concreto Twitter. Hasta ahora hemos visto (1) los preliminares y (2) hemos desarrollado un pequeño PoC accediendo a la API RESTFull, que como vimos permitía una gran variedad de opciones pero no era lo mejor para obtener información en tiempo real.

Por eso, en esta entrada veremos la utilización de la API de streaming, un poco mas complejo que usar que REST, pero que con un sencillo ejemplo nos quedará claro como utilizar. Como en anteriores entradas, si les queda alguna duda, pueden dejárnosla en los comentarios y la atenderemos encantados.

Si volvemos a la función OAuth() recordaremos que nos devolvía una tupla, y esta la asignamos a dos variables, api y auth, para el siguiente ejemplo utilizaremos la segunda.

Lo primero que deberemos hacer es crear una clase heredada de tweepy.StreamListener. Esta será, como bien indica la superclase, la que escuche el flujo de tweets.

class StreamListener(tweepy.StreamListener):
	'''Cuando un Tweet haga match con nuestros targetTerms será pasado a esta función'''
	def on_data(self, data):
		# Asignamos el JSON de los datos a la variable data
		data = json.loads(data)
		# Intentamos ejecutar el código
		try:
		# Si los datos no contienen coordenadas no nos interesan
		if data['geo'] is not None:
			'''recuperamos los elementos que nos interesan de data y los imprimimos por pantalla'''
			print('[>] {0}(@{1}), {2} -- LAT/LON: {3}'.format(
				data['user']['name'].encode('unicode', 'ignore'),
				data['user']['screen_name'].encode('unicode', 'ignore'),
				data['geo']['coordinates']
				)
			)
		return True
		
		# En caso un error lo imprimimos
		# https://dev.twitter.com/overview/api/response-codes
		except Exception, e:		
			print('[!] Error: {0}'.format(e))
	
	# Si alcanzamos el limite de llamadas, alerta y espera 10"
	def on_limit(self, track):
		print('[!] Limit: {0}').format(track)
		sleep(10)

	# En caso de producirse un error interrumpe el listener
	def on_error(self, status):
		print('[!] Error: {0}').format(status)
		return False

Los comentarios en el código ya lo explican todo, salvo el porqué de la elección de esos datos del tweet y no otros. Si nos fijamos, vemos que solo imprimimos tweets que contengan en ellos la geolocalización del usuario, y como para nuestro PoC no nos interesa lo que digan —salvo los keywords de los que estamos haciendo el tracking, y de eso ya se encarga nuestro listener— solo imprimimos el screen_name, el name y las coordinates.

Para indicarle al listener cuales serán nuestros keywords y poder usarlo, añadiremos la siguiente función a nuestro proyecto.

def streamAPI(auth):
	# Instanciamos nuestro listener
	l = StreamListener()
	# Iniciamos el streamer con el objeto OAuth y el listener
	streamer = tweepy.Stream(auth=auth, listener=l)
	# Definimos los términos de los que queremos hacer un tracking
	targetTerms = ['hola']
	# Iniciamos el streamer, pasándole nuestros trackTerms
	streamer.filter(track=targetTerms)

Y la llamaremos pasándole nuestro objeto auth de nuestra tupla OAuth de la siguiente forma.

try:
	streamAPI(auth)
	except KeyboardInterrupt, e:
	exit(1)

Si nos fijamos hemos añadido un bloque Try: except: que se disparará si interrumpimos la ejecución mediante el teclado – ctrl + c –. Esto es opcional, pero para evitar que el script se queje cuando lo finalicemos es recomendable, ya que si no hay errores deberemos finalizar la ejecución
nosotros mismos. Aquí tenemos parte de la salida que obtenemos en unos pocos minutos:

¿A alguno de los lectores se le ocurre que se podría hacer con unos términos de búsqueda apropiados?

Una vez que ya sabemos interactuar con la potente API de Twitter, en entradas siguientes pasaremos a obtener algo de información útil y a analizarla. Sí, también habrá gráficos, esos que tanto gustan a los jefes, pero esto será ya en el próximo post.

¡Un saludo!

El código completo se puede clonar del siguiente repositorio de GIT Hub. ¡Cualquier comentario y mejora es bienvenida!

Comments

  1. Muy interesante. Seguro que en la PyConEs de este fin de semana tus posts relacionados con python son muy comentados. :-)

  2. Muchas gracias, me alegra que te parezca interesante, pero son temas muy básicos, en la PyConEs tendrán mejores cosas que comentar. ;)

    Happy Coding!

  3. Muy interesante y muy inspirador para aplicarlo a un proyecto en el que estoy trabajando :)