11 noviembre 2010

KodiakDNS, cuando los pentesters escribían sus propias herramientas

El DNS es una base de datos jerárquica y distribuida que permite traducir nombres de dominio en direcciones IP y viceversa. Las especificaciones del sistema de nombres de dominio están basadas en las RFC rfc1034 y rfc1035 que datan de 1987, y en ellas se describen los detalles del protocolo.

El protocolo DNS se creó hace más de 20 años, y desde entonces se han producido más de 40 implementaciones de DNS independientes, algunas de estas implementaciones cuentan con más de 20 versiones.

Hace poco Chema Alonso nos habló sobre como consultar el registro de la versión de BIND en los servidores DNS a mano. Pudiendo ser útil para conocer si un determinado servidor se encuentra desactualizado o para descubrir una política de versiones descoordinada.

Durante un pentest es importante obtener las versiones del servidor de DNS, para extraer información que nos será útil para saber si es vulnerable al envenenamiento de DNS o a otro tipo de vulnerabilidades. En ocasiones, nmap no nos proporciona buenos resultados (opción -sV) sobre servidores de nombres de dominio. Podríamos pensar en capturar el banner que nos devuelve la petición al servidor, pero esta solución no es fiable, ya que podríamos modificar la información que deseamos mostrar.

La metodología que se debe utilizar para identificar las implementaciones de servidores de nombres se basa en cómo se comporta del protocolo en la frontera, al proporcionarnos un gran cantidad de información útil (mensajes de bits, tipos de respuesta, opcodes, clases, tipos de consulta, tipos de etiquetas)

Queremos desarrollar nuestra propia herramienta para DNS fingerprinting, para ello podemos utilizar el proyecto fpdns que determina de forma remota las versiones del servidor DNS, mediante el envío de una serie de consultas DNS que se comparan con una tabla con las respuestas y las versiones de los servidores. Este proyecto es bastante fiable y permite detectar la siguientes implementaciones. El descubrimiento de las versiones formará parte de nuestra herramienta de descubriendo de servidores DNS.

Y ya que estamos animados, ¿por qué no programar nuestra propia herramienta para hacer gathering de DNS?

Para animaros a desarrollar vuestra propia herramienta, he programado a modo ejemplo una tool de gathering de DNS llamada kodiakDNS. La herramienta está hecha en Perl, y usa la librería Net::DNS para resolver todas las consultas y fpdns.

Los pasos que debemos seguir son los siguientes:

1- Obtener los servidores de nombres y los tipos de registros DNS (NS, A, MX)

print "\n[Resolving DNS NS]\n\n";
foreach my $rr (grep { $_->type eq "NS" } $query->answer) {       
    print $rr->string, "\n";
    if ((grep { $_ eq $rr->nsdname } @nsdnamelist)==0){
         push(@nsdnamelist, $rr->nsdname);
    }
}

print "\n[Resolving DNS MX]\n\n";
my @mx = mx($res, $domain);
foreach my $rrmx (@mx) {   
   print $rrmx->string, "\n";
}
   
print "\n[Resolving DNS A]\n\n";
foreach my $rrns (@nsdnamelist) {
    resolveDomain($rrns);
} 
   
sub resolveDomain {
    my $resolver = Net::DNS::Resolver->new;
    my $domain = $_[0];
    my $query = $resolver->search($domain);

    if ($query) {   
        foreach my $rr ($query->answer ? $query->answer : $query->authority) {
            $rr->print;
            if ($rr->type eq "A") {
                if ((grep { $_ eq $rr->address } @iplist)==0){
                    push(@iplist, $rr->address);
                }
            }
        }
    } elsif ($resolver->errorstring eq "NXDOMAIN" || $resolver->errorstring eq "NOERROR") {
         warn "$domain NXDOMAIN doesnt exist" . $resolver->errorstring . "\n";
    } else {
         warn "Cannot resolve host $domain: " . $resolver->errorstring . "\n";
    }
}
2- Comprobar si el dominio soporta transferencia de zona.
foreach my $rrns (@nsdnamelist) {
       
    $res->nameservers($rrns);     

    my @zone = $res->axfr($domain);
    if (@zone) {
        $noaxfr = 1;
        print "\n[Resolving AXFR for ".$rrns."]\n\n";
        foreach my $rra (@zone) {
            $rra->print;
            if ($rra->type eq "A") {
                if ((grep { $_ eq $rra->address } @iplist)==0){
                    push(@iplist, $rra->address);
                }
            }
        }
    }  
}
3- En caso de no soportar transferencia de zona obtener los subdominios por fuerza bruta. Debemos obtener un diccionario con palabras lo más extenso posible. Por la red disponemos de varios a modo de ejemplo e ir ampliándolo. Podemos hacer uso de herramientas como dnsmap, que nos permite descubrir subdominios a través de fuerza bruta.
print "\n[Resolving DNS by bruteforcing]\n\n";
my $wordlist = "wordlist.txt";

if ($wordlist) {
    open DATA, $wordlist;
    my @list = ();
    @list = <DATA>;
    close DATA;
    chomp @list;

    my @mylist = map "$_.$domain", @list;

    foreach my $elto (@mylist){
        resolveDomain($elto);
    }
}
4- Una vez obtenidas las IPs de los hosts, devolvemos los PTRs de las IPs por el rango entero. Las librerias disponen de funcionen que nos permiten resolver los PTRs
print "\n[Resolving Reverse DNS [PTR]]\n";
foreach my $ip (@iplist){
    my $position = rindex $ip, '.';
    my $ip_range = substr ($ip,0,$position+1);
    if ((grep { $_ eq $ip_range } @iprange)==0){
        push(@iprange, $ip_range);
    }
}

foreach my $iprange (@iprange){
    print "\n".$iprange.'0-255'."\n\n";
    for ($i = 0; $i <= 255; $i++){
        resolveReverse($iprange.$i);
    }
}
   
sub resolveReverse {

    my $ip = new Net::IP($_[0],4);        
    my $mx_res = Net::DNS::Resolver->new();
    my $mxanswer = $mx_res->query($ip->reverse_ip(),'PTR');

    if($mxanswer) {
        foreach my $mrr (grep {$_->type eq "PTR" } $mxanswer->answer) {
            if ($ip->reverse_ip()) {       
                print $ip->reverse_ip()," PTR ",$mrr->ptrdname,"\n";
            } else {
                print "No Reverse IP \n";
            }     
        }
    } else {
        print "MX records not found\n";
    }
}
5- Obtener las versiones de los servidores de DNS. Para ello podemos utilizar el proyecto fpdns, del que hemos hablado antes. Podíamos invocarlo desde nuestra herramienta de la siguiente forma:
fpdns -D <nameserver>
print "\n[Resolving DNS Version]\n\n";
my $dnsversion = `fpdns -D $domain`;
print $dnsversion;
Podemos ver los resultados obtenidos para los dominios google.com y slackware.com (este último soporta transferencia de zona)

¿Has visto lo sencillo que es programar tu propia herramienta para gathering de DNS? ¿Te animas a programar la tuya?

Artículo cortesía de: Laura García.

3 comments :

Juan Antonio Calles dijo...

Hola, gran entrada chicos! Hace unos meses desarrollé la herramienta Anubis, que entre otras cosas te calcula las transferencias de zona, te hace un barrido a los DNS con los registros PTR e incluso te permite hacer ataques de fuerza bruta o por diccionario (utiliza los diccionarios por defecto de wfuzz y otro que diseñé expecíficamente para atacar universidades). La podéis descargar gratis desde este enlace:

http://elblogdecalles.blogspot.com/p/anubis.html

Actualmente he desarrollado hasta la versión 1.1, pero tengo en camino la 2.0 que lanza todos los ataques asíncronamente, lo único que ando fastidiado de tiempo por el curro y ando buscando un equipo de desarrollo que me ayude con el proyecto, mi objetivo es liberar el código cuando esté acabada la versión 2.0. Si estáis interesados alguno para mi será un placer hablar con vosotros del tema en privado.

saludos!

Mike dijo...

Muy bueno!

Seguid así :)

Alejandro Nolla dijo...

Buenísima entrada, es cierto que para estos temas Fierce "parte la pana" (lo siento pero me gusta demasiado jaja), pero considero que no hay nada como desarrollar una pequeña tool propia para hacer las cosas, por un lado para aprender bien qué se hace y cómo y por otro porque siempre podemos "customizarla" al gusto y las necesidades para cada caso.

Un saludo y seguid así :D