Mirror of metasploit
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

sunrpc.rb 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. # -*- coding: binary -*-
  2. require 'rex/proto/sunrpc'
  3. module Msf
  4. ###
  5. #
  6. # This mixin provides utility methods for interacting with a SunRPC service on
  7. # a remote machine. These methods may generally be useful in the context of
  8. # exploitation. This mixin extends the Tcp exploit mixin. Only one SunRPC
  9. # service can be accessed at a time using this class.
  10. #
  11. # http://www.ietf.org/rfc/rfc1057.txt
  12. #
  13. ###
  14. module Exploit::Remote::SunRPC
  15. include Exploit::Remote::Tcp
  16. XDR = Rex::Encoder::XDR
  17. MSG_ACCEPTED = 0
  18. SUCCESS = 0 # RPC executed successfully
  19. PROG_UMAVAIL = 1 # Remote hasn't exported program
  20. PROG_MISMATCH = 2 # Remote can't support version #
  21. PROC_UNAVAIL = 3 # Program can't support procedure
  22. GARBAGE_ARGS = 4 # Procedure can't decode params'
  23. SYSTEM_ERR = 5 # System encountered some error
  24. def initialize(info = {})
  25. super
  26. register_evasion_options(
  27. [
  28. OptBool.new('ONCRPC::tcp_request_fragmentation', [false, 'Enable fragmentation of TCP ONC/RPC requests', false]),
  29. ], Msf::Exploit::Remote::SunRPC
  30. )
  31. register_advanced_options(
  32. [
  33. OptInt.new('TIMEOUT', [true, 'Number of seconds to wait for responses to RPC calls', 5])
  34. # XXX: Use portmapper to do call - Direct portmap to make the request to the program portmap_req
  35. ], Msf::Exploit::Remote::SunRPC)
  36. register_options(
  37. [
  38. # XXX: XPORT
  39. Opt::RHOST,
  40. Opt::RPORT(111),
  41. ], Msf::Exploit::Remote::SunRPC
  42. )
  43. end
  44. def sunrpc_create(protocol, program, version, time_out = timeout)
  45. self.rpcobj = Rex::Proto::SunRPC::Client.new(
  46. :rhost => rhost,
  47. :rport => rport.to_i,
  48. :proto => protocol,
  49. :program => program,
  50. :timeout => time_out,
  51. :version => version,
  52. :context => {
  53. 'Msf' => framework,
  54. 'MsfExploit' => self,
  55. }
  56. )
  57. if datastore['ONCRPC::tcp_request_fragmentation']
  58. self.rpcobj.should_fragment = 1
  59. end
  60. ret = rpcobj.create
  61. raise ::Rex::Proto::SunRPC::RPCError, "#{rhost}:#{rport} - SunRPC - No response to Portmap request" unless ret
  62. arr = XDR.decode!(ret, Integer, Integer, Integer, String, Integer, Integer)
  63. if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS || arr[5] == 0
  64. err = "#{rhost}:#{rport} - SunRPC - Portmap request failed: "
  65. err << 'Message not accepted' if arr[1] != MSG_ACCEPTED
  66. err << 'RPC did not execute' if arr[4] != SUCCESS
  67. err << 'Program not available' if arr[5] == 0
  68. raise ::Rex::Proto::SunRPC::RPCError, err
  69. end
  70. rpcobj.pport = arr[5]
  71. end
  72. def sunrpc_call(proc, buf, timeout = timeout())
  73. ret = rpcobj.call(proc, buf, timeout)
  74. raise ::Rex::Proto::SunRPC::RPCError, "#{rhost}:#{rport} - SunRPC - No response to SunRPC call for procedure: #{proc}" unless ret
  75. arr = Rex::Encoder::XDR.decode!(ret, Integer, Integer, Integer, String, Integer)
  76. if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS
  77. progname = progresolv(rpcobj.program)
  78. err = "SunRPC call for program #{rpcobj.program} [#{progname}], procedure #{proc}, failed: "
  79. if (arr[1] != MSG_ACCEPTED)
  80. err << 'Message not accepted'
  81. elsif (arr[4] and arr[4] != SUCCESS)
  82. case arr[4]
  83. when PROG_UMAVAIL then err << "Program Unavailable"
  84. when PROG_MISMATCH then err << "Program Version Mismatch"
  85. when PROC_UNAVAIL then err << "Procedure Unavailable"
  86. when GARBAGE_ARGS then err << "Garbage Arguments"
  87. when SYSTEM_ERR then err << "System Error"
  88. else err << "Unknown Error"
  89. end
  90. end
  91. raise ::Rex::Proto::SunRPC::RPCError, "#{rhost}:#{rport} - SunRPC - #{err}"
  92. end
  93. return ret
  94. end
  95. def sunrpc_callsock
  96. self.rpcobj.call_sock
  97. end
  98. def sunrpc_destroy
  99. rpcobj.destroy
  100. rpcobj = nil
  101. end
  102. def sunrpc_authnull(*args)
  103. rpcobj.authnull_create(*args)
  104. end
  105. def sunrpc_authunix(*args)
  106. rpcobj.authunix_create(*args)
  107. end
  108. # XXX: Incomplete. Just moved from Rex::Proto::SunRPC::Client
  109. def portmap_qry()
  110. ret = portmap_req()
  111. arr = Rex::Encoder::XDR.decode!(ret, Integer, Integer, Integer, String, Integer)
  112. if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS || arr[5] == 0
  113. progname = progresolv(rpcobj.program)
  114. err = "Query for program #{rpcobj.program} [#{progname}] failed: "
  115. case arr[4]
  116. when PROG_UMAVAIL then err << "Program Unavailable"
  117. when PROG_MISMATCH then err << "Program Version Mismatch"
  118. when PROC_UNAVAIL then err << "Procedure Unavailable"
  119. when GARBAGE_ARGS then err << "Garbage Arguments"
  120. else err << "Unknown Error"
  121. end
  122. raise ::Rex::Proto::SunRPC::RPCError, "#{rhost}:#{rport} - SunRPC - #{err}"
  123. end
  124. return ret
  125. end
  126. def progresolv(number)
  127. names = File.join(Msf::Config.data_directory, "wordlists", "rpc_names.txt")
  128. File.open(names, "rb").each_line do |line|
  129. next if line.empty? || line =~ /^\s*#/
  130. if line =~ /^(\S+?)\s+(\d+)/ && number == $2.to_i
  131. return $1
  132. end
  133. end
  134. return "UNKNOWN-#{number}"
  135. end
  136. # Returns the time that this module will wait for RPC responses, in seconds
  137. def timeout
  138. datastore['TIMEOUT']
  139. end
  140. # Used to track the last SunRPC context
  141. attr_accessor :rpcobj
  142. end
  143. end