CVE-2016-4323
A directory traversal exists in the handling of the MXIT protocol in Pidgin. Specially crafted MXIT data sent from the server could potentially result in an overwrite of files. A malicious server or someone with access to the network traffic can provide an invalid filename for a splash image triggering the vulnerability.
4.8 CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:L
Pidgin 2.10.11
https://www.pidgin.im/
Pidgin allows the MXIT server to provide a splash image to show when connecting to the server. The server can also update this image by providing a new one via a command sent back from the server.
When the server provides a new image via a multimedia command then the function splash_update will be called at line 2170 of mxit/protocol.c:
2170 splash_update( session, chunk.id, splash->data, splash->datalen, clickable );
The variable chunk.id is read from data coming from the server in the function mxit_chunk_parse_cr at line 564:
pos += get_utf8_string( &chunkdata[pos], cr->id, sizeof( cr->id ) );
The function splash_update is defined in mxit/splashscreen.c at lines 115-136:
void splash_update(struct MXitSession* session, const char* splashId, const char* data, int datalen, gboolean clickable)
{
char* dir;
char* filename;
/* Remove the current splash-screen */
splash_remove(session);
/* Save the new splash image */
dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "mxit", purple_user_dir());
purple_build_dir(dir, S_IRUSR | S_IWUSR | S_IXUSR);
/* ensure directory exists */
127 filename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s.png", dir, purple_escape_filename(splashId));
if (purple_util_write_data_to_file_absolute(filename, data, datalen)) {
/* Store new splash-screen ID to settings */
purple_account_set_string(session->acc, MXIT_CONFIG_SPLASHID, splashId);
purple_account_set_bool(session->acc, MXIT_CONFIG_SPLASHCLICK, clickable );
}
g_free(dir);
g_free(filename);
}
At line 127 splashId will be correctly escaped to prevent a directory traversal from occurring. However the unescaped string is stored in the MXIT_CONFIG_SPLASHID variable at line 130. The function splash_remove, which is called at line 121 in this function, will use MXIT_CONFIG_SPLASHID to find the file to delete (lines 84-104):
void splash_remove(struct MXitSession* session)
{
const char* splashId = NULL;
char* filename;
/* Get current splash ID */
splashId = splash_current(session);
if (splashId != NULL) {
purple_debug_info(MXIT_PLUGIN_ID, "Removing splashId: '%s'\n", splashId);
/* Delete stored splash image */
filename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "mxit" G_DIR_SEPARATOR_S "%s.png", purple_user_dir(), splashId);
g_unlink(filename);
g_free(filename);
/* Clear current splash ID from settings */
purple_account_set_string(session->acc, MXIT_CONFIG_SPLASHID, "");
purple_account_set_bool(session->acc, MXIT_CONFIG_SPLASHCLICK, FALSE);
}
}
However unlike in splash_update, in this case there is no escaping of the filename, allowing an attacker to delete arbitrary png files on the system.
2016-04-12 - Initial Vendor Contact
2016-06-21 - Public Disclosure
Discovered by Yves Younan of Cisco Talos.