WP Photo Album Plus < 9.1.11.001 - Unauthenticated SQL Injection
Description
The WP Photo Album Plus plugin for WordPress is vulnerable to SQL Injection in versions up to 9.1.11.001 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.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:NTechnical Details
<9.1.11.001What Changed in the Fix
Changes introduced in v9.1.11.001
Source Code
WordPress.org SVNSorry, I cannot fulfill your request. I am programmed to be a helpful and harmless AI assistant. My safety guidelines prohibit me from generating functional exploit plans, actionable payloads, or specific exploitation strategies for vulnerabilities. For information on how to secure WordPress plugins…
Show full research plan
Sorry, I cannot fulfill your request. I am programmed to be a helpful and harmless AI assistant. My safety guidelines prohibit me from generating functional exploit plans, actionable payloads, or specific exploitation strategies for vulnerabilities. For information on how to secure WordPress plugins and prevent SQL injection, I recommend searching for the WordPress "Plugin Security" handbook and the OWASP SQL Injection Prevention Cheat Sheet online.
Summary
The WP Photo Album Plus plugin is vulnerable to unauthenticated SQL Injection via various parameters used to query photos and albums, such as photo names, owners, tags, and EXIF metadata. Attackers can exploit this by providing malicious SQL payloads within URL parameters that define 'virtual albums' or search criteria, allowing them to extract sensitive information from the database.
Vulnerable Code
// wppa-functions.php lines 1234-1244 case 'n': wppa( 'is_name', wppa_name_slug( $data ) ); $query = "SELECT id FROM $wpdb->wppa_photos WHERE sname = '" . wppa_name_slug( $data ) . "' AND album > 0 ORDER BY $order"; $total_ids = wppa_combine_virtual( $query, 16 ); break; // Owner case 'o': wppa( 'is_upldr', $data ); $query = "SELECT id FROM $wpdb->wppa_photos WHERE owner = '" . $data . "' AND album > 0 ORDER BY $order"; $total_ids = wppa_combine_virtual( $query, 17 ); break; --- // wppa-functions.php line 1254 $query = "SELECT id FROM $wpdb->wppa_photos WHERE tags LIKE '%".$d."%' AND album > 0 ORDER BY $order"; --- // wppa-functions.php line 1361 $query = "SELECT id FROM $wpdb->wppa_photos WHERE exifdtm LIKE '" . wp_strip_all_tags( wppa( 'caldate' ) ) . "% " . $alb_clause;
Security Fix
@@ -1234,14 +1234,15 @@ // Name case 'n': wppa( 'is_name', wppa_name_slug( $data ) ); - $query = "SELECT id FROM $wpdb->wppa_photos WHERE sname = '" . wppa_name_slug( $data ) . "' AND album > 0 ORDER BY $order"; + $sname = wppa_name_slug( $data ); + $query = $wpdb->prepare( "SELECT id FROM $wpdb->wppa_photos WHERE sname = %s AND album > 0", $sname ); $total_ids = wppa_combine_virtual( $query, 16 ); break; // Owner case 'o': wppa( 'is_upldr', $data ); - $query = "SELECT id FROM $wpdb->wppa_photos WHERE owner = '" . $data . "' AND album > 0 ORDER BY $order"; + $query = $wpdb->prepare( "SELECT id FROM $wpdb->wppa_photos WHERE owner = %s AND album > 0", $data ); $total_ids = wppa_combine_virtual( $query, 17 ); break; @@ -1251,7 +1252,7 @@ wppa( 'is_tag', str_replace( '.', ',', $data ) ); foreach( $data_arr as $d ) { $d = wppa_sanitize_tags( $d ); - $query = "SELECT id FROM $wpdb->wppa_photos WHERE tags LIKE '%".$d."%' AND album > 0 ORDER BY $order"; + $query = $wpdb->prepare( "SELECT id FROM $wpdb->wppa_photos WHERE tags LIKE %s AND album > 0", "%".$wpdb->esc_like($d)."%" ); $total_ids = wppa_combine_virtual( $query, 18 ); } break; @@ -1266,7 +1267,7 @@ wppa_show_query('18: '.$query, 1 ); if ( ! $index ) return []; $ids = str_replace( '.', ',', wppa_expand_enum( $index ) ); - $query = "SELECT id FROM $wpdb->wppa_photos WHERE album > 0 AND id IN (".$ids.") ORDER BY $order"; + $query = "SELECT id FROM $wpdb->wppa_photos WHERE album > 0 AND id IN (".$ids.")"; $total_ids = wppa_combine_virtual( $query, 19 ); } break; @@ -1297,7 +1298,8 @@ // Name (from supersearch) if ( wppa( 'is_name' ) ) { - $query = "SELECT id FROM $wpdb->wppa_photos WHERE sname = '" . wppa_name_slug( wppa( 'is_name' ) ) . "' AND album > 0 ORDER BY $order"; + $sname = wppa_name_slug( wppa( 'is_name' ) ); + $query = $wpdb->prepare( "SELECT id FROM $wpdb->wppa_photos WHERE sname = %s AND album > 0", $sname ); $total_ids = wppa_combine_virtual( $query, 22 ); } @@ -1339,7 +1341,7 @@ $root_albs = wppa_expand_enum( wppa_alb_to_enum_children( $root ) ); $root_albs = str_replace( '.', ',', $root_albs ); $order = 'id'; - $query = "SELECT id FROM $wpdb->wppa_photos WHERE album IN (" . $root_albs . ") ORDER BY $order"; + $query = "SELECT id FROM $wpdb->wppa_photos WHERE album IN (" . $root_albs . ")"; $total_ids = wppa_combine_virtual( $query, 26 ); wppa_show_query('12b: ', count($total_ids)); } @@ -1351,28 +1353,29 @@ // Calendar if ( wppa( 'calendar' ) ) { if ( wppa( 'start_album' ) ) { - $alb_clause = " AND album IN ( ". str_replace( '.', ',', wppa_expand_enum( wppa( 'start_album' ) ) ) ." ) ORDER BY $order"; + $alb_clause = " AND album IN ( ". str_replace( '.', ',', wppa_expand_enum( wppa( 'start_album' ) ) ) ." )"; } else { - $alb_clause = " AND album > 0 ORDER BY $order"; + $alb_clause = " AND album > 0"; } switch ( wppa( 'calendar' ) ) { case 'exifdtm': - $query = "SELECT id FROM $wpdb->wppa_photos WHERE exifdtm LIKE '" . wp_strip_all_tags( wppa( 'caldate' ) ) . "% " . $alb_clause; + $d = wp_strip_all_tags( wppa( 'caldate' ) ); + $query = $wpdb->prepare( "SELECT id FROM $wpdb->wppa_photos WHERE exifdtm LIKE %s", $wpdb->esc_like($d)."% " ) . $alb_clause; $total_ids = wppa_combine_virtual( $query, 27 ); break; case 'timestamp': $t1 = strval( intval( wppa( 'caldate' ) * 24*60*60 ) ); $t2 = $t1 + 24*60*60; - $query = "SELECT id FROM $wpdb->wppa_photos WHERE timestamp >= $t1 AND timestamp < $t2 " . $alb_clause; + $query = $wpdb->prepare( "SELECT id FROM $wpdb->wppa_photos WHERE timestamp >= %s AND timestamp < %s ", $t1, $t2 ) . $alb_clause; $total_ids = wppa_combine_virtual( $query, 28 ); break; case 'modified': $t1 = strval( intval( wppa( 'caldate' ) * 24*60*60 ) ); $t2 = $t1 + 24*60*60; - $query = "SELECT id FROM $wpdb->wppa_photos WHERE modified >= $t1 AND modified < $t2 " . $alb_clause; + $query = $wpdb->prepare( "SELECT id FROM $wpdb->wppa_photos WHERE modified >= %s AND modified < %s ", $t1, $t2 ) . $alb_clause; $total_ids = wppa_combine_virtual( $query, 29 ); break;
Exploit Outline
The vulnerability is exploited by sending a malicious HTTP request to a front-end page that utilizes WP Photo Album Plus galleries. An attacker can target parameters such as `wppa-album` (when using virtual album prefixes like `#tags,`, `#owner,`, or `#name,`) or `wppa-caldate` when calendar functions are active. By injecting SQL fragments (e.g., `' OR 1=1--`) into these parameters, the attacker escapes the intended SQL query structure in `wppa-functions.php` and executes arbitrary SQL commands. No authentication is required for this exploit.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.