On March 25th, 2024, a critical security vulnerability was discovered in the LayerSlider plugin for WordPress, marked as CVE-2024-2879. The plugins have more than 10 lakh active installations. This flaw, rated with a CVSS score of 7.5 out of 10.0, is identified as an SQL injection vulnerability impacting LayerSlider versions 7.9.11 through 7.10.0.
Qualys Web Application Scanning released a QID 150868 to address CVE-2024-2879. The detection is part of the OWASP Top 10 Injection category. SQL injections have been getting a lot of visibility recently which we have discussed in our blog on Navigating SQL Injections.
QID | 150868 |
---|---|
Severity | 5 |
CVSS 3.1 Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N |
CVSS 3.1 Score | 7.5 |
Affected Versions | 7.9.11 – 7.10.0 |
The LayerSlider plugin for WordPress is vulnerable to SQL Injection via the ls_get_popup_markup action in versions 7.9.11 and 7.10.0 due to insufficient escaping on the user-supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for unauthenticated attackers to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
The ls_get_popup_markup()
function is utilized to query slider markup for popups. It accepts the 'id' parameter value to identify the slider.
303 function ls_get_popup_markup() {
304
305 $id = is_numeric( $_GET['id'] ) ? (int) $_GET['id'] : $_GET['id'];
306 $popup = LS_Sliders::find( $id );
307
308 if( $popup ) {
309 $GLOBALS['lsAjaxOverridePopupSettings'] = true;
310 $parts = LS_Shortcode::generateSliderMarkup( $popup );
311 die( $parts['container'].$parts['markup'].'' );
312 }
313
314 die();
315 }
The function checks if the 'id' parameter is numeric using is_numeric()
. If the 'id' parameter is not a number, it is passed without sanitization to the find()
function in the LS_Sliders
class.
157 // Where
158 $where = '';
159 if(!empty($args['where']) && !empty($args['exclude'])) {
160 $where = "WHERE ({$args['exclude']}) AND ({$args['where']}) ";
161
162 } elseif(!empty($args['where'])) {
163 $where = "WHERE {$args['where']} ";
164
165 } elseif(!empty($args['exclude'])) {
166 $where = "WHERE {$args['exclude']} ";
167 }
168
169 // Some adjustments
170 $args['limit'] = ($args['limit'] * $args['page'] - $args['limit']).', '.$args['limit'];
171
172 // Build the query
173 global $wpdb;
174 $table = $wpdb->prefix.LS_DB_TABLE;
175 $sliders = $wpdb->get_results("
176 SELECT SQL_CALC_FOUND_ROWS {$args['columns']}
177 FROM $table
178 $where
179 ORDER BY `{$args['orderby']}` {$args['order']}, name ASC
180 LIMIT {$args['limit']}
181
182 ", ARRAY_A);
The vulnerability arises within the find()
function of the LS_Sliders
class because it doesn't properly validate user-provided input. While all other $args
values are sanitized with the esc_sql()
function, the 'where' value lacks this protection.
In this code, the $where
variable is constructed using string concatenation with user-provided input ($args['where']
). Then it passed to the query.
Let's consider an example of an attack. Suppose an attacker provides the following values:
id[where]=(SELECT 0 FROM (SELECT SLEEP(5))qualysWAS)
The resulting SQL query would be:
SELECT SQL_CALC_FOUND_ROWS {$args['columns']} FROM $table (SELECT 0 FROM (SELECT SLEEP(5))qualysWAS)
ORDER BY `{$args['orderby']}` {$args['order']}, name ASC LIMIT {$args['limit']}
In this modified query, the payload (SELECT 0 FROM (SELECT SLEEP(5))qualysWAS)
is injected into the $args['where']
parameter. This payload instructs the database to sleep for 5 seconds if the condition is true.
Customers can detect this vulnerability with Qualys Web Application Scanning using the following QID:
QID 150868: WordPress LayerSlider Plugin: Unauthenticated SQL Injection Vulnerability (CVE-2024-2879)
Customers are advised to upgrade to LayerSlider 7.10.1, or a later version to remediate this vulnerability. For more information please refer LayerSlider Release logs.