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.
  • 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: '[email protected]: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 2 times, most recently from 752d418 to 46d565c Compare August 19, 2025 14:27
- 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 46d565c to 2df584b Compare August 19, 2025 15:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants