CVE-2023-2249: Wordpress Wpforo Plugin Root Cause Analysis
On June 1st, 2023, a vulnerability was published within the WPForo Plugin - a user-friendly forum solution for WordPress websites. According to the official WordPress site, the plugin boasts over 20,000 active installations.
This vulnerability registered a CVSS score of 8.8 and exposes the plugin to multiple attack vectors. which includes Local File Inclusion (LFI), Server-Side Request Forgery (SSRF), and PHP Archive (PHAR) deserialization. There is the potential of leading to Remote Code Execution. Notably, this issue affects versions up to 2.1.7, but has been addressed in subsequent updates.
Since there is no public Proof-of-Concept (POC) available, we aim to conduct a root cause analysis of the vulnerability and present a proof of concept.
Enter Patch Diffing
Since WordPress plugins are open-source, diffing should be relatively easy. Fortunately, to make our life easy, NIST references of the CVE ID gives points to the file ‘classes/Actions.php’ file of the plugin. We diffed the version 2.17 and 2.18 of the same as shown below:
Fig 1: Versions being compared
We can see only 2 functions have been modified between the vulnerable and the patched versions of the file namely the ‘profiles_default_cover_upload’ and ‘profile_cover_upload’ which seem to be functionalities related to profile picture upload.
Fig 2: Functions being changed
Also, from NIST description, we know that there was usage of ‘file_get_contents’ without any sanitization which was the cause of the vulnerability. We can see the same was patched in the diff, so we are on the right track.
Fig 3: NIST description of the vulnerability
Fig 4: image_blob data being processed
From rough static code analysis, it seems like the user input for profile image data which is passed as ‘image_blob’ parameter if it doesn’t conform to a certain format, it gets passed to ‘file_get_contents’ as part of the else block. Before proceeding further analysis, let’s setup a vulnerable environment to understand the dynamic behavior.
Cooking up the Exploit
Setting up WordPress should be relatively easy, there are countless online tutorials. We will use a docker instance to speed things up.
- We setup a bitnami WordPress docker instance from here.
- At the time of writing the blog the vulnerable version of the plugin in the WordPress store was already replaced but we can download the vulnerable version of plugin from here.
- We can just upload the Plugin file as following and activate it.
Fig 5: Uploading Plugins to Wordpress
Once the plugin is activated, the home webpage should have a new ‘Forums’ button as below.
Fig 6: Forums option
We can figure out what type of permission is needed for the exploit later, for now let’s login as admin in the forums area and explore.
Fig 7: Logging In
Since we know from before, the vulnerability is in the profile picture upload functionality, we explore the profile section and try uploading a picture (that’s my cat below)
Fig 8: Profile picture upload
To inspect what is really going on, we fire up BurpSuite proxy and inspect the traffic.
Fig 9: Request Response from BurpSuite
We can confirm we are in-fact hitting the endpoint since we have the action name ‘wpforo_profile_cover_upload’ (the function name from before with wpforo prepended which seems to be the naming convention) and also have the parameter ‘image_blob’ as we saw during our code analysis. If we decode the value of the blob, we can see it consists of file format (image/jpeg), encoding (base64) and the actual data separated by a comma.
Fig 10: image_blob data decoded
If we look at the code again, it tries to split the data by comma and if there is no second index it will pass the entire thing to ‘get_file_contents’, so we can pass whatever we want as part of the ‘image_blob’ parameter except a comma and it should reach the vulnerable section of the code and fetch the file as shown below -
Fig 11: Exploitation
We can try the same request by replacing the action name to be ‘wpforo_profiles_default_cover_upload’ the other vulnerable and we also get a success there. We don’t get the file contents back since it’s stored as an image. Retrieving the data for the ‘profiles_default_cover_upload’ action since it saves it with a static name profiles_custom_default_cover.jpg
Fig 12: Hardcoded image path
So, we can easily retrieve the contents by sending a curl request as below -
Fig 13: contents of /etc/passwd retrieved
We can have implemented the exploit with a proof-of-concept code at https://github.com/ixiacom/CVE-2023-2249. Since ‘file_get_contents’ can also take remote paths, the exploit can be used to reach internal endpoints as following where we deploy a file which is fetched with our proof-of-concept.
Fig 14: Mimicking internal files hosted
Fig 15: SSRF able to fetch internal files
In the proof-of-concept screenshot above we provided the credentials of a user ‘victimtest’ who is just a subscriber which also works, so very little privileges is required.
Fig 16: victimtest, low privileged user
Mitigations
The plugin vendor has released patches for the vulnerability in version 2.18, so it’s advised to update your version of the plugin.
You can also use the Keysight test platforms with ATI subscription to safeguard your network against such attacks. Keysight Threat Simulator or BreakingPoint products can help you assess your network security controls and determine whether you can be protected before the patch. This kind of assessment is valuable as it can let you know if you have protection during the time before a change management window will open. More on this below.
Leverage subscription service to stay ahead of attacks
Keysight's Application and Threat Intelligence (ATI) Subscription provides daily malware and bi-weekly updates of the latest application protocols and vulnerabilities for use with Keysight test platforms. The ATI Research Centre continuously checks threats as they appear in the wild to help keep your network secure and has added coverage for this vulnerability in release ATI-2023-13. More information is present here.
Fig 8: CVE-2023-2249 in BreakingPoint