Exploit-DB #7796
Description: MKPortal 1.2.1 - Multiple Vulnerabilities
Type: webapps
Platform: php
Date: 2009-01-15
Author: waraxe

Exploit:
[waraxe-2009-SA#070] - Multiple Vulnerabilities in MKPortal <= 1.2.1
==============================================================================

Author: Janek Vind "waraxe"
Date: 15. January 2009
Location: Estonia, Tartu
Web: http://www.waraxe.us/advisory-70.html


Description of vulnerable software:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

MKPortal is a free Portal/Content Management System (CMS) which seamlessly
integrates with the most popular forum softwares. It uses the forum user
management system and other features and adds many powerful modules to create
and manage a light but powerful web site. MKPortal has an intuitive user
interface and is very simple to install and administer.

Homepage: http://www.mkportal.it/


List of found vulnerabilities
===============================================================================

1. Insecure file upload in blog personal gallery
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Security risk: critical
Preconditions:
 1. attacker must be registered user
 2. attacker must have blog editing privileges

Registered users with blog keeping privileges can access personal gallery
functionality, example URL:

http://localhost/mkportal.1.2.1/index.php?ind=blog&op=p_gal

They can also upload image files to the server. File uploading can be
dangerous without proper security checks. So let's have a closer look
at the source code of "modules/blog/index.php" line ~2452: 

---------------------[source code]---------------------
function upload_imm () {
		global $mkportals, $DB, $mklib, $Skin, $_FILES;

..
		$file =  $_FILES['FILE_UPLOAD']['tmp_name'];
		$file_name =  $_FILES['FILE_UPLOAD']['name'];
		//$file_type =  $_FILES['FILE_UPLOAD']['type'];
		$peso =  $_FILES['FILE_UPLOAD']['size'];		
		
		if (!$file) {
			$message = "{$mklib->lang['b_compfile']}";
			$mklib->error_page($message);
			exit;
		}

		//Validate file extension
		$file_ext = preg_replace("`.*\.(.*)`", "\\1", $file_name);
		$file_ext = substr ($file_name, (strlen($file_name)-3), 3);
		$file_ext = strtolower($file_ext);

		switch($file_ext)
		{
			case 'gif':
				$ext = 'gif';
				break;
			case 'jpg':
				$ext = 'jpg';
				break;
			case 'png':
				$ext = 'png';
				break;
			case 'tif':
				$ext = 'tif';
				break;
			case 'bmp':
				$ext = 'bmp';
				break;
			default:
				$ext = 'not_supported';
				break;
		}
		if ($ext == "not_supported")  {
			$message = "{$mklib->lang['b_gnotsup']}";
			$mklib->error_page($message);
			exit;
		}

--------------------[/source code]---------------------

So this piece of code suppose to be let in only files with specific extensions.
In reality it will pass through files like "foobar.agif" or "whatever.pbmp ...
Let's assume, that we have jpg picture named "pic.php.jjpg". This can be valid
picture file and in same time contain malicious php code inside.

What happens next:

---------------------[source code]---------------------
		//Move file from server tmp directory to blog "tmp" directory			
		if (!move_uploaded_file("$file", "mkportal/blog/images/tmp/$file_name")) {
			$message = "{$mklib->lang['b_nopermupl']}";
			$mklib->error_page($message);
			exit;
		}
		@chmod("mkportal/blog/images/tmp/$file_name", 0644);
	
		//Validate by mime type
		$tmpfilename = "mkportal/blog/images/tmp/$file_name";
		$size = @getimagesize($tmpfilename);
		//If getimagesize does not recognize file as an image delete file
		if (!$size)  {
			@unlink($tmpfilename);
			$message .= "{$mklib->lang['error_filetype']}";
			$mklib->error_page($message);
			exit;
		}
--------------------[/source code]---------------------

As this image file is perfectly normal jpg picture, then it will bypass
"getimagesize()" successfully. And "chmod()" will not make any differents in
specific situation.

Next:

---------------------[source code]---------------------
$file_type = $size['mime'];

		if (!$mklib->check_attach($file_type, $file_ext))  {
			//Delete invalid file and display error
			@unlink($tmpfilename);
			$message .= "{$mklib->lang['b_gnotsup']}";
			$mklib->error_page($message);
			exit;
		}

		//Validate by file contents
		$fcontents = file_get_contents ($tmpfilename);
		$carray = array("html", "javascript", "vbscript", "alert",
 "onmouseover", "onclick", "onload", "onsubmit");		
		foreach ($carray as $fch) {
            		if (strstr($fcontents, $fch)) {
                		@unlink($tmpfilename);
				$message .= "{$mklib->lang['error_filetype']}";
				$mklib->error_page($message);
                		exit;
            		}
        	}
        	if (preg_match("#script(.+?)/script#ies", $fcontents)) {
           		@unlink($tmpfilename);
			$message .= "{$mklib->lang['error_filetype']}";
			$mklib->error_page($message);
            		exit;
		}
--------------------[/source code]---------------------

Again, MIME-type will be correct and html-code detection can't stop
malicious php code inside of that jpg file. 

Finally:

---------------------[source code]---------------------
$image = $totr.$file_name;

//move file from "tmp" directory to "images" directory
@rename($tmpfilename, "mkportal/blog/images/$image");
--------------------[/source code]---------------------

What's the possibilities? Attacker can upload picture file with php code
inside with filename like "pic.php.pjpg" and it will be stored in remote
server as result. And when attacker issues direct request to uploaded
picture:

http://localhost/mkportal.1.2.1/mkportal/blog/images/1pic.php.pjpg"

.. then in case of Apache webserver php code inside of picture will
be executed. Therefore it's basically remote php code execution.


2. Insecure file upload in Downloads module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Security risk: critical
Preconditions:
 1. attacker must be registere