e-matters GmbH www.e-matters.de -= Security Advisory =- Advisory: 12 x Gaim remote overflows Release Date: 2004/01/26 Last Modified: 2004/01/26 Author: Stefan Esser [s.esser@e-matters.de] Application: Gaim <= 0.75 Severity: 12 vulnerabilities were found in the instant messenger GAIM that allow remote compromise Risk: Critical Vendor Status: Vendor has fixed in CVS, but feels not ready for release because of problems with HEAD Reference: http://security.e-matters.de/advisories/012004.html Overview: Gaim is a multi-protocol instant messaging client for Linux, BSD, MacOS X, and Windows. It is compatible with AIM (Oscar and TOC protocols), ICQ, MSN Messenger, Yahoo, IRC, Jabber, Gadu-Gadu, and Zephyr networks. It is a very popular choice among the users of instant messaging networks and especially in the community of migrated windows users. While developing a custom add-on, an integer overflow in the handling of AIM DirectIM packets was revealed that could lead to a remote compromise of the IM client. After disclosing this bug to the vendor, they had to make a hurried release because of a change in the Yahoo connection procedure that rendered GAIM useless. Unfourtunately at the same time a closer look onto the sourcecode revealed 11 more vulnerabilities. The 12 identified problems range from simple standard stack overflows, over heap overflows to an integer overflow that can be abused to cause a heap overflow. Due to the nature of instant messaging many of these bugs require man-in-the-middle attacks between client and server. But the underlying protocols are easy to implement and MIM attacks on ordinary TCP sessions is a fairly simple task. In combination with the latest kernel vulnerabilities or the habit of users to work as root/administrator these bugs can result in remote root compromises. Details: While auditing the Gaim source code the following 12 vulnerabilities were discovered: Overflows in YMSG protocol (yahoo messenger) handler ---------------------------------------------------- 01) Yahoo Octal-Encoding Decoder Overflow 02) Yahoo Octal-Encoding Decoder Out-Of-Bounds Overflow 03) Yahoo Web Cookie Parser Overflow 04) Yahoo Login Page Name Parser Overflow 05) Yahoo Login Page Value Parser Overflow 06) Yahoo Packet Parser Overflow Overflows in oscar protocol (AIM) handler ----------------------------------------- 07) AIM/Oscar DirectIM Integer Overflow Overflows in utility functions (called in various protocols) ------------------------------ 08) Quoted Printable Decoder Overflow 09) Quoted Printable Decoder Out-Of-Bounds Overflow 10) URL Parser Function Overflow 11) Extract Info Field Function Overflow Overflows that do not fit into the other categories ------------------------------ 12) HTTP Proxy Connect Overflow Detailed Bug Description ------------------------ [01 - Yahoo Octal-Encoding Decoder Overflow] [02 - Yahoo Octal-Encoding Decoder Out-Of-Bounds Overflow] When the Yahoo Messenger handler decodes an octal value for email notification functions 2 different kind of overflows can be triggered Affected version: 0.75 (only) File: gaim/src/protocols/yahoo/yahoo.c Function: yahoo_decode() Code: static char *yahoo_decode(const char *text) { char *converted; char *p, *n, *new; n = new = g_malloc(strlen (text) + 1); for (p = (char *)text; *p; p++, n++) { if (*p == '\\') { sscanf(p + 1, "%3o\n", (int *)n); <-------- [01] p += 3; <--------------------------------- [02] } else *n = *p; } *n = '\0'; ... The way sscanf is used, it will always write 4 bytes to the allocated buffer. The author did not see the possibility of malformed input like "\1" (the backslash is only a backslash) it is possible to write 1-2 zero bytes over the buffer boundaries. On linux this is exploitable like any heap off by one into the malloc() chunks. The second vulnerability is that no matter how many bytes sscanf() consumes it always increases the pointer with assumed 4 bytes. This can result in overjumping the terminating zero byte and with special prepared memory after the string it is possible to overwrite the heap with an arbitrary amount of bytes. These bugs are counted as 2 because for most people [02] is not obvious. As an example the vendor fixed only [01] first, because my description was not good enough. Additionally the misuse of sscanf() caused an incompatibility to all big endian platforms. [03 - Yahoo Web Cookie Parser Overflow] When parsing the cookies within the HTTP reply header of a yahoo web connection a bufferoverflow can happen. Affected version: <= 0.75 File: gaim/src/protocols/yahoo/yahoo.c Function: yahoo_web_pending() Code: void yahoo_web_pending(gpointer data, gint source, ... { GaimConnection *gc = data; GaimAccount *account = gaim_connection_get_account(gc); struct yahoo_data *yd = gc->proto_data; char buf[1024], buf2[256], *i = buf, *r = buf2; int len, o = 0; len = read(source, buf, sizeof(buf)); ... while ((i = strstr(i, "Set-Cookie: ")) && 0 < 2) { i += strlen("Set-Cookie: "); for (;*i != ';'; r++, i++) { *r = *i; } *r=';'; r++; ... } ... Here all cookie data contained in the first 1024 byte of a HTTP reply header is copied into a 256 byte buffer without a size check. Because source and destination buffer are both on the stack and stack layout will most probably result in the smaller buffer overflowing into the smaller one this bug is believed to be not exploitable with the normal stack layout. Note also the typo in the while() condition 0 < 2 which should be o < 2 [04 - Yahoo Login Page Name Parser Overflow] [05 - Yahoo Login Page Value Parser Overflow] When parsing the Yahoo Login Webpage the YMSG protocol overflows stachbuffers if the webpage returns oversized values. Affected version: <= 0.75 File: gaim/src/protocols/yahoo/yahoo.c Function: yahoo_login_page_hash() Code: static GHashTable *yahoo_login_page_hash(const char *buf,size_t len) { GHashTable *hash = g_hash_table_new_full(g_str_hash, g_s... const char *c = buf; char *d; char name[64], value[64]; while ((c < (buf + len)) && (c = strstr(c, "') < d) break; for (c = d, d = value; *c!='"'; c++, d++) <--- [05] *d = *c; <-----------------------------/ *d = '\0'; g_hash_table_insert(hash, g_strdup(name), g_strdup(value)); } return hash; } The content of the yahoo login webpage is trusted although it could be changed with a simple man-in-the-middle attack on the HTTP session. name and value are filled directly from the page without any kind of size check. This results in two independent ways to overflow the stack. [06 - Yahoo Packet Parser Overflow] A Yahoo Messenger packet consist of a header and a list of keys with their associated values. When reading an oversized keyname a standard stackoverflow can be triggered. This is nost probably the most dangerous discovered vulnerability because the nature of the bug makes it very easy to exploit and additonally a TCP man-in-the-middle attack is NOT needed. It is possible to send a malicious YMSG packet to the yahoo server so that it will be forwarded like any normal message. Affected version: <= 0.75 File: gaim/src/protocols/yahoo/yahoo.c Function: yahoo_packet_read() Code: static void yahoo_packet_read(struct yahoo_packet *pkt, guchar *data, int len) { int pos = 0; while (pos + 1 < len) { char key[64], *value = NULL, *esc; int accept; int x; struct yahoo_pair *pair = g_new0(struct yahoo_pair, 1); x = 0; while (pos + 1 < len) { if (data[pos] == 0xc0 && data[pos + 1] == 0x80) break; key[x++] = data[pos++]; <----------------- [06] } key[x] = 0; pos += 2; ... Everytime the YMSG handler receives a complete packet it will give it this function to split it into its keys and values. Because the keyname is copied without any kind of size check into the key variable which is a 64 byte stackbuffer it is very easy to exploit. NOTE: This bug is also exploitable on systems with non executable stacks, or stack overflow detections as long free() exploits are possible on that platform, [07 - AIM/Oscar DirectIM Integer Overflow] Integer Overflow when allocating memory for a directIM packet results in heap overflow. directIM is a client 2 client protocol and therefore does not require a mim. Affected version: <= 0.74 File: gaim/src/protocols/oscar/ft.c Function: handlehdr_odc() Code: static int handlehdr_odc(aim_session_t *sess, aim_... { aim_frame_t fr; int ret = 0; aim_rxcallback_t userfunc; fu32_t payloadlength; fu16_t flags, encoding; char *snptr = NULL; fr.conn = conn; /* AAA - ugly */ aim_bstream_setpos(bs, 20); payloadlength = aimbs_get32(bs); ... if (payloadlength) { char *msg; ... if (!(msg = calloc(1, payloadlength+1))) { <--- [07] free(snptr); return -ENOMEM; } while (payloadlength - recvd) { if (payloadlength - recvd >= 1024) i = aim_recv(conn->fd, &msg[recvd], 1024); else ... Within this code snipset payloadlength is taken directly from the network and passed to the calloc() function in an unsafe manner. A user supplied payloadlength of UINT_MAX (0xffffffff) will cause an integer overflow within the second parameter of calloc() and therefore only allocate a 0 byte buffer. Please notice that this bug is not an integer overflow due to the multiplication within calloc() and therefore it is not catched by the recent security patches to calloc() on different platforms. Please also note that calloc(1, 0) will not return a NULL pointer but a pointer into the legal heap on at least all tested platforms (f.e. linux, bsd) On BSD systems this is configureable but it defaults to this behaviour. After allocating the 0 byte buffer aim_recv() is called repeatedly by the while loop to read and overwrite with up to 4GB of data. [08 - Quoted Printable Decoder Overflow] [09 - Quoted Printable Decoder Out-Of-Bounds Overflow] When the MIME decoder decosed a quoted printable encoded string for email notification 2 different kind of overflows can be triggered. Affected version: 0.75 (only) File: gaim/src/util.c Function: quotedp_decode() Code: void gaim_quotedp_decode(const char *str, char **ret_str, int ... { char *p, *n, *new; n = new = g_malloc(strlen (str) + 1); for (p = (char *)str; *p; p++, n++) { if (*p == '=') { sscanf(p + 1, "%2x\n", (int *)n); <-------- [08] p += 2; <--------------------------------- [09] } else if (*p == '_') *n = ' '; else *n = *p; } *n = '\0'; ... Because these bugs are very similar to [01] and [02] only the vulnerable code snipset is shown here. For an explanation read the yahoo_decode() vulnerability description. [10 - URL Parser Function Overflow] At various placed this utility function is used to split an url into its parts. Because temporary fixed size stackbuffers are used in an unsafe way a standard stackoverflow can be caused. Affected version: <= 0.75 File: gaim/src/util.c Function: gaim_url_parse() Code: gboolean gaim_url_parse(const char *url, char **ret_host, int *ret_port, char **ret_path) { char scan_info[255]; char port_str[5]; int f; const char *turl; char host[256], path[256]; int port = 0; /* hyphen at end includes it in control set */ static char addr_ctrl[] = "A-Za-z0-9.-"; static char port_ctrl[] = "0-9"; static char page_ctrl[] = "A-Za-z0-9.~_/:*!@&%%?=+^-"; ... g_snprintf(scan_info, sizeof(scan_info), "%%[%s]:%%[%s]/%%[%s]", addr_ctrl, port_ctrl, page_ct f = sscanf(url, scan_info, host, port_str, path); <-- [10] ... Here sscanf() is again used in an unsafe manner. When this function is called with an oversized url, which can be triggered from several protocol handlers in different ways sscanf() will overwrite the stackbuffers host and path. The problem at this point is, that it is only possible to overwrite the buffers with a limited characterset which makes exploitation tricky. [11 - Extract Info Field Function Overflow] At various places this utility function is called to copy the data between 2 tokens into a fixed size stackbuffer without a size check. Affected version: <= 0.74 File: gaim/src/util.c Function: gaim_markup_extract_info_field() Code: ... const char *p, *q; char buf[1024]; ... p = strstr(str, start_token); ... p += strlen(start_token) + skip; ... q = strstr(p, end_token); if (q != NULL && (!no_value_token || (no_value_token && strncmp(p, no_value { ... if (is_link) { strcat(dest_buffer, "
inpa); while ((nlc != 2) && (read(source, &inputline[pos++], 1) == 1)) { if (inputline[pos - 1] == '\n') nlc++; else if (inputline[pos - 1] != '\r') nlc = 0; } inputline[pos] = '\0'; ... Here the author never thought about the possibility that a proxy server could be malicious. The inputline is read into the 8192 byte buffer byte after byte until a double \r\n is found. Because there is no size check at all the buffer will overflow as soon the proxy sends more than 8192 bytes in a line. This bug is exploitable even if stack overwrite protections are in place because it is possible to overwrite the pointer phb which points to a struct that contains a callback function which is later called in the function. By overwriting the pointer and so controlling the callback function pointer it is possible to gain control over the instruction pointer before the function is left. Proof of Concept: e-matters is not going to release exploit for any of the these vulnerability to the public. CVE Information: The Common Vulnerabilities and Exposures project (cve.mitre.org) has assigned the following names to these issues. CAN-2004-0005: version 0.75 only, buffer overflows: [01 - Yahoo Octal-Encoding Decoder Overflow] [02 - Yahoo Octal-Encoding Decoder Out-Of-Bounds Overflow] [08 - Quoted Printable Decoder Overflow] [09 - Quoted Printable Decoder Out-Of-Bounds Overflow] CAN-2004-0006: 0.75 and earlier, buffer overflows: [03 - Yahoo Web Cookie Parser Overflow] [04 - Yahoo Login Page Name Parser Overflow] [05 - Yahoo Login Page Value Parser Overflow] [06 - Yahoo Packet Parser Overflow] [10 - URL Parser Function Overflow] [12 - HTTP Proxy Connect Overflow] CAN-2004-0007: 0.74 and earlier, buffer overflows: [11 - Extract Info Field Function Overflow] CAN-2004-0008: 0.74 and earlier, integer overflow: [07 - AIM/Oscar DirectIM Integer Overflow] Disclosure Timeline: 04. January 2004 - The Oscar filetransfer bug was sent to the Gaim vendor by email. Within an hour the bug was fixed within the CVS 10. January 2004 - Gaim vendor released version 0.75 because of a Yahoo protocol change problem(?) Some freetime allowed deeper analysis of the new version. This revealed more bugs: 1 fixed in 0.75, some new in 0.75 and some old which are still in 0.75. All these bugs were again mailed to the vendor 15. January 2004 - Vendor was contacted with a patch because they had not fixed the bugs yet. Our Patch was applied in the same night 16. January 2004 - Vendor-sec was contacted to coordinate the disclosure process. Vendor was asked by email when 0.76 is about to come out and that this should be as soon as possible because the bugfixes were visible in their CVS with explicit commit messaged. No response to this mail until today 23. January 2004 - Vendor was notified about public disclosure at the 26th. 25. January 2004 - Notification by the vendor that gaim 0.76 releasedate is not planned yet. 26. January 2004 - Public Disclosure Recommendation: Because there is no official new version out yet, you can download a diff against version 0.75 from http://security.e-matters.de/patches/gaim-0.75-fix.diff This patch was done by the FreeBSD security team. It is different from the official patches in the Gaim CVS. We suggest that you upgrade as soon as possible, because the explicit commit message into the official CVS tree seems to have leaked. At least it was reported to us that a link to the message on the sourceforge WebCVS was pasted into an IRC channel. GPG-Key: http://security.e-matters.de/gpg_key.asc pub 1024D/75E7AAD6 2002-02-26 e-matters GmbH - Securityteam Key fingerprint = 43DD 843C FAB9 832A E5AB CAEB 81F2 8110 75E7 AAD6 Copyright 2004 Stefan Esser. All rights reserved. -- -------------------------------------------------------------------------- Stefan Esser s.esser@e-matters.de e-matters Security http://security.e-matters.de/ GPG-Key gpg --keyserver pgp.mit.edu --recv-key 0xCF6CAE69 Key fingerprint B418 B290 ACC0 C8E5 8292 8B72 D6B0 7704 CF6C AE69 -------------------------------------------------------------------------- Did I help you? Consider a gift: http://wishlist.suspekt.org/ --------------------------------------------------------------------------