|
| 1 | +require 'metasploit/framework/login_scanner/http' |
| 2 | + |
| 3 | +module Metasploit |
| 4 | + module Framework |
| 5 | + module LoginScanner |
| 6 | + |
| 7 | + # Wordpress XML RPC login scanner |
| 8 | + class WordpressRPC < HTTP |
| 9 | + |
| 10 | + # (see Base#attempt_login) |
| 11 | + def attempt_login(credential) |
| 12 | + http_client = Rex::Proto::Http::Client.new( |
| 13 | + host, port, {}, ssl, ssl_version |
| 14 | + ) |
| 15 | + |
| 16 | + result_opts = { |
| 17 | + credential: credential, |
| 18 | + host: host, |
| 19 | + port: port, |
| 20 | + protocol: 'tcp' |
| 21 | + } |
| 22 | + if ssl |
| 23 | + result_opts[:service_name] = 'https' |
| 24 | + else |
| 25 | + result_opts[:service_name] = 'http' |
| 26 | + end |
| 27 | + |
| 28 | + begin |
| 29 | + http_client.connect |
| 30 | + |
| 31 | + request = http_client.request_cgi( |
| 32 | + 'uri' => uri, |
| 33 | + 'method' => method, |
| 34 | + 'data' => generate_xml_request(credential.public,credential.private), |
| 35 | + ) |
| 36 | + response = http_client.send_recv(request) |
| 37 | + |
| 38 | + if response && response.code == 200 && response.body =~ /<value><int>401<\/int><\/value>/ || response.body =~ /<name>user_id<\/name>/ |
| 39 | + result_opts.merge!(status: Metasploit::Model::Login::Status::SUCCESSFUL, proof: response) |
| 40 | + elsif res.body =~ /<value><int>-32601<\/int><\/value>/ |
| 41 | + result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT) |
| 42 | + else |
| 43 | + result_opts.merge!(status: Metasploit::Model::Login::Status::INCORRECT, proof: response) |
| 44 | + end |
| 45 | + rescue ::EOFError, Rex::ConnectionError, ::Timeout::Error |
| 46 | + result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT) |
| 47 | + end |
| 48 | + |
| 49 | + Result.new(result_opts) |
| 50 | + |
| 51 | + end |
| 52 | + |
| 53 | + # This method generates the XML data for the RPC login request |
| 54 | + # @param user [String] the username to authenticate with |
| 55 | + # @param pass [String] the password to authenticate with |
| 56 | + # @return [String] the generated XML body for the request |
| 57 | + def generate_xml_request(user, pass) |
| 58 | + xml = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>" |
| 59 | + xml << '<methodCall>' |
| 60 | + xml << '<methodName>wp.getUsers</methodName>' |
| 61 | + xml << '<params><param><value>1</value></param>' |
| 62 | + xml << "<param><value>#{user}</value></param>" |
| 63 | + xml << "<param><value>#{pass}</value></param>" |
| 64 | + xml << '</params>' |
| 65 | + xml << '</methodCall>' |
| 66 | + xml |
| 67 | + end |
| 68 | + |
| 69 | + # (see Base#set_sane_defaults) |
| 70 | + def set_sane_defaults |
| 71 | + @method = "POST".freeze |
| 72 | + super |
| 73 | + end |
| 74 | + |
| 75 | + end |
| 76 | + end |
| 77 | + end |
| 78 | +end |
| 79 | + |
| 80 | + |
0 commit comments