Introduction
CVE : CVE-2022–41544
Description: GetSimple CMS v3.3.16 was discovered to contain a remote code execution (RCE) vulnerability via the edited_file parameter in admin/theme-edit.php
.
Version: v3.3.16 and the lasted in this time
Product: Get-Simple CMS
Based on fofa (a cyberspace search engine), using the filter (body=" content=\\\"GetSimple" || body=" Powered by GetSimple")
approximately 4,276 instances are found using this vulnerable version, which is publicly exploitable as shown bellow
What is GetSimple CMS ?
GetSimple CS is an open-source, light content manager without database, Ideal for small websites and user-friendly customizable templates, built in PHP language
Let’s set up the testing Lab and start hunting for some fun!
Building The Testing Lab
I will use Ubuntu as the local host server to host the app,
for downloading the CMS code you can get it from the offical repositroy or execute the following command:
wget https://github.com/GetSimpleCMS/GetSimpleCMS/archive/refs/tags/v3.3.16.tar.gz
and install the essentials CMS components like (apache2, mysql, php..etc) to run the application:
sudo apt-get install apache2 wget guzip php7.2 libapache2-mod-php7.2 php7.2-common php7.2-mbstring php7.2-xmlrpc php7.2-soap php7.2-gd php7.2-xml php7.2-cli php7.2-curl php7.2-zip -y
extract and move the application files to the /var/www/html/
directory
and setup the files permission by the following
sudo chown -R www-data:www-data /var/www/html/CMS
sudo chmod -R 755 /var/www/html/CMS/
And after completing the preparation steps above, check the status of the Apache2 server and byy visiting localhost by the application’s file name. you should see something similar like the following
then make an account:
And the application will generate a random password for you to use when logging into the admin panel as shown below:
login using the username and the pass
time to reviwing the code and spot the root case in the static analysis
Static Analysis
The directory tree of the application is structured as follows
And as mentioned in the CVE Description the vulnerability exists in admin/theme-edit.php
file in the theme edit HTTP request and this file which is the responsible file for editing themes in the GetSimple CMS panel.
Therefore by reviewing the code for the theme edit request, which handles the HTTP request form in the theme-edit.php
file to understand how it works as the following
The code first checks for a form submission by validating the CSRF token to avoid a Cross-site Request Forgery attack (CSRF) by checking if the nonce value exists in the POST request parameter or not If the nonce value exists, the code checks if it’s a valid or not using the check_nonce()
function. If the nonce
value is invalid, the script prints an error message saying "CSRF detected!" and stops processing of the request.
and by looking at the check_nonce()
function code which exists in admin/inc/security_functions.php
as shown bellow
In the function body, the code calls the get_nonce()
function, which is responsible for generating the nonce
value and then returning it. so the check_nonce()
compares between the the nonce
value sent by the user in the HTTP request and the true nonce
value which is returned by get_nonce()
function.
so to understand how the application generates and obtains the nonce
parameter value. which was returned by get_nonce()
function and we need to review the code of the function which is existed in file admin/inc/security_functions.php
as shown bellow
the function generates a unique and time-limited nonce
value by concatenating the $action
, $file
, $uid
, $USR
, $SALT
variables and the current date@date('YmdH',$time)
to ensure the nonce
value is unique and secure and then hashing it to the SHA-1 and return its value.
so after understanding how the application generates the nonce value and processes it to prevent CSRF attacks let’s return to reviewing the code for the vulnerable theme edit HTTP request which is located in the theme-edit.php
file as mentioned earlier.
i found the code responsible for editing the file to be modified and saving its value, which starts at line 55, as the following
first the code retrieves the name of the theme template file to be edited from the edited_file
parameter in the HTTP POST request and next it retrieves the contents of the file to be saved from the content
parameter in the HTTP POST request.
Then, the code opens the file specified in the edited_file
parameter using the fopen()
PHP built-in function and writes the content
parameter values into it using the fwrite()
PHP built-in function which is used for writing to an open file.
The vulnerable part of the code is when it uses fopen
to open a file with write permission (w) during the theme-edit
process. This means that anyone with access to the theme-edit
functionality can potentially write to the server and it's normal for file upload functions but there is another issue that makes it more dangerous the edited_file
value is not filtered/santizated, which could lead to a directory traversal attack that gives the attacker to manipulate this value to write to files outside of the intended directory and potentially overwrite any file in the root directory
Reproducing the Vulnerability as a PoC
by login into the GetSimple panel then go to Edit Theme
save the template to intercept the request with Burp Suite and replace some of its content with our own web shell or code as shown below
after inspecting the request in burp suite, modify the edited_file
parameter value to another file and i edited it to ../hack.php
and then modify the content
parameter with the code/content you want to upload to the crafted file which is hack.php
and in this case we will upload the phpinfo()
to proof the bug
and go to uploaded file hack.php
as demonstrated in the following picture and this mean vulnerability exploited successfully
but still, this vulnerability requires the attacker to have an admin user in the Get-simple panel to access this vulnerable functionality so let’s see how the Authentication works in the Runtime to bypass it and achieve a RCE (Remote Code Execution)
Dynamic Analysis
time to Debugging the application to get a solid understanding of the application flow and the Authentication process
I will use PhpStorm
and Xdebug
chrome extension in the debugging
And you can get the Xdebug form this here
Setting up the Debugging
after installing Xdebug on your system using the following Command
sudo apt-get install php-xdebug
Next edit the configuration file located at /etc/php/7.2/mods-available/xdebug.ini
and add the following lines
zend_extension="xdebug.so"
xdebug.remote_enable = 1
xdebug.remote_port = 9000
xdebug.idekey = PHPSTORM
xdebug.show_error_trace = 1
xdebug.remote_autostart = 0
These settings configure Xdebug for remote debugging with PHPStorm
like communication port, enable error traces, and disable automatic starting of remote debugging sessions.
Now, open the extension and choose the Debug
option as shown below
And start the debugging listing for the xdebug connection
Accept the connection request from Xdebug
the in php storm and I will start the debugging process from the admin/index.php
because it's considered the entry-point for the Web app
After the login process, the debugger shows that the app calls another function from a different file, which is the login_cookie_check()
function, as shown in the previous screenshot. This function is located in the admin/inc/cookie_functions.php
path and is responsible for checking cookies when the admin logs in:
login_cookie_check()
As shown in the function body, it uses two other functions: create_cookie()
and cookie_check()
and if cookie_check()
returns true, then it will call the create_cookie()
function. Both functions are located in the same file so let's dive deeper into this code to gain a full understanding of the cookie creation and checking process.
create_cookie()
GetSimple CMS uses two cookies:
- the first cookie name is
GS_ADMIN_USERNAME
and its value is the admin username - the second cookie’s name is stored in the
$saltCOOKIE
variable which contains the hashed SHA-1 values of the$cookie_name
variable concatenated with the$SALT
variable. The value of this cookie is stored in the$saltUSR
variable which contains the hashed SHA-1 values of the$USR
variable concatenated with the$SALT
variable.
to understand the second cookie’s name and value generation, we first need to determine the values of the $SALT
and $cookie_name
variables. so let's start by finding the $SALT
value. To do this, i will search for the $SALT =
keyword in all CMS files. and i already found the $SALT
assignment in the code in the /admin/inc/common.php
file, as shown below:
The code checks if the GSUSECUSTOMSALT
constant is defined or not. If it is defined the $SALT
value will be the constant value (custom admin salt). If it is not defined the $SALT
value is auto-generated and retrieved directly from the authorization.xml
file, which is contain the CMS app API key.
and to disable the auto-generation of the SALT value and use a custom value instead, admin will assign his custom SALT value to the GSUSECUSTOMSALT constant that exists in the gsconfig.php
file.
now that we know how the $SALT value is generated, let’s determine how the $cookie_name variable value is generated. To do this, i searched through all CMS files for the $cookie_name variable assignment using the keyword $cookie_name =
, I found it defined in the configuration.php
file, as shown below in line 16:
The $cookie_name
variable value is generated by combining the SiteName (getsimple), the _cookie_
word, and the CMS version without dots (e.g., 3316).
so the complete $cookie_name value is ‘getsimple_cookie_3316’.
And as mentioned earlier the application combines these variables $SALT
,$USR
(admin username) and hashes SHA1 them to generate the cookie value.
the final form of the cookie looks like the following, where the second name and value represent the hashed $saltCOOKIE
and $saltUSR
variables
And the another function used in the login_cookie_check()
function is the cookie_check()
function:
cookie_check()
The cookie_check()
function verifies the validity of the cookie by checking the values used in both the cookie_create()
function and the application code. It returns true if the cookie is valid and indicates that the user is logged in and false if the cookie is invalid
going back to the main function for theme edit after getting authenticated to the application,
edited_file
parameter which is vulnerable to Path Traversal as explained earlier
as we can see, the value of the file is passed without any filtration, which allows the attacker to change the directory of uploaded files anywhere they choose and also change its value.
GetSimpleCMS works on apache server and it’s a common server for php language, the default configuration of the Apache HTTP Server no longer includes the AllowOverride directive, meaning that any .htaccess
files in your directory structure will be ignored so as a result, unauthorized users may gain access to restricted information, leading to the exposure of sensitive data. (information disclosure)
the default setting for apache server existed in /etc/apache2/apache2.conf
was like the following:
The AllowOverride
directive was set to None
and this allowed unauthorized users to access sensitive information like api_key which exists in /data/other/authorization.xml
and access the apikey
and this key was used to generate the cookie as explained in the dynamic analysis above
With all the information we’ve obtained, we can now write an exploit for the CVE to regenerate the admin’s cookie and upload a web shell. The details of this exploit will be discussed in a another post.
Mitigation
unfortunately, there is no patch or updates for this Vulnrable version yet but there are ways to limit the vulnerability to achive the RCE by disabling some functions like exec, system
by editing the php.ini
file to prevent the common simple web shells to execute commands on the system
Conclusion
As we saw during the analysis, GetSimple CMS was not Simple to debug because there are many functions related to each other in different places, which makes it a bit difficult to trace. After mixing multiple vulnerabilities, such as Path Traversal and Information Disclosure, we were able to bypass the Authentication and upload a web shell anywhere under the root directory.