Herramientas de usuario

Herramientas del sitio


informatica:programacion:cursos:python_avanzado_proyectos_seguridad:extraccion_informacion_servidores_dns

Extracción de información de servidores DNS

Módulo perteneciente al curso Python avanzado para proyectos de seguridad

La dirección IP se puede traducir en cadenas legibles por humanos llamadas nombres de dominio. En esta sección, veremos como obtener la información de los servidores DNS y crearemos un cliente DNS en Python.

DNS son las siglas de Domain Name Server, servicio de nombres de dominio utilizado para relacionar direcciones IP con nombres de dominio.

El protocolo DNS se utiliza para distintos propósitos. Los más comunes son:

  • Se emplea para asignar un rango de ips a un único dominio.
  • Resolución de nombres: Dado el nombre completo de un host, obtener su dirección IP.
  • Resolución inversa de direcciones: Es el mecanismo inverso al anterior. Consiste en, dada una dirección IP, obtener el nombre de host asociado a la misma.
  • Resolución de servidores de correo: Dado un nombre de dominio (por ejemplo gmail.com) obtener el servidor a través del cual debe realizarse la entrega del correo electrónico (por ejemplo, gmail-smtp-in.l.google.com).

DNS también es un protocolo que los dispositivos usan para consultar a los servidores DNS con el objetivo de resolver nombres de host en direcciones IP (y viceversa).

La herramienta nslookup viene con la mayoría de los sistemas Linux y Windows y nos permite realizar consultas DNS desde la línea de comandos.

En este ejemplo determinamos que el dominio python.org tiene la dirección IPv4 45.55.99.72:

$ nslookup python.org

Esta es la resolución de dirección para el dominio python.org:

Server: 192.168.18.1
Address: 192.168.18.1#53

Non-authoritative answer:
Name: python.org
Address: 45.55.99.72

Servidores DNS

Los seres humanos recordamos mucho mejor los nombres para relacionar objetos que secuencias largas de números. Para cualquiera es mucho más sencillo recordar el dominio google.com que la dirección ip. Además, la dirección ip puede cambiar por movimientos en la infraestructura de red, mientras que el nombre de dominio puede continuar siendo el mismo.

Su funcionamiento se basa en el uso de una base de datos distribuida y jerárquica en la que se almacenan nombres de dominios y direcciones IP, así como la capacidad de prestar servicios de localización de servidores de correo. Los servidores DNS permiten la consulta de diferentes tipos de registros en los que se incluyen servidores de correo, direcciones IP, nombres de dominios y otros servicios.

Los servidores DNS se ubican en la capa de aplicación y suelen utilizar el puerto 53 (UDP).

Cuando un cliente envía un paquete DNS para realizar algún tipo de consulta, debe enviar el tipo de registro que desea consultar. Algunos de los registros más utilizados son:

  • A: Permite consultar la dirección IPv4
  • AAAA: Permite consultar la dirección IPv6
  • MX: Permite consultar los servidores de correo
  • NS: Permite consultar el nombre del servidor (Name Server)
  • TXT: Permite consultar información en formato texto

Módulo DNSPython

Python dispone del módulo dnspython que permite realizar operaciones de consulta de registros contra servidores DNS.

Este módulo permite el acceso tanto a alto nivel por medio de consultas a registros DNS, como a bajo nivel permitiendo la manipulación directa de zonas, mensajes, nombres y registros.

La instalación se puede hacer tanto a través del comando pip install dnspython como bajando el código fuente del repositorio de github y ejecutar el comando setup.py install.

La principal utilidad de dnspython con respecto a otras herramientas de consulta de DNS, como nslookup, es que puede controlar el resultado de las consultas desde Python y luego esa información puede usarse para otros fines en un script.

A la hora de hacer uso de este módulo los paquetes necesarios serían los siguientes:

>>> import dns
>>> import dns.resolver

La información que podemos obtener de un determinado dominio es:

  • Registros para servidores de correo
    • ansMX = dns.resolver.query("dominio","MX")
  • Registros para servidores de nombre
    • ansNS = dns.resolver.query("dominio","NS")
  • Registros para direcciones IPV4
    • ansA = dns.resolver.query("dominio","A")
  • Registros para direcciones IPV6
    • ansAAAA = dns.resolver.query("dominio","AAAA")

En este ejemplo, estamos haciendo una consulta con respecto a la dirección IPv4 de del dominio python.org con el submódulo dns.resolver:

>>> import dns.resolver
>>> respuestas = dns.resolver.query('python.org', 'A')
>>> for respuesta in respuestas:
>>>   print('IP', respuesta.to_text())

Determinar el destino de un registro MX y su preferencia

Con el submódulo dns.resolver también podemos acceder a la información almacenada en los registros de intercambio de correo de ExChange para ver qué hosts tienen prioridad al intercambiar correos electrónicos a través de Internet.

Puede encontrar el siguiente código en el archivo dns_registro_mx.py:

import dns.resolver
respuestas = dns.resolver.query('google.com', 'MX')
for respuesta in respuestas:
    print('Host', respuesta.exchange, 'tiene una preferencia de ', respuesta.preference)

Este podría ser el resultado del script anterior:

Host alt3.aspmx.l.google.com. tiene una preferencia de  40
Host alt2.aspmx.l.google.com. tiene una preferencia de  30
Host alt4.aspmx.l.google.com. tiene una preferencia de  50
Host aspmx.l.google.com. tiene una preferencia de  10
Host alt1.aspmx.l.google.com. tiene una preferencia de  2

Implementar un cliente consulta de registros DNS

En este ejemplo práctico utilizaremos dnspython para ejecutar consultas en varios tipos de registros DNS, como IPv4 (A), IPv6 (AAAA), servidores de nombres (NS) e intercambio de correo (MX).

Puede encontrar el siguiente código en el archivo registros_dns_python.py:

#!/usr/bin/env python
 
import dns
import dns.resolver
import dns.query
import dns.zone
import dns.name
import dns.reversename
import sys
 
if len(sys.argv) != 2:
    print("[-] uso python DNSPythonExample.py <nombre_dominio>")
    sys.exit()
 
dominio = sys.argv[1]
 
respuestaRegistroA,respuestaRegistroMX,respuestaRegistroNS,respuestaRegistroTXT=(dns.resolver.query(dominio,'A'),
                          dns.resolver.query(dominio,'MX'),
                          dns.resolver.query(dominio, 'NS'),
                          dns.resolver.query(dominio, 'TXT'))
 
print("Servidores de correo")
print("--------------------")
print(respuestaRegistroMX.response.to_text())
 
print("\nServidores de nombre")
print("--------------------")
print(respuestaRegistroNS.response.to_text())
 
print("\nDirecciones IPV4")
print("--------------------")
print(respuestaRegistroA.response.to_text())
 
print("\nRegistros DNS")
print("--------------------")
print(respuestaRegistroTXT.response.to_text())

En la salida el anterior script podemos ver los diferentes tipos de registros para el dominio python.org:

Servidores de correo
--------------------
id 56661
opcode QUERY
rcode NOERROR
flags QR RD RA
;QUESTION
python.org. IN MX
;ANSWER
python.org. 532200 IN MX 50 mail.python.org.
;AUTHORITY
python.org. 1050 IN NS ns-2046.awsdns-63.co.uk.
python.org. 1050 IN NS ns-484.awsdns-60.com.
python.org. 1050 IN NS ns-981.awsdns-58.net.
python.org. 1050 IN NS ns-1134.awsdns-13.org.
;ADDITIONAL
ns-1134.awsdns-13.org. 69879 IN A 205.251.196.110
ns-1134.awsdns-13.org. 68501 IN AAAA 2600:9000:5304:6e00::1
ns-484.awsdns-60.com. 50041 IN A 205.251.193.228
ns-484.awsdns-60.com. 50002 IN AAAA 2600:9000:5301:e400::1
ns-981.awsdns-58.net. 67318 IN A 205.251.195.213
ns-981.awsdns-58.net. 162880 IN AAAA 2600:9000:5303:d500::1     

Servidores de nombre
--------------------
id 26653
opcode QUERY
rcode NOERROR
flags QR RD RA
;QUESTION
python.org. IN NS
;ANSWER
python.org. 1050 IN NS ns-1134.awsdns-13.org.
python.org. 1050 IN NS ns-2046.awsdns-63.co.uk.
python.org. 1050 IN NS ns-484.awsdns-60.com.
python.org. 1050 IN NS ns-981.awsdns-58.net.
;AUTHORITY
;ADDITIONAL
ns-1134.awsdns-13.org. 69879 IN A 205.251.196.110
ns-1134.awsdns-13.org. 68501 IN AAAA 2600:9000:5304:6e00::1
ns-484.awsdns-60.com. 50041 IN A 205.251.193.228
ns-484.awsdns-60.com. 50002 IN AAAA 2600:9000:5301:e400::1
ns-981.awsdns-58.net. 67318 IN A 205.251.195.213
ns-981.awsdns-58.net. 162880 IN AAAA 2600:9000:5303:d500::1     

Direcciones IPV4
--------------------
id 35266
opcode QUERY
rcode NOERROR
flags QR RD RA
;QUESTION
python.org. IN A
;ANSWER
python.org. 575142 IN A 45.55.99.72
;AUTHORITY
;ADDITIONAL     

Registros DNS
--------------------
id 1524
opcode QUERY
rcode NOERROR
flags QR RD RA
;QUESTION
python.org. IN TXT
;ANSWER
python.org. 3600 IN TXT "_globalsign-domain-verification=MK_ZKmss4D_DdzGOsssHxxBOK6hJc6LGycFvNOESdZ"
python.org. 3600 IN TXT "google-site-verification=9852CbTRhQ51-9gCUayPbGYqJeBle_MXLb6E4AL_qQk"
python.org. 3600 IN TXT "google-site-verification=QALZObrGl2OVG8lWUE40uVSMCAka316yADn9ZfCU5OA"
python.org. 3600 IN TXT "google-site-verification=dqhMiMzpbkSyEhgjGKyEOMlEg2tF0MSHD7UN-MYfD-M"
python.org. 3600 IN TXT "google-site-verification=w3b8mU3wU6cZ8uSrj3E_5f1frPejJskDpSp_nMWJ99o"
python.org. 3600 IN TXT "status-page-domain-verification=9y2klhzbxsgk"
python.org. 3600 IN TXT "v=spf1 mx a:mail.wooz.org ip4:188.166.95.178/32 ip6:2a03:b0c0:2:d0::71:1 include:stspg-customer.com include:_spf.google.com include:mailgun.org ~all"
python.org. 3600 IN TXT "888acb5757da46ad83b7e341ec544c64"
;AUTHORITY
python.org. 1049 IN NS ns-2046.awsdns-63.co.uk.
python.org. 1049 IN NS ns-484.awsdns-60.com.
python.org. 1049 IN NS ns-1134.awsdns-13.org.
python.org. 1049 IN NS ns-981.awsdns-58.net.
;ADDITIONAL
ns-1134.awsdns-13.org. 69878 IN A 205.251.196.110
ns-1134.awsdns-13.org. 68500 IN AAAA 2600:9000:5304:6e00::1
ns-484.awsdns-60.com. 50040 IN A 205.251.193.228
ns-484.awsdns-60.com. 50001 IN AAAA 2600:9000:5301:e400::1
ns-981.awsdns-58.net. 67317 IN A 205.251.195.213
ns-981.awsdns-58.net. 162879 IN AAAA 2600:9000:5303:d500::1 

Añadiendo tratamiento de excepciones a la consulta de registros DNS

En este ejemplo práctico utilizaremos dnspython para ejecutar las consultas del ejemplo anterior, con la diferencia de que en este caso estamos realizando un tratamiento y en caso de que no se pueda obtener información para un tipo de registro concreto, informar al usuario con un mensaje de error.

Puede encontrar el siguiente código en el archivo registros_dns_excepciones.py:

#!/usr/bin/env python
 
import argparse
import dns.zone
import dns.resolver
import socket
 
def main(dominio):
    # Regstros DNS IPv4
    try:
        respuestaIPV4 = dns.resolver.query(dominio, 'A')
        for i in range(0, len(respuestaIPV4)):
            print("IPV4: ", respuestaIPV4[i])
    except dns.resolver.NoAnswer as error:
        print("Error al obtener los registros IPv4:", error)
 
    # Regstros DNS IPv6
    try:
        respuestaIPV6 = dns.resolver.query(dominio, 'AAAA')
        for i in range(0, len(respuestaIPV6)):
            print("IPV6: ", respuestaIPV6[i])
    except dns.resolver.NoAnswer as error:
        print("Error al obtener los registros IPv6:", error)
 
    # Registros de correo MX (Mail Exchanger)
    try:
        mx = dns.resolver.query(dominio, 'MX')
        for i in range(0, len(mx)):
            print("MX: ", mx[i])
    except dns.resolver.NoAnswer as error:
        print("Error al obtener los registros MX:", error)
 
    # Registros de CNAME
    try:
        cname_answer = dns.resolver.query(dominio, 'CNAME')
        print("CNAME: ", cname_answer)
    except dns.resolver.NoAnswer as error:
        print('Error al obtener los registros CNAME', error)
 
     # Registros de NS
    try:
        ns_answer = dns.resolver.query(dominio, 'NS')
        print(ns_answer)
    except dns.resolver.NoAnswer as error:
        print("Error al obtener los registros NS:", error)
 
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='DNS Python')
    parser.add_argument('-dominio', action="store", dest="dominio",  default='python.org')
    given_args = parser.parse_args()
    dominio = given_args.dominio
    main(dominio)

En la salida el anterior script podemos ver los diferentes mensajes de error en caso de poder obtener información sobre los registros:

IPV4: 45.55.99.72
Error al obtener los registros IPv6: The DNS response does not contain an answer to the question: python.org. IN AAAA
MX: 50 mail.python.org.
Error al obtener los registros CNAME The DNS response does not contain an answer to the question: python.org. IN CNAME
<dns.resolver.Answer object at 0x7f5981d4a2e0>

Actividad práctica: Completar el código para la extracción de información de un servidor DNS mediante el módulo DNSPython

Completar el código para la extracción de información de un servidor DNS mediante el módulo DNSPython. Sustituir las xxx por variables y métodos que permitan completar la funcionalidad de obtener información sobre los diferentes registros DNS.

Para ello hacemos uso del módulo dnspython y el submódulo dns.resolver para realizar la consulta a los diferentes registros para obtener información relativa a direcciones ip y nombres de servidores de nombres.

import dns.resolver
 
def main(xxx):
    registros = ['A','AAAA','NS','SOA','MX','MF','MD','TXT']
    for registro in xxx:
        try:
            respuestas = dns.xxx.xxx(xxx, xxx)
            print("Respuestas del registro ",xxx)
            print("-----------------------------------")
            for respuesta in xxx:
                print(xxx)
        except:
            print("No pude resolver la consulta para el registro ",xxx)
 
if __name__ == '__main__':
    try:
        main('google.com')
    except KeyboardInterrupt:
        exit()

Solución

import dns.resolver
 
def main(dominio):
	registros = ['A','AAAA','NS','SOA','MX','MF','MD','TXT']
	for registro in registros:
		try:
			respuestas = dns.resolver.query(dominio, registro)
			print("Respuestas del registro ",registro)
			print("-----------------------------------")
			for respuesta in respuestas:
				print(respuesta)
		except:
			print("No pude resolver la consulta para el registro ",registro)
 
if __name__ == '__main__':
	try:
		main('google.com')
	except KeyboardInterrupt:
		exit()

Otras operaciones con el módulo dnspython

Con el módulo dnspython podemos comprobar si un dominio es subdominio de otro a través del método is_subdomain():

>>> import dns.resolver
>>> dominio1 = dns.name.from_text('dominio1')
>>> dominio2 = dns.name.from_text('dominio2')
>>> dominio1.is_subdomain(dominio2)

En el siguiente script utilizamos el método anterior para comprobar si un dominio es subdominio o superdominio de otros las direcciones ip a partir de una lista de dominios.

Puede encontrar el siguiente código en el archivo comprobar_dominios.py:

#!/usr/bin/env python
 
import argparse
import dns.name
 
def main(dominio1, dominio2):
    dominio1 = dns.name.from_text(dominio1)
    dominio2 = dns.name.from_text(dominio2)
    print("dominio1 is subdomain of dominio2: ", dominio1.is_subdomain(dominio2))
    print("dominio1 is superdomain of dominio2: ", dominio1.is_superdomain(dominio2))
 
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Comprobar 2 dominios con dns Python')
    parser.add_argument('--dominio1', action="store", dest="dominio1",  default='www.python.org')
    parser.add_argument('--dominio2', action="store", dest="dominio2",  default='python.org')
    given_args = parser.parse_args()
    dominio1 = given_args.dominio1
    dominio2 = given_args.dominio2
    main (dominio1, dominio2)

Obtener un nombre de dominio a partir de una dirección IP:

>>> import dns.reversename
>>> dominio = dns.reversename.from_address('direccion_ip')

Obtener una dirección IP a partir de un nombre de dominio:

>>> import dns.reversename
>>> ip = dns.reversename.to_address('dominio')

Actividad práctica: Completar el código para la obtención de las direcciones ip a partir de una lista de dominios

Completar el código para la obtención de las direcciones ip a partir de una lista de dominios. Sustituir las xxx por variables y métodos que permitan completar la funcionalidad para realizar esta consulta.

import dns.xxx
 
dominios = ["google.com", "microsoft.com", "python.org"]
 
for dominio in xxx:
    print('Direcciones ip del dominio',xxx)
    #utilizamos el registro A para obtener direcciones ip
    direcciones = xxx.xxx.xxx(xxx, xxx)
    for direccion_ip in xxx:
        print(xxx)

Solución

import dns.resolver
 
dominios = ["google.com", "microsoft.com", "python.org"]
 
for dominio in dominios :
    print('Direcciones ip del dominio',dominio )
    #utilizamos el registro A para obtener direcciones ip
    direcciones = dns.resolver.query(dominio, "A")
    for direccion_ip in direcciones :
        print(direccion_ip )

Búsqueda inversa

Si desea realizar una búsqueda inversa, debe usar el submódulo dns.reversename, como se muestra en el siguiente ejemplo:

>>> import dns.reversename
>>> name = dns.reversename.from_address("ip_address")
>>> print(dns.reversename.to_address(name))

En el siguiente script utilizamos el método anterior para obtener el nombre dns a partir de la ip y viceversa.

Puede encontrar el siguiente código en el archivo busqueda_inversa.py:

import dns.reversename
 
nombre = dns.reversename.from_address("8.8.8.8")
print(nombre)
print(dns.reversename.to_address(nombre))

Servicios DNS

Robtex se trata de un servicio considerado la navaja suiza de internet.

Permite obtener, sin dejar rastro alguno en el objetivo, consultas sobre los dominios, subdominios, servidores DNS.

Este tipo de consultas suelen categorizarse como footprinting activo, aunque, al realizarlo a través de este servicio, en realidad se lleva a cabo de manera pasiva.

Robtex utiliza varias fuentes para recopilar información pública sobre números de IP, nombres de dominio, nombres de host, rutas, etc. Posteriormente indexa los datos en una base de datos y proporciona acceso gratuito a los mismos. El objetivo es conseguir la herramienta de búsqueda de DNS gratuita más rápida y completa en Internet.

Robtex proporciona una gran cantidad de información sobre un dominio. Por ejemplo puede ver aquellos dominios relacionados.

Disponemos también de una API que devuelve los datos de geolocalización y de red de una dirección ip.

https://freeapi.robtex.com/ipquery/<dirección_ip>

Ejemplo de consulta:

https://freeapi.robtex.com/ipquery/8.8.8.8

{"status":"ok","act":[{"o":"dns.google","t":1643550746}],"acth":[{"o":"google-public-dns-a.google.com","t":1643550747}],"pas":[{"o":"easymacao.com","t":1502146206},{"o":"73ldvunq.com","t":1501351840},{"o":"opon.com.cn","t":1501352406},{"o":"dc-20363e99abf1.skgrader.tk","t":1497273068},{"o":"aqb029.com","t":1555678182},{"o":"texwff.net","t":1527997086},{"o":"phreeek.de","t":1506111284},{"o":"itnovo.com","t":1491719020},{"o":"n23999.com","t":1576462182},{"o":"vns66jj.com","t":1505282792}],"pash":[{"o":"beautifulagony.info","t":1498868389},{"o":"easymacao.com","t":1613254599},{"o":"73ldvunq.com","t":1589141225},{"o":"nugraha.com","t":1521410905},{"o":"bzly.gov.cn","t":1488104799},{"o":"xn--cnq17rc0ni4a.cn","t":1506096329},{"o":"meumlaboratorium.net","t":1581563249},{"o":"craftbeerhq.com","t":1497272993},{"o":"50661.red","t":1505943755},{"o":"flowerpowermosquito.com","t":1493294473}],"city":"Mountain View","country":"United States","as":15169,"asname":"Google Google, Inc","asdesc":"NeuStar NeuStar, Inc","whoisdesc":"Google LLC (GOGL)","routedesc":"SP_BEEKSFX","bgproute":"8.8.8.0/24"}

Podríamos utilizar el servicio de dns-lookup para obtener más información sobre un dominio: https://www.robtex.com/dns-lookup/

¿Qué tipos de información proporciona Robtex?

  • Búsqueda de DNS inversa. Permite buscar un número de IP para averiguar qué nombres de host lo apuntan. Los registros DNS inversos funcionan no solo para la dirección IP, sino también para los registros MX (servidor de correo) y los registros NS (servidor de nombres).
  • Buscar un número de IP y obtener qué nombres de host lo apuntan. Los registros DNS inversos funcionan no solo para la dirección IP, sino también para los registros MX (servidor de correo) y los registros NS (servidor de nombres).
  • Información Whois. Permite realizar búsquedas para un dominio registrado en varias bases de datos de whois. En esta base de datos es posible encontrar información de contacto del registro de dominio junto con la fecha de registro y la fecha de vencimiento. Se trata de un protocolo TCP que permite realizar consultas a bases de datos. Entre los principales datos que se pueden obtener podemos destacar el propietario del dominio, la dirección ip, direcciones de correo, fechas de creación y actualización de dominios.

DNSLookup

Un dominio tiene una cantidad de registros asociados, se puede consultar un servidor DNS para determinar la dirección IP del dominio principal (registro A), servidores de correo (registros MX), servidores DNS (servidores de nombres NS) y otros elementos como registros TXT.

El comando más común que se utiliza es nslookup que está disponible en muchos sistemas operativos, incluidos Windows y la mayoría de las distribuciones de Linux. Otra herramienta que se encuentra en sistemas basados en Linux es la herramienta dig. En general, esta es una herramienta más avanzada que tiene una serie de características que nslookup no posee.</p>

Los siguientes servicios web permiten realizar una consulta del tipo dns-lookup:

FAQ

¿Qué es Shodan?

Shodan corresponde al acrónimo de Sentient Hyper Optimized Data Access Network. A diferencia de los motores de búsqueda tradicionales que rastrean el sitio web para mostrar los resultados, Shodan ayuda a encontrar los servicios vulnerables en un servidor web.

Shodan es un motor de búsqueda para encontrar dispositivos específicos que funciona escaneando todo Internet y analizando los banners que devuelven los dispositivos. Con esa información, Shodan puede decirle cosas como qué servidor web es más popular, o cuántos servidores FTP anónimos existen en una ubicación determinada.

Funciona escaneando todo Internet y analizando los banners que devuelven los dispositivos. Utilizando esa información, Shodan puede devolver datos como qué servidor web (y versión) es más popular, o cuántos servidores FTP anónimos existen en una ubicación determinada.

Es de particular utilidad para la investigación de seguridad en Internet de las cosas, ya que actualmente podemos encontrar miles de millones de dispositivos conectados a Internet que tienen vulnerabilidades específicas que deben corregirse, y pueden identificarse rápidamente mediante su información de banner.

informatica/programacion/cursos/python_avanzado_proyectos_seguridad/extraccion_informacion_servidores_dns.txt · Última modificación: por tempwin