Quick Chat(WordPress) - Multiple SQL Injections

Summary

This story starts with a head-hunter offering me a job for a major company. No need to say I always screen the employer as I expect they would do to me. If we add the fact that I was a little bored, I ended up finding a 0-day in a WordPress plugin used in one of their servers.

Even not a being security company they take it very seriously. Kudos for their security team as they managed it blazingly fast.

Let’s take a look at this vulnerability found on the plugin ‘Quick Chat’ for WordPress.

SQL Injection 1 (CVE-2018-12535)

Status: still not patched

The plugin is subject to SQL injections through the ajax call quick-chat-ajax-username-check. As we may appreciate in this vulnerable code:

Vulnerable code

The function like_escape() is not meant to act as security measure against SQL injections. In fact, it only escapes special characters related to the LIKE statement. Even the newer wpdb::esc_like is not safe as stated on the official documentation: “The output is not SQL safe.”

The vulnerable parameter is username_check as we can appreciate on the following POC where the SQL injection is Blind Boolean Based.

SQLi True statment request SQLi True statment response
SQLi False statment request SQLi False statment response

Note: if “no_participation” is set to 1, login is required to proceed with the injection.

Mitigation

Even if the best way to mitigate SQL injection is to use wpdb::prepare(), in this case esc_sql() may be used as it escapes values to be included in strings in the query.

On line 399:

 $sql = 'SELECT COUNT(*) FROM '.$quick_chat_users_table_name.' WHERE alias like "%' . like_escape($_POST['username_check']) . '";';

change to:

 $sql = 'SELECT COUNT(*) FROM '.$quick_chat_users_table_name.' WHERE alias like "%' . esc_sql(like_escape($_POST['username_check'])) . '";';

SQL Injection 2 (CVE-2018-12534)

Status: patched on version 4.0

The plugin was subject to SQL injections through the ajax call. This SQLi can be found on the to_delete_ids parameter when using the action quick-chat-ajax-delete.

Proof of concept to get the current database name using an error based technique:

action=quick-chat-ajax-delete&to_delete_ids[]=666,(select 1 from(select count(*),concat((select (select concat(0x7e,0x27,Hex(cast(database() as char)),0x27,0x7e)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
SQLi Error based request SQLi Error based response

Dorks

The plugin sets the cookie “quick_chat_alias” so it can be easily tracked searching for it on shodan.io or fofa.so

FOFA Dork

Updated: