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

#client, #cookie_jar

Instance Method Summary collapse

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, #strip_tags, #target_uri, #validate_fingerprint, #vhost

Methods included from Auxiliary::LoginScanner

#configure_login_scanner

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

  register_options([
    OptString.new('TARGETURI', [true, 'Path to Spip install', '/'])
  ])
end

#parse_plugin_version(body, plugin_name) ⇒ Rex::Version?

Parse the plugin version from config.txt or composed-by

Parameters:

  • body (String)

    The body content to parse

  • plugin_name (String)

    Name of the plugin to find the version for

Returns:

  • (Rex::Version, nil)

    Version of the plugin as Rex::Version, or nil if not found



71
72
73
74
75
76
77
78
# File 'lib/msf/core/exploit/remote/http/spip.rb', line 71

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_plugin_version(plugin_name) ⇒ Rex::Version?

Determine Spip plugin version by name

Parameters:

  • plugin_name (String)

    Name of the plugin to search for

Returns:

  • (Rex::Version, nil)

    Version of the plugin as Rex::Version, or nil if not found



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/msf/core/exploit/remote/http/spip.rb', line 49

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

  nil
end

#spip_versionRex::Version

Determine Spip version

Returns:



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
# File 'lib/msf/core/exploit/remote/http/spip.rb', line 18

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