OSINT + Python = hacking a medida

El pasado 10 y 11 de mayo se celebró el curso de Perito Informático Forense en Reus (España) por la Asociación Nacional de Tasadores y Peritos Judiciales Informáticos (ANTPJI), de la que soy miembro y profesor en los cursos, donde tuve el placer de dar una charla sobre dos de mis pasiones como son Python y OSINT (Open Source Intelligence).

Python es un estupendo lenguaje para desarrollar rápidamente todo tipo de aplicaciones potentes y con multitud de librerías para realizar exploits, ingeniería inversa, herramientas web y más. Sin duda un conocimiento útil para cualquier experto en seguridad.

Internet es inmenso y abarca toda información inimaginable, por ello las técnicas OSINT son de vital importancia para recolectar, analizar y presentar esta información.

Para este curso decidí que sería interesante para los asistentes aprender a desarrollar simples herramientas (scripts) que les permitan realizar OSINT mediante Python con una serie de ejercicios prácticos con un objetivo concreto cada uno.

La presentación y el código están disponibles en la web de VULNEX.

Nota: he quitado la query de Google Hacking de los scripts para que el lector pueda meter su propia query.

Herramienta #1

Objetivo: buscar miembros ANTPJI en LinkedIn mediante Google Custom Search API

Estos scripts son muy sencillos y hacen lo mismo pero de forma diferente. El primero utiliza el Google API Client, mientras que el segundo utiliza la fantástica librería Requests.

En este script estamos utilizando un poco de Google Hacking para buscar miembros de la asociación en LinkedIn.


# File: ex1_a.py
# Date: 05/14/13
# Author: Simon Roses Femerling
# Desc: Basic Google Hacking 
#
# VULNEX (C) 2013
# www.vulnex.com

import const
from apiclient.discovery import build
import pprint

# your google hacking query
query=''
query_params=''

doquery=query+query_params

service = build("customsearch","v1",developerKey=const.cse_token)

res = service.cse().list(
	q=doquery,
	cx=const.cse_id,
	num=10).execute()

pprint.pprint(res)

# VULNEX EOF

# File: ex1_b.py        
# Date: 05/14/13
# Author: Simon Roses Femerling
# Desc: Simple Google Hacking                
#
# VULNEX (C) 2013
# www.vulnex.com

import requests
import json
import urllib
import const

site="https://www.googleapis.com/customsearch/v1?key="

# Your Google Hacking query
query='' 
query_params='' 

url=site+const.cse_token+"&cx="+const.cse_id+"&q=" + urllib.quote(query+query_params)
response = requests.get(url)
print json.dumps(response.json,indent=4)

# VULNEX EOF

Al ejecutar cualquiera de estos scripts obtenemos el siguiente resultado:

py_osint_img1

No demasiado interesante por el momento :)

Herramienta #2

Objetivo: obtener las fotos de los miembros ANTPJI en LinkedIn mediante Google Custom Search API.

El siguiente script obtiene las fotos de los miembros de la asociación en LinkedIn y de paso sacamos los metadatos ;) El script genera una página HTML con todas las fotos.

Librerías utilizadas: Google API Client, PIL, Requests y Markup.


# File: ex2.py         
# Date: 05/14/13
# Author: Simon Roses Femerling
# Desc: Download picture and extract metadata               
#
# VULNEX (C) 2013
# www.vulnex.com

import const
from apiclient.discovery import build
import pprint
import os
from PIL import Image
from StringIO import StringIO
from PIL.ExifTags import TAGS
import requests
import markup

def do_query(istart=0):
	if istart == 0:
		res = service.cse().list(
		q=doquery,
		cx=const.cse_id,
		num=10).execute()
	else:
		res = service.cse().list(
		q=doquery,
		cx=const.cse_id,
		num=10,
		start=istart).execute()
	return res

pic_id=1
do_stop=10
cnt=1

page=markup.page()

# Set page title
page.init(title="ANTPJI OSINT") 
page.h1("ANTPJI OSINT")

# Set output directory
out_dir = "pics_gepl"

# Your Google Hacking query 
query=''
query_params=''

doquery=query+query_params

service = build("customsearch","v1",developerKey=const.cse_token)

if not os.path.exists(out_dir):
	os.makedirs(out_dir)

res=[]
while True:
	if cnt==1:
		res = do_query()
	else:
		if not res['queries'].has_key("nextPage"): break
		res = do_query(res['queries']['nextPage'][0]['startIndex'])
	cnt+=1
	if cnt > do_stop: break
	if res.has_key("items"):
		for item in res['items']:
			name=""
			if not item.has_key('pagemap'): continue
			if not item['pagemap'].has_key('hcard'): continue
			hcard = item['pagemap']['hcard']
			for card in hcard:
				pic_url=""
				if 'title' in card:
					if 'fn' in card: name = card['fn']
					if 'photo' in card: pic_url = card['photo']
				if pic_url != "":	
					image = requests.get(pic_url)
					pic_n = os.path.join(out_dir,"%s.jpg") % pic_id
					file = open(pic_n,"w")
					pic_id+=1
					try:
						i = Image.open(StringIO(image.content))
						if hasattr(i,"_getexif"):
							ret = {}
							info = i._getexif()
							if info:
								for k,v in info.items():
									decode = TAGS.get(k,v)
									ret[decode] = v
								print ret
						i.save(file,"JPEG")
						page.p(name.encode('ascii','ignore')) 
						page.img(src=pic_n)
						page.br()
						page.br()
					except IOError, e:
						print "error: %s" % e
					file.close()			

# Set your output filename
with open('index_gepl.html','w') as fp:
	fp.write(str(page))

# VULNEX EOF

Y este es el resultado:

py_osint_img2

Con unas pocas líneas de código hemos conseguido una herramienta bastante interesante.

Herramienta #3

Objetivo: ¿cuál es la relación de los miembros de ANTPJI en LinkedIn?

Con este script buscamos la relación entre los miembros de la asociación en LinkedIn y creamos un gráfico que relaciona las palabras.

Librerías utilizadas: Google API Client, NetworkX y Matplotlib.


# File: ex3.py         
# Date: 05/14/13
# Author: Simon Roses Femerling
# Desc: Build graph from profiles                
#
# VULNEX (C) 2013
# www.vulnex.com

import const
from apiclient.discovery import build
import networkx as nx
import matplotlib.pyplot as plt

def do_query(istart=0):
	if istart == 0:
		res = service.cse().list(
		q=doquery,
		cx=const.cse_id,
		num=10).execute()
	else:
		res = service.cse().list(
		q=doquery,
		cx=const.cse_id,
		num=10,
		start=istart).execute()
	return res

do_stop=10
cnt=1

# Your Google Hacking query here
query=''
query_params=''

doquery=query+query_params

service = build("customsearch","v1",developerKey=const.cse_token)

G=nx.DiGraph()
res=[]
while True:
	if cnt==1:
		res = do_query()
	else:
		if not res['queries'].has_key("nextPage"): break
		res = do_query(res['queries']['nextPage'][0]['startIndex'])
	cnt+=1
	if cnt > do_stop: break
	if res.has_key("items"):
		for item in res['items']:
			name=""
			if not item.has_key('pagemap'): continue
			if not item['pagemap'].has_key('hcard'): continue
			hcard = item['pagemap']['hcard']
			for card in hcard:
				if 'title' in card:
					if 'fn' in card: name = card['fn']
				G.add_edge(name,card["fn"])		
			
plt.figure(figsize=(30,30))
nx.draw(G)
# Set your output filename
plt.savefig('antpji_rela_map.png')

# VULNEX EOF

Y este es el gráfico que se genera:

py_osint_img3

Herramienta #4

Objetivo: ¿de qué se habla en el Twitter de la asociación?

Este script baja los últimos tweets de la cuenta de la asociación y genera una nube de palabras. Útil para ver rápidamente de qué se habla.

Librerías utilizadas: Requests, pytagcloud.


# File: ex4.py         
# Date: 05/14/13
# Author: Simon Roses Femerling
# Desc: Create word cloud               
#
# VULNEX (C) 2013
# www.vulnex.com

import requests
import json
import urllib
import const

from pytagcloud import create_tag_image, make_tags
from pytagcloud.lang.counter import get_tag_counts

site="http://search.twitter.com/search.json?q="

# Your query here
query=""

url=site+urllib.quote(query)

response = requests.get(url)

tag = []
for res in response.json["results"]:
	tag.append(res["text"].encode('ascii','ignore'))

text = "%s" % "".join(tag)	
tags = make_tags(get_tag_counts(text),maxsize=100)
# Set your output filename
create_tag_image(tags,"antpji_word_cloud.png", size=(600,500), fontname="Lobster")

# VULNEX EOF

Y esta es la nube de palabras:

py_osint_img4

Herramienta #5

Objetivo: ¿dónde tienen cuenta los alias que participan en el Twitter de ANTPJI?

El siguiente script extrae los alias que han publicado o mencionado en el Twitter de la asociación y se comprueba si existe ese alias en 160 redes sociales.

Librerías utilizadas: Requests.


# File: ex5.py         
# Date: 05/14/13
# Author: Simon Roses Femerling
# Desc: Check usernames on 160 social network sites               
#
# VULNEX (C) 2013
# www.vulnex.com

import requests
import json
import urllib
import const
import pprint

site="http://search.twitter.com/search.json?q="

# Your query here
query=""

url=site+urllib.quote(query)

print "Recolectando alias en Twitter: %s\n" % query
response = requests.get(url)

users = []

for res in response.json["results"]:
	if res.has_key('to_user'):
		if not res['to_user'] in users: users.append(str(res["to_user"]))
	if res.has_key('from_user'):
		if not res['from_user'] in users: users.append(str(res["from_user"]))

print "ALIAS-> %s" % users

print "\nComprobrando alias en 160 websites\n"
for username in users:	
	for service in const.services:  
      		try:    
			res1 = requests.get('http://checkusernames.com/usercheckv2.php?target=' + service + '&username=' + username, headers={'X-Requested-With': 'XMLHttpRequest'}).text
			if 'notavailable' in res1: 
				print ""
				print username + " -> " + service 
				print "" 
      		except Exception as e:  
           		print e 

# VULNEX EOF

Y el resultado es el siguiente:

py_osint_img5

Herramienta #6

Objetivo: ¿se pueden obtener los metadatos en las fotos de ANTPJI?

Este script baja las fotos relacionadas con la asociación en Google y extrae los metadatos.

Librerías utilizadas: Requests, PIL y Markup.


# File: ex6.py         
# Date: 05/14/13
# Author: Simon Roses Femerling
# Desc: Download pictures from Google and extract metadata               
#
# VULNEX (C) 2013
# www.vulnex.com

import const
from apiclient.discovery import build
import pprint
import os
from PIL import Image
from StringIO import StringIO
from PIL.ExifTags import TAGS
import requests
import markup

def do_query(istart=0):
	if istart == 0:
		res = service.cse().list(
		q=doquery,
		cx=const.cse_id,
		num=10).execute()
	else:
		res = service.cse().list(
		q=doquery,
		cx=const.cse_id,
		num=10,
		start=istart).execute()
	return res

pic_id=1
do_stop=10
cnt=1

page=markup.page()
# Set your page title
page.init(title="ANTPJI OSINT") 
page.h1("ANTPJI OSINT")

# Set output directory
out_dir = "pics_gepl"

# Define your Google hacking query here
query=''
query_params=''

doquery=query+query_params

service = build("customsearch","v1",developerKey=const.cse_token)

if not os.path.exists(out_dir):
	os.makedirs(out_dir)

res=[]
while True:
	if cnt==1:
		res = do_query()
	else:
		if not res['queries'].has_key("nextPage"): break
		res = do_query(res['queries']['nextPage'][0]['startIndex'])
	cnt+=1
	if cnt > do_stop: break
	if res.has_key("items"):
		for item in res['items']:
			name=""
			if not item.has_key('pagemap'): continue
			if not item['pagemap'].has_key('hcard'): continue
			hcard = item['pagemap']['hcard']
			for card in hcard:
				pic_url=""
				if 'title' in card:
					if 'fn' in card: name = card['fn']
					if 'photo' in card: pic_url = card['photo']
				if pic_url != "":	
					image = requests.get(pic_url)
					pic_n = os.path.join(out_dir,"%s.jpg") % pic_id
					file = open(pic_n,"w")
					pic_id+=1
					try:
						i = Image.open(StringIO(image.content))
						if hasattr(i,"_getexif"):
							ret = {}
							info = i._getexif()
							if info:
								for k,v in info.items():
									decode = TAGS.get(k,v)
									ret[decode] = v
								print ret
						i.save(file,"JPEG")
						page.p(name.encode('ascii','ignore')) 
						page.img(src=pic_n)
						page.br()
						page.br()
					except IOError, e:
						print "error: %s" % e
					file.close()			

# Set your output filename
with open('index_gepl.html','w') as fp:
	fp.write(str(page))

# VULNEX EOF

Una imagen vale más que mil palabras!

py_osint_img6

Como hemos visto a lo largo de este artículo podemos escribir sofisticadas herramientas de OSINT de forma sencilla con un poco de Python que nos
permiten recabar mucha información sobre individuos o colectivos.

Si te gustaría que profundizara sobre algún tema en Python y OSINT por favor házmelo saber :)

¿Y tú qué herramientas utilizas para OSINT?

– Simon Roses Femerling

Referencias

Leave a Reply

  

  

  

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>