4 vulnerabilities in libpurple
Mark Doliner
mark at kingant.net
Sun Apr 13 01:20:12 EDT 2014
Hi! I fixed the three remaining issues in our private code repo. We're
still working on a few other issues and we don't yet have an ETA for
release. We'll keep you updated on any progress.
On Sun, Feb 9, 2014 at 12:45 PM, Daniel Atallah
<daniel.atallah at gmail.com> wrote:
> VRT-2014-0203 - Pidgin libpurple Mxit Emoticon ASN Length Denial of Service
> Vulnerability:
> This looks legitimate and still exists in Pidgin 2.10.9
I fixed this in our private 2.x.y repo (patch attached in case you'd
like to review it).
> VRT-2014-0205 - Pidgin libpurple Novell Protocol Multiple Denial of Service
> Vulnerabilities:
> This looks legitimate and still exists in Pidgin 2.10.9.
> The title for this one in the file refers to Gadu-Gadu - I assume that's
> just a copy/paste error.
I fixed this in our private 2.x.y repo (patch attached in case you'd
like to review it).
> VRT-2014-0205 - Pidgin Theme/Smiley Untar Arbitrary File Write
> Vulnerability:
> This looks legitimate and still exists in Pidgin 2.10.9
I fixed this in our private 2.x.y repo (patch attached in case you'd
like to review it). Were you guys actually able to exploit this? I
wasn't able to. I could not drag links from a browser to the smiley
pane of prefs in Windows. I could drag a local file from Windows
Explorer to the smiley window, but of course that's a valid file name.
-------------- next part --------------
diff -r 6c4d5b524296 -r 6436e14bdb9d ChangeLog
--- a/ChangeLog Mon Mar 24 20:01:11 2014 -0400
+++ b/ChangeLog Mon Apr 07 23:45:55 2014 -0700
@@ -12,6 +12,11 @@ version 2.10.10 (?/?/?):
Gadu-Gadu:
* Updated internal libgadu to version 1.12.0-rc2.
+ MXit:
+ * Fix potential remote crash parsing a malformed emoticon response.
+ (Discovered by Yves Younan and Richard Johnson of Sourcefire VRT)
+ (CVE-2014-NNNN)
+
version 2.10.9 (2/2/2014):
XMPP:
* Fix problems logging into some servers including jabber.org and
diff -r 6c4d5b524296 -r 6436e14bdb9d libpurple/protocols/mxit/markup.c
--- a/libpurple/protocols/mxit/markup.c Mon Mar 24 20:01:11 2014 -0400
+++ b/libpurple/protocols/mxit/markup.c Mon Apr 07 23:45:55 2014 -0700
@@ -163,16 +163,22 @@ void mxit_add_html_link( struct RXMsgDat
* Extract an ASN.1 formatted length field from the data.
*
* @param data The source data
+ * @param data_len Length of data
* @param size The extracted length
* @return The number of bytes extracted
*/
-static unsigned int asn_getlength( const gchar* data, int* size )
+static unsigned int asn_getlength( const gchar* data, gsize data_len, int* size )
{
unsigned int len = 0;
unsigned char bytes;
unsigned char byte;
int i;
+ if ( data_len < 1 ) {
+ /* missing first byte! */
+ return -1;
+ }
+
/* first byte specifies the number of bytes in the length */
bytes = ( data[0] & ~0x80 );
if ( bytes > sizeof( unsigned int ) ) {
@@ -181,6 +187,11 @@ static unsigned int asn_getlength( const
}
data++;
+ if ( data_len - 1 < bytes ) {
+ /* missing length! */
+ return -1;
+ }
+
/* parse out the actual length */
for ( i = 0; i < bytes; i++ ) {
byte = data[i];
@@ -197,15 +208,21 @@ static unsigned int asn_getlength( const
* Extract an ASN.1 formatted UTF-8 string field from the data.
*
* @param data The source data
+ * @param data_len Length of data
* @param type Expected type of string
* @param utf8 The extracted string. Must be deallocated by caller.
* @return The number of bytes extracted
*/
-static int asn_getUtf8( const gchar* data, gchar type, char** utf8 )
+static int asn_getUtf8( const gchar* data, gsize data_len, gchar type, char** utf8 )
{
unsigned int len;
gchar *out_str;
+ if ( data_len < 2 ) {
+ /* missing type or length! */
+ return -1;
+ }
+
/* validate the field type [1 byte] */
if ( data[0] != type ) {
/* this is not a utf-8 string! */
@@ -214,6 +231,11 @@ static int asn_getUtf8( const gchar* dat
}
len = (guint8)data[1]; /* length field [1 byte] */
+ if ( data_len - 2 < len ) {
+ /* not enough bytes left in data! */
+ return -1;
+ }
+
out_str = g_malloc(len + 1);
memcpy(out_str, &data[2], len); /* data field */
out_str[len] = '\0';
@@ -500,7 +522,7 @@ static void emoticon_returned( PurpleUti
#endif
/* validate that the returned data starts with the magic constant that indicates it is a custom emoticon */
- if ( memcmp( MXIT_FRAME_MAGIC, &data[pos], strlen( MXIT_FRAME_MAGIC ) ) != 0 ) {
+ if ( len - pos < strlen( MXIT_FRAME_MAGIC ) || memcmp( MXIT_FRAME_MAGIC, &data[pos], strlen( MXIT_FRAME_MAGIC ) ) != 0 ) {
purple_debug_error( MXIT_PLUGIN_ID, "Invalid emoticon received from wapsite (bad magic)\n" );
goto done;
}
@@ -514,7 +536,7 @@ static void emoticon_returned( PurpleUti
pos++;
/* get the frame image data length */
- res = asn_getlength( &data[pos], &em_size );
+ res = asn_getlength( &data[pos], len - pos, &em_size );
if ( res <= 0 ) {
purple_debug_error( MXIT_PLUGIN_ID, "Invalid emoticon received from wapsite (bad frame length)\n" );
goto done;
@@ -525,7 +547,7 @@ static void emoticon_returned( PurpleUti
#endif
/* utf-8 (emoticon name) */
- res = asn_getUtf8( &data[pos], 0x0C, &str );
+ res = asn_getUtf8( &data[pos], len - pos, 0x0C, &str );
if ( res <= 0 ) {
purple_debug_error( MXIT_PLUGIN_ID, "Invalid emoticon received from wapsite (bad name string)\n" );
goto done;
@@ -538,7 +560,7 @@ static void emoticon_returned( PurpleUti
str = NULL;
/* utf-8 (emoticon shortcut) */
- res = asn_getUtf8( &data[pos], 0x81, &str );
+ res = asn_getUtf8( &data[pos], len - pos, 0x81, &str );
if ( res <= 0 ) {
purple_debug_error( MXIT_PLUGIN_ID, "Invalid emoticon received from wapsite (bad shortcut string)\n" );
goto done;
@@ -550,7 +572,7 @@ static void emoticon_returned( PurpleUti
em_id = str;
/* validate the image data type */
- if ( data[pos] != '\x82' ) {
+ if ( len - pos < 1 || data[pos] != '\x82' ) {
purple_debug_error( MXIT_PLUGIN_ID, "Invalid emoticon received from wapsite (bad data type)\n" );
g_free( em_id );
goto done;
@@ -558,7 +580,7 @@ static void emoticon_returned( PurpleUti
pos++;
/* get the data length */
- res = asn_getlength( &data[pos], &em_size );
+ res = asn_getlength( &data[pos], len - pos, &em_size );
if ( res <= 0 ) {
/* bad frame length */
purple_debug_error( MXIT_PLUGIN_ID, "Invalid emoticon received from wapsite (bad data length)\n" );
@@ -570,6 +592,13 @@ static void emoticon_returned( PurpleUti
purple_debug_info( MXIT_PLUGIN_ID, "read the length '%i'\n", em_size );
#endif
+ if ( len - pos < em_size ) {
+ /* not enough bytes left in data! */
+ purple_debug_error( MXIT_PLUGIN_ID, "Invalid emoticon received from wapsite (data length too long)\n");
+ g_free( em_id );
+ goto done;
+ }
+
/* strip the mxit markup tags from the emoticon id (eg, .{XY} -> XY) */
if ( ( em_id[0] == '.' ) && ( em_id[1] == '{' ) ) {
char emo[MXIT_MAX_EMO_ID + 1];
-------------- next part --------------
diff -r 6436e14bdb9d -r 44fd89158777 ChangeLog
--- a/ChangeLog Mon Apr 07 23:45:55 2014 -0700
+++ b/ChangeLog Tue Apr 08 00:31:25 2014 -0700
@@ -12,6 +12,11 @@ version 2.10.10 (?/?/?):
Gadu-Gadu:
* Updated internal libgadu to version 1.12.0-rc2.
+ Groupwise:
+ * Fix potential remote crash parsing server message that indicates that
+ a large amount of memory should be allocated. (Discovered by Yves Younan
+ and Richard Johnson of Sourcefire VRT) (CVE-2014-NNNN)
+
MXit:
* Fix potential remote crash parsing a malformed emoticon response.
(Discovered by Yves Younan and Richard Johnson of Sourcefire VRT)
diff -r 6436e14bdb9d -r 44fd89158777 libpurple/protocols/novell/nmevent.c
--- a/libpurple/protocols/novell/nmevent.c Mon Apr 07 23:45:55 2014 -0700
+++ b/libpurple/protocols/novell/nmevent.c Tue Apr 08 00:31:25 2014 -0700
@@ -149,7 +149,7 @@ handle_receive_message(NMUser * user, NM
/* Read the conference guid */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 1000) return NMERR_PROTOCOL;
if (rc == NM_OK) {
guid = g_new0(char, size + 1);
@@ -164,7 +164,7 @@ handle_receive_message(NMUser * user, NM
/* Read the message text */
if (rc == NM_OK) {
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 100000) return NMERR_PROTOCOL;
if (rc == NM_OK) {
msg = g_new0(char, size + 1);
@@ -270,7 +270,7 @@ handle_conference_invite(NMUser * user,
/* Read the conference guid */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 1000) return NMERR_PROTOCOL;
if (rc == NM_OK) {
guid = g_new0(char, size + 1);
@@ -280,7 +280,7 @@ handle_conference_invite(NMUser * user,
/* Read the the message */
if (rc == NM_OK) {
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 100000) return NMERR_PROTOCOL;
if (rc == NM_OK) {
msg = g_new0(char, size + 1);
@@ -349,7 +349,7 @@ handle_conference_invite_notify(NMUser *
/* Read the conference guid */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 1000) return NMERR_PROTOCOL;
if (rc == NM_OK) {
guid = g_new0(char, size + 1);
@@ -401,7 +401,7 @@ handle_conference_reject(NMUser * user,
/* Read the conference guid */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 1000) return NMERR_PROTOCOL;
if (rc == NM_OK) {
guid = g_new0(char, size + 1);
@@ -440,7 +440,7 @@ handle_conference_left(NMUser * user, NM
/* Read the conference guid */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 1000) return NMERR_PROTOCOL;
if (rc == NM_OK) {
guid = g_new0(char, size + 1);
@@ -490,7 +490,7 @@ handle_conference_closed(NMUser * user,
/* Read the conference guid */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 1000) return NMERR_PROTOCOL;
if (rc == NM_OK) {
guid = g_new0(char, size + 1);
@@ -530,7 +530,7 @@ handle_conference_joined(NMUser * user,
/* Read the conference guid */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 1000) return NMERR_PROTOCOL;
if (rc == NM_OK) {
guid = g_new0(char, size + 1);
@@ -589,7 +589,7 @@ handle_typing(NMUser * user, NMEvent * e
/* Read the conference guid */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 1000) return NMERR_PROTOCOL;
if (rc == NM_OK) {
guid = g_new0(char, size + 1);
@@ -632,7 +632,7 @@ handle_status_change(NMUser * user, NMEv
/* Read the status text */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 10000) return NMERR_PROTOCOL;
if (rc == NM_OK) {
text = g_new0(char, size + 1);
@@ -670,7 +670,7 @@ handle_undeliverable_status(NMUser * use
/* Read the conference guid */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 1000) return NMERR_PROTOCOL;
if (rc == NM_OK) {
guid = g_new0(char, size + 1);
@@ -833,7 +833,10 @@ nm_process_event(NMUser * user, int type
/* Read the event source */
rc = nm_read_uint32(conn, &size);
if (rc == NM_OK) {
- if (size > 0) {
+ if (size > 1000000) {
+ /* Size is larger than our 1MB sanity check. Ignore it. */
+ rc = NMERR_PROTOCOL;
+ } else {
source = g_new0(char, size);
rc = nm_read_all(conn, source, size);
-------------- next part --------------
diff -r 89c89c449595 -r 68b8eb10977f ChangeLog
--- a/ChangeLog Sat Mar 01 16:35:47 2014 -0800
+++ b/ChangeLog Tue Mar 04 23:12:23 2014 -0800
@@ -1,6 +1,11 @@
Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
version 2.10.10 (?/?/?):
+ Windows-Specific Changes:
+ * Don't allow overwriting arbitrary files on the file system when the
+ user installs a smiley theme from a tar file. (Discovered by Yves
+ Younan of Sourcefire VRT)
+
Finch:
* Fix build against Python 3. (Ed Catmur) (#15969)
diff -r 89c89c449595 -r 68b8eb10977f pidgin/win32/untar.c
--- a/pidgin/win32/untar.c Sat Mar 01 16:35:47 2014 -0800
+++ b/pidgin/win32/untar.c Tue Mar 04 23:12:23 2014 -0800
@@ -122,8 +122,6 @@ static const char *inname = NULL;
static FILE *infp = NULL; /* input byte stream */
static FILE *outfp = NULL; /* output stream, for file currently being extracted */
static Ulong_t outsize = 0; /* number of bytes remainin in file currently being extracted */
-static char **only = NULL; /* array of filenames to extract/list */
-static int nonlys = 0; /* number of filenames in "only" array; 0=extract all */
static int didabs = 0; /* were any filenames affected by the absence of -p? */
static untar_opt untarops = 0; /* Untar options */
@@ -392,24 +390,35 @@ static int untar_block(Uchar_t *blk) {
/* combine prefix and filename */
memset(nbuf, 0, sizeof nbuf);
- name = nbuf;
if ((tblk)->prefix[0])
{
- strncpy(name, (tblk)->prefix, sizeof (tblk)->prefix);
- strcat(name, "/");
- strncat(name + strlen(name), (tblk)->filename,
- sizeof (tblk)->filename);
+ snprintf(nbuf, sizeof(nbuf), "%s/%s",
+ (tblk)->prefix, (tblk)->filename);
}
else
{
- strncpy(name, (tblk)->filename,
- sizeof (tblk)->filename);
+ g_strlcpy(nbuf, (tblk)->filename,
+ sizeof (nbuf));
+ }
+
+ /* Possibly strip the drive from the path */
+ if (!ABSPATH) {
+ /* If the path contains a colon, assume everything before the
+ * colon is intended to be a drive name and ignore it. This
+ * should be just a single drive letter, but it should be safe
+ * to drop it even if it's longer. */
+ const char *lastcolon = strrchr(nbuf, ':');
+ if (lastcolon) {
+ memmove(nbuf, lastcolon, strlen(lastcolon) + 1);
+ didabs = 1; /* Path was changed from absolute to relative */
+ }
}
/* Convert any backslashes to forward slashes, and guard
* against doubled-up slashes. (Some DOS versions of "tar"
* get this wrong.) Also strip off leading slashes.
*/
+ name = nbuf;
if (!ABSPATH && (*name == '/' || *name == '\\'))
didabs = 1;
for (n2 = nbuf; *name; name++)
@@ -474,26 +483,6 @@ static int untar_block(Uchar_t *blk) {
}
#endif
- /* If we have an "only" list, and this file isn't in it,
- * then skip it.
- */
- if (nonlys > 0)
- {
- for (i = 0;
- i < nonlys
- && strcmp(only[i], nbuf)
- && (strncmp(only[i], nbuf, strlen(only[i]))
- || nbuf[strlen(only[i])] != '/');
- i++)
- {
- }
- if (i >= nonlys)
- {
- outfp = NULL;
- return 1;
- }
- }
-
/* list the file */
if (VERBOSE)
untar_verbose("%c %s",
@@ -520,18 +509,19 @@ static int untar_block(Uchar_t *blk) {
*/
if (tblk->type == '5')
{
+ char *tmp;
if (LISTING)
- n2 = " directory";
+ tmp = " directory";
#ifdef _POSIX_SOURCE
else if (mkdir(nbuf, mode) == 0)
#else
else if (g_mkdir(nbuf, 0755) == 0)
#endif
- n2 = " created";
+ tmp = " created";
else
- n2 = " ignored";
+ tmp = " ignored";
if (VERBOSE)
- untar_verbose("%s\n", n2);
+ untar_verbose("%s\n", tmp);
return 1;
}
More information about the security
mailing list