prerequisite
two conditions:
1.XunRuiCMS version is v4.3.3 to v4.5.1
2.You can log in to the background,And it is an administrator account or have the management permission of “应用”->“任务队列”
environment setup
-
install and configure php and web middleware, note that the low version of the cms requires a low version of php
-
clone the official open source address of the cms https://gitee.com/dayrui/xunruicms
-
search for the version number in the commit message to fall back to the specified version
In PhpStorm, right-click the specified commit version and select “Reset Current Branch to Here”.
Select “Hard” and click “Reset”.
- Access, install, and login to the backend
Backend address:/admin.php
Translated with www.DeepL.com/Translator (free version)
vulnerability description
Admin controller folder, Cron.php controller, add() function, there is no special filtering for user input, this will cause the attacker to execute the attack when he has administrator privileges or administrative privileges of “应用”->“任务队列”, write anything to the WRITEPATH.'config/cron.php'
, at the same time, the file has multiple points that can be executed and utilized, under normal circumstances, the above trigger conditions can stably trigger the vulnerability
vulnerability principle
before version v4.3.3
before version v4.3.3, there is no “add()” function under “cron.php”
Under versions v4.3.3 to v4.5.0
1.The CMS, with the above permissions, Can be accessed through http://host:port/Admin.php?c=Cron&m=add
call the add() function of the Cron.php controller under the Admin controller folder
2.code of add() function:
|
|
analysis of add() function
|
|
The add() function will first include the WRITEPATH.'config/cron.php'
file when it exists, WRITEPATH
can be configured in index.php under the root directory of the website, By default, it is cache/
under the root directory of the website
|
|
Then the add() function assigns Null
to $data
through the json_decode($json, true)
function
|
|
Then enter an if branch statement, When IS_AJAX_POST
, then execute the relevant code written to the file, otherwise, skip writing to the file, show cron’s add page, the add() function ends, IS_AJAX_POST
is defined as returning TRUE
when a post request is received and the content of post is not empty, otherwise, return to FALSE
|
|
In if statement, first \Phpcmf\Service::L('input')->post('data', true)
The code calls the post() function of class Input defined in the Input.php file, When a post request is received and the key is data
, perform “XSS cleaning” and return, otherwise, return to false
directly, then assign it to $post
, the code of “XSS cleaning” is relatively long, I put it at the end of this article, the “XSS cleaning” here can be easily bypassed, so as to write whatever we want
|
|
In if statement, post request received, then, the received content is encoded by JSON and written into WRITEPATH.'config/cron.php'
file, the controllable write point is located in the assignment of string $json
, and in the package of two '
’s, here is the main reason for the vulnerability, write the corresponding file without making sufficient judgment or cleaning on the user’s input
|
|
End of if statement, write log and display operation results, the cron add interface is displayed, and the add() function ends
Bypass JSON encoding and “XSS cleaning” and package '
in WRITEPATH.'config/cron.php'
file
Through the above analysis, we can find that, the add() function basically has no special precautions against user input, as long as we bypass the “XSS cleaning” and JSON encoding and the package '
in the WRITEPATH.'config/cron.php'
file, we can write whatever we want
The following is one of my methods. In the WRITEPATH.'config/cron.php'
file, write the PHP statement of a file named webshell.php with the content of <?php eval(@$_POST["password"]);?>
in the root directory of the website when running the WRITEPATH.'config/cron.php'
file
Note that the following operations need to obtain csrf_test_name first and obtain the method:
1.Visit http://host:port/Admin.php?c=Cron&m=add
2.Capture the post package sent when clicking “save”
3.csrf_test_name in the content of post can be used as csrf_test_name for a period of time
After obtaining csrf_test_name", give http://host:port/Admin.php?c=Cron&m=add
post the following:
|
|
After URL decoding, it is:
|
|
After bypassing JSON encoding and “XSS cleaning”, the contents written in WRITEPATH.'config/cron.php'
file are:
|
|
The key points in this post content are
|
|
After bypassing JSON encoding and “XSS cleaning”, the content here becomes:
|
|
The package of '
in document WRITEPATH.'config/cron.php'
is closed
include the WRITEPATH.'config/cron.php'
file written to
Through the analysis of add() function, when you call the add() function, you will first include the WRITEPATH.'config/cron.php'
file when it exists, therefore, you can access http://host:port/Admin.php?c=Cron&m=add
directly
After accessing http://host:port/Admin.php?c=Cron&m=add
, http://host:port/Admin.php?c=Cron&m=add
file named webshell.php will be generated in the root directory of the website, and the content of the file is <?php eval(@$_POST["password"]);?>
version v4.5.1
code of add() function:
|
|
Compared with previous versions, version v4.5.1 modified the following code when obtaining the content of post:
|
|
change to
|
|
The second parameter of the post() function is whether to “XSS clean”. Since the default value of the second parameter of the post() function is true
, this change will not have any impact in theory
At the same time, after obtaining the content of post and before writing WRITEPATH.'config/cron.php'
file, the following code is added:
|
|
The above code first determines whether the content of post exists and is an array. If it does not meet the requirements, it will set the content of post as an empty array. If it meets the requirements, it will traverse the content of post. If the value of a key value pair does not exist or the value of 'name'
key of value of a key value pair does not exist, it will destroy the key value pair, and then clean the 'name'
key and 'code'
key of value of each key value pair through the dr_safe_filename() function, the following is the code of the dr_safe_filename() function:
|
|
bypass the JSON encoding, “XSS cleaning”, dr_safe_filename() function filtering and packages in WRITEPATH.'config/cron.php'
file
Instead of trying to bypass the dr_safe_filename() function, let’s try another extremely simple method
Through the audit of the “XSS cleaning” function and the newly added code of the v5add() function, we can find that there is no filter for the key of the array, including the key of each dimension of the multidimensional array. Therefore, we can modify the key in the content of post to write any content we want
The following is my method. In the whole process of vulnerability exploitation, except for the above-mentioned filtering of value of key value pairs added in the add() function, other processes have no change compared with the previous version:
After obtaining csrf_test_name, give http://host:port/Admin.php?c=Cron&m=add
post the following contents:
|
|
After url decoding, it is:
|
|
After bypassing the filtering of JSON encoding, “XSS cleaning” and dr_safe_filename() function, the contents written in WRITEPATH.'config/cron.php'
file are:
|
|
The key points in this post content are
|
|
After bypassing the filtering of JSON encoding, “XSS cleaning” and dr_safe_filename() function, the content here becomes:
|
|
The package of '
in document WRITEPATH.'config/cron.php'
is closed
include the WRITEPATH.'config/cron.php'
file written to
Through the analysis of the add() function in front, when calling the add() function, the WRITEPATH.'config/cron.php'
file will be included when the WRITEPATH.'config/cron.php'
file exists, so you can directly access http://host:port/Admin.php?c=Cron&m=add
After accessing http://host:port/Admin.php?c=Cron&m=add
, http://host:port/Admin.php?c=Cron&m=add
file named webshell.php will be generated in the root directory of the website, and the content of the file is <?php eval(@$_POST["password"]);?>
after version v4.5.1
The add() function is deleted
POC && EXP
It’s very simple. I won’t write it, but note that there may be holes in the CMS of the target site. For example, the version number is low but the actual site file has been updated
POC
Log in to the background, get the version number, and then verify whether it is an administrator or has the management permission of “应用”->“任务队列”
EXP
Log in to the background, then post write malicious code, and finally get access to malicious files
xss_clean() function
|
|