Files
metasploit-gs/lib/msf/core/module/reference.rb
T
Valentin Lobstein f41eda1128 Add GHSA and OSV reference type support
Add support for GHSA (GitHub Security Advisories) and OSV (Open Source
Vulnerabilities) as structured reference types in Metasploit modules.

Convert 49 hardcoded GHSA URLs to structured ['GHSA', 'GHSA-xxxx'] format
across existing modules, and add support for repository-specific GHSA
references with an optional third parameter ['GHSA', 'GHSA-xxxx', 'repo'].

Update reference validation, module validator, and info_fixups to handle
the new reference types correctly.
2026-02-09 15:17:23 +01:00

197 lines
5.1 KiB
Ruby

# -*- coding: binary -*-
###
#
# A reference to some sort of information. This is typically a URL, but could
# be any type of referential value that people could use to research a topic.
#
###
class Msf::Module::Reference
#
# Serialize a reference from a string.
#
def self.from_s(str)
return self.new(str)
end
#
# Initializes a reference from a string.
#
def initialize(in_str)
self.str = in_str
end
#
# Compares references to see if they're equal.
#
def ==(tgt)
return (tgt.to_s == to_s)
end
#
# Returns the reference as a string.
#
def to_s
return self.str
end
#
# Serializes the reference instance from a string.
#
def from_s(in_str)
self.str = in_str
end
#
# The reference string.
#
attr_reader :str
protected
attr_writer :str # :nodoc:
end
###
#
# A reference to a website.
#
###
class Msf::Module::SiteReference < Msf::Module::Reference
#
# Class method that translates a URL into a site reference instance.
#
def self.from_s(str)
instance = self.new
if (instance.from_s(str) == false)
return nil
end
return instance
end
#
# Initializes a site reference from an array. ary[0] is the site and
# ary[1] is the site context identifier, such as CVE.
# ary[2] is optional and can be used for additional context (e.g., repo for GHSA)
#
def self.from_a(ary)
return nil if (ary.length < 2)
# Reject if first element is an array (nested array structure)
return nil if ary[0].kind_of?(Array)
self.new(ary[0], ary[1], ary[2])
end
#
# Initialize the site reference.
# If you're updating the references, please also update:
# * tools/module_reference.rb
# * https://docs.metasploit.com/docs/development/developing-modules/module-metadata/module-reference-identifiers.html
#
def initialize(in_ctx_id = 'Unknown', in_ctx_val = '', in_ctx_repo = nil)
# Ensure ctx_id and ctx_val are strings (handle constants like ATT&CK techniques)
in_ctx_id = in_ctx_id.to_s if in_ctx_id.respond_to?(:to_s) && !in_ctx_id.is_a?(String)
in_ctx_val = in_ctx_val.to_s if in_ctx_val.respond_to?(:to_s) && !in_ctx_val.is_a?(String)
self.ctx_id = in_ctx_id
self.ctx_val = in_ctx_val
self.ctx_repo = in_ctx_repo
if in_ctx_id == 'CVE'
self.site = "https://nvd.nist.gov/vuln/detail/CVE-#{in_ctx_val}"
elsif in_ctx_id == 'CWE'
self.site = "https://cwe.mitre.org/data/definitions/#{in_ctx_val}.html"
elsif in_ctx_id == 'BID'
self.site = "http://www.securityfocus.com/bid/#{in_ctx_val}"
elsif in_ctx_id == 'MSB'
year = in_ctx_val[2..3]
century = year[0] == '9' ? '19' : '20'
self.site = "https://docs.microsoft.com/en-us/security-updates/SecurityBulletins/#{century}#{year}/#{in_ctx_val}"
elsif in_ctx_id == 'EDB'
self.site = "https://www.exploit-db.com/exploits/#{in_ctx_val}"
elsif in_ctx_id == 'US-CERT-VU'
self.site = "https://www.kb.cert.org/vuls/id/#{in_ctx_val}"
elsif in_ctx_id == 'ZDI'
self.site = "http://www.zerodayinitiative.com/advisories/ZDI-#{in_ctx_val}"
elsif in_ctx_id == 'WPVDB'
self.site = "https://wpscan.com/vulnerability/#{in_ctx_val}"
elsif in_ctx_id == 'PACKETSTORM'
self.site = "https://packetstormsecurity.com/files/#{in_ctx_val}"
elsif in_ctx_id == 'GHSA'
# Handle both formats: with or without GHSA- prefix
ghsa_id = in_ctx_val.start_with?('GHSA-') ? in_ctx_val : "GHSA-#{in_ctx_val}"
# Use repo-specific URL if repo is provided, otherwise use global format
if in_ctx_repo && !in_ctx_repo.empty?
self.site = "https://github.com/#{in_ctx_repo}/security/advisories/#{ghsa_id}"
else
self.site = "https://github.com/advisories/#{ghsa_id}"
end
elsif in_ctx_id == 'OSV'
self.site = "https://osv.dev/vulnerability/#{in_ctx_val}"
elsif in_ctx_id == 'URL'
self.site = in_ctx_val.to_s
elsif in_ctx_id == 'LOGO'
self.site = "Logo: #{in_ctx_val}"
elsif in_ctx_id == 'SOUNDTRACK'
self.site = "Soundtrack: #{in_ctx_val}"
elsif in_ctx_id == 'ATT&CK'
match = in_ctx_val.match(/\A(?<category>[A-Z]+)(?<id>[\d.]+)\z/)
path = Msf::Mitre::Attack::Categories::PATHS[match[:category]]
id_path = match[:id].gsub('.', '/')
self.site = "https://attack.mitre.org/#{path}/#{match[:category]}#{id_path}/"
else
self.site = in_ctx_id
self.site += " (#{in_ctx_val})" if (in_ctx_val)
end
end
#
# Returns the absolute site URL.
#
def to_s
return site || ''
end
#
# Serializes a site URL string.
#
def from_s(str)
if (/(http:\/\/|https:\/\/|ftp:\/\/)/.match(str))
self.site = str
self.ctx_id = 'URL'
self.ctx_val = self.site
else
return false
end
return true
end
#
# The site being referenced.
#
attr_reader :site
#
# The context identifier of the site, such as CVE.
#
attr_reader :ctx_id
#
# The context value of the reference, such as MS02-039
#
attr_reader :ctx_val
#
# The context repository for GHSA references (optional)
#
attr_reader :ctx_repo
protected
attr_writer :site, :ctx_id, :ctx_val, :ctx_repo
end