Skip to content

RHOSTS implementation in external exploit modules inconsistent with other modules #13061

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
un1c0rn-sec opened this issue Mar 11, 2020 · 4 comments
Labels
external modules PRs dealing with modules run as their own process Stale Marks an issue as stale, to be closed if no action is taken usability Usability improvements

Comments

@un1c0rn-sec
Copy link

un1c0rn-sec commented Mar 11, 2020

Problem

MSF5 added the use of RHOSTS functionality to exploit modules, expanding upon its use in auxiliary modules.

The implementation of RHOSTS in an external exploit module is inconsistent with the way it is implemented in other modules, including external auxiliary modules, leading to confusion in module development and broken functionality within MSF.

RHOSTS in Auxiliary modules:

Implementation in module code (example taken from an external python module):

Option definition as metadata, note type and name:

'rhost': {'type': 'address', 'description': 'Target address', 'required': True, 'default': None}

Use of the rhost argument in code:

session = function_here(username, password, args['rhost'])

When multiple IPs (space-delimited or CIDR or a range) are supplied to the module within MSF as the RHOSTS option, the module processes them individually. (This behavior has been in MSF for a while)

   Name     Current Setting                  Required  Description
   ----     ---------------                  --------  -----------
   RHOSTS   192.168.189.177 192.168.189.188  yes       The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'

You are also able to populate RHOSTS within MSF using the database with the -R flag. This puts the results of your database search in RHOSTS as a space-delimited list.

RHOSTS in External Exploit Modules:

Implementation in module code (example taken from an external python module):

Option definition as metadata (again note name and type):

'RHOSTS': {'type': 'AddressRange', 'description': 'Target address', 'required': True, 'default': None}'

Use of the RHOST argument in code to access just one member of the list of RHOSTS:

system = args['RHOST']

MSF requires multiple IPs in RHOSTS within an external exploit to be supplied as a comma-space-delimited list:

Module options (exploit/linux/my_exploit):
   Name            Current Setting                   Required  Description
   ----            ---------------                   --------  -----------
   RHOSTS          192.168.189.177, 192.168.189.188  yes       Target address

Anything else causes errors:

msf5 exploit(linux/my_exploit) > set RHOSTS 192.168.189.177 192.168.189.188
[-] The following options failed to validate: Value '192.168.189.177 192.168.189.188' is not valid for option 'RHOSTS'.

You are also unable to populate RHOSTS via the database:

Credentials
===========

host             origin           service   public           private          realm  private_type  JtR Format
----             ------           -------   ------           -------          -----  ------------  ----------
192.168.189.177 ** CREDENTIALS REDACTED **
192.168.189.188 ** CREDENTIALS REDACTED **
[-] Error while running command creds: The following options failed to validate: Value '192.168.189.177 192.168.189.188' is not valid for option 'RHOSTS'.
Call stack:
/usr/share/metasploit-framework/lib/msf/core/data_store.rb:40:in `[]='
/usr/share/metasploit-framework/lib/msf/ui/console/command_dispatcher/common.rb:96:in `set_rhosts_from_addrs'
/usr/share/metasploit-framework/lib/msf/ui/console/command_dispatcher/creds.rb:582:in `creds_search'
/usr/share/metasploit-framework/lib/msf/ui/console/command_dispatcher/creds.rb:113:in `cmd_creds'
/usr/share/metasploit-framework/lib/rex/ui/text/dispatcher_shell.rb:523:in `run_command'
/usr/share/metasploit-framework/lib/rex/ui/text/dispatcher_shell.rb:474:in `block in run_single'
/usr/share/metasploit-framework/lib/rex/ui/text/dispatcher_shell.rb:468:in `each'
/usr/share/metasploit-framework/lib/rex/ui/text/dispatcher_shell.rb:468:in `run_single'
/usr/share/metasploit-framework/lib/rex/ui/text/shell.rb:158:in `run'
/usr/share/metasploit-framework/lib/metasploit/framework/command/console.rb:48:in `start'
/usr/share/metasploit-framework/lib/metasploit/framework/command/base.rb:82:in `start'
/usr/bin/msfconsole:49:in `<main>'

Expected Behavior:

  1. RHOSTS implementation should be consistent across all module types, including datatype of the option whether external or not
  2. RHOSTS in an exploit should accept the same formatting for IP ranges, lists, and CIDR as in an other modules
@Stefan-mcp
Copy link

does this effectively break the setg option when doing an aux scan followed by exploit against multiple hosts?

@un1c0rn-sec
Copy link
Author

While looking into the question posed by @Stefan-mcp, I noticed an error in my submission. If you define your option in the exploit metadata as an address type, as you would in an aux module, everything breaks as I described.

In an auxiliary module, if you define your rhost option as

'rhost': {'type': 'address', 'description': 'Target address', 'required': True, 'default': None},

You get an option of

RHOSTS        yes       The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'

in the console.

In an exploit module, if you define your rhost option the same way your results differ:

   Name            Current Setting  Required  Description
   ----            ---------------  --------  -----------
   rhost                            yes       Target address

This behavior should be consistent across module types.

If you use AddressRange (as opposed to address) addresses can be set as intended, including setting RHOSTS from the db commands (creds, hosts, services, etc.) and setg, with the exception of how the option is described in the options menu. That still does not show the same behavior as in an aux module.

Using the global datastore, with the space-delimited format and the RHOSTS option type being address breaks in a different way:

Global
======

  Name    Value
  ----    -----
  RHOSTS  192.168.189.177 192.168.189.188

Module options (exploit/linux/my_exploit):

   Name            Current Setting                  Required  Description
   ----            ---------------                  --------  -----------
   RHOSTS          192.168.189.177 192.168.189.188  yes       Target address

...

[*] Exploiting target 192.168.189.177

[-] Exploit failed: The following options failed to validate: RHOSTS.
[*] Exploiting target 192.168.189.188
[-] Exploit failed: The following options failed to validate: RHOSTS.
[*] Exploit completed, but no session was created.

Adding to the issue with the inconsistency of RHOSTS in an aux module vs. an external one, if your exploit does not explicitly define the RHOSTS option (as in the rhost example above), it does not register or use the RHOSTS value from the global datastore, whereas an aux module does.

To sum up:

  • Aux modules use RHOSTS as expected
  • External exploit modules require you to explicitly define an option named 'RHOSTS' with a type of 'AddressRange' in order to have similar functionality. If you use 'rhost' and 'address' as is common in auxiliary modules, behavior and interaction are not consistent.

Potential Fixes:

  • Update RHOSTS implementation in exploit modules to be consistent with auxiliary modules.
  • Document distinct differences in requirements for this functionality in exploit modules vs. conventions used in auxiliary modules.

@ccondon-r7 ccondon-r7 added external modules PRs dealing with modules run as their own process usability Usability improvements labels Apr 10, 2020
@github-actions
Copy link

github-actions bot commented Oct 9, 2020

Hi!

This issue has been left open with no activity for a while now.

We get a lot of issues, so we currently close issues after 60 days of inactivity. It’s been at least 30 days since the last update here.
If we missed this issue or if you want to keep it open, please reply here. You can also add the label "not stale" to keep this issue open!

As a friendly reminder: the best way to see this issue, or any other, fixed is to open a Pull Request.

@github-actions github-actions bot added the Stale Marks an issue as stale, to be closed if no action is taken label Oct 9, 2020
@github-actions
Copy link

github-actions bot commented Nov 9, 2020

Hi again!

It’s been 60 days since anything happened on this issue, so we are going to close it.
Please keep in mind that I’m only a robot, so if I’ve closed this issue in error please feel free to reopen this issue or create a new one if you need anything else.

As a friendly reminder: the best way to see this issue, or any other, fixed is to open a Pull Request.

@github-actions github-actions bot closed this as completed Nov 9, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
external modules PRs dealing with modules run as their own process Stale Marks an issue as stale, to be closed if no action is taken usability Usability improvements
Projects
None yet
Development

No branches or pull requests

3 participants