Skip to content
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

Implement the zeitwerk autoloader within lib/msf/core #14202

Merged
merged 2 commits into from Dec 8, 2020

Conversation

dwelch-r7
Copy link
Contributor

You can check out what zeitwerk is what it does and how it works here: https://github.com/fxn/zeitwerk

This is the first in a series of PRs that will have us transition to using the zeitwerk autoloader.
The main goal of this effort is to reduce boot up times of msfconsole/msfvenom but it also has added benefits of enforcing consistent organization fo the code and will allow us to hopefully transition to rails 6 and it's built in use of zeitwerk

This first PR tackles the lib/msf/core folder, a vast majority of requires which reference this path are being removed and the entire folder is being managed by zeitwerk so any constants referenced that live in this folder will be loaded when needed. Testing locally on Ubuntu this resulted in a 0.7s boot time reduction with more gains expected as this effort continues.

Future PRs will follow a similar pattern to this one targeting a subsection of the library folders until as much as we can reasonably manage with zeitwerk is done.

More work and testing still needs done with this PR (for example deleting rather than commenting out the requires), all entry points (msfconsole, msfvenom, msfdb, etc.) all need to be tested and working too.

Opening this up as a draft to get some eyes on it and let the tests run through

@bwatters-r7
Copy link
Contributor

bwatters-r7 commented Oct 1, 2020

Sanity test failures:
image

Looks like the https handlers are failing:

resource (/home/msfuser/rapid7/test_artifacts/test_rc/linux-x64-meterpreter_reverse_https-192x168x16x127-30002.rc)> run -z
[-] Handler failed to bind to 192.168.15.71:30002
[-] Handler failed to bind to 0.0.0.0:30002
[-] Exploit failed: NameError uninitialized constant Rex::ServiceManager
[*] Exploit completed, but no session was created.
[*] resource (/home/msfuser/rapid7/test_artifacts/test_rc/linux-x64-meterpreter_reverse_https-192x168x16x127-30002.rc)> Ruby Code (82 bytes)

@dwelch-r7
Copy link
Contributor Author

@msjenkins-r7 test this please

2 similar comments
@bwatters-r7
Copy link
Contributor

@msjenkins-r7 test this please

@dwelch-r7
Copy link
Contributor Author

@msjenkins-r7 test this please

@dwelch-r7 dwelch-r7 force-pushed the zeitwork-msf-core-only branch 2 times, most recently from 81d737a to 333c035 Compare October 14, 2020 11:14
@dwelch-r7 dwelch-r7 marked this pull request as ready for review October 14, 2020 11:21
Copy link
Contributor

@jmartin-tech jmartin-tech left a comment

Choose a reason for hiding this comment

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

This look pretty sane.

A question about class variable usage, and a question about possible file refactor change that as is stands would be a breaking change and mean this PR should bump version to 6.1.0.

Mostly whitespace comments and minor code cleanup nits.

require 'msf/core/auxiliary/web/target'

include Auxiliary::Report
include Auxiliary::Report
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
include Auxiliary::Report
include Auxiliary::Report

@@ -10,8 +10,7 @@
#
###
class Msf::Exploit::Local < Msf::Exploit
require 'msf/core/post_mixin'
include Msf::PostMixin
include Msf::PostMixin
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
include Msf::PostMixin
include Msf::PostMixin

require 'msf/core/payload'
require 'msf/core/payload/php'
include Payload::Php
include Payload::Php
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
include Payload::Php
include Payload::Php

#
###
class Exploit::Remote < Exploit
include Msf::Exploit::AutoTarget
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
include Msf::Exploit::AutoTarget
include Msf::Exploit::AutoTarget

require 'msf/core/exploit/kerberos/client/cache_credential'

include Msf::Exploit::Remote::Kerberos::Client::Base
include Msf::Exploit::Remote::Kerberos::Client::Base
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
include Msf::Exploit::Remote::Kerberos::Client::Base
include Msf::Exploit::Remote::Kerberos::Client::Base

include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HTTP::Typo3::Login
include Msf::Exploit::Remote::HTTP::Typo3::URIs
include Msf::Exploit::Remote::HttpClient
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HttpClient

include Msf::Exploit::Remote::HTTP::Wordpress::Users
include Msf::Exploit::Remote::HTTP::Wordpress::Version
include Msf::Exploit::Remote::HTTP::Wordpress::XmlRpc
include Msf::Exploit::Remote::HttpClient
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HttpClient

module Exploit::Remote::SMB::Server
module Share
module InformationLevel
end
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
end
end

require 'msf/core/exploit/smb/server/share/command/trans2/query_path_information'

# Handles an SMB_COM_TRANSACTION2 command, used to provide support for a richer set of
# Handles an SMB_COM_TRANSACTION2 command, used to provide support for a richer set of
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
# Handles an SMB_COM_TRANSACTION2 command, used to provide support for a richer set of
# Handles an SMB_COM_TRANSACTION2 command, used to provide support for a richer set of

Comment on lines 3 to 5
# autoload :ApiToken, 'msf/core/web_services/authentication/strategies/api_token'
# autoload :AdminApiToken, 'msf/core/web_services/authentication/strategies/admin_api_token'
# autoload :UserPassword, 'msf/core/web_services/authentication/strategies/user_password'
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
# autoload :ApiToken, 'msf/core/web_services/authentication/strategies/api_token'
# autoload :AdminApiToken, 'msf/core/web_services/authentication/strategies/admin_api_token'
# autoload :UserPassword, 'msf/core/web_services/authentication/strategies/user_password'

@sempervictus
Copy link
Contributor

This caught my eye because I tried to do something like this in the ancient port-to-rubinius (gil-free ruby) effort. What I learned during that process is that meddling with loader semantics can produce some really messed up objects due to our use of #extend on already instantiated objects (required for our interactions w/ stdlib FD-based objects of instance because the FD is marshalled from outside the runtime so we cant compose it proper).
I can dig for it, but the the test I wrote to check for these was something stupid simple - made arrays for #methods available for objects between the runtimes and compared them and their call returns. The more nuanced version of this is the #extend call falling into the wrong procedural step of definition because something was included on demand 1/3 of the way thru which only redefined an existing method used in the object construction with differing results. Being untyped hurts there.
Haven't pulled this PR in to take a look yet, but just a word of caution: this kind of stuff can bring multidimensional gremlins with pointy sticks. :)
Thanks for digging into this, takes a brave soul.

@dwelch-r7
Copy link
Contributor Author

@sempervictus if you could find that test I'd love to see it, anything to help with this is much appreciated 😅

@dwelch-r7 dwelch-r7 force-pushed the zeitwork-msf-core-only branch 2 times, most recently from c59a833 to 487f278 Compare November 10, 2020 13:06
@adfoster-r7
Copy link
Contributor

adfoster-r7 commented Nov 13, 2020

Looks like this introduces a regression to the verify_datastore tool:

bundle exec ./tools/modules/verify_datastore.rb ./modules/exploits/unix/http/ctek_skyrouter.rb
[-] Error including mixin: Msf::Exploit::Remote::Tcp
[-] Error including mixin: Msf::Exploit::Remote::HttpClient
bundler: failed to load command: ./tools/modules/verify_datastore.rb (./tools/modules/verify_datastore.rb)
TypeError: superclass must be a Class (NilClass given)
  /Users/user/Documents/code/metasploit-framework/tools/modules/verify_datastore.rb:77:in `<top (required)>'

It errors out trying to include the mixins with the approach that it's using. I believe the tool is broken in the first place, but this was a difference in behavior I spotted

@adfoster-r7
Copy link
Contributor

adfoster-r7 commented Nov 13, 2020

Looks like this is failing for me if I run the http scanner title module:

msf6 > use http scanner title

Matching Modules
================

   #  Name                          Disclosure Date  Rank    Check  Description
   -  ----                          ---------------  ----    -----  -----------
   0  auxiliary/scanner/http/title                   normal  No     HTTP HTML Title Tag Content Grabber


Interact with a module by name or index. For example info 0, use 0 or use auxiliary/scanner/http/title

[*] Using auxiliary/scanner/http/title
msf6 auxiliary(scanner/http/title) > set rhosts_http_url http://example.com
rhosts_http_url => http://example.com
msf6 auxiliary(scanner/http/title) > run
[-] Auxiliary failed: NameError uninitialized constant Msf::OptionContainer::OptionValidateError
[-] Call stack:
[-]   /Users/adfoster/Documents/code/metasploit-framework/lib/msf/core/option_container.rb:217:in `validate'

Edit: Looks like this isn't specific to the scanner module:

use scanner/smb/smb_ms17_010
run
[-] Auxiliary failed: NameError uninitialized constant Msf::OptionContainer::OptionValidateError
[-] Call stack:
[-]   /Users/adfoster/Documents/code/metasploit-framework/lib/msf/core/option_container.rb:217:in `validate'

@adfoster-r7
Copy link
Contributor

adfoster-r7 commented Nov 13, 2020

Noticed another failure with:

use scanner/smb/smb_ms17_010
reload

Which gives:

[*] Reloading module...
[-] Failed to reload: uninitialized constant Msf::Encoding::UTF_8

Edit: Looks like you can get a stack trace with rerun:

msf6 auxiliary(scanner/smb/smb_ms17_010) > rerun
[*] Reloading module...
[-] Error while running command rerun: uninitialized constant Msf::Encoding::UTF_8

Call stack:
/Users/adfoster/Documents/code/metasploit-framework/lib/msf/core/modules/metadata/obj.rb:108:in `initialize'
/Users/adfoster/Documents/code/metasploit-framework/lib/msf/core/modules/metadata/cache.rb:127:in `new'
/Users/adfoster/Documents/code/metasploit-framework/lib/msf/core/modules/metadata/cache.rb:127:in `refresh_metadata_instance_internal'
/Users/adfoster/Documents/code/metasploit-framework/lib/msf/core/modules/metadata/cache.rb:24:in `block in refresh_metadata_instance'
/Users/adfoster/Documents/code/metasploit-framework/lib/msf/core/modules/metadata/cache.rb:22:in `synchronize'
/Users/adfoster/Documents/code/metasploit-framework/lib/msf/core/modules/metadata/cache.rb:22:in `refresh_metadata_instance'
/Users/adfoster/Documents/code/metasploit-framework/lib/msf/core/module_manager/cache.rb:111:in `refresh_cache_from_module_files'
/Users/adfoster/Documents/code/metasploit-framework/lib/msf/core/modules/loader/base.rb:322:in `reload_module'
/Users/adfoster/Documents/code/metasploit-framework/lib/msf/core/module_manager/reloading.rb:25:in `reload_module'
/Users/adfoster/Documents/code/metasploit-framework/lib/msf/ui/console/module_command_dispatcher.rb:308:in `reload'
/Users/adfoster/Documents/code/metasploit-framework/lib/msf/ui/console/command_dispatcher/auxiliary.rb:227:in `cmd_rerun'
/Users/adfoster/Documents/code/metasploit-framework/lib/rex/ui/text/dispatcher_shell.rb:525:in `run_command'
/Users/adfoster/Documents/code/metasploit-framework/lib/rex/ui/text/dispatcher_shell.rb:476:in `block in run_single'
/Users/adfoster/Documents/code/metasploit-framework/lib/rex/ui/text/dispatcher_shell.rb:470:in `each'
/Users/adfoster/Documents/code/metasploit-framework/lib/rex/ui/text/dispatcher_shell.rb:470:in `run_single'
/Users/adfoster/Documents/code/metasploit-framework/lib/rex/ui/text/shell.rb:158:in `run'
/Users/adfoster/Documents/code/metasploit-framework/lib/metasploit/framework/command/console.rb:48:in `start'
/Users/adfoster/Documents/code/metasploit-framework/lib/metasploit/framework/command/base.rb:82:in `start'
/Users/adfoster/Documents/code/metasploit-framework/msfconsole:23:in `<top (required)>'
/Users/adfoster/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/bundler/cli/exec.rb:63:in `load'
/Users/adfoster/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/bundler/cli/exec.rb:63:in `kernel_load'
/Users/adfoster/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/bundler/cli/exec.rb:28:in `run'
/Users/adfoster/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/bundler/cli.rb:476:in `exec'
/Users/adfoster/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
/Users/adfoster/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
/Users/adfoster/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/bundler/vendor/thor/lib/thor.rb:399:in `dispatch'
/Users/adfoster/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/bundler/cli.rb:30:in `dispatch'
/Users/adfoster/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/bundler/vendor/thor/lib/thor/base.rb:476:in `start'
/Users/adfoster/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/bundler/cli.rb:24:in `start'
/Users/adfoster/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/libexec/bundle:46:in `block in <top (required)>'
/Users/adfoster/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/bundler/friendly_errors.rb:123:in `with_friendly_errors'
/Users/adfoster/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/libexec/bundle:34:in `<top (required)>'
/Users/adfoster/.rvm/rubies/ruby-2.7.2/bin/bundle:23:in `load'
/Users/adfoster/.rvm/rubies/ruby-2.7.2/bin/bundle:23:in `<main>'
/Users/adfoster/.rvm/gems/ruby-2.7.2@metasploit-framework/bin/ruby_executable_hooks:24:in `eval'
/Users/adfoster/.rvm/gems/ruby-2.7.2@metasploit-framework/bin/ruby_executable_hooks:24:in `<main>'

Should be an easy Encoding::UTF_8 -> ::Encoding::UTF_8 fix I believe. Maybe worth a quick grep to see that there's no other places that need updated too.

@dwelch-r7
Copy link
Contributor Author

./tools/modules/verify_datastore.rb ./modules/exploits/unix/http/ctek_skyrouter.rb

I imagine this is just completely broken like you said, it's regex for a class is:

regex[:class] = /^[\s]*class[\s]+Metasploit3[\s]*<[\s]*([A-Z][^\s]+)/

hasn't been that in a long time 😬

@adfoster-r7
Copy link
Contributor

Looks like I can't upgrade sessions:

use scanner/ssh/ssh_login
run rhosts=x.x.x.x username=xxxx password=xxxx
sessions -u 1
[*] Executing 'post/multi/manage/shell_to_meterpreter' on session(s): [1]

[*] Upgrading session ID: 1
[*] Starting exploit/multi/handler
[*] Started reverse TCP handler on x.x.x.x:4433 
[-] Post failed: NameError uninitialized constant Rex::Exploitation::CmdStagerBourne
[-] Call stack:
[-]   /Users/adfoster/Documents/code/metasploit-framework/modules/post/multi/manage/shell_to_meterpreter.rb:208:in `transmit_payload'
[-]   /Users/adfoster/Documents/code/metasploit-framework/modules/post/multi/manage/shell_to_meterpreter.rb:175:in `run'

@adfoster-r7
Copy link
Contributor

Can't upgrade osx meterpreter from python either:

msf6 payload(cmd/unix/reverse_python) > sessions -u 1
[*] Executing 'post/multi/manage/shell_to_meterpreter' on session(s): [1]

[*] Upgrading session ID: 1
[-] Post failed: NameError uninitialized constant Msf::Module::Platform::Osx
[-] Call stack:
[-]   /Users/adfoster/Documents/code/metasploit-framework/modules/post/multi/manage/shell_to_meterpreter.rb:104:in `run'

@adfoster-r7
Copy link
Contributor

Running through the jsofu tool breaks:

$ bundle exec ruby tools/exploit/jsobfu.rb -p alert -i /tmp/js.js
Traceback (most recent call last):
	1: from tools/exploit/jsobfu.rb:116:in `<main>'
tools/exploit/jsobfu.rb:77:in `run': uninitialized constant Rex::Exploitation::JSObfu (NameError)

Replication steps: #6511

@adfoster-r7
Copy link
Contributor

I've ran through a few workflows, and any issues I've come across have been fixed now.

@jmartin-r7 / @acammack-r7 Are there any critical paths that you'd like us to test through before this is landed? Either from Metasploit framework's perspective or Pro

:wmap_generic
end
end
end
Copy link
Contributor

Choose a reason for hiding this comment

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

nab: It might be nice to fix up missing trailing whitespace/remove the extra whitespace added to the top of the file 👍

require 'msf/core/exploit/smb/server/share/information_level'

include Msf::Exploit::Remote::SMB::Server::Share::Command::Close
include Msf::Exploit::Remote::SMB::Server::Share::Command::Close
Copy link
Contributor

Choose a reason for hiding this comment

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

Indentation issue

end
end
end
end
Copy link
Contributor

Choose a reason for hiding this comment

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

Indentation issue

@adfoster-r7
Copy link
Contributor

@dwelch-r7 I was poking at the zeitwerk testing again, and I extracted all of referenced constants in framework and spot-checked a few, and and hit some failures on this branch:

# NameError (uninitialized constant Msf::Payload::Php::MeterpreterLoader)
# modules/payloads/stages/multi/meterpreter.rb
c.include(::Msf::Payload::Php::MeterpreterLoader)
    when 'windows'
# NameError (uninitialized constant Mdm::HostDetails)
# NameError (uninitialized constant Mdm::VulnDetails)
# lib/rex/parser/nokogiri_doc_mixin.rb

when :vuln_details
::Mdm::VulnDetails.new.attribute_names.map {|x| x.to_sym} | [ :key ]
when :host_details
::Mdm::HostDetails.new.attribute_names.map {|x| x.to_sym} | [ :key ]

I don't know if these are already a problem on master, but worth cross checking that 😄

@dwelch-r7
Copy link
Contributor Author

@adfoster-r7 Those super just don't exist on master by the looks of it, not just that they aren't being required properly but they aren't defined anywhere from a quick look

@dwelch-r7 dwelch-r7 force-pushed the zeitwork-msf-core-only branch 3 times, most recently from 0138e85 to 4cbdb3d Compare November 17, 2020 09:29
@@ -21,7 +20,7 @@ module Exception
# can be obtained through the options attribute.
#
###
class OptionValidateError < ArgumentError
class Msf::OptionValidateError < ArgumentError
Copy link
Contributor

Choose a reason for hiding this comment

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

Just confirming if this is needed?

Suggested change
class Msf::OptionValidateError < ArgumentError
class OptionValidateError < ArgumentError

# framework events occur, such as the loading and creation of a module.
#
###
module GeneralEventSubscriber
Copy link
Contributor

Choose a reason for hiding this comment

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

nab: It looks like this could be namespaced, as it's an internal concept

loader.push_dir("#{__dir__}/msf/core/", namespace: Msf)
loader.push_dir("#{__dir__}/../app/validators/")

loader.ignore("#{__dir__}/msf/core/constants.rb", "#{__dir__}/msf/core/cert_provider.rb", "#{__dir__}/msf/core/rpc/json/error.rb", "#{__dir__}/msf/core/rpc/json/v2_0/", "#{__dir__}/msf/core/modules/external/ruby/metasploit.rb", "#{__dir__}/msf/core/rpc/v10/constants.rb")
Copy link
Contributor

Choose a reason for hiding this comment

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

If we split this on to new lines, it'll make future reviews easier when new items are added to this list 👍

loader.ignore(
  "#{__dir__}/msf/core/constants.rb",
  "#{__dir__}/msf/core/cert_provider.rb",
   # ...
)

loader.push_dir("#{__dir__}/../app/validators/")

loader.ignore("#{__dir__}/msf/core/constants.rb", "#{__dir__}/msf/core/cert_provider.rb", "#{__dir__}/msf/core/rpc/json/error.rb", "#{__dir__}/msf/core/rpc/json/v2_0/", "#{__dir__}/msf/core/modules/external/ruby/metasploit.rb", "#{__dir__}/msf/core/rpc/v10/constants.rb")
loader.collapse("#{__dir__}/msf/core", "#{__dir__}/msf/core/rpc/v10", "#{__dir__}/msf/core/payload/osx/x64", "#{__dir__}/msf/core/payload/windows/x64", "#{__dir__}/msf/core/payload/linux/x64", "#{__dir__}/msf/core/web_services/servlet")
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above 👍

@@ -0,0 +1,167 @@
require "zeitwerk"

Copy link
Contributor

Choose a reason for hiding this comment

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

If we're treating this file as all of the things we need to fix with namespacing at some point; What are your thoughts on keeping track of the other files we want to fix later as comments? i.e. namespacing wmap/events properly. At the very least it won't be lost in a ticket

@dwelch-r7 dwelch-r7 force-pushed the zeitwork-msf-core-only branch 2 times, most recently from 3e1181d to e02dda4 Compare November 18, 2020 10:43
@adfoster-r7 adfoster-r7 merged commit 85a9acc into rapid7:master Dec 8, 2020
@adfoster-r7
Copy link
Contributor

adfoster-r7 commented Dec 8, 2020

Release Notes

Updated Metasploit to only load core library files when they are explicitly required. Previously, all core library files would be loaded eagerly on console start up. This initial work will reduce console start up time by around 0.5 seconds. Future releases will build upon this initial effort of lazily loading internal library files to further improve both the console and msfvenom's startup performance.

@busterb
Copy link
Member

busterb commented Dec 9, 2020

Absolutely adore this (and the speedup), thanks a lot!

wvu added a commit to wvu/metasploit-framework that referenced this pull request Dec 9, 2020
wvu added a commit to wvu/metasploit-framework that referenced this pull request Dec 9, 2020
@wvu
Copy link
Contributor

wvu commented Dec 9, 2020

Awesome job! Fixed on my end to work with #14446's refactor of Msf::Exploit::Remote::SSH.

@dwelch-r7 dwelch-r7 deleted the zeitwork-msf-core-only branch December 10, 2020 10:54
jmartin-tech added a commit to jmartin-tech/metasploit-framework that referenced this pull request Dec 21, 2020
…or lib/msf/core"

This reverts commit 85a9acc, reversing
changes made to 384e99f.
@dwelch-r7 dwelch-r7 mentioned this pull request Jan 18, 2021
17 tasks
@dwelch-r7 dwelch-r7 mentioned this pull request Feb 1, 2021
20 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
library rn-enhancement release notes enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants