Shodan y su API de Python

Shodan es un motor de búsqueda que permite buscar computadoras y otros dispositivos conectados a Internet por el software utilizado en los servicios que estos publican en ciertos puertos estándar (por defecto, Shodan muestra información de los puertos 21, 22, 25, 80, 110 y 143, y con un «addon» se puede obtener información de los puertos 23 y 443). Así pues si deseamos encontrar servidores que ejecuten «Apache» en la red, Shodan es nuestro buscador.

Shodan recoge y almacena los «banners» de los servicios que los dispositivos publican hacia Internet.

Al contrario que los buscadores de páginas web como Google o Bing que son totalmente gratuitos y no ponen limitaciones en sus búsquedas, Shodan no es así.

Cuando se realiza un búsqueda en shodan, este muestra en la esquina superior derecha de la pantalla el número total de resultados que contiene en su base de datos, pero en pantalla solo muestra 10 resultados. En el momento en que un usuario intenta acceder a la siguiente página de resultados, shodan indica que necesita registrarse para obtener acceso a un mayor número de resultados.

Además tampoco permite la utilización de filtros o modificadores avanzados para las búsquedas si no se está registrado.

El registro es gratuito, y puede utilizarse la cuenta de Twitter, Gmail u otras para registrarse, o se puede rellenar un formulario de registro. Una vez registrado, un usuario obtendrá acceso a más información, pero aún así esta estará limitada.

Un usuario registrado puede acceder hasta 100 resultados de una búsqueda, y puede utilizar los filtros de búsqueda para afinar mejor y obtener resultados de calidad.

Por ejemplo, supongamos que deseamos encontrar cámaras ip que nos ofrezcan acceso vía web y que estén situadas en España. Si buscamos «camera», shodan indica que tiene 598298 resultados. Si añadimos «port:80» a la búsqueda los resultados bajan a 489730. Además, si añadimos «country:es» para buscar las que están en España, los resultados se reducen a 11230. Ahora supongamos que buscamos cámaras situadas en Valencia, pues tan solo hay que añadir «city:Valencia» a la búsqueda y los resultados se quedan en 299, de los cuales podemos acceder a 100.

Como usuario registrado también obtenemos acceso a la API, la cual podemos utilizar para realizar búsquedas desde nuestros programas. Existe API para Python, Ruby y Perl. El acceso a la API todavía está más restringido, ya que tan solo nos deja obtener 100 resultados al igual que la web, pero no nos permite utilizar modificadores en la búsqueda como «country», «city», «organization», etc. (el filtro «port» si que está permitido en este caso).

Si se desea obtener más resultados y más potencia de las búsquedas, hay que pasar por caja. Han inventado un sistema de créditos, donde cada crédito vale $5, los cuales pueden utilizarse para desbloquear las distintas restricciones (acceder a más resultados (hasta 10000 resultados por búsqueda), acceder a la API completa y realizar búsquedas sobre servicios HTTPS y Telnet (por defecto https y telnet no están en la lista de servicios).

En estos momentos, tienen una promoción de aniversario donde te dan todo lo anterior más 5 créditos para gastar exportando datos o en futuras extensiones todo por $19 (realmente vale la pena si va a utilizarse, sobre todo desde la API).

API de Python.

Vamos a ver como utilizar la API de Python para Shodan, con la que podremos realizar búsquedas fácilmente desde nuestros scripts.

En primer lugar debemos instalar las librerías Shodan para python. Esto es tan fácil como:

[code]easy_install shodan[/code]

En caso de tener «easy_install» disponible deberemos instalar las «python-setuptools». En Kali o Debian simplente:

[code]sudo apt-get update
sudo apt-get install python-setuptools[/code]

Una vez instaladas las librerías de shodan, importamos «WebAPI» a nuestro script y lo llamamos pasándole domo parámetro la API Key que Shodan nos proporciona. Después utilizamos el método «search» para realizar las búsquedas.

[code lang=»python»]
from shodan import WebAPI
SHODAN_API_KEY = "insert your shodan AOI key here"
api=WebAPI(SHODAN_API_KEY)
try:
res = api.search("terminos de búsqueda")
print "Resultados encontrados: %d" % res[‘total’]
except Exception, e:
print "Error: %s" % e
[/code]

El método «search» devolverá en un diccionario los resultados encontrados en la base de datos con la estructura del siguiente ejemplo:

[code]
{
‘total’: 8669969,
‘countries’: [
{
‘code’: ‘US’,
‘count’: 4165703,
‘name’: ‘United States’
},
{‘code’: ‘DE’, ‘count’: 610270, ‘name’: ‘Germany’},
{‘code’: ‘JP’, ‘count’: 496556, ‘name’: ‘Japan’},
{‘code’: ‘RO’, ‘count’: 486107, ‘name’: ‘Romania’},
{‘code’: ‘GB’, ‘count’: 273948, ‘name’: ‘United Kingdom’}
],
‘matches’: [
{
‘country’: ‘DE’,
‘data’: ‘HTTP/1.0 200 OK\r\nDate: Mon, 08 Nov 2010 05:09:59 GMT\r\nSer…’,
‘hostnames’: [‘pl4t1n.de’],
‘ip’: ‘89.110.147.239’,
‘os’: ‘FreeBSD 4.4’,
‘port’: 80,
‘updated’: ‘08.11.2010’
},

]
}
[/code]

En la sección «matches» se encuentran cada uno de los resultados de la búsqueda realizada.

Aunque en la sección «total» Shodan devuelve el número total de resultados encontrados, en «matches» tan solo habrá 100 resultados.

Modificamos un poco nuestro «script» para poder utilizarlo desde la línea de comandos quedando de la siguiente forma.

[code lang=»python»]
import sys
from shodan import WebAPI
SHODAN_API_KEY = ‘pon aquí tu api key’
api=WebAPI(SHODAN_API_KEY)

if __name__ == ‘__main__’:
try:
res = api.search(sys.argv[1])
print "Resultados encontrados: %d" % res[‘total’]
except Exception, e:
print "Error: %s" % e
[/code]

Al método «search», se le pasa como parámetro los términos de búsqueda, donde podemos utilizar los mismos modificadores que en la página web (siempre que tengamos el API completa, o sea si pasamos por caja). En caso de utilizar el API gratuita, hay ciertos operadores que no podemos utilizar como (country, city, after, before).

A continuación vemos lo que pasa si utilizamos el operador «country» con el API gratuita:

search_shodan1

Si por el contrario utilizamos una clave de API «completa», podemos utilizar todos los operadores disponibles sin ninguna restricción, pero cuando examinemos los resultados, observaremos que seguimos obteniendo solo 100 resultados.

Para probar esto, añadimos a nuestro script una linea que nos muestre por pantalla el tamaño de la sección «matches» del diccionario de resultados.

[code lang=»python»]
import sys
from shodan import WebAPI
SHODAN_API_KEY = ‘pon aquí tu api key’
api=WebAPI(SHODAN_API_KEY)

if __name__ == ‘__main__’:
try:
res = api.search(sys.argv[1])
print "Resultados encontrados: %d" % res[‘total’]
print "Resultados devueltos: %d" % len(res[‘matches’])
except Exception, e:
print "Error: %s" % e
[/code]

A continuación vemos el resultado de la búsqueda anterior pero con un API completo.

search_shodan2

Como podemos observar, los resultados devueltos son 100. Entonces, ¿Como logramos ver el resto de resultados?

La API completa, según he leído en la documentación de Shodan, permite obtener resultados ilimitados, pero consultando la ayuda y los tutoriales oficiales de la API de Python, no he podido encontrar como acceder a ellos.

Buscando por Internet a cerca de este problema y consultando el código fuente de la API, he sabido que el método «search», además del parámetro «query», acepta varios parámetros más opcionales, que son «page», «limit» y «offset». Estos tres parámetros sirven para indicarle a la API que página de resultados queremos, e límite de resultados por página (debe ser múltiplo de 100) y el desplazamiento desde el que empezar a mostrar los resultados.

Así pues, modificando la línea en la que llamamos a «search» por la siguiente podemos obtener 200 resultados.

[code lang=»python»]
res = api.search(sys.argv[1],page=1,limit=200,offset=None)
[/code]

search_shodan3
De nuevo, esto solo sirve para el API completo, si lo intentamos con una clave de API gratuita, obtendremos el siguiente resultado.

search_shodan4

Así pues, una buena modificación para nuestro «script» de búsqueda con shodan podría ser utilizar el módulo «getopt» de Python para pasar parámetros por línea de comando y así poder pasarle al «script» el valor deseado para «page», «limit» y «offset», aunque esto ya lo dejo en manos del lector.

Espero que os haya gustado leer el post tanto como a mi me ha gustado escribirlo. Un saludo a todos y gracias por llegar hasta aquí.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

*