Module: Msf::Exploit::Remote::HTTP::Spip
- Includes:
- Msf::Exploit::Remote::HttpClient
- Defined in:
- lib/msf/core/exploit/remote/http/spip.rb
Instance Attribute Summary
Attributes included from Msf::Exploit::Remote::HttpClient
Instance Method Summary collapse
- #initialize(info = {}) ⇒ Object
-
#parse_paquet_xml_version(plugin_name) ⇒ Rex::Version?
Attempt to read the plugin version from its paquet.xml file.
-
#parse_plugin_version(body, plugin_name) ⇒ Rex::Version?
Parse the plugin version from config.txt or composed-by.
-
#spip_extract_cvt_fields(html, action_name) ⇒ Hash?
Extract the HMAC-signed CVT hidden fields for a given form action.
-
#spip_login(username, password) ⇒ String
Authenticate against the SPIP login form.
-
#spip_plugin_version(plugin_name) ⇒ Rex::Version?
Determine Spip plugin version by name.
-
#spip_version ⇒ Rex::Version
Determine Spip version.
Methods included from Msf::Exploit::Remote::HttpClient
#basic_auth, #cleanup, #configure_http_login_scanner, #connect, #connect_ws, #deregister_http_client_options, #disconnect, #download, #full_uri, #handler, #http_fingerprint, #lookup_http_fingerprints, #normalize_uri, #path_from_uri, #peer, #proxies, #reconfig_redirect_opts!, #request_opts_from_url, #request_url, #rhost, #rport, #send_request_cgi, #send_request_cgi!, #send_request_raw, #service_details, #setup, #ssl, #ssl_version, #sslkeylogfile, #strip_tags, #target_uri, #validate_fingerprint, #vhost
Methods included from CertificateTrace
#certificate_csr_trace, #certificate_peer_cert_trace, #certificate_trace, #certificate_trace_enabled?
Methods included from Kerberos::ServiceAuthenticator::Options
#kerberos_auth_options, #kerberos_clock_skew_seconds
Methods included from Kerberos::Ticket::Storage
#kerberos_storage_options, #kerberos_ticket_storage, store_ccache
Methods included from Auxiliary::LoginScanner
Methods included from Auxiliary::Report
#active_db?, #create_cracked_credential, #create_credential, #create_credential_and_login, #create_credential_login, #db, #db_warning_given?, #get_client, #get_host, #inside_workspace_boundary?, #invalidate_login, #mytask, #myworkspace, #myworkspace_id, #report_auth_info, #report_client, #report_exploit, #report_host, #report_loot, #report_note, #report_service, #report_vuln, #report_web_form, #report_web_page, #report_web_site, #report_web_vuln, #store_cred, #store_local, #store_loot
Methods included from Metasploit::Framework::Require
optionally, optionally_active_record_railtie, optionally_include_metasploit_credential_creation, #optionally_include_metasploit_credential_creation, optionally_require_metasploit_db_gem_engines
Instance Method Details
#initialize(info = {}) ⇒ Object
7 8 9 10 11 12 13 |
# File 'lib/msf/core/exploit/remote/http/spip.rb', line 7 def initialize(info = {}) super ([ OptString.new('TARGETURI', [true, 'Path to Spip install', '/']) ]) end |
#parse_paquet_xml_version(plugin_name) ⇒ Rex::Version?
Attempt to read the plugin version from its paquet.xml file. Plugins can be installed under plugins/ or plugins/auto/.
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/msf/core/exploit/remote/http/spip.rb', line 130 def parse_paquet_xml_version(plugin_name) %W[ plugins/#{plugin_name}/paquet.xml plugins/auto/#{plugin_name}/paquet.xml ].each do |path| res = send_request_cgi('method' => 'GET', 'uri' => normalize_uri(target_uri.path, path)) next unless res&.code == 200 if res.body =~ /prefix="#{plugin_name}"/ && res.body =~ /version="(\d+(?:\.\d+)+)"/ return Rex::Version.new(::Regexp.last_match(1)) end end nil end |
#parse_plugin_version(body, plugin_name) ⇒ Rex::Version?
Parse the plugin version from config.txt or composed-by
151 152 153 154 155 156 157 158 |
# File 'lib/msf/core/exploit/remote/http/spip.rb', line 151 def parse_plugin_version(body, plugin_name) body.each_line do |line| if line =~ /#{plugin_name}\((\d+(\.\d+)+)\)/ return Rex::Version.new(::Regexp.last_match(1)) end end nil end |
#spip_extract_cvt_fields(html, action_name) ⇒ Hash?
Extract the HMAC-signed CVT hidden fields for a given form action.
20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/msf/core/exploit/remote/http/spip.rb', line 20 def spip_extract_cvt_fields(html, action_name) container = html.css("input[name='formulaire_action']").find { |n| n['value'] == action_name }&.parent return unless container args = container.at_css("input[name='formulaire_action_args']") return unless args sign = container.at_css("input[name='formulaire_action_sign']") return unless sign { 'args' => args['value'].to_s, 'sign' => sign['value'].to_s } end |
#spip_login(username, password) ⇒ String
Authenticate against the SPIP login form. Sets @spip_cookie on success. Requires USERNAME and PASSWORD datastore options.
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 |
# File 'lib/msf/core/exploit/remote/http/spip.rb', line 40 def spip_login(username, password) res = send_request_cgi( 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'spip.php'), 'vars_get' => { 'page' => 'login' } ) raise Rex::RuntimeError, 'Login page did not respond' unless res cvt = spip_extract_cvt_fields(res.get_html_document, 'login') raise Rex::RuntimeError, 'Login form not found' unless cvt = res. res = send_request_cgi( 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'spip.php'), 'cookie' => , 'vars_post' => { 'page' => 'login', 'formulaire_action' => 'login', 'formulaire_action_args' => cvt['args'], 'formulaire_action_sign' => cvt['sign'], 'var_login' => username, 'password' => password } ) raise Rex::RuntimeError, 'No response to login' unless res @spip_cookie = res. raise Rex::RuntimeError, 'Authentication failed: no spip_session cookie' unless @spip_cookie&.include?('spip_session') @spip_cookie end |
#spip_plugin_version(plugin_name) ⇒ Rex::Version?
Determine Spip plugin version by name
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/msf/core/exploit/remote/http/spip.rb', line 107 def spip_plugin_version(plugin_name) res = send_request_cgi('method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'spip.php')) return unless res composed_by = res.headers['Composed-By'] # Case 1: Check if 'Composed-By' header is present and not empty version = composed_by&.present? ? parse_plugin_version(composed_by, plugin_name) : nil return version if version # Case 2: Extract URL from 'Composed-By' header and send a request to fetch the config.txt file config_url = composed_by =~ %r{(https?://[^\s]+/local/config\.txt)}i ? ::Regexp.last_match(1) : normalize_uri(target_uri.path, 'local', 'config.txt') config_res = send_request_cgi('method' => 'GET', 'uri' => config_url) return parse_plugin_version(config_res.body, plugin_name) if config_res&.code == 200 # Case 3: Try fetching paquet.xml directly from common plugin paths parse_paquet_xml_version(plugin_name) end |
#spip_version ⇒ Rex::Version
Determine Spip version
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 |
# File 'lib/msf/core/exploit/remote/http/spip.rb', line 76 def spip_version res = send_request_cgi( 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'spip.php') ) return unless res version = nil potential_sources = [ res.get_html_document.at('head/meta[@name="generator"]/@content')&.text, res.headers['Composed-By'] ] potential_sources.each do |text| next unless text if text =~ /SPIP\s(\d+(\.\d+)+)/ version = ::Regexp.last_match(1) break end end return version ? Rex::Version.new(version) : nil end |