Talos Vulnerability Report

TALOS-2016-0128

Pidgin MXIT Splash Image Arbitrary File Overwrite Vulnerability

June 21, 2016
CVE Number

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 mxitchunkparse_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 MXITCONFIGSPLASHID variable at line 130. The function splashremove, which is called at line 121 in this function, will use MXITCONFIG_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.

TIMELINE

2016-04-12 - Initial Vendor Contact
2016-06-21 - Public Disclosure

Credit

Discovered by Yves Younan of Cisco Talos.