Talos Vulnerability Report

TALOS-2016-0128

Pidgin MXIT Splash Image Arbitrary File Overwrite Vulnerability

June 21, 2016

Report ID

CVE-2016-4323

Description

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.

CVSSv3 Score

4.8 CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:L

Tested Versions

Pidgin 2.10.11

Product URLs

https://www.pidgin.im/

Details

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.

Credit

Discovered by Yves Younan of Cisco Talos.

Timeline

2016-04-12 - Initial vendor contact
2016-06-21 - Public Disclosure