what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

bindinfo.c

bindinfo.c
Posted Sep 29, 1999
Authored by Joshua James Drake

Bindinfo v1.01: allows root to make DNS queries behind firewalls. Works on Solaris, OpenBSD.

tags | root
systems | unix, solaris, openbsd
SHA-256 | e29d6b8da305c8f8800aec4d238d658d7d8ec51f60cf8b5a1659907388cfb189

bindinfo.c

Change Mirror Download
/*
* This code was written by:
* Joshua James Drake (jdrake@pulsar.net)
*
* Published 6/9/98 @ 12:02 AM
*
* The following lines of code are, in a nutshell, written to pry
* some information from a nameserver. The information it gives
* you may or may not be useful. That is for you to decide.
*
* However, it will tell you if the server supports IQUERY and, if
* possible, what version of bind (by Paul Vixie) it is running.
*
*/

/* --- code was modified to allow root users to send queries using source
--- port 53 in order to query behind (some) packet filters
---
--- version v1.00 torh@bogus.net 29/9/1999
|
+-does not seem to work with Linux (won't run)
| fixes appreciated!
|
+-does not seem to work with OpenBSD (source port still random)
| fixes appreciated!
|
+- COMPILE WITH gcc -DSOLARIS -lsocket -lnsl (tested on Solaris 2.6)

--- version v1.01 torh@bogus.net 29/9/1999
|
+-now works with OpenBSD (tested on 2.4)

*/

/* local type includes */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <sys/errno.h>
/* network type includes */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <netdb.h>

/* another addition for 2.6 / torh */

#ifdef SOLARIS
#include <errno.h>
#endif

/* bulky shit for printing dnspkts need to link dnspkt.o from dnspkt.c too */
#ifdef DEBUG
#include "dnspkt.h"
#endif

/* prototypes */
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);

/*
* here we simply check arguments, resolve the hostname given and
* if all is well, initialize the radom seed and probe away.
*/
void
main(argc, argv)
int argc;
char *argv[];
{
struct sockaddr_in ra;

if (argc != 2)
{
printf("usage: %s <host>\n", argv[0]);
return;
}
if (!lookup_host(&ra, argv[1], NAMESERVER_PORT))
return;
srand(time(NULL));
probe_bind(ra);
}

/*
* resolve a hostname to a sockaddr_in struct.
* we first try treating it like an ip address in a.b.c.d notation
* then, if that fails, we try to resolve using DNS ways
* if all fails, we return 0. (failed)
* if we get the sockaddr_in struct all filled out, we return 1.
*/
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;
}
#ifdef SOLARIS
perror("Unable to resolve hostname");
#else
herror("Unable to resolve hostname");
#endif
return 0;
}

/*
* here we allocate some space for our packets and make sure it's
* "fullanull". then we attempt to allocate and setup our socket.
* if failure occurs, we shall report error and return.
* the we attempt to reverse our address in the sockaddr_in structure
* passed as the only argument into a dns name, if that fails, we go
* with the ascii ip address representation. then we attempt to
* communicate the remote server, if failure, we return. after we
* have successfully got our packets back, we close the socket and
* print out a summary of what we got.
*/
void
probe_bind(ra)
struct sockaddr_in ra;
{
int sd;
char iquery[512], vquery[512], rname[256];
struct hostent *he;

/* --- in order to manipulate source details, use another sockaddr
--- struct (sa), which contains source port and source ip / torh */

struct sockaddr_in sa;
char localhost[128+1];
struct hostent *hp;

HEADER *dh = (HEADER *)iquery;

memset(vquery, 0, sizeof(vquery));
memset(iquery, 0, sizeof(iquery));

/* --- this portion has been modified so that root issues source_port=53
--- in attempt to bypass packet filters / torh */

if(getuid()) {

/* --- running as luser, no special privs, use original code / torh */

printf("Unable to set source port < 1024, using luser privileges (random port).\n");

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;
}

} else {

/* --- running as root, so we are allowed to force the source port
--- value / torh */

printf("This code is executing as root, assuming source port 53.\n");

if((sd = socket(AF_INET,SOCK_DGRAM,0)) == -1) {
perror("Unable to create socket()");
return;
}

/* --- set localhost information / torh */

gethostname(localhost, 128);
printf("localhost: %s\n", localhost);
if ((hp = gethostbyname(localhost)) == NULL) {
perror("Couldn't resolve localhost");
return;
}

/* --- change source port, and bind the socket file descriptor
--- with the new host/port pair / torh */

sa.sin_family=AF_INET;
bcopy(hp->h_addr,(char *)&sa.sin_addr,hp->h_length);
sa.sin_port=htons(53);
if(bind(sd,(struct sockaddr *)&sa,sizeof(sa)) == -1) {
perror("Unable to bind()");
if(sd != -1) {close(sd);}
return;
}

if(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("read failed");
close(sd);
return 0;
}
#ifdef DEBUG
printf("read success\n");
#endif
alarm(0);
return 1;
}

/*
* this forms a valid dns packet based on the op code given by opc.
* only two opcodes are supported because that's all we need to support.
* the packet ends up in pktbuf and the length of the packet is returned.
*/
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;
}

/*
* This function takes a DNS packet in buf, and whether or not it reponds to IQUERY in vul.
* We cast the packet and extract the response as long as there is one.
* If there isn't one, then we assume that the remote server is an old version of bind.
* this is the end of the line.
*/
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 */
printf("%s's named that %s iquery is version: %s\n", host, vul ? "supports" : "errors on", 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
}


Login or Register to add favorites

File Archive:

April 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    10 Files
  • 2
    Apr 2nd
    26 Files
  • 3
    Apr 3rd
    40 Files
  • 4
    Apr 4th
    6 Files
  • 5
    Apr 5th
    26 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    22 Files
  • 9
    Apr 9th
    14 Files
  • 10
    Apr 10th
    10 Files
  • 11
    Apr 11th
    13 Files
  • 12
    Apr 12th
    14 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    30 Files
  • 16
    Apr 16th
    10 Files
  • 17
    Apr 17th
    22 Files
  • 18
    Apr 18th
    45 Files
  • 19
    Apr 19th
    8 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    11 Files
  • 23
    Apr 23rd
    68 Files
  • 24
    Apr 24th
    0 Files
  • 25
    Apr 25th
    0 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close