a few fixes to sunrpc code
this fixes a couple of errors handling error messages also, some whitespace/indenting adjustments git-svn-id: file:///home/svn/framework3/trunk@8365 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
9b79ebd000
commit
a052340703
|
@ -6,9 +6,9 @@ module Msf
|
||||||
#
|
#
|
||||||
# This mixin provides utility methods for interacting with a SunRPC service on
|
# This mixin provides utility methods for interacting with a SunRPC service on
|
||||||
# a remote machine. These methods may generally be useful in the context of
|
# a remote machine. These methods may generally be useful in the context of
|
||||||
# exploitation. This mixin extends the Tcp exploit mixin. Only one SunRPC
|
# exploitation. This mixin extends the Tcp exploit mixin. Only one SunRPC
|
||||||
# service can be accessed at a time using this class.
|
# service can be accessed at a time using this class.
|
||||||
#
|
#
|
||||||
# http://www.ietf.org/rfc/rfc1057.txt
|
# http://www.ietf.org/rfc/rfc1057.txt
|
||||||
#
|
#
|
||||||
###
|
###
|
||||||
|
@ -16,7 +16,7 @@ module Exploit::Remote::SunRPC
|
||||||
include Exploit::Remote::Tcp
|
include Exploit::Remote::Tcp
|
||||||
|
|
||||||
XDR = Rex::Encoder::XDR
|
XDR = Rex::Encoder::XDR
|
||||||
|
|
||||||
MSG_ACCEPTED = 0
|
MSG_ACCEPTED = 0
|
||||||
SUCCESS = 0 # RPC executed successfully
|
SUCCESS = 0 # RPC executed successfully
|
||||||
PROG_UMAVAIL = 1 # Remote hasn't exported program
|
PROG_UMAVAIL = 1 # Remote hasn't exported program
|
||||||
|
@ -55,8 +55,8 @@ module Exploit::Remote::SunRPC
|
||||||
end
|
end
|
||||||
|
|
||||||
ret = rpcobj.create
|
ret = rpcobj.create
|
||||||
return print_error("#{rhost} - No response to SunRPC PortMap request") unless ret
|
return print_error("#{rhost} - No response to SunRPC PortMap request") unless ret
|
||||||
|
|
||||||
arr = XDR.decode!(ret, Integer, Integer, Integer, String, Integer, Integer)
|
arr = XDR.decode!(ret, Integer, Integer, Integer, String, Integer, Integer)
|
||||||
if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS || arr[5] == 0
|
if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS || arr[5] == 0
|
||||||
err = "#{rhost} - SunRPC PortMap request failed: "
|
err = "#{rhost} - SunRPC PortMap request failed: "
|
||||||
|
@ -65,7 +65,7 @@ module Exploit::Remote::SunRPC
|
||||||
err << 'Program not available' if arr[5] == 0
|
err << 'Program not available' if arr[5] == 0
|
||||||
print_error(err)
|
print_error(err)
|
||||||
end
|
end
|
||||||
|
|
||||||
rpcobj.pport = arr[5]
|
rpcobj.pport = arr[5]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -75,7 +75,8 @@ module Exploit::Remote::SunRPC
|
||||||
|
|
||||||
arr = Rex::Encoder::XDR.decode!(ret, Integer, Integer, Integer, String, Integer)
|
arr = Rex::Encoder::XDR.decode!(ret, Integer, Integer, Integer, String, Integer)
|
||||||
if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS
|
if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS
|
||||||
err = "SunRPC call for program #{program} [#{progresolv(program)}], procedure #{procedure}, failed: "
|
progname = progresolv(rpcobj.program)
|
||||||
|
err = "SunRPC call for program #{rpcobj.program} [#{progname}], procedure #{proc}, failed: "
|
||||||
case arr[4]
|
case arr[4]
|
||||||
when PROG_UMAVAIL then err << "Program Unavailable"
|
when PROG_UMAVAIL then err << "Program Unavailable"
|
||||||
when PROG_MISMATCH then err << "Program Version Mismatch"
|
when PROG_MISMATCH then err << "Program Version Mismatch"
|
||||||
|
@ -100,13 +101,14 @@ module Exploit::Remote::SunRPC
|
||||||
def sunrpc_authunix(*args)
|
def sunrpc_authunix(*args)
|
||||||
rpcobj.authunix_create(*args)
|
rpcobj.authunix_create(*args)
|
||||||
end
|
end
|
||||||
|
|
||||||
# XXX: Incomplete. Just moved from Rex::Proto::SunRPC::Client
|
# XXX: Incomplete. Just moved from Rex::Proto::SunRPC::Client
|
||||||
def portmap_qry()
|
def portmap_qry()
|
||||||
ret = portmap_req()
|
ret = portmap_req()
|
||||||
arr = Rex::Encoder::XDR.decode!(ret, Integer, Integer, Integer, String, Integer)
|
arr = Rex::Encoder::XDR.decode!(ret, Integer, Integer, Integer, String, Integer)
|
||||||
if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS || arr[5] == 0
|
if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS || arr[5] == 0
|
||||||
err = "SunRPC call for program #{program} [#{progresolv(program)}], procedure #{procedure}, failed: "
|
progname = progresolv(rpcobj.program)
|
||||||
|
err = "SunRPC query for program #{rpcobj.program} [#{progname}] failed: "
|
||||||
case arr[4]
|
case arr[4]
|
||||||
when PROG_UMAVAIL then err << "Program Unavailable"
|
when PROG_UMAVAIL then err << "Program Unavailable"
|
||||||
when PROG_MISMATCH then err << "Program Version Mismatch"
|
when PROG_MISMATCH then err << "Program Version Mismatch"
|
||||||
|
@ -116,25 +118,25 @@ module Exploit::Remote::SunRPC
|
||||||
end
|
end
|
||||||
print_error("#{rhost} - #{err}")
|
print_error("#{rhost} - #{err}")
|
||||||
end
|
end
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
def progresolv(number)
|
def progresolv(number)
|
||||||
names = File.join(Msf::Config.install_root, "data", "wordlists", "rpc_names.txt")
|
names = File.join(Msf::Config.install_root, "data", "wordlists", "rpc_names.txt")
|
||||||
File.open(names,"r").each_line do |line|
|
File.open(names,"r").each_line do |line|
|
||||||
next if line.empty? || line =~ /^\s*#/
|
next if line.empty? || line =~ /^\s*#/
|
||||||
|
|
||||||
if line =~ /^(\S+?)\s+(\d+)/ && number == $2.to_i
|
if line =~ /^(\S+?)\s+(\d+)/ && number == $2.to_i
|
||||||
return $1
|
return $1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return "UNKNOWN-#{number}"
|
return "UNKNOWN-#{number}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Used to track the last SunRPC context
|
# Used to track the last SunRPC context
|
||||||
attr_accessor :rpcobj
|
attr_accessor :rpcobj
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,16 +16,16 @@ class RPCTimeout < ::Interrupt
|
||||||
end
|
end
|
||||||
|
|
||||||
# XXX: CPORT!
|
# XXX: CPORT!
|
||||||
class Client
|
class Client
|
||||||
AUTH_NULL = 0
|
AUTH_NULL = 0
|
||||||
AUTH_UNIX = 1
|
AUTH_UNIX = 1
|
||||||
|
|
||||||
PMAP_PROG = 100000
|
PMAP_PROG = 100000
|
||||||
PMAP_VERS = 2
|
PMAP_VERS = 2
|
||||||
PMAP_GETPORT = 3
|
PMAP_GETPORT = 3
|
||||||
|
|
||||||
CALL = 0
|
CALL = 0
|
||||||
|
|
||||||
attr_reader :rhost, :rport, :proto, :program, :version
|
attr_reader :rhost, :rport, :proto, :program, :version
|
||||||
attr_accessor :pport
|
attr_accessor :pport
|
||||||
|
|
||||||
|
@ -40,13 +40,13 @@ class Client
|
||||||
rhost, rport, program, version, proto.downcase
|
rhost, rport, program, version, proto.downcase
|
||||||
|
|
||||||
@pport = nil
|
@pport = nil
|
||||||
|
|
||||||
@auth_type = AUTH_NULL
|
@auth_type = AUTH_NULL
|
||||||
@auth_data = ''
|
@auth_data = ''
|
||||||
|
|
||||||
@call_sock = nil
|
@call_sock = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
# XXX: Add optional parameter to have proto be something else
|
# XXX: Add optional parameter to have proto be something else
|
||||||
def create()
|
def create()
|
||||||
proto_num = 0
|
proto_num = 0
|
||||||
|
@ -60,7 +60,7 @@ class Client
|
||||||
Rex::Encoder::XDR.encode(CALL, 2, PMAP_PROG, PMAP_VERS, PMAP_GETPORT,
|
Rex::Encoder::XDR.encode(CALL, 2, PMAP_PROG, PMAP_VERS, PMAP_GETPORT,
|
||||||
@auth_type, [@auth_data, 400], AUTH_NULL, '',
|
@auth_type, [@auth_data, 400], AUTH_NULL, '',
|
||||||
@program, @version, proto_num, 0)
|
@program, @version, proto_num, 0)
|
||||||
|
|
||||||
sock = make_rpc(@proto, @rhost, @rport)
|
sock = make_rpc(@proto, @rhost, @rport)
|
||||||
send_rpc(sock, buf)
|
send_rpc(sock, buf)
|
||||||
ret = recv_rpc(sock)
|
ret = recv_rpc(sock)
|
||||||
|
@ -73,46 +73,46 @@ class Client
|
||||||
buf =
|
buf =
|
||||||
Rex::Encoder::XDR.encode(CALL, 2, @program, @version, procedure,
|
Rex::Encoder::XDR.encode(CALL, 2, @program, @version, procedure,
|
||||||
@auth_type, [@auth_data, 400], AUTH_NULL, '')+
|
@auth_type, [@auth_data, 400], AUTH_NULL, '')+
|
||||||
buffer
|
buffer
|
||||||
|
|
||||||
if !@call_sock
|
if !@call_sock
|
||||||
@call_sock = make_rpc(@proto, @rhost, @pport)
|
@call_sock = make_rpc(@proto, @rhost, @pport)
|
||||||
end
|
end
|
||||||
|
|
||||||
send_rpc(@call_sock, buf)
|
send_rpc(@call_sock, buf)
|
||||||
recv_rpc(@call_sock, timeout)
|
recv_rpc(@call_sock, timeout)
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
close_rpc(@call_sock) if @call_sock
|
close_rpc(@call_sock) if @call_sock
|
||||||
@call_sock = nil
|
@call_sock = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def authnull_create
|
def authnull_create
|
||||||
@auth_type = AUTH_NULL
|
@auth_type = AUTH_NULL
|
||||||
@auth_data = ''
|
@auth_data = ''
|
||||||
end
|
end
|
||||||
|
|
||||||
def authunix_create(host, uid, gid, groupz)
|
def authunix_create(host, uid, gid, groupz)
|
||||||
raise ::Rex::ArgumentError, 'Hostname length is too long' if host.length > 255
|
raise ::Rex::ArgumentError, 'Hostname length is too long' if host.length > 255
|
||||||
# 10?
|
# 10?
|
||||||
raise ::Rex::ArgumentError, 'Too many groups' if groupz.length > 10
|
raise ::Rex::ArgumentError, 'Too many groups' if groupz.length > 10
|
||||||
|
|
||||||
@auth_type = AUTH_UNIX
|
@auth_type = AUTH_UNIX
|
||||||
@auth_data =
|
@auth_data =
|
||||||
Rex::Encoder::XDR.encode(0, host, uid, gid, groupz) # XXX: TIME! GROUPZ?!
|
Rex::Encoder::XDR.encode(0, host, uid, gid, groupz) # XXX: TIME! GROUPZ?!
|
||||||
end
|
end
|
||||||
|
|
||||||
# XXX: Dirty, integrate some sort of request system into create/call?
|
# XXX: Dirty, integrate some sort of request system into create/call?
|
||||||
def portmap_req(host, port, rpc_vers, procedure, buffer)
|
def portmap_req(host, port, rpc_vers, procedure, buffer)
|
||||||
buf = Rex::Encoder::XDR.encode(CALL, 2, PMAP_PROG, rpc_vers, procedure,
|
buf = Rex::Encoder::XDR.encode(CALL, 2, PMAP_PROG, rpc_vers, procedure,
|
||||||
AUTH_NULL, '', AUTH_NULL, '') + buffer
|
AUTH_NULL, '', AUTH_NULL, '') + buffer
|
||||||
|
|
||||||
sock = make_rpc('tcp', host, port)
|
sock = make_rpc('tcp', host, port)
|
||||||
send_rpc(sock, buf)
|
send_rpc(sock, buf)
|
||||||
ret = recv_rpc(sock)
|
ret = recv_rpc(sock)
|
||||||
close_rpc(sock)
|
close_rpc(sock)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -128,11 +128,11 @@ class Client
|
||||||
if !self.should_fragment
|
if !self.should_fragment
|
||||||
return Rex::Encoder::XDR.encode(0x80000000 | buf.length) + buf
|
return Rex::Encoder::XDR.encode(0x80000000 | buf.length) + buf
|
||||||
end
|
end
|
||||||
|
|
||||||
str = buf.dup
|
str = buf.dup
|
||||||
|
|
||||||
fragmented = ''
|
fragmented = ''
|
||||||
|
|
||||||
while (str.size > 0)
|
while (str.size > 0)
|
||||||
frag = str.slice!(0, rand(3) + 1)
|
frag = str.slice!(0, rand(3) + 1)
|
||||||
len = frag.size
|
len = frag.size
|
||||||
|
@ -153,7 +153,7 @@ class Client
|
||||||
end
|
end
|
||||||
sock.write(buf)
|
sock.write(buf)
|
||||||
end
|
end
|
||||||
|
|
||||||
def recv_rpc(sock, timeout=60)
|
def recv_rpc(sock, timeout=60)
|
||||||
buf = sock.get(timeout)
|
buf = sock.get(timeout)
|
||||||
buf.slice!(0..3)
|
buf.slice!(0..3)
|
||||||
|
@ -163,11 +163,11 @@ class Client
|
||||||
return buf if buf.length > 1
|
return buf if buf.length > 1
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def close_rpc(sock)
|
def close_rpc(sock)
|
||||||
sock.close
|
sock.close
|
||||||
end
|
end
|
||||||
|
|
||||||
def gen_xid
|
def gen_xid
|
||||||
return Rex::Encoder::XDR.encode(rand(0xffffffff) + 1)
|
return Rex::Encoder::XDR.encode(rand(0xffffffff) + 1)
|
||||||
end
|
end
|
||||||
|
@ -175,4 +175,4 @@ end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue