Skip to content

Conversation

@cdelafuente-r7
Copy link
Contributor

@cdelafuente-r7 cdelafuente-r7 commented Jul 29, 2025

This PR updates how vulnerability and services are reported by adding a resource field to both models. It also add a parents field to make layered services possible.

This PR needs to be landed prior this one.

Description

#report_service and #report_vuln have been updated to add the necessary logic for resources and layered services. An optional resource field can now be provided and the existing service field has been updated to also accept an option hash. For example:

    vuln = report_vuln(
      host: host,
      port: 80,
      proto: 'tcp',
      name: 'Test Vulnerability - Web',
      info: "Module #{fullname}",
      refs: references,
      exploited_at: Time.now.utc,
      service: {
        name: 'http',
        port: 80,
        proto: 'tcp',
        resource: {method: 'GET'}
      },
      resource: {uri: '/profile'}
    )
    report_service(
      host: rhost,
      port: 389,
      proto: 'tcp',
      name: 'LDAP',
      resource: {dn: 'CN=Foo,DC=anothercompany,DC=com'},
      info: 'Windows Server 2019 DC',
    )

Services can also include a resource. Note that this field is not validated and any key/value pair is accepted, as long as it is a valid hash. It will be serialized and stored as a JSONB in the database.

Services can also have parents to better describe the service layers. For example:

Wordpress > HTTPS > SSL > TCP

This can be set from a call to #report_service:

    report_service(
      name: 'Wordpress'
      ...
      parents: {
          name: 'https',
          port: 443,
          proto: 'tcp'
          parents: {
            name: 'ssl',
            port: 443,
            proto: 'tcp'
            parents: {
              name: 'tcp',
              port: 443,
              proto: 'tcp'
              parents: nil
            }
          }
        }
    )

or calling #report_vuln:

    vuln = report_vuln(
      ...
      service: {
        name: 'http',
        port: 80,
        proto: 'tcp',
        resource: {method: 'GET'},
        parents: {
          name: 'tcp',
          port: 80,
          proto: 'tcp'
          parents: nil
        }
      },
      resource: {uri: '/profile'},
    )

Note that a service can have multiple parents (e.i. Web App can have HTTP and HTTPS parent services). An array of hashes can be passed as a value of the parents key:


...
      parents: [
        {
          name: 'http',
          port: 80,
          proto: 'tcp'
          parents: tcp_service1
        },
        {
          name: 'https',
          port: 443,
          proto: 'tcp'
          parents: tcp_service2
        }
      ]
...

This PR updates the way a vulnerability is reported report when a session is established and adds the service used by the exploit that got a session.

It updates CheckCode and the check command to report a vulnerability when a Vulnerable checkcode is returned. It is now possible to pass a vuln argument with the vulnerability details that will be passed to #report_vuln:

CheckCode::Vulnerable(
  'Vulnerable!',
  vuln: {
    host: host,
    port: 80,
    proto: 'tcp',
    name: 'Test Vulnerability - Web',
    info: "Module #{fullname}",
    refs: references,
    exploited_at: Time.now.utc,
    service: {
      name: 'http',
      port: 80,
      proto: 'tcp',
      resource: {method: 'GET'}
    },
    resource: {uri: '/profile'}
  })

Finally, it updates the vulns and services commands to display the resource and parent services.

Verification

  • Reinitialize the database with ./msfdb reinit to update the schema
  • Start msfconsole
  • use any module that reports vulnerabilities against a vulnerable target. I used this example module I created for this: https://gist.github.com/cdelafuente-r7/3ee77925cedb151d0bb35fd3d9d90b33
  • run check and make sure it returns a Vulnerable CheckCode
  • Verify the vulnerability has been reported with the vulns command
  • Verify the service has been reported with the services command (also services -v
  • Update the code to add a call to report_vuln following the new schema (see above)
  • Verify the vulnerability has been reported with the vulns command
  • Verify the service has been reported with the services command

Scenarios

msf auxiliary(admin/report_vuln) > vulns

Vulnerabilities
===============

Timestamp                Host       Service            Resource                       Name                               References
---------                ----       -------            --------                       ----                               ----------
2025-07-29 12:13:26 UTC  127.0.0.1  othercms (80/tcp)  {"uri":"/profile"}             Test Vulnerability - Web           CVE-2005-3398,OSVDB-877
2025-07-29 12:13:26 UTC  127.0.0.1  ldap (389/tcp)     {"template":"Esc1-Template"}   Test Vulnerability #4 - ESC1       CVE-2005-3398,OSVDB-877
2025-07-29 12:13:26 UTC  127.0.0.1  ad cs (445/tcp)    {"CA":"msflab-DC-CA"}          CA Allows Write Privileges         URL-https://example.com
2025-07-29 12:13:26 UTC  127.0.0.1  http (80/tcp)      {}                             Report Vuln Project - Old Fashion  CVE-2005-3398,OSVDB-877
2025-07-29 12:13:26 UTC  127.0.0.1  mycms (80/tcp)     {"uri":"/profile"}             Test Vulnerability - Web           CVE-2005-3398,OSVDB-877
2025-07-29 12:13:26 UTC  127.0.0.1  mycms (80/tcp)     {"uri":"/search?param=query"}  Test Vulnerability - Web           CVE-2005-3398,OSVDB-877
msf auxiliary(admin/report_vuln) > vulns -v

Vulnerabilities
===============
  0. Vuln ID: 13
     Timestamp: 2025-07-29 12:13:26 UTC
     Host: 127.0.0.1
     Name: Test Vulnerability - Web
     References: CVE-2005-3398,OSVDB-877
     Information: Module auxiliary/admin/report_vuln
     Resource: {"uri":"/profile"}
     Service: othercms (port: 80, resource: {"base_url":"/othercms"})
       Parent Services:
         http (port: 80, resource: {"method":"GET"})
           tcp (port: 80, resource: {"port":80})
         https (port: 443, resource: {"method":"GET"})
           ssl (port: 443, resource: {"cert_chain":["CN=*.foo.com","C=US, O=foo, CN=www"]})
             tcp (port: 443, resource: {"port":443})
     Vuln attempts:
     0. ID: 17
        Vuln ID: 13
        Timestamp: 2025-07-29 12:13:26 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/admin/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
[...SNIP...]
msf auxiliary(admin/report_vuln) > services
Services
========

host       port  proto  name      state  info                                                                              resource                                                 parents
----       ----  -----  ----      -----  ----                                                                              --------                                                 -------
127.0.0.1  5060  tcp    sip       open   report service without resource                                                   {}
127.0.0.1  80    tcp    mycms     open                                                                                     {"base_url"=>"/mycms"}                                   http (80/tcp)
127.0.0.1  80    tcp    http      open                                                                                     {"method"=>"GET"}                                        tcp (80/tcp)
127.0.0.1  80    tcp    tcp       open                                                                                     {"port"=>80}
127.0.0.1  389   tcp    tcp       open                                                                                     {"port"=>389}
127.0.0.1  389   tcp    ldap      open   report service without resource: should pick the already registered LDAP service  {"dn"=>"CN=Certificate,DC=company,DC=com"}               tcp (389/tcp)
127.0.0.1  389   tcp    ldap      open   report service with a new resource: should create a new LDAP service              {"dn"=>"CN=Foo,DC=anothercompany,DC=com"}
127.0.0.1  443   tcp    tcp       open                                                                                     {"port"=>443}
127.0.0.1  443   tcp    ssl       open                                                                                     {"cert_chain"=>["CN=*.foo.com", "C=US, O=foo, CN=www"]}  tcp (443/tcp)
127.0.0.1  443   tcp    https     open                                                                                     {"method"=>"GET"}                                        ssl (443/tcp)
127.0.0.1  445   tcp    dcerpc    open                                                                                     {"named_pipe"=>"icpr"}                                   smb (445/tcp)
127.0.0.1  445   tcp    tcp       open                                                                                     {"port"=>445}
127.0.0.1  445   tcp    smb       open                                                                                     {"share"=>"IPC$"}                                        tcp (445/tcp)
127.0.0.1  445   tcp    ad cs     open                                                                                     {}                                                       dcerpc (445/tcp)
127.0.0.1  80    tcp    othercms  open                                                                                     {"base_url"=>"/othercms"}                                http (80/tcp), https (443/tcp)

Gemfile Outdated
Comment on lines 6 to 7
gem 'metasploit_data_models', git: 'git@github.com:cdelafuente-r7/metasploit_data_models.git', branch: 'MS-9930_resource_layered_services'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been added to make testing possible before the metasploit_data_models PR is landed. This will need to be removed before landing this PR

@bcoles
Copy link
Contributor

bcoles commented Jul 29, 2025

It updates CheckCode and the check command to report a vulnerability when a Vulnerable checkcode is returned. It is now possible to pass a vuln argument with the vulnerability details that will be passed to #report_vuln:

Neat. Is there any way we can do this programmatically? Automatically populating vulnerabilities for every module which returns CheckCode::Vulnerable would be significantly more valuable than requiring modules to opt in to reporting vulnerabilities.

service = (port ? host.services.find_by_port(port.to_i) : nil)

vuln_info[:service] = service if service
if session.exploit.respond_to?(:service_details) && session.exploit.service_details
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This takes advantage of the #service_details method, which some modules implement. For now, the lib/msf/core/exploit/remote/http_client.rb mixin implement it. Maybe we can enforce exploit modules to implemented it in the future.

For example:
https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/multi/http/tomcat_mgr_upload.rb#L428
https://github.com/rapid7/metasploit-framework/blob/master/lib/msf/core/exploit/remote/http_client.rb#L932

@cdelafuente-r7
Copy link
Contributor Author

@bcoles, report_vuln was already called in case a Vulnerable CheckCode is returned. The vulnerability was reported with very little information, only a name derived from the exploit module, references from the exploit module as well, etc. I updated it to let the module writer the flexibility to report a vulnerability with more accurate data (name, port, service, etc.)

See the previous implementation: https://github.com/rapid7/metasploit-framework/blob/master/lib/msf/ui/console/module_command_dispatcher.rb#L177

@cdelafuente-r7 cdelafuente-r7 force-pushed the enh/MS-9930/vuln_report branch from 0b71adf to 3a8499a Compare July 29, 2025 12:52
@bcoles
Copy link
Contributor

bcoles commented Jul 29, 2025

@bcoles, report_vuln was already called in case a Vulnerable CheckCode is returned. The vulnerability was reported with very little information, only a name derived from the exploit module, references from the exploit module as well, etc. I updated it to let the module writer the flexibility to report a vulnerability with more accurate data (name, port, service, etc.)

Thanks. I tried to verify this before posting, but as usual the database config is broken in my dev environment.

@cdelafuente-r7 cdelafuente-r7 force-pushed the enh/MS-9930/vuln_report branch 4 times, most recently from 43f4854 to 7a41ca5 Compare July 30, 2025 18:08
@cdelafuente-r7 cdelafuente-r7 force-pushed the enh/MS-9930/vuln_report branch 3 times, most recently from 46d565c to 2df584b Compare August 19, 2025 15:55
@smcintyre-r7 smcintyre-r7 self-assigned this Oct 2, 2025
@smcintyre-r7 smcintyre-r7 moved this from Todo to In Progress in Metasploit Kanban Oct 7, 2025
@smcintyre-r7 smcintyre-r7 removed their assignment Nov 17, 2025
return
end
service_obj.state ||= Msf::ServiceState::Open
service_obj.info ||= ''
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably propagate the service info here.

Suggested change
service_obj.info ||= ''
service_obj.info = service[:info] if service[:info]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the heads up. This has been addressed in b628c75

@cgranleese-r7 cgranleese-r7 self-assigned this Nov 24, 2025
@cgranleese-r7
Copy link
Contributor

cgranleese-r7 commented Nov 24, 2025

I have tested this and recorded the outputs below for each verification step. I believe everything is working as expected.

Module used for testing

Output
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary

  # Exploit mixins should be called first
  include Msf::Exploit::Remote::HttpClient
  include Msf::Auxiliary::WmapScanServer
  # Scanner mixin should be near last
  include Msf::Auxiliary::Scanner
  include Msf::Auxiliary::Report

  def initialize
    super(
      'Name' => 'Report Vuln Project',
      'Description' => 'Reports vulns with services that include resources and parent services',
      'Author' => 'cdelafuente-r7',
      'License' => MSF_LICENSE
    )
    register_options(
      [
        OptString.new('TARGETURI', [true, 'URI to test', '/']),
      ]
    )
  end

  def check_host(target_host)
    # Build service layers
    tcp_service = {
      name: 'TCP',
      proto: 'tcp',
      port: rport,
      resource: {port: rport},
      parents: nil
    }

    http_service = {
      name: 'HTTP',
      proto: 'tcp',
      port: rport,
      resource: {method: 'GET'},
      parents: tcp_service
    }

    web_app_service = {
      name: 'MyCMS',
      proto: 'tcp',
      port: rport,
      resource: {base_url: '/mycms'},
      parents: http_service
    }

    # Return Vulnerable with vuln details
    Exploit::CheckCode::Vulnerable(
      'Target is vulnerable!',
      vuln: {
        host: target_host,
        port: rport,
        proto: 'tcp',
        name: 'Test Vulnerability from check method',
        info: "Module #{fullname} - vulnerability detected during check",
        refs: references,
        exploited_at: Time.now.utc,
        service: web_app_service,
        resource: {uri: datastore['TARGETURI']}
      }
    )
  end

  def run_host(target_host)
    print_status("Reporting vuln\n")

    tcp_service = {}
    [80, 443, 389, 445].each do |port|
      tcp_service[port] = {
        name: 'TCP',
        proto: 'tcp',
        port: port,
        resource: {port: port},
        parents: nil
      }
    end
    ssl_service = {
      name: 'SSL',
      proto: 'tcp',
      port: 443,
      resource: {cert_chain: ['CN=*.foo.com', 'C=US, O=foo, CN=www']},
      parents: tcp_service[443]
    }
    http_service = {
      name: 'HTTP',
      proto: 'tcp',
      port: 80,
      resource: {method: 'GET'},
      parents: tcp_service[80]
    }
    https_service = {
      name: 'HTTPS',
      proto: 'tcp',
      port: 443,
      resource: {method: 'GET'},
      parents: ssl_service
    }
    web_app_service = {
      name: 'MyCMS',
      proto: 'tcp',
      port: 80,
      resource: {base_url: '/mycms'},
      parents: http_service
    }
    web_app_service2 = {
      name: 'OtherCMS',
      proto: 'tcp',
      port: 80, #[80, 443]
      resource: {base_url: '/othercms'},
      parents: [http_service, https_service]
    }
    ldap_service = {
      name: 'LDAP',
      proto: 'tcp',
      port: 389,
      resource: {dn: 'CN=Certificate,DC=company,DC=com'},
      parents: tcp_service[389]
    }

    vuln = report_vuln(
      host: target_host,
      port: rport,
      proto: 'tcp',
      name: 'Test Vulnerability - Web',
      info: "Module #{fullname}",
      refs: references,
      exploited_at: Time.now.utc,
      service: web_app_service,
      resource: {uri: '/profile'}
    )
    print_vuln_details(vuln)

    vuln = report_vuln(
      host: target_host,
      port: rport,
      proto: 'tcp',
      name: 'Test Vulnerability - Web',
      info: "Module #{fullname}",
      refs: references,
      exploited_at: Time.now.utc,
      service: web_app_service,
      resource: {uri: '/search?param=query'}
    )
    print_vuln_details(vuln)

    vuln = report_vuln(
      host: target_host,
      port: rport,
      proto: 'tcp',
      name: 'Test Vulnerability - Web',
      info: "Module #{fullname}",
      refs: references,
      exploited_at: Time.now.utc,
      service: web_app_service2,
      resource: {uri: '/profile'},
      )
    print_vuln_details(vuln)

    vuln = report_vuln(
      host: target_host,
      port: rport,
      proto: 'tcp',
      name: 'Test Vulnerability #4 - ESC1',
      info: "Module #{fullname}",
      refs: references,
      exploited_at: Time.now.utc,
      service: ldap_service,
      resource: {template: 'Esc1-Template'}
    )
    print_vuln_details(vuln)

    # Another example with HTTPS service showing SSL layer
    vuln = report_vuln(
      host: target_host,
      port: 443,
      proto: 'tcp',
      name: 'Test Vulnerability - HTTPS API',
      info: "Module #{fullname} - API endpoint vulnerability",
      refs: references,
      exploited_at: Time.now.utc,
      service: {
        name: 'API',
        proto: 'tcp',
        port: 443,
        resource: {endpoint: '/api/v1'},
        parents: https_service
      },
      resource: {path: '/users', method: 'POST'}
    )
    print_vuln_details(vuln)

    # Since the service is not specified, this will assign the first service
    # registered in the database for this host with the given port and proto (default: tcp).
    # This is likely to be the TCP service.
    # Setting sname and proto will help to find the right service.
    vuln = report_vuln({
                         :host => rhost,
                         :port => rport,
                         #:sname => 'HTTPS',
                         #:proto => 'tcp',
                         :name => "#{self.name} - Old Fashion",
                         :refs => self.references,
                         :info => "Module #{self.fullname} found vulnerable JBoss Seam 2 resource."
                       })
    print_vuln_details(vuln)

    # Old fashion way to report a service
    report_service(
      host: rhost,
      port: 5060,
      proto: 'tcp',
      name: 'SIP',
      info: 'report service without resource'
    )
    report_service(
      host: rhost,
      port: 389,
      proto: 'tcp',
      name: 'LDAP',
      info: 'report service without resource: should pick the already registered LDAP service',
      )
    report_service(
      host: rhost,
      port: 389,
      proto: 'tcp',
      name: 'LDAP',
      resource: {dn: 'CN=Foo,DC=anothercompany,DC=com'},
      info: 'report service with a new resource: should create a new LDAP service',
      )

    # Reporting a vulnerability on a DCERPC service running over SMB
    vuln = report_vuln(
      workspace: myworkspace,
      host: rhost,
      name: "CA Allows Write Privileges",
      info: "Certificate Authority allows unauthorized write access",
      refs: [ SiteReference.new('URL', 'https://example.com') ],
      port: 445,
      proto: 'tcp',
      service: {
        name: 'AD CS',
        proto: 'tcp',
        port: 445,
        #resource: {CA: 'My-CA'},
        parents: {
          name: 'DCERPC',
          proto: 'tcp',
          port: 445,
          resource: {named_pipe: 'icpr'},
          parents: {
            name: 'SMB',
            proto: 'tcp',
            port: 445,
            resource: {share: 'IPC$'},
            parents: tcp_service[445]
          }
        }
      },
      resource: {CA: 'msflab-DC-CA'}  # the CA name needed in requests
    )
  end

  def print_vuln_details(vuln)
    print_status("Vulnerability ID: #{vuln.id}")
    print_status("Name: #{vuln.name}")
    print_status("Info: #{vuln.info}")
    print_status("References: #{vuln.refs.map { |ref| "#{ref.name}" }.join(', ')}")
    print_status("Exploited at: #{vuln.exploited_at}")
    print_status("Resource: #{vuln.resource.to_json}")
    print_status("Service: #{vuln.service.name} (port: #{vuln.service.port}, resource: #{vuln.service.resource.to_json})")
    str = "Parent Services:\n"
    service = vuln.service.parents.first
    loop do
      break unless service
      str << "\t#{service.name} (resource: #{service.resource.to_json})\n"
      service = service.parents.first
    end
    print_status(str)
  end
end

run check and make sure it returns a Vulnerable CheckCode

image

Verify the vulnerability has been reported with the vulns command

vulns

image

vulns -v

Output
msf auxiliary(gather/report_vuln) > vulns -v

Vulnerabilities
===============
  0. Vuln ID: 1
     Timestamp: 2025-11-24 10:23:55 UTC
     Host: 127.0.0.1
     Name: Test Vulnerability - Web
     References:
     Information: Module auxiliary/gather/report_vuln
     Resource: {"uri":"/profile"}
     Service: mycms (port: 80, resource: {"base_url":"/mycms"})
       Parent Services:
         http (port: 80, resource: {"method":"GET"})
           tcp (port: 80, resource: {"port":80})
     Vuln attempts:
     0. ID: 1
        Vuln ID: 1
        Timestamp: 2025-11-24 10:23:55 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
  1. Vuln ID: 2
     Timestamp: 2025-11-24 10:23:55 UTC
     Host: 127.0.0.1
     Name: Test Vulnerability - Web
     References:
     Information: Module auxiliary/gather/report_vuln
     Resource: {"uri":"/search?param=query"}
     Service: mycms (port: 80, resource: {"base_url":"/mycms"})
       Parent Services:
         http (port: 80, resource: {"method":"GET"})
           tcp (port: 80, resource: {"port":80})
     Vuln attempts:
     0. ID: 2
        Vuln ID: 2
        Timestamp: 2025-11-24 10:23:55 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
  2. Vuln ID: 3
     Timestamp: 2025-11-24 10:23:55 UTC
     Host: 127.0.0.1
     Name: Test Vulnerability - Web
     References:
     Information: Module auxiliary/gather/report_vuln
     Resource: {"uri":"/profile"}
     Service: othercms (port: 80, resource: {"base_url":"/othercms"})
       Parent Services:
         http (port: 80, resource: {"method":"GET"})
           tcp (port: 80, resource: {"port":80})
         https (port: 443, resource: {"method":"GET"})
           ssl (port: 443, resource: {"cert_chain":["CN=*.foo.com","C=US, O=foo, CN=www"]})
             tcp (port: 443, resource: {"port":443})
     Vuln attempts:
     0. ID: 3
        Vuln ID: 3
        Timestamp: 2025-11-24 10:23:55 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
  3. Vuln ID: 4
     Timestamp: 2025-11-24 10:23:55 UTC
     Host: 127.0.0.1
     Name: Test Vulnerability #4 - ESC1
     References:
     Information: Module auxiliary/gather/report_vuln
     Resource: {"template":"Esc1-Template"}
     Service: ldap (port: 389, resource: {"dn":"CN=Certificate,DC=company,DC=com"})
       Parent Services:
         tcp (port: 389, resource: {"port":389})
     Vuln attempts:
     0. ID: 4
        Vuln ID: 4
        Timestamp: 2025-11-24 10:23:55 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
  4. Vuln ID: 5
     Timestamp: 2025-11-24 10:23:55 UTC
     Host: 127.0.0.1
     Name: Report Vuln Project - Old Fashion
     References:
     Information: Module auxiliary/gather/report_vuln found vulnerable JBoss Seam 2 resource.
     Resource: {}
     Service: http (port: 80, resource: {"method":"GET"})
       Parent Services:
         tcp (port: 80, resource: {"port":80})
     Vuln attempts:
     0. ID: 5
        Vuln ID: 5
        Timestamp: 2025-11-24 10:23:55 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
  5. Vuln ID: 6
     Timestamp: 2025-11-24 10:23:55 UTC
     Host: 127.0.0.1
     Name: CA Allows Write Privileges
     References: URL-https://example.com
     Information: Certificate Authority allows unauthorized write access
     Resource: {"CA":"msflab-DC-CA"}
     Service: ad cs (port: 445, resource: {})
       Parent Services:
         dcerpc (port: 445, resource: {"named_pipe":"icpr"})
           smb (port: 445, resource: {"share":"IPC$"})
             tcp (port: 445, resource: {"port":445})
     Vuln attempts:
     0. ID: 6
        Vuln ID: 6
        Timestamp: 2025-11-24 10:23:55 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified

Verify the service has been reported with the services command

services

image

Update the code to add a call to report_vuln following the new schema

Verify the vulnerability has been reported with the vulns command

vulns

image

vulns -v

Output
msf auxiliary(gather/report_vuln) > vulns -v

Vulnerabilities
===============
  0. Vuln ID: 1
     Timestamp: 2025-11-24 12:02:34 UTC
     Host: 127.0.0.1
     Name: Test Vulnerability - Web
     References:
     Information: Module auxiliary/gather/report_vuln
     Resource: {"uri":"/profile"}
     Service: mycms (port: 80, resource: {"base_url":"/mycms"})
       Parent Services:
         http (port: 80, resource: {"method":"GET"})
           tcp (port: 80, resource: {"port":80})
     Vuln attempts:
     0. ID: 1
        Vuln ID: 1
        Timestamp: 2025-11-24 12:02:34 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
     1. ID: 8
        Vuln ID: 1
        Timestamp: 2025-11-24 12:02:37 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
  1. Vuln ID: 2
     Timestamp: 2025-11-24 12:02:34 UTC
     Host: 127.0.0.1
     Name: Test Vulnerability - Web
     References:
     Information: Module auxiliary/gather/report_vuln
     Resource: {"uri":"/search?param=query"}
     Service: mycms (port: 80, resource: {"base_url":"/mycms"})
       Parent Services:
         http (port: 80, resource: {"method":"GET"})
           tcp (port: 80, resource: {"port":80})
     Vuln attempts:
     0. ID: 2
        Vuln ID: 2
        Timestamp: 2025-11-24 12:02:34 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
     1. ID: 9
        Vuln ID: 2
        Timestamp: 2025-11-24 12:02:37 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
  2. Vuln ID: 3
     Timestamp: 2025-11-24 12:02:34 UTC
     Host: 127.0.0.1
     Name: Test Vulnerability - Web
     References:
     Information: Module auxiliary/gather/report_vuln
     Resource: {"uri":"/profile"}
     Service: othercms (port: 80, resource: {"base_url":"/othercms"})
       Parent Services:
         http (port: 80, resource: {"method":"GET"})
           tcp (port: 80, resource: {"port":80})
         https (port: 443, resource: {"method":"GET"})
           ssl (port: 443, resource: {"cert_chain":["CN=*.foo.com","C=US, O=foo, CN=www"]})
             tcp (port: 443, resource: {"port":443})
     Vuln attempts:
     0. ID: 3
        Vuln ID: 3
        Timestamp: 2025-11-24 12:02:34 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
     1. ID: 10
        Vuln ID: 3
        Timestamp: 2025-11-24 12:02:37 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
  3. Vuln ID: 4
     Timestamp: 2025-11-24 12:02:34 UTC
     Host: 127.0.0.1
     Name: Test Vulnerability #4 - ESC1
     References:
     Information: Module auxiliary/gather/report_vuln
     Resource: {"template":"Esc1-Template"}
     Service: ldap (port: 389, resource: {"dn":"CN=Certificate,DC=company,DC=com"})
       Parent Services:
         tcp (port: 389, resource: {"port":389})
     Vuln attempts:
     0. ID: 4
        Vuln ID: 4
        Timestamp: 2025-11-24 12:02:34 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
     1. ID: 11
        Vuln ID: 4
        Timestamp: 2025-11-24 12:02:37 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
  4. Vuln ID: 5
     Timestamp: 2025-11-24 12:02:34 UTC
     Host: 127.0.0.1
     Name: Test Vulnerability - HTTPS API
     References:
     Information: Module auxiliary/gather/report_vuln - API endpoint vulnerability
     Resource: {"path":"/users","method":"POST"}
     Service: api (port: 443, resource: {"endpoint":"/api/v1"})
       Parent Services:
         https (port: 443, resource: {"method":"GET"})
           ssl (port: 443, resource: {"cert_chain":["CN=*.foo.com","C=US, O=foo, CN=www"]})
             tcp (port: 443, resource: {"port":443})
     Vuln attempts:
     0. ID: 5
        Vuln ID: 5
        Timestamp: 2025-11-24 12:02:34 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
     1. ID: 12
        Vuln ID: 5
        Timestamp: 2025-11-24 12:02:37 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
  5. Vuln ID: 6
     Timestamp: 2025-11-24 12:02:34 UTC
     Host: 127.0.0.1
     Name: Report Vuln Project - Old Fashion
     References:
     Information: Module auxiliary/gather/report_vuln found vulnerable JBoss Seam 2 resource.
     Resource: {}
     Service: http (port: 80, resource: {"method":"GET"})
       Parent Services:
         tcp (port: 80, resource: {"port":80})
     Vuln attempts:
     0. ID: 6
        Vuln ID: 6
        Timestamp: 2025-11-24 12:02:34 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
     1. ID: 13
        Vuln ID: 6
        Timestamp: 2025-11-24 12:02:37 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
  6. Vuln ID: 7
     Timestamp: 2025-11-24 12:02:35 UTC
     Host: 127.0.0.1
     Name: CA Allows Write Privileges
     References: URL-https://example.com
     Information: Certificate Authority allows unauthorized write access
     Resource: {"CA":"msflab-DC-CA"}
     Service: ad cs (port: 445, resource: {})
       Parent Services:
         dcerpc (port: 445, resource: {"named_pipe":"icpr"})
           smb (port: 445, resource: {"share":"IPC$"})
             tcp (port: 445, resource: {"port":445})
     Vuln attempts:
     0. ID: 7
        Vuln ID: 7
        Timestamp: 2025-11-24 12:02:35 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
     1. ID: 14
        Vuln ID: 7
        Timestamp: 2025-11-24 12:02:37 UTC
        Exploit:
        Fail reason: Untried
        Username: unknown
        Module: auxiliary/gather/report_vuln
        Session ID: nil
        Loot ID: nil
        Fail Detail: vulnerability identified
msf auxiliary(gather/report_vuln) >

Verify the service has been reported with the services command

services

image

@cgranleese-r7
Copy link
Contributor

cgranleese-r7 commented Nov 25, 2025

Will hold off on landing this until the following is resolved.
cdelafuente-r7#4 (comment)

@cgranleese-r7
Copy link
Contributor

cgranleese-r7 commented Nov 26, 2025

I also tested the db_import and db_export command.

  1. I reinitialized the db on master
  2. Got some vulns and services and then exported those via db_export
  3. I reinitialized the db on this branch
  4. Imported the file via db_import

Everything seems to be backwards compatible and worked as expected:

msf auxiliary(gather/report_vuln) > db_import master_db_export.xml
[*] Importing 'Metasploit XML' data
[*] Importing host 127.0.0.1
[*] Successfully imported /Users/cgranleese/code/metasploit-framework/master_db_export.xml
msf auxiliary(gather/report_vuln) > vulns

Vulnerabilities
===============

Timestamp                Host       Service  Resource  Name                               References
---------                ----       -------  --------  ----                               ----------
2025-11-26 12:49:40 UTC  127.0.0.1  None     {}        Report Vuln Project - Old Fashion

msf auxiliary(gather/report_vuln) > services
Services
========

host       port  proto  name  state  info                                                                  resource  parents
----       ----  -----  ----  -----  ----                                                                  --------  -------
127.0.0.1  80    tcp                                                                                       {}
127.0.0.1  389   tcp    ldap  open   report service with a new resource: should create a new LDAP service  {}
127.0.0.1  5060  tcp    sip   open   report service without resource                                       {}

msf auxiliary(gather/report_vuln) >

@cdelafuente-r7
Copy link
Contributor Author

The last commit (d9d4e6d) fixes a bug found by @smcintyre-r7 (see cdelafuente-r7#4 (comment)).

The issue was that deleting a service automatically delete its children via dependent: :destroy on the association. The delete_service was trying to delete services that were already deleted.

@cgranleese-r7
Copy link
Contributor

cgranleese-r7 commented Dec 10, 2025

Everything seems to be working as intended. The previous issue has also been fixed and services can now be deleted in bulk:

msf auxiliary(gather/report_vuln) > services -d
Services
========

host       port  proto  name      state  info                                                               resource                                         parents
----       ----  -----  ----      -----  ----                                                               --------                                         -------
127.0.0.1  5060  tcp    sip       open   report service without resource                                    {}
127.0.0.1  80    tcp    mycms     open                                                                      {"base_url":"/mycms"}                            http (80/tcp)
127.0.0.1  80    tcp    http      open                                                                      {"method":"GET"}                                 tcp (80/tcp)
127.0.0.1  80    tcp    tcp       open                                                                      {"port":80}
127.0.0.1  389   tcp    tcp       open                                                                      {"port":389}
127.0.0.1  389   tcp    ldap      open   report service without resource: should pick the already register  {"dn":"CN=Certificate,DC=company,DC=com"}        tcp (389/tcp)
                                         ed LDAP service
127.0.0.1  389   tcp    ldap      open   report service with a new resource: should create a new LDAP serv  {"dn":"CN=Foo,DC=anothercompany,DC=com"}
                                         ice
127.0.0.1  443   tcp    tcp       open                                                                      {"port":443}
127.0.0.1  443   tcp    api       open                                                                      {"endpoint":"/api/v1"}                           https (443/tcp)
127.0.0.1  443   tcp    https     open                                                                      {"method":"GET"}                                 ssl (443/tcp)
127.0.0.1  443   tcp    ssl       open                                                                      {"cert_chain":["CN=*.foo.com","C=US, O=foo, CN=  tcp (443/tcp)
                                                                                                            www"]}
127.0.0.1  445   tcp    dcerpc    open                                                                      {"named_pipe":"icpr"}                            smb (445/tcp)
127.0.0.1  445   tcp    ad cs     open                                                                      {}                                               dcerpc (445/tcp)
127.0.0.1  445   tcp    tcp       open                                                                      {"port":445}
127.0.0.1  445   tcp    smb       open                                                                      {"share":"IPC$"}                                 tcp (445/tcp)
127.0.0.1  80    tcp    othercms  open                                                                      {"base_url":"/othercms"}                         http (80/tcp), https (443/tcp)

[*] Deleted 10 services
msf auxiliary(gather/report_vuln) > services
Services
========

host  port  proto  name  state  info  resource  parents
----  ----  -----  ----  -----  ----  --------  -------

msf auxiliary(gather/report_vuln) >

@cgranleese-r7 cgranleese-r7 added the rn-enhancement release notes enhancement label Dec 10, 2025
@cgranleese-r7
Copy link
Contributor

Release Notes

Updates how vulnerabilities and services are reported by adding a resource field to both models. It also add a parents field to make layered services possible. An optional resource field can now be provided and the existing service field has been updated to also accept an option hash.

@cdelafuente-r7 cdelafuente-r7 force-pushed the enh/MS-9930/vuln_report branch from a29034f to baeb61f Compare December 12, 2025 16:11
cdelafuente-r7 and others added 5 commits December 15, 2025 12:36
- update `#report_service` and `#report_vuln`
- update vulnerability report when a session is established
- update CheckCode and `#cmd_check` to report a vulnerability when
  Vulnerable checkcode is returned
- update `vulns` and `services` commands to display the `resource` and
  parent services
- specs
@cdelafuente-r7 cdelafuente-r7 force-pushed the enh/MS-9930/vuln_report branch from baeb61f to fbea976 Compare December 15, 2025 11:36
@cgranleese-r7
Copy link
Contributor

CI failures unrelated to these changes.

@cgranleese-r7 cgranleese-r7 merged commit 3936fc7 into rapid7:master Dec 15, 2025
60 of 61 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in Metasploit Kanban Dec 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement rn-enhancement release notes enhancement

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

5 participants