Shodan IP dump desde bash
Shodan es un motor de búsquedas que nos permite escudriñar la red como si buscáramos, por definirlo de alguna manera, en una base de datos de todo internet creada por nmap (salvando las diferencias).
Hace unos meses shodan tenía una promoción de aniversario que reducía el precio normal de la cuenta de 49$ a 19$ durante tiempo limitado, por lo que decidí que era el mejor momento para comprar ese servicio que tantas veces me había propuesto. Lo primero que hice fue pasarme horas probando dorks en la web para conocer los filtros y la forma de presentar los datos de shodan. Una vez que me sentí cómodo con el entorno y vi que me estaba gustando (enganchando, más bien) quería probar y obtener los resultados de las búsquedas en consola. En este punto instalé el ‘cliente oficial’ de shodan, escrito en python y que se puede clonar o descargar desde: https://github.com/achillean/shodan-python (más info aquí). En ese momento mi intención para usar shodan desde consola era, dada una consulta, poder recibir todas las IP’s que coincidieran con los datos de esa consulta.
Como seguía con la novedad, estuve haciendo consultas y pruebas sin parar, hasta que en un punto me saltó un ‘warning’ en la aplicación de consola que decía, a grosso modo, que había superado el límite de consultas, que esperará al mes que viene. Esto no me sentó nada bien, estaba con mi juguete nuevo, por el que había pagado y no sabía (no me había informado) que tenía un límite! No me planteé devolver el producto, me gustaba demasiado, pero tampoco quería quedarme «a medias» con la experiencia de uso y como la forma de pensar de los que nos «dedicamos» a esto, es «diferente» (los que estáis leyendo esto sabéis a que me refiero) decidí crear mi propio cliente de shodan desde consola.
Como he dicho antes, mi objetivo al utilizar shodan desde consola era conseguir un ‘dumpeo’ de IP’s dada una consulta, no quería nombres DNS ni ubicaciones ni nada de eso, solo IP’s. Lo primero que hice fue utilizar la API de shodan desde un script en bash, pero claro, la limitación seguía ahí. Tras 100 consultas, ya no obtenía más datos; no me servía. Entonces recordé que cuando empezó todo, con las ‘querys’ en la web, había hecho muchas más búsquedas que desde consola y en ningún momento se había parado el chorreo de resultados. Aquí estaba la clave, tenía que hacer consultas web, pero desde el terminal.
El primer paso era loguearse en la web desde consola, ya que sin login, muchos filtros no funcionarían, por lo que pegando un vistazo al código de la página de login (https://account.shodan.io/login) podemos ver como se envían las credenciales:
Ahora tenía en mente curl y wget para las consultas web y pese a que reconozco que curl es muchísimo más potente, me decanté por wget ya que lo conozco más y me siento cómodo trabajando con él. Lo primero será loguearnos con nuestro user/pass y guardar la cookie válida obtenida del proceso. Esto lo podemos hacer con wget de la siguiente manera:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
USER='TuUserDeShodan' PASSWORD='TuPasswordDeShodan' POST_DATA="username=$USER&password=$PASSWORD" wget -U 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/37.0.2062.120 Chrome/37.0.2062.120 Safari/537.36' \ --secure-protocol=auto \ --save-cookies /tmp/save.txt \ --keep-session-cookies \ --post-data $POST_DATA \ -q \ -O /tmp/login \ https://account.shodan.io/login |
En un primer momento este proceso me dio ciertos problemas (supongo que debido al uso del cloudflare por parte de shodan) hasta llegar al código anterior que me ha funcionado perfectamente. En la definición del User Agent se puede poner cualquiera que corresponda a un UA real, yo en aquel momento estaba usando Chromium, por lo que es el UA de Chromium. Terminado este proceso, tenemos una cookie válida almacenada en ‘/tmp/save.txt’ que podemos utilizar como auntenticación en las sucesivas consultas. Veamos como hacer una consulta con wget, utilizando la cookie guardada anteriormente:
1 2 3 4 5 6 7 8 |
QUERY='country:es+port:80+title:IIS7' PAGE='1' wget -U 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/37.0.2062.120 Chrome/37.0.2062.120 Safari/537.36' \ --load-cookies /tmp/save.txt \ -q \ -O /tmp/result_shodan_download \ https://www.shodan.io/search?query=$QUERY\&page=$PAGE |
Ahora tendremos un documento llamado ‘result_shodan_download’ en ‘/tmp’ con un contenido similar a este (fragmento):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
<div class="search-result-summary"><span>213.99.28.17</span><br/><a href="/search?query=country%3Aes+port%3A80+title%3AIIS7+org%3A%22Telefonica+de+Espana%22" class="os">Telefonica de Espana</a> <div></div><span>Added on 2015-06-02 15:40:01 GMT</span><br/><img src="https://static.shodan.io/shodan/img/flags/16/ES.png" title="Spain"/><a href="/search?query=country%3Aes+port%3A80+title%3AIIS7+country%3A%22ES%22" class="city">Spain</a> <div class="clear"></div><a href="/host/213.99.28.17" class="details">Details</a> </div> <pre>HTTP/1.1 200 OK Content-Type: text/html Last-Modified: Wed, 29 Oct 2014 15:32:14 GMT Accept-Ranges: bytes ETag: "8856f6838df3cf1:0" Server: Microsoft-IIS/7.5 X-Powered-By: ASP.NET Date: Tue, 02 Jun 2015 15:39:33 GMT Content-Length: 689 </pre> <div class="clear"></div> </div> <div class="search-result"> <div class="ip"><a href="http://84.127.224.231:80">IIS7</a> </div> <div class="search-result-summary"><span>84.127.224.231</span><br/><span>84.127.224.231.static.user.ono.com</span><br/><a href="/search?query=country%3Aes+port%3A80+title%3AIIS7+org%3A%22ONO%22" class="os">ONO</a> <div></div><span>Added on 2015-06-02 15:39:46 GMT</span><br/><img src="https://static.shodan.io/shodan/img/flags/16/ES.png" title="Spain"/><a href="/search?query=country%3Aes+port%3A80+title%3AIIS7+country%3A%22ES%22" class="city">Spain</a>, <a href="/search?query=country%3Aes+port%3A80+title%3AIIS7+city%3A%22Valencia%22" class="city">Valencia</a> <div class="clear"></div><a href="/host/84.127.224.231" class="details">Details</a> </div> <pre>HTTP/1.1 200 OK Content-Type: text/html Last-Modified: Fri, 21 Jun 2013 09:36:18 GMT Accept-Ranges: bytes ETag: "b6e4ac8626ece1:0" Server: Microsoft-IIS/7.5 Date: Tue, 02 Jun 2015 15:39:13 GMT Content-Length: 689 </pre> <div class="clear"></div> </div> <div class="search-result"> <div class="ip"><a href="http://213.0.97.242:80">IIS7</a> </div> <div class="search-result-summary"><span>213.0.97.242</span><br/><a href="/search?query=country%3Aes+port%3A80+title%3AIIS7+org%3A%22Telefonica+de+Espana%22" class="os">Telefonica de Espana</a> <div></div><span>Added on 2015-06-02 15:38:39 GMT</span><br/><img src="https://static.shodan.io/shodan/img/flags/16/ES.png" title="Spain"/><a href="/search?query=country%3Aes+port%3A80+title%3AIIS7+country%3A%22ES%22" class="city">Spain</a> <div class="clear"></div><a href="/host/213.0.97.242" class="details">Details</a> </div> <pre>HTTP/1.1 200 OK Content-Type: text/html Last-Modified: Wed, 15 Jan 2014 10:18:36 GMT Accept-Ranges: bytes ETag: "f36e27db11cf1:0" Server: Microsoft-IIS/7.0 X-Powered-By: ASP.NET Date: Tue, 02 Jun 2015 15:37:50 GMT Content-Length: 689 </pre> <div class="clear"></div> </div> <div class="search-result"> <div class="ip"><a href="http://194.140.132.7:80">IIS7</a> </div> <div class="search-result-summary"><span>194.140.132.7</span><br/><span>194.140.132.7.static.user.ono.com</span><br/><a href="/search?query=country%3Aes+port%3A80+title%3AIIS7+org%3A%22ONO%22" class="os">ONO</a> <div></div><span>Added on 2015-06-02 15:37:11 GMT</span><br/><img src="https://static.shodan.io/shodan/img/flags/16/ES.png" title="Spain"/><a href="/search?query=country%3Aes+port%3A80+title%3AIIS7+country%3A%22ES%22" class="city">Spain</a> <div class="clear"></div><a href="/host/194.140.132.7" class="details">Details</a> </div> <pre>HTTP/1.1 200 OK Content-Type: text/html Last-Modified: Tue, 16 Dec 2008 11:21:42 GMT Accept-Ranges: bytes ETag: "4423d978705fc91:0" Server: Microsoft-IIS/7.0 X-Powered-By: ASP.NET Date: Tue, 02 Jun 2015 15:36:42 GMT Content-Length: 689 </pre> <div class="clear"></div> </div> <div class="search-result"> <div class="ip"><a href="http://213.60.47.183:80">IIS7</a> </div> <div class="search-result-summary"><span>213.60.47.183</span><br/><span>183.47.60.213.static.mundo-r.com</span><br/><a href="/search?query=country%3Aes+port%3A80+title%3AIIS7+org%3A%22A+Coruna%22" class="os">A Coruna</a> <div></div><span>Added on 2015-06-02 15:29:51 GMT</span><br/><img src="https://static.shodan.io/shodan/img/flags/16/ES.png" title="Spain"/><a href="/search?query=country%3Aes+port%3A80+title%3AIIS7+country%3A%22ES%22" class="city">Spain</a> <div class="clear"></div><a href="/host/213.60.47.183" class="details">Details</a> </div> |
Este fragmento es el resultado de una búsqueda real con el dork: ‘country:es port:80 title:IIS7’ a fecha: 02/06/2015
Para obtener la información que queremos tendremos que ‘parsear’ este archivo para extraer únicamente las IP’s:
1 |
strings /tmp/result_shodan_download | grep '/host/' | awk -F\" '{ print $4 }' | awk -F/ '{ print $3 }' | uniq |
Ahora, si juntamos todo lo anterior en un script, tendremos algo como esto:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
#!/bin/bash # # Search in shodan.io # Given a query, get the ip addresses # ########################################### # @mark__os ## http://hackaffeine.com # ########################################### # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. # #Shodan user credentials (inside single quotes!) #YOU MUST CHANGE THIS WITH YOUR OWN USER AND PASSWORD! USER='YourShodanUSER' PASSWORD='YourShodanPASSWORD' #Forge Post Data to send with wget POST_DATA="username=$USER&password=$PASSWORD" #Color definitions red="\033[0;31m" redC="\033[1;31m" green="\033[0;32m" greenC="\033[1;32m" yellow="\033[1;33m" gray="\033[1;30m" brown="\033[0;33m" white="\033[1;37m" blueC="\033[1;34m" reverse="\E[7m" basecolor="\E[0m" help(){ echo -e ""$greenC"┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓"$basecolor"" echo -e ""$greenC"┃"$basecolor" "$white"SHODAN IP DUMPER - http://hackaffeine.com "$greenC"┃"$basecolor"" echo -e ""$greenC"┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛"$basecolor"" echo -e "\n "$white"- USAGE:"$basecolor"" echo -e "\n\t $0 'seach query'" echo -e "\n "$white"- Examples:"$basecolor"" echo -e "\n\t $0 'port:8080 country:es admin/admin'" echo -e "\t $0 'city:Madrid port:21 vsftpd'" echo -e "\t $0 'port:23 UNITED STATES GOVERNMENT COMPUTER'\n" exit 1 } #Do login and save cookies login() { wget -U 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/37.0.2062.120 Chrome/37.0.2062.120 Safari/537.36' \ --secure-protocol=auto \ --save-cookies /tmp/save.txt \ --keep-session-cookies \ --post-data $POST_DATA \ -q \ -O /tmp/login \ https://account.shodan.io/login if [ -z "$(grep 'Show API Key' /tmp/login)" ] then echo -e "["$redC"-"$basecolor"] Login ERROR" echo -e "\n"$redC" * "$white"Edit the script "$redC"$0"$basecolor""$white" with a correct USER and PASSWORD for shodan.io"$basecolor"\n" exit 1 else echo -e "["$greenC"+"$basecolor"] Login OK" fi } #Search query search(){ wget -U 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/37.0.2062.120 Chrome/37.0.2062.120 Safari/537.36' \ --load-cookies /tmp/save.txt \ -q \ -O /tmp/result_shodan_download \ https://www.shodan.io/search?query=$QUERY\&page=$PAGE IPS=$(strings /tmp/result_shodan_download | grep '/host/' | awk -F\" '{ print $4 }' | awk -F/ '{ print $3 }' | uniq) #When no find more IP's, try six times. If no results, exit script if [ "$IPS" == "" ] then let ATTEMPT=$ATTEMPT+1 if [ "$ATTEMPT" == "6" ] then exit 0 else search fi fi } #Show results stored in IPS var show(){ for i in $(echo $IPS) do echo "$i" let TOTAL_IP_CONT=$TOTAL_IP_CONT+1 done } #################### ### MAIN PROGRAM ### #################### if [ ! -z "$1" ] then QUERY=$(echo "$@") else help fi #Format query to GET call (substitute spaces with + symbol) QUERY=$(echo $QUERY | sed 's/ /+/g') #If exist previous downloaded info, remove it if [ -f /tmp/save.txt ] then rm -rf /tmp/save.txt elif [ -f /tmp/login ] then rm -rf /tmp/login fi #Show Loading on screen echo -e "["$yellow"i"$basecolor"] Loading . . ." #Execute login in shodan.io, search query and show IP's as result echo -e "["$yellow"i"$basecolor"] Do login" login #First search to get total results number echo -e "["$yellow"i"$basecolor"] Searching" search #Extract total results and save it in NUM_RESULTS NUM_RESULTS=$(awk '/Total results/ { print $4 }' /tmp/result_shodan_download | awk -F\< '{ print $1 }' | sed 's/,//g') echo -e ""$reverse""$white" TOTAL RESULTS: "$basecolor""$greenC" $NUM_RESULTS "$basecolor"" #IP results counter TOTAL_IP_CONT=0 #Results page of shodan to start downloading PAGE=1 #Main loop to download all results while [ "$TOTAL_IP_CONT" -le "$NUM_RESULTS" ] do ATTEMPT=1 search show let PAGE=$PAGE+1 done |
Lo podeis clonar desde github:
1 |
git clone https://github.com/mmsystems/shipdump |
No es bonito, ni está muy bien programado (lo iré reorganizando a medida que saque tiempo) y para descargar muchos resultados, como va página por página, es más lento que «compilar en una Rasberry-pi™», pero me sigue dando horas de juego después de gastar las 100 querys que me permite la API oficial:
shipdump.sh descargando 190 IP’s resultantes del dork: ‘country:es port:445 public’ en unos 40 segundos.