223 lines
5.0 KiB
Ruby
223 lines
5.0 KiB
Ruby
# -*- coding: binary -*-
|
|
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 !(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 !(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 !(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 !(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 !(resp and resp =~ /VERSION/)
|
|
disconnect
|
|
return false
|
|
end
|
|
|
|
# Store the version information
|
|
mver = resp.match(/IVERSION\x00([^\x00]+)/n)
|
|
info['Version'] = mver[1] if mver
|
|
|
|
# Store the hostname information
|
|
mver = resp.match(/ISERVNAME\x00([^\x00]+)/n)
|
|
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 !(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 !(resp and resp.length > 0)
|
|
break if resp[0,2] == "\x00\x69"
|
|
}
|
|
if !(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]+)/n)
|
|
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
|