/*********************************************/ /* namedscan.c will check the named version */ /* of a host, and tell you if its a vuln version */ /***********************************************/ /* buffer0verfl0w security */ /*******************************/ /* coded by eth0 from b0f */ /* [http://www.b0f.com] */ /*******************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int lookup_host(struct sockaddr_in *ra, char *hn, unsigned short rp); void probe_bind(struct sockaddr_in ra); int talk(int sd, char *pkt, int pktl, char opc); int make_keypkt(char *pktbuf, char opc); void print_ver(char *host, int vul, char *buf); void handle_alarm(int signum); int lookup_host(ra, hn, rp) struct sockaddr_in *ra; char *hn; unsigned short rp; { struct hostent *he; ra->sin_family = AF_INET; ra->sin_port = htons(rp); if ((ra->sin_addr.s_addr = inet_addr(hn)) != -1) return 1; if ((he = gethostbyname(hn)) != (struct hostent *)NULL) { memcpy(&ra->sin_addr.s_addr, he->h_addr, 4); return 1; } herror("Unable to resolve hostname"); return 0; } void probe_bind(ra) struct sockaddr_in ra; { int sd; char iquery[512], vquery[512], rname[256]; struct hostent *he; HEADER *dh = (HEADER *)iquery; memset(vquery, 0, sizeof(vquery)); memset(iquery, 0, sizeof(iquery)); if (((sd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) || (connect(sd, (struct sockaddr *)&ra, sizeof(ra)) == -1)) { perror("Unable to connect"); if (sd != -1) close(sd); return; } if ((he = gethostbyaddr((char *)&ra.sin_addr, sizeof(ra.sin_addr), AF_INET)) == (struct hostent *)NULL) sprintf(rname, "%s", inet_ntoa(ra.sin_addr)); else strncpy(rname, he->h_name, sizeof(rname)); if (!talk(sd, iquery, sizeof(iquery), IQUERY)) return; if (!talk(sd, vquery, sizeof(vquery), QUERY)) return; close(sd); /* if dh->rcode == 0, then our iquery request was answered and the remote server supports iquery */ print_ver(rname, dh->rcode == 0, vquery); } /* * write our packet from pkt, wait for a response and put it in pkt. * if the alarm goes off or the read fails, we print error * and return 0. otherwise, our response packet is in pkt and we return 1. */ int talk(sd, pkt, pktl, opc) int sd, pktl; char *pkt, opc; { int pktlen; pktlen = make_keypkt(pkt, opc); if (!write(sd, pkt, pktlen)) { perror("write failed"); close(sd); return 0; } /* #ifdef DEBUG printf("write() success\n"); #endif */ siginterrupt(SIGALRM, 1); signal(SIGALRM, handle_alarm); alarm(3); pktlen = read(sd, pkt, pktl); if (pktlen <= 0) { if (errno == EINTR) errno = ETIMEDOUT; perror("<[Namedscan]>:([ Read Failed *shrugs* ]) -> read failed"); close(sd); return 0; } /* #ifdef DEBUG printf("read success\n"); #endif */ alarm(0); return 1; } int make_keypkt(pktbuf, opc) char *pktbuf; char opc; { HEADER *dnsh; char *ptr = pktbuf; int pktlen = 0; dnsh = (HEADER *) ptr; /* fill out the parts of the DNS header that aren't 0 */ dnsh->id = htons(rand() % 65535); dnsh->opcode = opc; dnsh->rd = 1; dnsh->ra = 1; /* one answer for IQUERY, one question for QUERY */ if (opc == IQUERY) dnsh->ancount = htons(1); else if (opc == QUERY) dnsh->qdcount = htons(1); pktlen += sizeof(HEADER); ptr += sizeof(HEADER); /* we have to make a QUERY, fill out the question section */ if (opc == QUERY) { /* version.bind. == elite */ char qstr[] = "\007version\004bind\000"; int qlen = strlen(qstr) + 1; memcpy(ptr, qstr, qlen); ptr += qlen; pktlen += qlen; PUTSHORT(T_TXT, ptr); PUTSHORT(C_CHAOS, ptr); pktlen += sizeof(short) * 2; } /* add a resource record for the inverse query */ else if (opc == IQUERY) { unsigned long addr = inet_addr("1.2.3.4"); unsigned long ttl = 31337; unsigned short addrlen = 4; *(ptr++) = '\0'; pktlen++; PUTSHORT(T_A, ptr); PUTSHORT(C_IN, ptr); PUTLONG(ttl, ptr); PUTSHORT(addrlen, ptr); PUTLONG(addr, ptr); pktlen += (sizeof(short) * 3) + (sizeof(long) * 2); } /* if we're debugging, show what we just made */ /* #ifdef DEBUG print_dnspkt(pktbuf, pktbuf + pktlen); #endif */ return pktlen; } int checknamed(char *verstr) { if(strstr(verstr,"4.9.5")||strstr(verstr,"4.9.6-REL") || strstr(verstr,"4.9.5-REL")||strstr(verstr,"4.9.5-P1")||strstr(verstr, "8.1-REL") ||strstr(verstr,"8.1.1")||strstr(verstr,"8.2")||strstr(verstr,"8.2.1")) { if(strstr(verstr,"8.2.2-P5")||strstr(verstr,"8.2.2-P4")||strstr(verstr,"8.2.2-P3")||strstr(verstr,"8.2.2-P2")){printf("<[Name d Version [%s] ]>\n",verstr);return(0);} printf("<[Named version [%s]]> Possible Vuln\n",verstr); } else { printf("<[No named vulns found. version [%s]]>\n",verstr); } return(0); } void print_ver(host, vul, buf) char *host, *buf; int vul; { HEADER *dnsh = (HEADER *)buf; char *ptr, *verstr; int len; if (dnsh->rcode != 0) { /* printf("%s's named that %s iquery does not respond to version.bind.\n", host, vul ? "supports" : "errors on"); */ return; } /* So we actually have a response. Lets skip the crap, starting with the header */ ptr = (buf + sizeof(HEADER)); /* then the question section domain name. */ while (*ptr != '\0') ptr++; /* then the trailing null and the type/class of the question */ ptr += 1 + (sizeof(short) * 2); /* now we skip the answer section domain name. (should be the same as the question) */ while (*ptr != '\0') ptr++; /* don't forget the trailing null, type, class, and time to live. */ ptr += 1 + (sizeof(long) + (sizeof(short) * 2)); /* Here we are at the resource record data length, extract it */ GETSHORT(len, ptr); /* avoid the need to decompress the string (treat it as one) */ ptr++; /* allocate space for and copy the version response txt */ verstr = (char *)malloc(len); memset(verstr, 0, len); memcpy(verstr, ptr, len-1); /* run through the vesion string and replace non-printable and non-whitespace characters with a '.' */ for (ptr = verstr; ptr - verstr != len - 1; ptr++) if (!isprint(*ptr) && !isspace(*ptr)) *ptr = '.'; /* print the version and iquery support status, woo hoo */ #ifdef debugz printf("%s's named that %s iquery is version: %s\n", host, vul ? "supports" : "errors on", verstr); #endif checknamed(verstr); } /* * handle the alarm signal by resetting the alarm timer and * the signal handler for SIGALRM. This stuff probably isn't needed, * but I did it anyway. It's good for debugging, ran into some problems with * alarm() not doing its job. */ void handle_alarm(signum) int signum; { alarm(0); signal(SIGALRM, SIG_DFL); /* #ifdef DEBUG printf("recieved alarm\n"); #endif */ } int main(int argc, char *argv[]) { struct in_addr addr; struct sockaddr_in sin; struct hostent *he; int sock; struct sockaddr_in ra; if(argv[1]==NULL) { printf("coded by eth0 [b0f]\n"); printf("Usage: %s [host]\n",argv[0]); exit(1); } if ((he=gethostbyname(argv[1])) == NULL) { herror("gethostbyname"); exit(0); } if (!lookup_host(&ra, argv[1], NAMESERVER_PORT)) return; srand(time(NULL)); probe_bind(ra); return(0); }