Index: dns.c =================================================================== --- dns.c (revision 1135) +++ dns.c (working copy) @@ -26,7 +26,7 @@ #include "dns.h" -static void buffer_add_dns_name(buffer_t *buffer, char *name) +void buffer_add_dns_name(buffer_t *buffer, char *name) { char *domain_base = safe_strdup(name); char *domain_start; @@ -527,6 +527,13 @@ safe_free(dns->answers[i].answer->AAAA.address); } #endif + else if(dns->answers[i].type == DNS_TYPE_NAPTR) + { + safe_free(dns->answers[i].answer->NAPTR.flags); + safe_free(dns->answers[i].answer->NAPTR.services); + safe_free(dns->answers[i].answer->NAPTR.regexp); + safe_free(dns->answers[i].answer->NAPTR.replacement); + } else if(dns->answers[i].type == DNS_TYPE_NB) { safe_free(dns->answers[i].answer->NB.address); @@ -538,6 +545,10 @@ safe_free(dns->answers[i].answer->NBSTAT.names[j].name); safe_free(dns->answers[i].answer->NBSTAT.names); } + else if(dns->answers[i].type == DNS_TYPE_RAW) + { + safe_free(dns->answers[i].answer->RAW.data); + } safe_free(dns->answers[i].answer); } safe_free(dns->answers); @@ -691,7 +702,7 @@ dns->answers = (answer_t*) safe_malloc(sizeof(answer_t)); /* Set up the last element. */ - (dns->answers[dns->answer_count - 1]).question = safe_strdup(question); + (dns->answers[dns->answer_count - 1]).question = question ? safe_strdup(question) : NULL; (dns->answers[dns->answer_count - 1]).type = type; (dns->answers[dns->answer_count - 1]).class = class; (dns->answers[dns->answer_count - 1]).ttl = ttl; @@ -747,6 +758,19 @@ } #endif +void dns_add_answer_NAPTR(dns_t *dns, char *question, uint16_t class, uint32_t ttl, uint16_t order, uint16_t preference, char *flags, char *services, char *regexp, char *replacement) +{ + answer_types_t *answer = safe_malloc(sizeof(answer_types_t)); + answer->NAPTR.order = order; + answer->NAPTR.preference = preference; + answer->NAPTR.flags = safe_strdup(flags); + answer->NAPTR.services = safe_strdup(services); + answer->NAPTR.regexp = safe_strdup(regexp); + answer->NAPTR.replacement = safe_strdup(replacement); + + dns_add_answer(dns, question, DNS_TYPE_NAPTR, class, ttl, answer); +} + void dns_add_answer_NB(dns_t *dns, char *question, uint8_t question_type, char *scope, uint16_t class, uint32_t ttl, uint16_t flags, char *address) { /* Create a buffer where we're going to build our complete question. */ @@ -793,6 +817,16 @@ safe_free(encoded); } +void dns_add_answer_RAW(dns_t *dns, uint8_t *data, uint16_t data_length) +{ + answer_types_t *answer = safe_malloc(sizeof(answer_types_t)); + answer->RAW.data = safe_malloc(data_length); + memcpy(answer->RAW.data, data, data_length); + answer->RAW.data_length = data_length; + + dns_add_answer(dns, NULL, DNS_TYPE_RAW, 0, 0, answer); +} + /* This is pretty much identical to dns_add_answer. */ static void dns_add_additional(dns_t *dns, char *question, uint16_t type, uint16_t class, uint32_t ttl, additional_types_t *additional) { @@ -933,11 +967,15 @@ for(i = 0; i < dns->answer_count; i++) { - buffer_add_dns_name(buffer, (char*)dns->answers[i].question); /* Pointer to the name. */ -/* buffer_add_int16(buffer, 0xc00c);*/ - buffer_add_int16(buffer, dns->answers[i].type); /* Type. */ - buffer_add_int16(buffer, dns->answers[i].class); /* Class. */ - buffer_add_int32(buffer, dns->answers[i].ttl); /* Time to live. */ + /* Don't add the base stuff if this is a RAW request. Let the programmer + * handle that stuff. */ + if(dns->answers[i].type != DNS_TYPE_RAW) + { + buffer_add_dns_name(buffer, (char*)dns->answers[i].question); /* Pointer to the name. */ + buffer_add_int16(buffer, dns->answers[i].type); /* Type. */ + buffer_add_int16(buffer, dns->answers[i].class); /* Class. */ + buffer_add_int32(buffer, dns->answers[i].ttl); /* Time to live. */ + } if(dns->answers[i].type == DNS_TYPE_A) { @@ -973,12 +1011,41 @@ buffer_add_ipv6_address(buffer, dns->answers[i].answer->AAAA.address); } #endif + else if(dns->answers[i].type == DNS_TYPE_NAPTR) + { + /* Length */ + buffer_add_int16(buffer, 2 + /* Order */ + 2 + /* Preference */ + strlen(dns->answers[i].answer->NAPTR.flags) + 1 + /* Flags */ + strlen(dns->answers[i].answer->NAPTR.services) + 1 + /* Services */ + strlen(dns->answers[i].answer->NAPTR.regexp) + 1 + /* Regexp */ + strlen(dns->answers[i].answer->NAPTR.replacement) + 2 /* Replacement */ + ); + + buffer_add_int16(buffer, dns->answers[i].answer->NAPTR.order); + buffer_add_int16(buffer, dns->answers[i].answer->NAPTR.preference); + + buffer_add_int8(buffer, strlen(dns->answers[i].answer->NAPTR.flags)); + buffer_add_string(buffer, dns->answers[i].answer->NAPTR.flags); + + buffer_add_int8(buffer, strlen(dns->answers[i].answer->NAPTR.services)); + buffer_add_string(buffer, dns->answers[i].answer->NAPTR.services); + + buffer_add_int8(buffer, strlen(dns->answers[i].answer->NAPTR.regexp)); + buffer_add_string(buffer, dns->answers[i].answer->NAPTR.regexp); + + buffer_add_dns_name(buffer, dns->answers[i].answer->NAPTR.replacement); + } else if(dns->answers[i].type == DNS_TYPE_NB) { buffer_add_int16(buffer, 6); buffer_add_int16(buffer, dns->answers[i].answer->NB.flags); buffer_add_ipv4_address(buffer, dns->answers[i].answer->NB.address); } + else if(dns->answers[i].type == DNS_TYPE_RAW) + { + buffer_add_bytes(buffer, dns->answers[i].answer->RAW.data, dns->answers[i].answer->RAW.data_length); + } else { fprintf(stderr, "WARNING: Don't know how to build answer type 0x%02x; skipping!\n", dns->answers[i].type); @@ -1252,35 +1319,35 @@ void dns_do_test(char *domain) { - buffer_t *command; - char *command_str; + buffer_t *command; + char *command_str; - command = buffer_create(BO_NETWORK); - buffer_add_string(command, "dnstest "); - buffer_add_ntstring(command, domain); - command_str = (char*) buffer_create_string_and_destroy(command, NULL); - if(system(command_str)) - { - safe_free(command_str); - command = buffer_create(BO_NETWORK); - buffer_add_string(command, "./dnstest "); - buffer_add_ntstring(command, domain); - command_str = (char*) buffer_create_string_and_destroy(command, NULL); - if(system(command_str)) - { - safe_free(command_str); - command = buffer_create(BO_NETWORK); - buffer_add_string(command, "./dnstest "); - buffer_add_ntstring(command, domain); - command_str = (char*) buffer_create_string_and_destroy(command, NULL); - if(system(command_str)) - { - fprintf(stderr, "Couldn't figure out how to run 'dnstest'. Sorry!\n"); - exit(1); - } - } - } - safe_free(command_str); - exit(0); + command = buffer_create(BO_NETWORK); + buffer_add_string(command, "dnstest "); + buffer_add_ntstring(command, domain); + command_str = (char*) buffer_create_string_and_destroy(command, NULL); + if(system(command_str)) + { + safe_free(command_str); + command = buffer_create(BO_NETWORK); + buffer_add_string(command, "./dnstest "); + buffer_add_ntstring(command, domain); + command_str = (char*) buffer_create_string_and_destroy(command, NULL); + if(system(command_str)) + { + safe_free(command_str); + command = buffer_create(BO_NETWORK); + buffer_add_string(command, "./dnstest "); + buffer_add_ntstring(command, domain); + command_str = (char*) buffer_create_string_and_destroy(command, NULL); + if(system(command_str)) + { + fprintf(stderr, "Couldn't figure out how to run 'dnstest'. Sorry!\n"); + exit(1); + } + } + } + safe_free(command_str); + exit(0); } Index: dns.h =================================================================== --- dns.h (revision 1135) +++ dns.h (working copy) @@ -18,6 +18,7 @@ #ifndef __DNS_H__ #define __DNS_H__ +#include "buffer.h" #include "types.h" /* Define a list of dns types. Windows defines these automatically, @@ -25,6 +26,9 @@ #ifndef DNS_TYPE_A typedef enum { + /* A special type that I use internally. */ + DNS_TYPE_RAW = 0xFFFF, + /* RFC 1034/1035 */ DNS_TYPE_A = 0x0001, DNS_TYPE_NS = 0x0002, @@ -183,6 +187,17 @@ uint8_t length; } TEXT_answer_t; +/* A NAPTR record has flags, services, a regular expression, and a replacement. */ +typedef struct +{ + uint16_t order; + uint16_t preference; + char *flags; + char *services; + char *regexp; + char *replacement; +} NAPTR_answer_t; + /* A NetBIOS answer (NB) is used by Windows on port 137. */ typedef struct { @@ -206,6 +221,12 @@ uint8_t stats[64]; } NBSTAT_answer_t; +typedef struct +{ + uint8_t *data; + uint16_t data_length; +} RAW_answer_t; + /* Let us refer to any kind of answer type together. */ typedef union { @@ -217,8 +238,10 @@ #ifndef WIN32 AAAA_answer_t AAAA; #endif + NAPTR_answer_t NAPTR; NB_answer_t NB; NBSTAT_answer_t NBSTAT; + RAW_answer_t RAW; } answer_types_t; /* And finally, define a DNS answer. */ @@ -327,6 +350,9 @@ additional_t *additionals; } dns_t; +/* An extension to the buffer class to add encoded DNS names. */ +void buffer_add_dns_name(buffer_t *buffer, char *name); + /* Allocate memory for a blank dns structure. Should be freed with dns_free(). */ dns_t *dns_create(); @@ -354,7 +380,9 @@ #ifndef WIN32 void dns_add_answer_AAAA(dns_t *dns, char *question, uint16_t class, uint32_t ttl, char *address); #endif +void dns_add_answer_NAPTR(dns_t *dns, char *question, uint16_t class, uint32_t ttl, uint16_t order, uint16_t preference, char *flags, char *services, char *regexp, char *replacement); void dns_add_answer_NB(dns_t *dns, char *question, uint8_t question_type, char *scope, uint16_t class, uint32_t ttl, uint16_t flags, char *address); +void dns_add_answer_RAW(dns_t *dns, uint8_t *data, uint16_t data_length); /* These functions add additionals of the various types. */ void dns_add_additional_A(dns_t *dns, char *question, uint16_t class, uint32_t ttl, char *address); Index: Makefile =================================================================== --- Makefile (revision 1135) +++ Makefile (working copy) @@ -14,7 +14,7 @@ LIBS= CFLAGS+=$(COMMON_CFLAGS) -all: nbquery nbsniff dnsxss dnslogger dnscat dnstest samples_build +all: nbquery nbsniff dnsxss dnslogger dnsms11-058 dnscat dnstest samples_build @echo Compile should be complete samples_build: @@ -33,6 +33,7 @@ ldid -S smbserver ldid -S dnsxss ldid -S dnslogger + ldid -S dnsms11-058 ldid -S dnscat ldid -S dnstest @@ -42,12 +43,14 @@ cp nbsniff /usr/local/bin/nbsniff cp dnsxss /usr/local/bin/dnsxss cp dnslogger /usr/local/bin/dnslogger + cp dnsms11-058 /usr/local/bin/dnsms11-058 cp dnscat /usr/local/bin/dnscat cp dnstest /usr/local/bin/dnstest chown root.root /usr/local/bin/nbquery chown root.root /usr/local/bin/nbsniff chown root.root /usr/local/bin/dnsxss chown root.root /usr/local/bin/dnslogger + chown root.root /usr/local/bin/dnsms11-058 chown root.root /usr/local/bin/dnscat chown root.root /usr/local/bin/dnstest @@ -59,13 +62,14 @@ rm -f /usr/local/bin/genhash rm -f /usr/local/bin/dnsxss rm -f /usr/local/bin/dnslogger + rm -f /usr/local/bin/dnsms11-058 rm -f /usr/local/bin/dnscat rm -f /usr/local/bin/dnstest uninstall: remove clean: - rm -f *.o *.exe *.stackdump nbquery nbregister nbpoison nbsniff genhash dnsxss dnslogger dnscat dnstest smbserver smbtest core + rm -f *.o *.exe *.stackdump nbquery nbregister nbpoison nbsniff genhash dnsxss dnslogger dnsms11-058 dnscat dnstest smbserver smbtest core rm -f nbtool buffer select_group crypto smbclient -cd samples && make clean @@ -90,6 +94,9 @@ dnslogger: dnslogger.o buffer.o tcp.o udp.o select_group.o types.o memory.o dns.o ${CC} ${CFLAGS} -o dnslogger dnslogger.o buffer.o tcp.o udp.o select_group.o types.o memory.o dns.o ${LIBS} +dnsms11-058: dnsms11-058.o buffer.o tcp.o udp.o select_group.o types.o memory.o dns.o + ${CC} ${CFLAGS} -o dnsms11-058 dnsms11-058.o buffer.o tcp.o udp.o select_group.o types.o memory.o dns.o ${LIBS} + #smbtest: smbtest.o smbclient.o buffer.o udp.o tcp.o select_group.o smb.o nameservice.o crypto.o smb_types.o memory.o types.o # ${CC} ${CFLAGS} -o smbtest smbtest.o smbclient.o buffer.o udp.o tcp.o select_group.o smb.o nameservice.o crypto.o smb_types.o memory.o types.o ${LIBS} Index: dnsms11-058.c =================================================================== --- dnsms11-058.c (revision 0) +++ dnsms11-058.c (revision 0) @@ -0,0 +1,515 @@ +/* dnslogger.c + * By Ron Bowes + * Created January, 2010 + * + * (See LICENSE.txt) + * + *==Intro== + * [[dnslogger]] has two primary functions: + * # Print all received DNS requests + * # Reply to them with an error or a static ip address (IPv4 or IPv6) + * + * This is obviously very simple, but is also powerful. + * + *==Usage== + *
+ * -h --help + * Help (this page) + * --test+ * + *==Printing requests== + * Printing DNS requests has a lot of uses. Essentially, it'll tell you if + * a program tried to connect to your site, without the program ever + * attempting the connection. There are a great number of possible uses for + * that: + * * Finding open proxies without making an actual connection through it + * * Finding open mail relays without sending an email through it + * * Finding errors in mail-handling code on a site + * * Finding shell injection on a Web application without outbound traffic or delays + * * Checking if a user visited a certain page + * + * In every one of those cases, the server will try to look up the domain name + * to perform some action, and fails. For example, to find an open proxy you + * can connect to the potential proxy and send it "CONNECT+ * Test to see if we are the authoritative nameserver for the given domain. + * -s --source + * The local address to bind to. Default: any (0.0.0.0) + * -p --port + * The local port to listen on. I don't recommend changing this. + * default: 53 + * -A + * The A record to return when a record is requested. Default: NXDOMAIN. + * --AAAA + * The AAAA record to return when a record is requested. Default: NXDOMAIN. + * --TTL
+ * $ ping www.skullseclabs.org + * ping: unknown host www.skullseclabs.org + *+ * + * dnslogger, however, will have seen the request and we therefore know that + * the application is vulnerable. This is far more reliable than the classic + * 'ping localhost 4 times and see if it takes 3 seconds' approach to finding + * shell injection. + * + * One final note is discovering Web applications that handle email incorrectly. + * A classic vulnerability when sending email, besides shell injection, is + * letting the user terminate the email with a "." on its own line, then start + * a new email. Something like this: + *
+ * This is my email, hello! + * . + * mail from: test@test.com + * rcpt to: test@+ * + * So the first email was terminated on the second line, with a period. A new + * email is composed to test@+ * data + * This email won't get sent! + *