Module: PWN::Plugins::SBOM

Defined in:
lib/pwn/plugins/sbom.rb

Overview

Generic lockfile/image CVE scan with engine selection.

Class Method Summary collapse

Class Method Details

.authorsObject



52
53
54
# File 'lib/pwn/plugins/sbom.rb', line 52

public_class_method def self.authors
  "AUTHOR(S):\n  0day Inc. <[email protected]>\n"
end

.helpObject



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/pwn/plugins/sbom.rb', line 56

public_class_method def self.help
  puts "USAGE:
    # List host binaries this module expects to be installed.
    #{self}.required_bins

    # Scan a lockfile or image with the first available engine.
    #{self}.scan(
      path_or_image: 'required - lockfile, directory, or image reference',
      path: 'optional - alias for path_or_image',
      image: 'optional - alias for path_or_image',
      engine: 'optional - syft, grype, trivy, or osv-scanner',
      record: 'optional - true stores each CVE as a recon observation, not a finding',
      engagement_id: 'optional - engagement identifier for the observation'
    )

    # Print the AUTHOR(S) string for this module.
    #{self}.authors
  "
  constants.sort
end

.required_binsObject



10
11
12
# File 'lib/pwn/plugins/sbom.rb', line 10

public_class_method def self.required_bins
  []
end

.scan(opts = {}) ⇒ Object

Raises:

  • (ArgumentError)


14
15
16
17
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
44
45
46
47
48
49
50
# File 'lib/pwn/plugins/sbom.rb', line 14

public_class_method def self.scan(opts = {})
  target = (opts[:path_or_image] || opts[:path] || opts[:image]).to_s
  raise ArgumentError, 'path_or_image is required' if target.empty?

  engine = (opts[:engine] || select_engine(target: target)).to_s
  rows = case engine
         when 'grype' then parse_grype(target: target)
         when 'trivy' then parse_trivy(target: target)
         when 'osv-scanner' then parse_osv(target: target)
         when 'syft+grype', 'syft'
           inv = parse_syft(target: target)
           if PWN::Plugins::PreflightChecker.bin?(name: 'grype')
             parse_grype(target: target)
           else
             inv
           end
         else
           raise IOError, 'no SBOM engine installed (syft, grype, trivy, or osv-scanner)'
         end
  observations = []
  if defined?(PWN::Plugins::Recon) && opts[:record] == true
    rows.each do |row|
      next if row[:cve].to_s.empty?

      observations << PWN::Plugins::Recon.observe(
        host: target,
        product: row[:package].to_s,
        version: row[:version].to_s,
        evidence_path: target,
        source: 'sbom',
        lead: "#{row[:package]} #{row[:cve]}",
        engagement_id: opts[:engagement_id]
      )
    end
  end
  { engine: engine, target: target, vulns: rows, observations: observations }
end