CVE-2016-2375
An exploitable out-of-bounds ready exists in the handling of the MXIT protocol in Pidgin. Specially crafted MXIT contact information sent from the server can result in memory disclosure.
5.3 CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
Pidgin 2.10.11
https://www.pidgin.im/
In the function mxit_parse_cmd_suggestcontacts in the file mxit/protocol.c at line 2020 the number of attributes will be read from the incoming packet into the variable count.
2020 count = atoi( records[0]->fields[3]->data );
This value is subsequently used as the bounds for a loop at line 2030 and the loop index is used as an array index at lines 2034-2036.
2030 for ( j = 0; j < count; j++ ) {
2034 fname = records[0]->fields[4 + j]->data; /* field name */
if ( records[i]->fcount > ( 2 + j ) )
fvalue = records[i]->fields[2 + j]->data; /* field value */
The pointers set at these locations will subsequently be used to read data, potentially resulting in an out-of-bounds read, copying data into results fields, for example at lines 2056-2059:
2056 else if ( strcmp( CP_PROFILE_FULLNAME, fname ) == 0 ) {
/* nickname */
g_strlcpy( profile->nickname, fvalue, sizeof( profile->nickname ) );
2059 }
Most of the out-of-bounds reads would simply result in a crash if a memory page is inaccessible since most information is not sent back to the server. However, when the add button is pushed, the following callback is called (defined in mxit/profile.c at lines 288-291):
static void mxit_search_results_add_cb( PurpleConnection *gc, GList *row, gpointer user_data )
{
/* display add buddy dialog */
purple_blist_request_add_buddy( purple_connection_get_account( gc ), g_list_nth_data( row, 0 ), NULL, g_list_nth_data( row, 1 ) );
}
The data in this row is set in mxit_show_search_results() in mxit/profile.c at lines 340-346:
340 row = g_list_append( NULL, g_strdup_printf( "#%s", tmp ) );
341 row = g_list_append( row, g_strdup( profile->nickname ) );
row = g_list_append( row, g_strdup( profile->firstname ) );
row = g_list_append( row, g_strdup( profile->lastname ) );
row = g_list_append( row, g_strdup( profile->male ? "Male" : "Female" ) );
row = g_list_append( row, g_strdup_printf( "%i", calculateAge( profile->birthday ) ) );
346 row = g_list_append( row, g_strdup( profile->whereami ) );
This means that the nickname will be sent to the function purple_blist_request_add_buddy() as last argument, which ends up calling:
ui_ops->request_add_buddy(account, username, group, alias);
Which should call the callback mxit_add_buddy() defined in roster.c at line 729:
void mxit_add_buddy( PurpleConnection* gc, PurpleBuddy* buddy, PurpleGroup* group, const char* message )
This function then sends the alias back as a message to the server at lines 754 and 759:
741 list = purple_find_buddies( session->acc, buddy_name );
if ( g_slist_length( list ) == 1 ) {
purple_debug_info( MXIT_PLUGIN_ID, "mxit_add_buddy (scenario 1) (list:%i)\n", g_slist_length( list ) );
/*
* we only send an invite to MXit when the user is not already inside our
* blist. this is done because purple does an add_buddy() call when
* you accept an invite. so in that case the user is already
* in our blist and ready to be chatted to.
*/
if ( buddy_name[0] == '#' ) {
gchar *tmp = (gchar*) purple_base64_decode( buddy_name + 1, NULL );
if ( tmp ) {
754 mxit_send_invite( session, tmp, FALSE, buddy_alias, group_name, message );
g_free( tmp );
}
}
else
759 mxit\_send\_invite( session, buddy_name, TRUE, buddy_alias, group_name, message );
760 }
2016-04-13 - Vendor Notification
2016-06-21 - Public Disclosure
Discovered by Yves Younan of Cisco Talos.