COMMAND
Netscape
SYSTEMS AFFECTED
Netscape 3.0...4.73
PROBLEM
Solar Designer found following. This advisory explains a
vulnerability in Netscape browsers present since at least version
3.0 and up to Netscape 4.73 and Mozilla M15. The vulnerability
is fixed in Netscape 4.74 and Mozilla M16.
It may be possible, although hard to do reliably in a real-world
attack, for a malicious web site to execute arbitrary assembly
code in the context of the web browser. In the case of Netscape
Mail or News, the attack may be performed via a mail message or a
news article, as well.
JPEG interchange format streams consist of an ordered collection
of markers, parameters, and entropy-coded data segments. Many
markers start marker segments, which consist of the marker
followed by a sequence of related parameters. Marker segments are
of a variable length, with the first parameter being the two-byte
length. The encoded length includes the size of the length
parameter itself. Thus, lengths smaller than 2 are always
invalid.
Netscape browsers use the Independent JPEG Group's decoder library
for JPEG File Interchange Format (JFIF) files. However, they
install a custom handler for processing the COM (comment) marker
that stores the comment in memory rather than just skip it like
the library would do. Unfortunately, the new handler doesn't
check whether the length field is valid, and subtracts 2 from the
encoded length to calculate the length of the comment itself. It
then allocates memory for the comment (with one additional byte
for its NUL termination) and goes into a loop to read the comment
into that memory.
By setting the length field to 1, it is possible to ensure the
memory allocation call (of 0 bytes) will succeed. As the
calculated comment length is declared unsigned, it will be a huge
positive value rather than a small negative one, so the loop won't
terminate until the end of JPEG stream. It will read the JPEG
stream onto the heap, possibly overwriting other dynamically
allocated buffers of Netscape, as well as structures internal to
the malloc(3) implementation. Exploiting this vulnerability into
executing arbitrary code is non-trivial, but possible on some
platforms.
Is this problem in the lack of error checking in the code?
Indeed. A programmer's fault. Is this a problem because of the
choice of a programming language that doesn't offer overflow
checking and with compilers that traditionally don't offer bound
checking? Partially.
However, let's see how many different file formats, languages, and
protocols a modern web browser has to support. Have all of the
file parsers been initially implemented with intent to be robust
against untrusted and possibly malicious data? If not, have all
possible cases been covered with additional checks now? Do we
have a reason to believe there're no bugs in the implementation
of any of those, or do we have reasons to suspect the opposite?
The vulnerability lets us overwrite heap locations beyond the end
of allocated area. We're limited to printable characters, NUL,
and LF. Thus, the ability to exploit this into doing more than a
crash will depend on locale settings on some platforms.
First, we need to decide on what we overwrite. Structures
internal to the dynamic memory implementation are the most
promising target: they're always there and they typically contain
pointers. For the example below, we'll assume Doug Lea's malloc
(which is used by most Linux systems, both libc 5 and glibc) and
locale for an 8-bit character set (such as most locales that come
with glibc, including en_US, or ru_RU.KOI8-R).
The following fields are kept for every free chunk on the list:
size of the previous chunk (if free), this chunk's size, and
pointers to next and previous chunks. Additionally, bit 0 of the
chunk size is used to indicate whether the previous chunk is in
use (LSB of actual chunk size is always zero due to the structure
size and alignment).
By playing with these fields carefully, it is possible to trick
calls to free(3) into overwriting arbitrary memory locations with
our data. free(3) checks if a chunk adjacent to the one being
freed is in use and, if not, consolidates the two chunks by
unlinking the adjacent chunk from the list. Unlinking a chunk
involves setting the previous chunk's "next" pointer and the next
chunk's "previous" pointer, where both of these chunks are
addressed via pointers from the chunk being unlinked. Thus, in
order to get control over these memory writes, we need to
overwrite the two pointers within a chunk (or maybe allocated
memory at the time) and preferably reset the PREV_INUSE flag of
the next chunk. This takes 13 bytes on a 32-bit little endian,
such as Linux/x86 (8 bytes for the two pointers, four bytes
placeholder for the previous size field, and 1 byte to reset the
flag). In practice, we would want to repeat the desired 16-byte
pattern (of which only 9 bytes matter) at least several times to
increase our chances in case of larger allocated chunks.
The overwritten pointers each serve as both the address and the
data being stored, which limits our choice of data: it has to be a
valid address as well, and memory at that address should be
writable.
Now we need to decide what pointer we want to overwrite (there's
not that much use in overwriting a non-pointer with an address).
A good candidate would be any return address on the stack. That
would work, but not be very reliable as the location of a return
address depends on how much other data is on the stack, including
program arguments, and that is generally not known for a remote
attack. A better target would be a function pointer. We don't
want to guess exact locations on the stack and we can't get to the
ELF sections on x86 (BS isn't a printable character), so we're
effectively limited to pointers within shared libraries. A nice
one we can use is __free_hook, so that the second call to free(3)
will give us the control. The debugging hooks are always compiled
in when Doug Lea's code is a part of GNU libc.
Our next decision is about where we want the control transferred.
We would definitely prefer to have our "shellcode" within the JFIF
file itself. However, the character set restriction might prevent
us from passing heap addresses. We have to settle on the stack
and place our code in there via other parts of the browser prior
to the overflow. We can use a bunch of NOP's or equivalent to
avoid having to provide an exact stack location. A compiler to
produce JFIF files implementing the above approach is included in
the accompanying archive.
Please note that this is by no means limited to Linux/x86. It's
just that one platform had to be chosen for the example. So far,
this is known to be exploitable on at least one Win32 installation
in a very similar way (via ntdll!RtlFreeHeap).
Additional programs and example JFIF files mentioned in this
advisory are provided in the accompanying archive, which can be
downloaded via one of these links:
http://www.openwall.com/advisories/OW-002-netscape-jpeg-r1.tar.gz
http://www.openwall.com/advisories/OW-002-1.zip
JPEG interchange format is documented in ISO International
Standard 10918-1 and CCITT (now ITU-T) Recommendation T.81. JFIF
specification and the IJG library are available at:
ftp://ftp.uu.net/graphics/jpeg/
SOLUTION
Solutions? There's little an end user can do, but you can take
this advisory as yet another reminder to run the web browser you
use to access untrusted content in a restricted environment,
without access to your most critical data. Unfortunately, this
isn't easy to do in the Win32 world, yet.
Upgrade to Netscape 4.74 or Mozilla M16, or newer. Alternatively,
Mozilla users can apply the following patch (against Milestone 15)
and rebuild the sources:
--- mozilla/modules/libimg/jpgcom/jpeg.cpp.orig Tue Mar 28 02:08:15 2000
+++ mozilla/modules/libimg/jpgcom/jpeg.cpp Wed May 24 17:24:03 2000
@@ -469,6 +469,10 @@
/* Get 16-bit comment length word. */
INPUT_2BYTES(cinfo, length, return FALSE);
+ if (length < 2) {
+ cinfo->err->msg_code = JERR_BAD_LENGTH;
+ il_error_exit((j_common_ptr)cinfo);
+ }
length -= 2; /* discount the length word itself */
PR_FREEIF(ic->comment);
For Red Hat:
i386: ftp://updates.redhat.com/5.2/i386/netscape-common-4.74-0.5.2.i386.rpm
ftp://updates.redhat.com/5.2/i386/netscape-communicator-4.74-0.5.2.i386.rpm
ftp://updates.redhat.com/5.2/i386/netscape-navigator-4.74-0.5.2.i386.rpm
ftp://updates.redhat.com/6.2/i386/netscape-common-4.74-0.6.2.i386.rpm
ftp://updates.redhat.com/6.2/i386/netscape-communicator-4.74-0.6.2.i386.rpm
ftp://updates.redhat.com/6.2/i386/netscape-navigator-4.74-0.6.2.i386.rpm
sources: ftp://updates.redhat.com/5.2/SRPMS/netscape-4.74-0.5.2.src.rpm
ftp://updates.redhat.com/6.2/SRPMS/netscape-alpha-4.74-1.src.rpm
ftp://updates.redhat.com/6.2/SRPMS/netscape-4.74-0.6.2.src.rpm
alpha: ftp://updates.redhat.com/6.2/alpha/netscape-common-4.74-1.alpha.rpm
ftp://updates.redhat.com/6.2/alpha/netscape-communicator-4.74-1.alpha.rpm
ftp://updates.redhat.com/6.2/alpha/netscape-navigator-4.74-1.alpha.rpm
For Linux-Mandrake:
6.0/RPMS/netscape-common-4.74-2mdk.i586.rpm
6.0/RPMS/netscape-communicator-4.74-2mdk.i586.rpm
6.0/RPMS/netscape-navigator-4.74-2mdk.i586.rpm
6.0/SRPMS/netscape-4.74-2mdk.src.rpm
6.1/RPMS/netscape-common-4.74-2mdk.i586.rpm
6.1/RPMS/netscape-communicator-4.74-2mdk.i586.rpm
6.1/RPMS/netscape-navigator-4.74-2mdk.i586.rpm
6.1/SRPMS/netscape-4.74-2mdk.src.rpm
7.0/RPMS/netscape-castellano-4.74-1mdk.noarch.rpm
7.0/RPMS/netscape-common-4.74-2mdk.i586.rpm
7.0/RPMS/netscape-communicator-4.74-2mdk.i586.rpm
7.0/RPMS/netscape-francais-4.74-2mdk.noarch.rpm
7.0/RPMS/netscape-navigator-4.74-2mdk.i586.rpm
7.0/RPMS/netscape-walon-4.74-1mdk.noarch.rpm
7.0/SRPMS/netscape-4.74-2mdk.src.rpm
7.0/SRPMS/netscape-castellano-4.74-1mdk.src.rpm
7.0/SRPMS/netscape-francais-4.74-2mdk.src.rpm
7.0/SRPMS/netscape-walon-4.74-1mdk.src.rpm
7.1/RPMS/netscape-castellano-4.74-1mdk.noarch.rpm
7.1/RPMS/netscape-catalan-4.74-1mdk.noarch.rpm
7.1/RPMS/netscape-common-4.74-2mdk.i586.rpm
7.1/RPMS/netscape-communicator-4.74-2mdk.i586.rpm
7.1/RPMS/netscape-euskara-4.74-1mdk.noarch.rpm
7.1/RPMS/netscape-francais-4.74-2mdk.noarch.rpm
7.1/RPMS/netscape-navigator-4.74-2mdk.i586.rpm
7.1/RPMS/netscape-walon-4.74-1mdk.noarch.rpm
7.1/SRPMS/netscape-4.74-2mdk.src.rpm
7.1/SRPMS/netscape-castellano-4.74-1mdk.src.rpm
7.1/SRPMS/netscape-catalan-4.74-1mdk.src.rpm
7.1/SRPMS/netscape-euskara-4.74-1mdk.src.rpm
7.1/SRPMS/netscape-francais-4.74-2mdk.src.rpm
7.1/SRPMS/netscape-walon-4.74-1mdk.src.rpm
For TurboLinux:
netscape-communicator-4.74-2.i386.rpm
netscape-communicator-4.74-2.src.rpm
SuSE provides an updated package for the vulnerable software.
The update package introduces Netscape version 4.75, including the
SuSE-specific libraries that fix some of Netscape's "irregular"
behaviour. Please note that Netscape-4.75 is not available for
the glibc-2.0-based SuSE Distributions SuSE-6.0 and 6.1 because
Netscape doesn't provide any files for this glibc version. For
these distributions, SuSE provides Netscape Version 4.74 which
fixes problem. Alternatively, the package for the libc5-based
SuSE-5.3 distribution can be used as well if the package 'shlibs5'
is installed. This is recommended, since the 5.3 package may be
faster and more reliable:
ftp://ftp.gwdg.de/pub/linux/suse/6.4_update_de/xap1/netscape.rpm
As for NetBSD versions of Netscape Communicator and Navigator
older than version 4.74 are vulnerable. To find out the version
of Communicator or Navigator installed on your NetBSD system, you
can use pkg_info(1):
# pkg_info -e communicator-\*
# pkg_info -e navigator-\*
If Communicator or Navigator is not installed on your system, no
output will be generated, and your system is not vulnerable to
this problem. If you have a version older than 4.74, you should
upgrade to version 4.74 (or newer) of Netscape Communicator
and/or Navigator. A corrected version has been part of the NetBSD
packages collection since 25th July 2000. If a vulnerable version
of Communicator or Navigator is installed, then you should
immediately remove the vulnerability by deleting the package. As
root, type:
# pkg_delete -v communicator-\*
# pkg_delete -v navigator-\*
If you continue to need Communicator or Navigator, you should
install a new version of the package. You can use the pkgsrc
infrastructure to download the precompiled binaries directly from
their home site. First, make sure that you have a version of the
pkgsrc hierarchy from 25th July 2000 or later. You can then
install the new version of the packages:
cd pkgsrc/www/communicator; make clean; make install
and/or
cd pkgsrc/www/navigator; make clean; make install
For Conectiva Linux:
ftp://atualizacoes.conectiva.com.br/4.0/i386/netscape-common-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/4.0/i386/netscape-communicator-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/4.0/i386/netscape-navigator-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/4.0es/i386/netscape-common-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/4.0es/i386/netscape-communicator-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/4.0es/i386/netscape-navigator-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/4.1/i386/netscape-common-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/4.1/i386/netscape-communicator-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/4.1/i386/netscape-navigator-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/4.2/i386/netscape-common-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/4.2/i386/netscape-communicator-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/4.2/i386/netscape-navigator-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/5.0/i386/netscape-common-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/5.0/i386/netscape-communicator-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/5.0/i386/netscape-navigator-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/5.1/i386/netscape-common-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/5.1/i386/netscape-communicator-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/5.1/i386/netscape-navigator-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/ferramentas/ecommerce/i386/netscape-common-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/ferramentas/ecommerce/i386/netscape-communicator-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/ferramentas/ecommerce/i386/netscape-navigator-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/ferramentas/graficas/i386/netscape-common-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/ferramentas/graficas/i386/netscape-communicator-4.74-1cl.i386.rpm
ftp://atualizacoes.conectiva.com.br/ferramentas/graficas/i386/netscape-navigator-4.74-1cl.i386.rpm
For FreeBSD deinstall the netscape port/package, if you you have
installed it. Solution is one of the following:
1) Upgrade your entire ports collection and rebuild the relevant
netscape port.
2) Deinstall the old package and install a new package dated
after the correction date, obtained from the following
directories:
ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/i386/packages-3-stable/www/
ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/i386/packages-4-stable/www/
ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/alpha/packages-4-stable/www/
ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/i386/packages-5-current/www/
ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/alpha/packages-5-current/www/
3) download a new port skeleton for the netscape port from:
http://www.freebsd.org/ports/
and use it to rebuild the port.