Headline
CVE-2022-4021: Changeset 2818142 – WordPress Plugin Repository
The Permalink Manager Lite plugin for WordPress is vulnerable to Cross-Site Request Forgery in versions up to, and including, 2.2.20.1. This is due to missing or incorrect nonce validation on the extra_actions function. This makes it possible for unauthenticated attackers to change plugin settings including permalinks and site maps, via forged request granted they can trick a site administrator into performing an action such as clicking on a link.
permalink-manager/trunk/README.txt
r2807848
r2818142
8
8
Requires PHP: 5.4
9
9
Tested up to: 6.1.0
10
Stable tag: 2.2.20.1
10
Stable tag: 2.2.20.2
11
11
12
12
Permalink Manager lets you customize the complete URL addresses of your posts, pages, custom post types, terms, and WooCommerce links with ease without touching any core files.
…
…
93
93
94
94
\== Changelog ==
95
96
\= 2.2.20.2 (November 15, 2022) =
97
\* Fix - A nonce field has been added to debug tools code for increased security
98
\* Fix - The "Fix language mismatch" function now functions exactly the same way in Polylang as it does in WPML
95
99
96
100
\= 2.2.20.1 (October 31, 2022) =
permalink-manager/trunk/includes/core/permalink-manager-actions.php
r2807848
r2818142
41
41
'permalink\_manager\_options' => array('function' => 'save\_settings'),
42
42
'permalink\_manager\_permastructs' => array('function' => 'save\_permastructures'),
43
'flush\_sitemaps' => array('function' => 'flush\_sitemaps'),
44
43
'import' => array('function' => 'import\_custom\_permalinks\_uris'),
45
44
);
…
…
286
285
\*/
287
286
public static function extra\_actions() {
288
if(current\_user\_can('manage\_options')) {
289
if(isset($\_GET\['flush\_sitemaps'\])) {
290
self::flush\_sitemaps();
291
} else if(isset($\_GET\['clear-permalink-manager-uris'\])) {
287
if(current\_user\_can('manage\_options') && !empty($\_GET\['\_wpnonce'\])) {
288
// Check if the nonce field is correct
289
$nonce = sanitize\_key($\_GET\['\_wpnonce'\]);
290
291
if(!wp\_verify\_nonce($nonce, 'permalink-manager')) {
292
$permalink\_manager\_before\_sections\_html .= Permalink\_Manager\_Admin\_Functions::get\_alert\_message(\_\_( 'You are not allowed to remove Permalink Manager data!', 'permalink-manager' ), 'error updated\_slugs');
293
return;
294
}
295
296
if(isset($\_GET\['clear-permalink-manager-uris'\])) {
292
297
self::clear\_all\_uris();
293
298
} else if(isset($\_GET\['remove-permalink-manager-settings'\])) {
294
299
$option\_name = sanitize\_text\_field($\_GET\['remove-permalink-manager-settings'\]);
295
300
self::remove\_plugin\_data($option\_name);
296
} /\*else if(!empty($\_REQUEST\['remove-uri'\])) {
301
} else if(!empty($\_REQUEST\['remove-uri'\])) {
297
302
$uri\_key = sanitize\_text\_field($\_REQUEST\['remove-uri'\]);
298
303
self::force\_clear\_single\_element\_uris\_and\_redirects($uri\_key);
…
…
300
305
$redirect\_key = sanitize\_text\_field($\_REQUEST\['remove-redirect'\]);
301
306
self::force\_clear\_single\_redirect($redirect\_key);
302
}\*/
307
}
303
308
} else if(!empty($\_POST\['screen-options-apply'\])) {
304
309
self::save\_screen\_options();
…
…
414
419
if(!current\_user\_can('manage\_options')) {
415
420
$permalink\_manager\_before\_sections\_html .= Permalink\_Manager\_Admin\_Functions::get\_alert\_message(\_\_( 'You are not allowed to remove Permalink Manager data!', 'permalink-manager' ), 'error updated\_slugs');
416
}
417
418
// Check if the nonce field is correct
419
$nonce = sanitize\_key($\_GET\['\_wpnonce'\]);
420
if(!wp\_verify\_nonce($nonce, 'permalink-manager')) {
421
$permalink\_manager\_before\_sections\_html .= Permalink\_Manager\_Admin\_Functions::get\_alert\_message(\_\_( 'You are not allowed to remove Permalink Manager data!', 'permalink-manager' ), 'error updated\_slugs');
422
return;
423
421
}
424
422
…
…
703
701
704
702
/\*\*
705
\* Clear sitemaps cache
706
\*/
707
function flush\_sitemaps($types = array()) {
708
global $permalink\_manager\_before\_sections\_html;
709
710
if(class\_exists('WPSEO\_Sitemaps\_Cache')) {
711
$sitemaps = WPSEO\_Sitemaps\_Cache::clear($types);
712
713
$permalink\_manager\_before\_sections\_html .= Permalink\_Manager\_Admin\_Functions::get\_alert\_message(\_\_( 'Sitemaps were updated!', 'permalink-manager' ), 'updated');
714
}
715
}
716
717
/\*\*
718
703
\* Import old URIs from "Custom Permalinks" (Pro)
719
704
\*/
permalink-manager/trunk/includes/core/permalink-manager-core-functions.php
r2807848
r2818142
222
222
if(strpos($element\_id, 'tax-') !== false) {
223
223
// Remove the "tax-" prefix
224
$term\_id = intval(preg\_replace("/\[^0-9\]/", "", $element\_id));
224
$element\_id = intval(preg\_replace("/\[^0-9\]/", "", $element\_id));
225
225
226
226
// Filter detected post ID
227
$term\_id = apply\_filters('permalink\_manager\_detected\_term\_id', intval($term\_id), $uri\_parts, true);
227
$element\_id = apply\_filters('permalink\_manager\_detected\_term\_id', intval($element\_id), $uri\_parts, true);
228
228
229
229
// Get the variables to filter wp\_query and double-check if taxonomy exists
230
$term = get\_term($term\_id);
230
$term = get\_term($element\_id);
231
231
$term\_taxonomy = (!empty($term->taxonomy)) ? $term->taxonomy : false;
232
232
…
…
245
245
$query\_parameter = $term\_taxonomy;
246
246
}
247
$term\_ancestors = get\_ancestors($term\_id, $term\_taxonomy);
247
$term\_ancestors = get\_ancestors($element\_id, $term\_taxonomy);
248
248
$final\_uri = $term->slug;
249
249
permalink-manager/trunk/includes/core/permalink-manager-language-plugins.php
r2796526
r2818142
249
249
250
250
function fix\_language\_mismatch($item\_id, $uri\_parts, $is\_term = false) {
251
global $wp, $polylang, $language\_code, $permalink\_manager\_options;
251
global $wp, $polylang, $language\_code, $permalink\_manager\_options, $icl\_adjust\_id\_url\_filter\_off;
252
252
253
253
$mode = (!empty($permalink\_manager\_options\['general'\]\['fix\_language\_mismatch'\])) ? $permalink\_manager\_options\['general'\]\['fix\_language\_mismatch'\] : 0;
254
255
// Stop WPML from changing the output of the get\_term() and get\_post() functions
256
$icl\_adjust\_id\_url\_filter\_off\_prior = $icl\_adjust\_id\_url\_filter\_off;
257
$icl\_adjust\_id\_url\_filter\_off = true;
254
258
255
259
if($is\_term) {
…
…
295
299
}
296
300
297
$item\_id = (!empty($translated\_item\_id)) ? $translated\_item\_id : $item\_id;
301
$item\_id = (isset($translated\_item\_id)) ? $translated\_item\_id : $item\_id;
298
302
} else {
299
303
$item\_id = apply\_filters('wpml\_object\_id', $element\_id, $element\_type);
…
…
305
309
}
306
310
}
311
312
$icl\_adjust\_id\_url\_filter\_off = $icl\_adjust\_id\_url\_filter\_off\_prior;
307
313
308
314
return $item\_id;
permalink-manager/trunk/includes/core/permalink-manager-uri-functions-post.php
r2796526
r2818142
124
124
$slug = sanitize\_title($slug);
125
125
126
$new\_slug = wp\_unique\_post\_slug($slug, $id, get\_post\_status($id), get\_post\_type($id), null);
126
$new\_slug = wp\_unique\_post\_slug($slug, $id, get\_post\_status($id), get\_post\_type($id), 0);
127
127
$wpdb->query($wpdb->prepare("UPDATE {$wpdb->posts} SET post\_name = %s WHERE ID = %d", $new\_slug, $id));
128
128
…
…
538
538
539
539
// Process URI & slug
540
$new\_slug = wp\_unique\_post\_slug($correct\_slug, $row\['ID'\], get\_post\_status($row\['ID'\]), get\_post\_type($row\['ID'\]), null);
540
$new\_slug = wp\_unique\_post\_slug($correct\_slug, $row\['ID'\], get\_post\_status($row\['ID'\]), get\_post\_type($row\['ID'\]), 0);
541
541
$new\_post\_name = ($mode == 'slugs') ? $new\_slug : $old\_post\_name; // Post name is changed only in first mode
542
542
permalink-manager/trunk/includes/views/permalink-manager-tools.php
r2297504
r2818142
52
52
$home\_url = trim(get\_option('home'), "/");
53
53
54
$button\_url = add\_query\_arg(array(
55
'section' => 'tools',
56
'subsection' => 'duplicates',
57
'clear-permalink-manager-uris' => 1,
58
'\_wpnonce' => wp\_create\_nonce('permalink-manager')
59
), Permalink\_Manager\_Admin\_Functions::get\_admin\_url());
60
54
61
$html = sprintf("<h3>%s</h3>", \_\_("List of duplicated permalinks", "permalink-manager"));
55
$html .= wpautop(sprintf("<a class=\\"button button-primary\\" href=\\"%s\\">%s</a>", admin\_url('tools.php?page=permalink-manager§ion=tools&subsection=duplicates&clear-permalink-manager-uris=1'), \_\_('Fix custom permalinks & redirects', 'permalink-manager')));
62
$html .= wpautop(sprintf("<a class=\\"button button-primary\\" href=\\"%s\\">%s</a>", $button\_url, \_\_('Fix custom permalinks & redirects', 'permalink-manager')));
56
63
57
64
if(!empty($all\_duplicates)) {
permalink-manager/trunk/permalink-manager.php
r2807848
r2818142
5
5
\* Plugin URI: https://permalinkmanager.pro?utm\_source=plugin
6
6
\* Description: Advanced plugin that allows to set-up custom permalinks (bulk editors included), slugs and permastructures (WooCommerce compatible).
7
\* Version: 2.2.20.1
7
\* Version: 2.2.20.2
8
8
\* Author: Maciej Bis
9
9
\* Author URI: http://maciejbis.net/
…
…
13
13
\* Domain Path: /languages
14
14
\* WC requires at least: 3.0.0
15
\* WC tested up to: 7.0.0
15
\* WC tested up to: 7.1.0
16
16
\*/
17
17
…
…
26
26
define( 'PERMALINK\_MANAGER\_PLUGIN\_NAME', 'Permalink Manager' );
27
27
define( 'PERMALINK\_MANAGER\_PLUGIN\_SLUG', 'permalink-manager' );
28
define( 'PERMALINK\_MANAGER\_VERSION', '2.2.20.1' );
28
define( 'PERMALINK\_MANAGER\_VERSION', '2.2.20.2' );
29
29
define( 'PERMALINK\_MANAGER\_FILE', \_\_FILE\_\_ );
30
30
define( 'PERMALINK\_MANAGER\_DIR', untrailingslashit(dirname(\_\_FILE\_\_)) );
Related news
The Chained Quiz plugin for WordPress is vulnerable to Reflected Cross-Site Scripting via the 'dn' parameter on the 'chainedquiz_list' page in versions up to, and including, 1.3.2.2 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that execute if they can successfully trick a user into performing an action such as clicking on a link.
The Simple:Press plugin for WordPress is vulnerable to Reflected Cross-Site Scripting via the 'sforum_[md5 hash of the WordPress URL]' cookie value in versions up to, and including, 6.8 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that execute if they can successfully trick a user into performing an action such as clicking on a link. This would be highly complex to exploit as it would require the attacker to set the cookie a cookie for the targeted user.
The WP Affiliate Platform plugin for WordPress is vulnerable to Reflected Cross-Site Scripting via $_SERVER["REQUEST_URI"] in versions up to, and including, 6.3.9 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that execute if they can successfully trick a user into performing an action such as clicking on a link. This is unlikely to work in modern browsers.
The WP Affiliate Platform plugin for WordPress is vulnerable to Stored Cross-Site Scripting via several parameters in versions up to, and including, 6.3.9 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with administrator-level permissions and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
The Simple:Press plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'postitem' parameter manipulated during a forum response in versions up to, and including, 6.8 due to insufficient input sanitization and output escaping that makes injecting object and embed tags possible. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages when responding to forum threads that will execute whenever a user accesses an injected page.
The Simple:Press plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'postitem' parameter manipulated during the profile-save action when modifying a profile signature in versions up to, and including, 6.8 due to insufficient input sanitization and output escaping that makes injecting object and embed tags possible. This makes it possible for authenticated attackers, with minimal permissions, such as a subscriber to inject arbitrary web scripts in pages when modifying a profile signature that will execute whenever a user accesses an injected page.
The Appointment Hour Booking Plugin for WordPress is vulnerable to CSV Injection in versions up to, and including, 1.3.72. This makes it possible for unauthenticated attackers to embed untrusted input into content during booking creation that may be exported as a CSV file when a site's administrator exports booking details. This can result in code execution when these files are downloaded and opened on a local system with a vulnerable configuration.
The Appointment Hour Booking plugin for WordPress is vulnerable to CAPTCHA bypass in versions up to, and including, 1.3.72. This is due to the use of insufficiently strong hashing algorithm on the CAPTCHA secret that is also displayed to the user via a cookie.
The Quiz and Survey Master plugin for WordPress is vulnerable to iFrame Injection via the 'question[id]' parameter in versions up to, and including, 8.0.4 due to insufficient input sanitization and output escaping that allowed iframe tags to be injected. This makes it possible for unauthenticated attackers to inject iFrames in pages that will execute whenever a user accesses an injected page.
The Quiz and Survey Master plugin for WordPress is vulnerable to input validation bypass via the 'question[id]' parameter in versions up to, and including, 8.0.4 due to insufficient input validation that allows attackers to inject content other than the specified value (i.e. a number, file path, etc..). This makes it possible attackers to submit values other than the intended input type.
The Appointment Hour Booking plugin for WordPress is vulnerable to iFrame Injection via the ‘email’ or general field parameters in versions up to, and including, 1.3.72 due to insufficient input sanitization and output escaping that makes injecting iFrame tags possible. This makes it possible for unauthenticated attackers to inject iFrames when submitting a booking that will execute whenever a user accesses the injected booking details page.
The Theme and plugin translation for Polylang is vulnerable to authorization bypass in versions up to, and including, 3.2.16 due to missing capability checks in the process_polylang_theme_translation_wp_loaded() function. This makes it possible for unauthenticated attackers to update plugin and theme translation settings and to import translation strings.
The Betheme theme for WordPress is vulnerable to PHP Object Injection in versions up to, and including, 26.5.1.4 via deserialization of untrusted input supplied via the import, mfn-items-import-page, and mfn-items-import parameters passed through the mfn_builder_import, mfn_builder_import_page, importdata, importsinglepage, and importfromclipboard functions. This makes it possible for authenticated attackers, with contributor level permissions and above to inject a PHP Object. The additional presence of a POP chain would make it possible for attackers to execute code, retrieve sensitive data, delete files, etc..